"
dat += "General Settings"
- dat += "Fancy NanoUI: [(nanoui_fancy) ? "Yes" : "No"] "
- dat += "Ghost-Item Attack Animation: [(show_ghostitem_attack) ? "Yes" : "No"] "
- dat += "Window Flashing: [(windowflashing) ? "Yes" : "No"] "
- dat += "Custom UI settings: "
- dat += " - UI Style: [UI_style] "
- dat += " - Color: [UI_style_color] "
- dat += " - Alpha (transparency): [UI_style_alpha] "
- dat += " "
- dat += "Play admin midis: [(sound & SOUND_MIDI) ? "Yes" : "No"] "
- dat += "Play lobby music: [(sound & SOUND_LOBBY) ? "Yes" : "No"] "
+ dat += "Attack Animations: [(show_ghostitem_attack) ? "Yes" : "No"] "
if(user.client.holder)
- dat += "Adminhelp sound: "
- dat += "[(sound & SOUND_ADMINHELP)?"On":"Off"] "
-
- if(check_rights(R_ADMIN,0))
- dat += "OOC: Change "
- if(config.allow_Metadata)
- dat += "OOC notes: Edit "
+ dat += "Adminhelp sound: [(sound & SOUND_ADMINHELP)?"On":"Off"] "
if(unlock_content)
dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"] "
+ dat += "Custom UI settings: "
+ dat += " - Alpha (transparency): [UI_style_alpha] "
+ dat += " - Color: [UI_style_color] "
+ dat += " - UI Style: [UI_style] "
+ dat += "Deadchat Anonymity: [ghost_anonsay ? "Anonymous" : "Not Anonymous"] "
if(user.client.donator_level >= DONATOR_LEVEL_ONE)
dat += "Donator Publicity: [(toggles & DONATOR_PUBLIC) ? "Public" : "Hidden"] "
-
- dat += "Randomized character slot: [randomslot ? "Yes" : "No"] "
- dat += "Ghost ears: [(toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"] "
- dat += "Ghost sight: [(toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"] "
- dat += "Ghost radio: [(toggles & CHAT_GHOSTRADIO) ? "All Chatter" : "Nearest Speakers"] "
- dat += "Deadchat anonymity: [ghost_anonsay ? "Anonymous" : "Not Anonymous"] "
+ dat += "Fancy NanoUI: [(nanoui_fancy) ? "Yes" : "No"] "
dat += "FPS: [clientfps] "
+ dat += "Ghost Ears: [(toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"] "
+ dat += "Ghost Sight: [(toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"] "
+ dat += "Ghost Radio: [(toggles & CHAT_GHOSTRADIO) ? "All Chatter" : "Nearest Speakers"] "
+ if(check_rights(R_ADMIN,0))
+ dat += "OOC Color: Change "
+ if(config.allow_Metadata)
+ dat += "OOC Notes: Edit "
+ dat += "Play Admin MIDIs: [(sound & SOUND_MIDI) ? "Yes" : "No"] "
+ dat += "Play Lobby Music: [(sound & SOUND_LOBBY) ? "Yes" : "No"] "
+ dat += "Randomized Character Slot: [randomslot ? "Yes" : "No"] "
+ dat += "Window Flashing: [(windowflashing) ? "Yes" : "No"] "
+ // RIGHT SIDE OF THE PAGE
dat += " | "
dat += "Special Role Settings"
if(jobban_isbanned(user, "Syndicate"))
@@ -554,7 +552,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts
dat += "Reset Setup"
dat += ""
- var/datum/browser/popup = new(user, "preferences", "Character Setup ", 820, 640)
+ var/datum/browser/popup = new(user, "preferences", "Character Setup ", 820, 660)
popup.set_content(dat)
popup.open(0)
diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm
index f5bfb392c70..b355d921016 100644
--- a/code/modules/client/preference/preferences_mysql.dm
+++ b/code/modules/client/preference/preferences_mysql.dm
@@ -55,7 +55,7 @@
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
UI_style = sanitize_inlist(UI_style, list("White", "Midnight"), initial(UI_style))
default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot))
- toggles = sanitize_integer(toggles, 0, 1048575, initial(toggles))
+ toggles = sanitize_integer(toggles, 0, 2097151, initial(toggles))
sound = sanitize_integer(sound, 0, 65535, initial(sound))
UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color))
UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha))
diff --git a/code/modules/client/preference/preferences_toggles.dm b/code/modules/client/preference/preferences_toggles.dm
index 307f018f73c..703de37468e 100644
--- a/code/modules/client/preference/preferences_toggles.dm
+++ b/code/modules/client/preference/preferences_toggles.dm
@@ -224,10 +224,22 @@
set name = "Toggle Karma Gains"
set category = "Special Verbs"
set desc = "This button will allow you to stop other people giving you karma."
- if (prefs.toggles & DISABLE_KARMA)
+ prefs.toggles ^= DISABLE_KARMA
+ prefs.save_preferences(src)
+ if(prefs.toggles & DISABLE_KARMA)
to_chat(usr, "You have disabled karma gains.")
else
to_chat(usr, "You have enabled karma gains.")
- prefs.toggles ^= DISABLE_KARMA
- prefs.save_preferences(src)
+ return
+
+/client/verb/toggle_popup_limiter()
+ set name = "Toggle Text Popup Limiter"
+ set category = "Preferences"
+ set desc = "Will let you limit the text input popups to one at a time."
+ prefs.toggles ^= TYPING_ONCE
+ prefs.save_preferences(src)
+ if(prefs.toggles & TYPING_ONCE)
+ to_chat(usr, "You have enabled text popup limiting.")
+ else
+ to_chat(usr, "You have disabled text popup limiting.")
return
diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm
index 35c5243de64..b527bb2717d 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -532,6 +532,10 @@
actions_types = list(/datum/action/item_action/toggle)
up = 0
tint = 0
+ species_fit = list("Vox")
+ sprite_sheets = list(
+ "Vox" = 'icons/mob/species/vox/eyes.dmi'
+ )
/obj/item/clothing/glasses/tajblind/eng
name = "industrial veil"
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index fb4f3736d6c..d778ea5e63a 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -165,6 +165,10 @@
flags_cover = GLASSESCOVERSEYES
actions_types = list(/datum/action/item_action/toggle)
up = 0
+ species_fit = list("Vox")
+ sprite_sheets = list(
+ "Vox" = 'icons/mob/species/vox/eyes.dmi'
+ )
/obj/item/clothing/glasses/hud/security/tajblind/attack_self()
toggle_veil()
@@ -177,6 +181,10 @@
flags_cover = GLASSESCOVERSEYES
actions_types = list(/datum/action/item_action/toggle)
up = 0
+ species_fit = list("Vox")
+ sprite_sheets = list(
+ "Vox" = 'icons/mob/species/vox/eyes.dmi'
+ )
/obj/item/clothing/glasses/hud/health/tajblind/attack_self()
toggle_veil()
diff --git a/code/modules/clothing/gloves/rings.dm b/code/modules/clothing/gloves/rings.dm
index 590efa7cd91..9a512ca2cd5 100644
--- a/code/modules/clothing/gloves/rings.dm
+++ b/code/modules/clothing/gloves/rings.dm
@@ -6,6 +6,7 @@
icon_state = "ironring"
item_state = ""
icon = 'icons/obj/clothing/rings.dmi'
+ var/fluff_material = FALSE //If true, will ignore the material when examining
var/material = "iron"
var/stud = 0
@@ -21,7 +22,8 @@
/obj/item/clothing/gloves/ring/examine(mob/user)
..(user)
- to_chat(user, "This one is made of [material].")
+ if(!fluff_material)
+ to_chat(user, "This one is made of [material].")
if(stud)
to_chat(user, "It is adorned with a single gem.")
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 5bc13912a04..62873252ad1 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -430,7 +430,7 @@
/obj/item/clothing/head/griffin/proc/caw()
if(cooldown < world.time - 20) // A cooldown, to stop people being jerks
- playsound(src.loc, 'sound/misc/caw.ogg', 50, 1)
+ playsound(src.loc, 'sound/creatures/caw.ogg', 50, 1)
cooldown = world.time
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index 38f54b1067a..0c4dba9ae49 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -188,7 +188,7 @@
/obj/item/clothing/mask/gas/owl_mask/proc/hoot()
if(cooldown < world.time - 35) // A cooldown, to stop people being jerks
- playsound(src.loc, 'sound/misc/hoot.ogg', 50, 1)
+ playsound(src.loc, 'sound/creatures/hoot.ogg', 50, 1)
cooldown = world.time
// ********************************************************************
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 77fcd03c7df..113720caff1 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -491,5 +491,6 @@
/obj/item/clothing/mask/cursedclown/suicide_act(mob/user)
user.visible_message("[user] gazes into the eyes of [src]. [src] gazes back!")
spawn(10)
- user.gib()
- return BRUTELOSS
+ if(user)
+ user.gib()
+ return OBLITERATION
diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm
index 4579ec45f8b..23206e8b9b3 100644
--- a/code/modules/customitems/item_defines.dm
+++ b/code/modules/customitems/item_defines.dm
@@ -154,7 +154,7 @@
/obj/item/fluff/rsik_katana/suicide_act(mob/user)
user.visible_message("[user] tries to stab [src] into [user.p_their()] stomach! Except [src] shatters! [user.p_they(TRUE)] look[user.p_s()] as if [user.p_they()] might die from the shame.")
- return(BRUTELOSS)
+ return BRUTELOSS
/obj/item/crowbar/fluff/zelda_creedy_1 // Zomgponies: Griffin Rowley
name = "Zelda's Crowbar"
@@ -1156,9 +1156,19 @@
icon = 'icons/obj/custom_items.dmi'
icon_state = "shesicoat"
item_state = "shesicoat"
+ hoodtype = /obj/item/clothing/head/hood/fluff/shesi
body_parts_covered = UPPER_TORSO|LOWER_TORSO
cold_protection = UPPER_TORSO|LOWER_TORSO
+/obj/item/clothing/head/hood/fluff/shesi //MrSynnester : Shesi Skaklas
+ name = "custom made winter hood"
+ desc = "A custom made winter coat hood. Looks comfy."
+ icon = 'icons/obj/custom_items.dmi'
+ icon_state = "shesicoat_hood2"
+ body_parts_covered = HEAD
+ flags = NODROP|BLOCKHAIR
+ flags_inv = HIDEEARS
+
/obj/item/clothing/suit/jacket/dtx //AffectedArc07: DTX
name = "telecommunications bomber jacket"
desc = "Looks like something only a nerd would buy. Has a tag inside reading Property of DTX."
@@ -1683,6 +1693,14 @@
item_color = "Xann_necklace"
slot_flags = SLOT_TIE
+/obj/item/clothing/accessory/rbscarf //Rb303: Isthel Eisenwald
+ name = "Old purple scarf"
+ desc = "An old, striped purple scarf. It appears to be hand-knitted and has the name 'Isthel' written on it in bad handwriting."
+ icon = 'icons/obj/custom_items.dmi'
+ icon_state = "rbscarf"
+ item_state = "rbscarf"
+ item_color = "rbscarf"
+
/obj/item/instrument/accordion/fluff/asmer_accordion //Asmerath: Coloratura
name = "Rara's Somber Accordion"
desc = "A blue colored accordion with claw indentations on the keys made special for vulpkanins."
@@ -1734,4 +1752,25 @@
icon_state = "kiamask"
item_state = "kiamask"
item_color = "kiamask"
- species_restricted = list("Vox")
\ No newline at end of file
+ species_restricted = list("Vox")
+
+
+
+/obj/item/clothing/gloves/ring/fluff
+ name = "fluff ring"
+ desc = "Someone forgot to set this fluff item's description, notify a coder!"
+ icon = 'icons/obj/custom_items.dmi'
+ fluff_material = TRUE
+
+/obj/item/clothing/gloves/ring/fluff/update_icon()
+ return
+
+/obj/item/clothing/gloves/ring/fluff/attackby(obj/item/I as obj, mob/user as mob, params)
+ return
+
+
+
+/obj/item/clothing/gloves/ring/fluff/benjaminfallout //Benjaminfallout: Pretzel Brassheart
+ name = "Pretzel's Ring"
+ desc = "A small platinum ring with a large light blue diamond. Engraved inside the band are the words: 'To my lovely Pristine Princess. Forever yours, Savinien.'"
+ icon_state = "benjaminfallout_ring"
\ No newline at end of file
diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm
index 7ea71547123..6f23bbc5fcd 100644
--- a/code/modules/events/blob.dm
+++ b/code/modules/events/blob.dm
@@ -9,7 +9,7 @@
var/turf/T = pick(blobstart)
if(!T)
return kill()
- var/list/candidates = pollCandidates("Do you want to play as a blob?", ROLE_BLOB, 1)
+ var/list/candidates = pollCandidates("Do you want to play as a blob infested mouse?", ROLE_BLOB, 1)
if(!candidates.len)
return kill()
var/list/vents = list()
diff --git a/code/modules/events/grid_check.dm b/code/modules/events/grid_check.dm
index 8c099f22a91..d8d1f46ad9b 100644
--- a/code/modules/events/grid_check.dm
+++ b/code/modules/events/grid_check.dm
@@ -1,12 +1,18 @@
/datum/event/grid_check //NOTE: Times are measured in master controller ticks!
announceWhen = 5
-
+
/datum/event/grid_check/setup()
endWhen = rand(30,120)
/datum/event/grid_check/start()
power_failure(0)
-
+ var/sound/S = sound('sound/effects/powerloss.ogg')
+ for(var/mob/living/M in GLOB.player_list)
+ var/turf/T = get_turf(M)
+ if(!M.client || !is_station_level(T.z))
+ continue
+ SEND_SOUND(M, S)
+
/datum/event/grid_check/announce()
event_announcement.Announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Automated Grid Check", new_sound = 'sound/AI/poweroff.ogg')
diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm
index 59fbbc01e55..419bebfe2c1 100644
--- a/code/modules/events/sentience.dm
+++ b/code/modules/events/sentience.dm
@@ -33,6 +33,7 @@
SA.key = SG.key
SA.universal_speak = 1
SA.sentience_act()
+ SA.can_collar = 1
SA.maxHealth = max(SA.maxHealth + 200)
SA.melee_damage_lower = max(SA.melee_damage_lower + 15)
SA.melee_damage_upper = max(SA.melee_damage_upper + 15)
diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm
index 55e87f575b0..7d52d7cd969 100644
--- a/code/modules/events/spacevine.dm
+++ b/code/modules/events/spacevine.dm
@@ -684,6 +684,7 @@
wither()
/obj/structure/spacevine/temperature_expose(null, temp, volume)
+ ..()
var/override = 0
for(var/datum/spacevine_mutation/SM in mutations)
override += SM.process_temperature(src, temp, volume)
diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm
index b45a6882e80..9b1588e1161 100644
--- a/code/modules/events/vent_clog.dm
+++ b/code/modules/events/vent_clog.dm
@@ -29,7 +29,7 @@
R.add_reagent(pick(gunk), 50)
var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, rand(1, 2), 0, vent, 0, silent = 1)
+ smoke.set_up(R, vent, TRUE)
playsound(vent.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start(3)
qdel(R)
diff --git a/code/modules/examine/descriptions/weapons.dm b/code/modules/examine/descriptions/weapons.dm
index 98f60d01ac4..286391f1387 100644
--- a/code/modules/examine/descriptions/weapons.dm
+++ b/code/modules/examine/descriptions/weapons.dm
@@ -55,6 +55,11 @@
then click where you want to fire. After firing, you will need to pump the gun, by clicking on the gun in your hand. To reload, load more shotgun \
shells into the gun."
+/obj/item/toy/russian_revolver/trick_revolver //oh no
+ description_info = "This is a ballistic weapon. To fire the weapon, have your gun mode set to 'fire', \
+ then click where you want to fire. To reload, click the weapon in your hand to unload (if needed), then add the appropriate ammo. The description \
+ will tell you what caliber you need."
+
//*******
//*Melee*
//*******
diff --git a/code/modules/examine/examine.dm b/code/modules/examine/examine.dm
index 0956877d202..f39cb562ec8 100644
--- a/code/modules/examine/examine.dm
+++ b/code/modules/examine/examine.dm
@@ -60,12 +60,3 @@
stat(null,"[description_holders["fluff"]]") //Yellow, fluff-related text.
if(description_holders["antag"])
stat(null,"[description_holders["antag"]]") //Red, malicious antag-related text
-
-//override examinate verb to update description holders when things are examined
-/mob/examinate(atom/A as mob|obj|turf in view())
- if(..())
- return 1
-
- var/is_antag = (isAntag(src) || isobserver(src)) //ghosts don't have minds
- if(client)
- client.update_description_holders(A, is_antag)
diff --git a/code/modules/fish/fish_items.dm b/code/modules/fish/fish_items.dm
index 63a4b668930..a0882ae5df8 100644
--- a/code/modules/fish/fish_items.dm
+++ b/code/modules/fish/fish_items.dm
@@ -25,9 +25,9 @@
throw_speed = 3
throw_range = 7
- suicide_act(mob/user) //"A tiny net is a death sentence: it's a net and it's tiny!" https://www.youtube.com/watch?v=FCI9Y4VGCVw
- to_chat(viewers(user), "[user] places the [src.name] on top of [user.p_their()] head, [user.p_their()] fingers tangled in the netting! It looks like [user.p_theyre()] trying to commit suicide.")
- return(OXYLOSS)
+/obj/item/fish_net/suicide_act(mob/user) //"A tiny net is a death sentence: it's a net and it's tiny!" https://www.youtube.com/watch?v=FCI9Y4VGCVw
+ to_chat(viewers(user), "[user] places the [src.name] on top of [user.p_their()] head, [user.p_their()] fingers tangled in the netting! It looks like [user.p_theyre()] trying to commit suicide.")
+ return OXYLOSS
/obj/item/fishfood
name = "fish food can"
@@ -51,9 +51,9 @@
throw_range = 7
attack_verb = list("scrubbed", "brushed", "scraped")
- suicide_act(mob/user)
- to_chat(viewers(user), "[user] is vigorously scrubbing [user.p_them()]self raw with the [name]! It looks like [user.p_theyre()] trying to commit suicide.")
- return(BRUTELOSS|FIRELOSS)
+/obj/item/tank_brush/suicide_act(mob/user)
+ to_chat(viewers(user), "[user] is vigorously scrubbing [user.p_them()]self raw with the [name]! It looks like [user.p_theyre()] trying to commit suicide.")
+ return BRUTELOSS|FIRELOSS
//////////////////////////////////////////////
// Fish Items //
diff --git a/code/modules/flufftext/TextFilters.dm b/code/modules/flufftext/TextFilters.dm
index 7ff5a2fd0a5..02a02a6f5b2 100644
--- a/code/modules/flufftext/TextFilters.dm
+++ b/code/modules/flufftext/TextFilters.dm
@@ -64,9 +64,8 @@ proc/Ellipsis(original_msg, chance = 50)
if(chance <= 0) return "..."
if(chance >= 100) return original_msg
- var/list
- words = splittext(original_msg," ")
- new_words = list()
+ var/list/words = splittext(original_msg," ")
+ var/list/new_words = list()
var/new_msg = ""
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 2c9c2480a4b..785231a588d 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -11,6 +11,7 @@
possible_transfer_amounts = list(5,10,15,20,25,30,50)
volume = 50
burn_state = FIRE_PROOF
+ antable = FALSE
/obj/item/reagent_containers/food/drinks/New()
..()
@@ -106,17 +107,6 @@
return FALSE
-/obj/item/reagent_containers/food/drinks/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/clothing/mask/cigarette)) //ciggies are weird
- return FALSE
- if(is_hot(I))
- if(reagents)
- reagents.chem_temp += 15
- to_chat(user, "You heat [src] with [I].")
- reagents.handle_reactions()
- else
- return ..()
-
/obj/item/reagent_containers/food/drinks/examine(mob/user)
if(!..(user, 1))
return
diff --git a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
index f5bd0e8e4eb..bdc473d774e 100644
--- a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
@@ -27,7 +27,7 @@
else
..()
-/obj/item/reagent_containers/food/drinks/drinkingglass/fire_act()
+/obj/item/reagent_containers/food/drinks/drinkingglass/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
if(!reagents.total_volume)
return
..()
diff --git a/code/modules/food_and_drinks/drinks/drinks/shotglass.dm b/code/modules/food_and_drinks/drinks/drinks/shotglass.dm
index 393543b093c..cd158c70e74 100644
--- a/code/modules/food_and_drinks/drinks/drinks/shotglass.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/shotglass.dm
@@ -51,7 +51,7 @@
if(A.volume >= 5 && A.alcohol_perc >= 0.35) //Only an approximation to if something's flammable but it will do
return TRUE
-/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/fire_act(global_overlay = FALSE)
+/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = FALSE)
if(!isShotFlammable() || burn_state == ON_FIRE) //You can't light a shot that's not flammable!
return
..()
diff --git a/code/modules/food_and_drinks/food.dm b/code/modules/food_and_drinks/food.dm
index 0ecff55cba0..e931db813cf 100644
--- a/code/modules/food_and_drinks/food.dm
+++ b/code/modules/food_and_drinks/food.dm
@@ -13,10 +13,42 @@
var/transfer_efficiency = 1.0
var/instant_application = 0 //if we want to bypass the forcedfeed delay
var/taste = TRUE//whether you can taste eating from this
+ var/antable = TRUE // Will ants come near it?
+ var/ant_location = null
+ var/ant_timer = null
burn_state = FLAMMABLE
container_type = INJECTABLE
-/obj/item/reagent_containers/food/New()
- ..()
+/obj/item/reagent_containers/food/Initialize(mapload)
+ . = ..()
pixel_x = rand(-5, 5) //Randomizes postion
pixel_y = rand(-5, 5)
+ if(antable)
+ ant_location = get_turf(src)
+ ant_timer = addtimer(CALLBACK(src, .proc/check_for_ants), 3000, TIMER_STOPPABLE)
+
+/obj/item/reagent_containers/food/Destroy()
+ ant_location = null
+ if(ant_timer)
+ deltimer(ant_timer)
+ return ..()
+
+/obj/item/reagent_containers/food/proc/check_for_ants()
+ if(!antable)
+ return
+ var/turf/T = get_turf(src)
+ if(isturf(loc) && !locate(/obj/structure/table) in T)
+ if(ant_location == T)
+ if(prob(15))
+ if(!locate(/obj/effect/decal/ants) in T)
+ new /obj/effect/decal/ants(T)
+ antable = FALSE
+ desc += " It appears to be infested with ants. Yuck!"
+ reagents.add_reagent("ants", 1) // Don't eat things with ants in i you weirdo.
+ if(ant_timer)
+ deltimer(ant_timer)
+ else
+ ant_location = T
+ if(ant_timer)
+ deltimer(ant_timer)
+ ant_timer = addtimer(CALLBACK(src, .proc/check_for_ants), 3000, TIMER_STOPPABLE)
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm
index 64a585e9051..d512e3888a9 100644
--- a/code/modules/food_and_drinks/food/condiment.dm
+++ b/code/modules/food_and_drinks/food/condiment.dm
@@ -131,7 +131,7 @@
user.name = newname
user.real_name = newname
desc = "Salt. From dead crew, presumably."
- return (TOXLOSS)
+ return TOXLOSS
/obj/item/reagent_containers/food/condiment/peppermill
name = "pepper mill"
diff --git a/code/modules/food_and_drinks/food/foods/seafood.dm b/code/modules/food_and_drinks/food/foods/seafood.dm
index d06f1eeb77b..9e4407d9602 100644
--- a/code/modules/food_and_drinks/food/foods/seafood.dm
+++ b/code/modules/food_and_drinks/food/foods/seafood.dm
@@ -97,6 +97,24 @@
bitesize = 3
list_reagents = list("nutriment" = 2)
+/obj/item/reagent_containers/food/snacks/shrimp_skewer
+ name = "shrimp skewer"
+ desc = "Four shrimp lightly grilled on a skewer. Yummy!"
+ trash = /obj/item/stack/rods
+ icon = 'icons/obj/food/seafood.dmi'
+ icon_state = "shrimpskewer"
+ bitesize = 3
+ list_reagents = list("nutriment" = 8)
+
+/obj/item/reagent_containers/food/snacks/fish_skewer
+ name = "fish skewer"
+ desc = "A whole fish battered and grilled on a skewer. Hope you're hungry!"
+ trash = /obj/item/stack/rods
+ icon = 'icons/obj/food/seafood.dmi'
+ icon_state = "fishskewer"
+ bitesize = 3
+ list_reagents = list("protein" = 6, "vitamin" = 4)
+
/obj/item/reagent_containers/food/snacks/sliceable/Ebi_maki
name = "ebi makiroll"
desc = "A large unsliced roll of Ebi Sushi."
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index c5bcd22a885..edcb85e0d15 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -24,6 +24,18 @@
idle_power_usage = 2
active_power_usage = 500
+/obj/machinery/gibber/suicide_act(mob/user)
+ if(occupant || locked)
+ return FALSE
+ user.visible_message("[user] climbs into [src] and turns it on!")
+ user.Stun(10)
+ user.forceMove(src)
+ occupant = user
+ update_icon()
+ feedinTopanim()
+ addtimer(CALLBACK(src, .proc/startgibbing, user), 33)
+ return OBLITERATION
+
/obj/machinery/gibber/Destroy()
if(contents.len)
for(var/atom/movable/A in contents)
@@ -145,7 +157,7 @@
set name = "Empty Gibber"
set src in oview(1)
- if(usr.stat != CONSCIOUS)
+ if(usr.incapacitated())
return
go_out()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
index 8fe5d2cf4d8..1b8f61bb7bf 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
@@ -1,3 +1,5 @@
+GLOBAL_LIST_EMPTY(monkey_recyclers)
+
/obj/machinery/monkey_recycler
name = "Monkey Recycler"
desc = "A machine used for recycling dead monkeys into monkey cubes."
@@ -14,6 +16,7 @@
var/cube_production = 1
var/cycle_through = 0
var/obj/item/reagent_containers/food/snacks/monkeycube/cube_type = /obj/item/reagent_containers/food/snacks/monkeycube
+ var/list/connected = list()
/obj/machinery/monkey_recycler/New()
..()
@@ -21,8 +24,15 @@
component_parts += new /obj/item/circuitboard/monkey_recycler(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
component_parts += new /obj/item/stock_parts/matter_bin(null)
+ GLOB.monkey_recyclers += src
RefreshParts()
+/obj/machinery/monkey_recycler/Destroy()
+ GLOB.monkey_recyclers -= src
+ for(var/obj/machinery/computer/camera_advanced/xenobio/console in connected)
+ console.connected_recycler = null
+ return ..()
+
/obj/machinery/monkey_recycler/RefreshParts()
var/req_grind = 5
var/cubes_made = 1
@@ -47,21 +57,25 @@
default_deconstruction_crowbar(O)
if(istype(O, /obj/item/multitool))
- cycle_through++
- switch(cycle_through)
- if(1)
- cube_type = /obj/item/reagent_containers/food/snacks/monkeycube/farwacube
- if(2)
- cube_type = /obj/item/reagent_containers/food/snacks/monkeycube/wolpincube
- if(3)
- cube_type = /obj/item/reagent_containers/food/snacks/monkeycube/stokcube
- if(4)
- cube_type = /obj/item/reagent_containers/food/snacks/monkeycube/neaeracube
- if(5)
- cube_type = /obj/item/reagent_containers/food/snacks/monkeycube
- cycle_through = 0
- to_chat(user, "You change the monkeycube type to [initial(cube_type.name)].")
-
+ if(!panel_open)
+ cycle_through++
+ switch(cycle_through)
+ if(1)
+ cube_type = /obj/item/reagent_containers/food/snacks/monkeycube/farwacube
+ if(2)
+ cube_type = /obj/item/reagent_containers/food/snacks/monkeycube/wolpincube
+ if(3)
+ cube_type = /obj/item/reagent_containers/food/snacks/monkeycube/stokcube
+ if(4)
+ cube_type = /obj/item/reagent_containers/food/snacks/monkeycube/neaeracube
+ if(5)
+ cube_type = /obj/item/reagent_containers/food/snacks/monkeycube
+ cycle_through = 0
+ to_chat(user, "You change the monkeycube type to [initial(cube_type.name)].")
+ else
+ var/obj/item/multitool/M = O
+ M.buffer = src
+ to_chat(user, "You log [src] in the [M]'s buffer.")
if(stat != 0) //NOPOWER etc
return
if(istype(O, /obj/item/grab))
diff --git a/code/modules/food_and_drinks/recipes/recipes_grill.dm b/code/modules/food_and_drinks/recipes/recipes_grill.dm
index 921c2c86e99..e5c4cb6bce5 100644
--- a/code/modules/food_and_drinks/recipes/recipes_grill.dm
+++ b/code/modules/food_and_drinks/recipes/recipes_grill.dm
@@ -226,3 +226,22 @@
/obj/item/reagent_containers/food/snacks/catfishmeat,
)
result = /obj/item/reagent_containers/food/snacks/sushi_Tai
+
+/datum/recipe/grill/shrimp_skewer
+ items = list(
+ /obj/item/reagent_containers/food/snacks/shrimp,
+ /obj/item/reagent_containers/food/snacks/shrimp,
+ /obj/item/reagent_containers/food/snacks/shrimp,
+ /obj/item/reagent_containers/food/snacks/shrimp,
+ /obj/item/stack/rods,
+ )
+ result = /obj/item/reagent_containers/food/snacks/shrimp_skewer
+
+/datum/recipe/grill/fish_skewer
+ reagents = list("flour" = 10)
+ items = list(
+ /obj/item/reagent_containers/food/snacks/salmonmeat,
+ /obj/item/reagent_containers/food/snacks/salmonmeat,
+ /obj/item/stack/rods,
+ )
+ result = /obj/item/reagent_containers/food/snacks/fish_skewer
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/recipes/recipes_microwave.dm b/code/modules/food_and_drinks/recipes/recipes_microwave.dm
index 81fbe20e3d4..44c572b34e7 100644
--- a/code/modules/food_and_drinks/recipes/recipes_microwave.dm
+++ b/code/modules/food_and_drinks/recipes/recipes_microwave.dm
@@ -133,6 +133,13 @@
)
result = /obj/item/reagent_containers/food/snacks/baseballburger
+/datum/recipe/microwave/cheeseburger
+ items = list(
+ /obj/item/reagent_containers/food/snacks/monkeyburger,
+ /obj/item/reagent_containers/food/snacks/cheesewedge,
+ )
+ result = /obj/item/reagent_containers/food/snacks/cheeseburger
+
/datum/recipe/microwave/hotdog
items = list(
/obj/item/reagent_containers/food/snacks/bun,
diff --git a/code/modules/games/cards.dm b/code/modules/games/cards.dm
index 37a5e52b466..872bdc8e327 100644
--- a/code/modules/games/cards.dm
+++ b/code/modules/games/cards.dm
@@ -478,4 +478,5 @@
update_icon()
/obj/item/cardhand/pickup(mob/user as mob)
+ . = ..()
update_icon()
diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm
index 7acd3efc961..371822643a1 100644
--- a/code/modules/hydroponics/beekeeping/beebox.dm
+++ b/code/modules/hydroponics/beekeeping/beebox.dm
@@ -8,35 +8,36 @@
/mob/proc/bee_friendly()
- return 0
+ return FALSE
/mob/living/simple_animal/hostile/poison/bees/bee_friendly()
- return 1
+ return TRUE
/mob/living/simple_animal/bot/bee_friendly()
if(paicard)
- return 0
- return 1
+ return FALSE
+ return TRUE
/mob/living/simple_animal/diona/bee_friendly()
- return 1
+ return TRUE
/mob/living/carbon/human/bee_friendly()
if(isdiona(src)) //bees pollinate plants, duh.
- return 1
+ return TRUE
if((wear_suit && (wear_suit.flags & THICKMATERIAL)) && (head && (head.flags & THICKMATERIAL)))
- return 1
- return 0
+ return TRUE
+ return FALSE
/obj/structure/beebox
name = "apiary"
- desc = "Dr Miles Manners is just your average Wasp themed super hero by day, but by night he becomes DR BEES!"
+ desc = "Dr. Miles Manners is just your average wasp-themed super hero by day, but by night he becomes DR. BEES!"
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "beebox"
- anchored = 1
- density = 1
+ anchored = TRUE
+ density = TRUE
+ max_integrity = 300
var/mob/living/simple_animal/hostile/poison/bees/queen/queen_bee = null
var/list/bees = list() //bees owned by the box, not those inside it
var/list/honeycombs = list()
@@ -44,8 +45,8 @@
var/bee_resources = 0
-/obj/structure/beebox/New()
- ..()
+/obj/structure/beebox/Initialize(mapload)
+ . = ..()
processing_objects.Add(src)
@@ -66,12 +67,11 @@
var/random_reagent = FALSE
-/obj/structure/beebox/premade/New()
- ..()
-
+/obj/structure/beebox/premade/Initialize(mapload)
+ . = ..()
var/datum/reagent/R = null
if(random_reagent)
- R = get_random_reagent_id()
+ R = GLOB.chemical_reagents_list[get_random_reagent_id()]
queen_bee = new(src)
queen_bee.beehome = src
@@ -83,7 +83,7 @@
honey_frames += HF
for(var/i in 1 to get_max_bees())
- var/mob/living/simple_animal/hostile/poison/bees/worker/B = new(src)
+ var/mob/living/simple_animal/hostile/poison/bees/B = new(src)
bees += B
B.beehome = src
B.assign_reagent(R)
@@ -93,7 +93,7 @@
/obj/structure/beebox/process()
- if(queen_bee && (!queen_bee.beegent || !queen_bee.beegent.can_synth))
+ if(queen_bee)
if(bee_resources >= BEE_RESOURCE_HONEYCOMB_COST)
if(honeycombs.len < get_max_honeycomb())
bee_resources = max(bee_resources-BEE_RESOURCE_HONEYCOMB_COST, 0)
@@ -109,7 +109,7 @@
if((bee_resources >= BEE_RESOURCE_NEW_BEE_COST && prob(BEE_PROB_NEW_BEE)) || freebee)
if(!freebee)
bee_resources = max(bee_resources - BEE_RESOURCE_NEW_BEE_COST, 0)
- var/mob/living/simple_animal/hostile/poison/bees/worker/B = new(src)
+ var/mob/living/simple_animal/hostile/poison/bees/B = new(get_turf(src))
B.beehome = src
B.assign_reagent(queen_bee.beegent)
bees += B
@@ -152,14 +152,16 @@
if(istype(I, /obj/item/honey_frame))
var/obj/item/honey_frame/HF = I
if(honey_frames.len < BEEBOX_MAX_FRAMES)
+ if(!user.unEquip(HF))
+ return
visible_message("[user] adds a frame to the apiary.")
- user.unEquip(HF)
HF.forceMove(src)
honey_frames += HF
else
to_chat(user, "There's no room for anymore frames in the apiary!")
+ return
- if(istype(I, /obj/item/wrench))
+ if(iswrench(I))
if(default_unfasten_wrench(user, I, time = 20))
return
@@ -169,25 +171,27 @@
return
var/obj/item/queen_bee/qb = I
- user.unEquip(qb)
if(!qb.queen.beegent || (qb.queen.beegent && qb.queen.beegent.can_synth))
+ if(!user.unEquip(qb))
+ return
qb.queen.forceMove(src)
bees += qb.queen
queen_bee = qb.queen
qb.queen = null
else
visible_message("The [qb] refuses to settle down. Maybe it's something to do with its reagent?")
+ return
if(queen_bee)
visible_message("[user] sets [qb] down inside the apiary, making it [user.p_their()] new home.")
var/relocated = 0
for(var/b in bees)
- var/mob/living/simple_animal/hostile/poison/bees/worker/B = b
+ var/mob/living/simple_animal/hostile/poison/bees/B = b
if(B.reagent_incompatible(queen_bee))
bees -= B
B.beehome = null
if(B.loc == src)
- B.forceMove(get_turf(src))
+ B.forceMove(drop_location())
relocated++
if(relocated)
to_chat(user, "This queen has a different reagent to some of the bees who live here, those bees will not return to this apiary!")
@@ -196,6 +200,8 @@
to_chat(user, "The queen bee disappeared! bees disappearing has been in the news lately...")
qdel(qb)
+ return
+ return ..()
/obj/structure/beebox/attack_hand(mob/user)
@@ -208,7 +214,7 @@
if(B.isqueen)
continue
if(B.loc == src)
- B.forceMove(get_turf(src))
+ B.forceMove(drop_location())
B.target = user
bees = TRUE
if(bees)
@@ -254,3 +260,16 @@
QB.forceMove(get_turf(src))
visible_message("[user] removes the queen from the apiary.")
queen_bee = null
+
+/obj/structure/beebox/deconstruct(disassembled = TRUE)
+ new /obj/item/stack/sheet/wood(loc, 20)
+ for(var/mob/living/simple_animal/hostile/poison/bees/B in bees)
+ if(B.loc == src)
+ B.forceMove(drop_location())
+ for(var/obj/item/honey_frame/HF in honey_frames)
+ HF.forceMove(drop_location())
+ honey_frames -= HF
+ qdel(src)
+
+/obj/structure/beebox/unwrenched
+ anchored = FALSE
\ No newline at end of file
diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm
index 4515b3ad75f..dd56ade79be 100644
--- a/code/modules/hydroponics/grown/banana.dm
+++ b/code/modules/hydroponics/grown/banana.dm
@@ -30,13 +30,13 @@
playsound(loc, 'sound/items/bikehorn.ogg', 50, 1, -1)
sleep(25)
if(!user)
- return (OXYLOSS)
+ return OXYLOSS
user.say("BANG!")
sleep(25)
if(!user)
- return (OXYLOSS)
+ return OXYLOSS
user.visible_message("[user] laughs so hard [user.p_they()] begin[user.p_s()] to suffocate!")
- return (OXYLOSS)
+ return OXYLOSS
/obj/item/grown/bananapeel
seed = /obj/item/seeds/banana
@@ -52,7 +52,7 @@
/obj/item/grown/bananapeel/suicide_act(mob/user)
user.visible_message("[user] is deliberately slipping on the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.")
playsound(loc, 'sound/misc/slip.ogg', 50, 1, -1)
- return (BRUTELOSS)
+ return BRUTELOSS
// Mimana - invisible sprites are totally a feature!
diff --git a/code/modules/hydroponics/grown/flowers.dm b/code/modules/hydroponics/grown/flowers.dm
index adbb5f3152c..2b5817788a6 100644
--- a/code/modules/hydroponics/grown/flowers.dm
+++ b/code/modules/hydroponics/grown/flowers.dm
@@ -199,7 +199,7 @@
qdel(src)
/obj/item/grown/novaflower/pickup(mob/living/carbon/human/user)
- ..()
+ . = ..()
if(!user.gloves)
to_chat(user, "The [name] burns your bare hand!")
user.adjustFireLoss(rand(1, 5))
diff --git a/code/modules/hydroponics/grown/kudzu.dm b/code/modules/hydroponics/grown/kudzu.dm
index eea80e17e60..64b84649770 100644
--- a/code/modules/hydroponics/grown/kudzu.dm
+++ b/code/modules/hydroponics/grown/kudzu.dm
@@ -24,7 +24,7 @@
/obj/item/seeds/kudzu/suicide_act(mob/user)
user.visible_message("[user] swallows the pack of kudzu seeds! It looks like [user.p_theyre()] trying to commit suicide..")
plant(user)
- return (BRUTELOSS)
+ return BRUTELOSS
/obj/item/seeds/kudzu/proc/plant(mob/user)
if(istype(user.loc, /turf/space))
diff --git a/code/modules/hydroponics/grown/misc.dm b/code/modules/hydroponics/grown/misc.dm
index 605f5082522..0d60c7d864f 100644
--- a/code/modules/hydroponics/grown/misc.dm
+++ b/code/modules/hydroponics/grown/misc.dm
@@ -151,5 +151,4 @@
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb/proc/prime()
icon_state = "cherry_bomb_lit"
playsound(src, 'sound/goonstation/misc/fuse.ogg', seed.potency, 0)
- reagents.chem_temp = 1000 //Sets off the black powder
- reagents.handle_reactions()
+ reagents.set_reagent_temp(1000) //Sets off the black powder
\ No newline at end of file
diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm
index 8bbe4a4e240..444939ca861 100644
--- a/code/modules/hydroponics/grown/nettle.dm
+++ b/code/modules/hydroponics/grown/nettle.dm
@@ -45,22 +45,22 @@
/obj/item/grown/nettle/suicide_act(mob/user)
user.visible_message("[user] is eating some of the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.")
- return (BRUTELOSS|TOXLOSS)
+ return BRUTELOSS|TOXLOSS
/obj/item/grown/nettle/pickup(mob/living/user)
..()
if(!ishuman(user))
- return 0
+ return TRUE
var/mob/living/carbon/human/H = user
if(H.gloves)
- return 0
+ return TRUE
var/organ = ((H.hand ? "l_":"r_") + "arm")
var/obj/item/organ/external/affecting = H.get_organ(organ)
if(affecting)
if(affecting.receive_damage(0, force))
H.UpdateDamageIcon()
to_chat(H, "The nettle burns your bare hand!")
- return 1
+ return TRUE
@@ -95,8 +95,10 @@
force = round((5 + seed.potency / 2.5), 1)
/obj/item/grown/nettle/death/pickup(mob/living/carbon/user)
- if(..())
- if(prob(50))
+ . = ..()
+ if(. && ishuman(user)) // If the pickup succeeded and is humanoid
+ var/mob/living/carbon/human/H = user
+ if(!H.gloves && prob(50))
user.Paralyse(5)
to_chat(user, "You are stunned by the Deathnettle when you try picking it up!")
diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm
index f71cd6ed86a..4ed9d963274 100644
--- a/code/modules/hydroponics/grown/towercap.dm
+++ b/code/modules/hydroponics/grown/towercap.dm
@@ -153,7 +153,8 @@
Burn()
processing_objects.Add(src)
-/obj/structure/bonfire/fire_act(exposed_temperature, exposed_volume)
+/obj/structure/bonfire/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
+ ..()
StartBurning()
/obj/structure/bonfire/Crossed(atom/movable/AM)
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index a3453585817..14080c62bba 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -34,7 +34,7 @@
/obj/item/reagent_containers/spray/weedspray/suicide_act(mob/user)
user.visible_message("[user] is huffing the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.")
- return (TOXLOSS)
+ return TOXLOSS
/obj/item/reagent_containers/spray/pestspray // -- Skie
desc = "It's some pest eliminator spray! Do not inhale!"
@@ -56,7 +56,7 @@
/obj/item/reagent_containers/spray/pestspray/suicide_act(mob/user)
user.visible_message("[user] is huffing the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.")
- return (TOXLOSS)
+ return TOXLOSS
/obj/item/cultivator
name = "cultivator"
@@ -91,7 +91,7 @@
/obj/item/hatchet/suicide_act(mob/user)
user.visible_message("[user] is chopping at [user.p_them()]self with the [name]! It looks like [user.p_theyre()] trying to commit suicide.")
playsound(loc, 'sound/weapons/bladeslice.ogg', 50, 1, -1)
- return (BRUTELOSS)
+ return BRUTELOSS
/obj/item/hatchet/unathiknife
name = "duelling knife"
@@ -126,7 +126,7 @@
if(affecting)
affecting.droplimb(1, DROPLIMB_SHARP)
playsound(loc, pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg'), 50, 1, -1)
- return (BRUTELOSS)
+ return BRUTELOSS
/obj/item/scythe/pre_attackby(atom/A, mob/living/user, params)
if(swiping || !istype(A, /obj/structure/spacevine) || get_turf(A) == get_turf(user))
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index 1a9dc008376..2e95d21e10b 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -409,11 +409,8 @@
var/datum/effect_system/smoke_spread/chem/S = new
var/splat_location = get_turf(target)
var/smoke_amount = round(sqrt(G.seed.potency * 0.1), 1)
- S.attach(splat_location)
- S.set_up(G.reagents, 2, 0, splat_location)
+ S.set_up(G.reagents, splat_location)
S.start(smoke_amount)
- if(G && G.reagents)
- G.reagents.clear_reagents()
/datum/plant_gene/trait/plant_type // Parent type
name = "you shouldn't see this"
diff --git a/code/modules/martial_arts/krav_maga.dm b/code/modules/martial_arts/krav_maga.dm
index 9e889bdce7a..80498117343 100644
--- a/code/modules/martial_arts/krav_maga.dm
+++ b/code/modules/martial_arts/krav_maga.dm
@@ -132,13 +132,13 @@ datum/martial_art/krav_maga/grab_act(var/mob/living/carbon/human/A, var/mob/livi
if(D.hand)
if(istype(D.l_hand, /obj/item))
var/obj/item/I = D.l_hand
- D.drop_item()
- A.put_in_hands(I)
+ if(D.drop_item())
+ A.put_in_hands(I)
else
if(istype(D.r_hand, /obj/item))
var/obj/item/I = D.r_hand
- D.drop_item()
- A.put_in_hands(I)
+ if(D.drop_item())
+ A.put_in_hands(I)
D.visible_message("[A] has disarmed [D]!", \
"[A] has disarmed [D]!")
playsound(D, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
diff --git a/code/modules/martial_arts/martial.dm b/code/modules/martial_arts/martial.dm
index aed823b372b..2940e810ade 100644
--- a/code/modules/martial_arts/martial.dm
+++ b/code/modules/martial_arts/martial.dm
@@ -267,7 +267,7 @@
H.Weaken(4)
if(H.staminaloss && !H.sleeping)
var/total_health = (H.health - H.staminaloss)
- if(total_health <= config.health_threshold_crit && !H.stat)
+ if(total_health <= HEALTH_THRESHOLD_CRIT && !H.stat)
H.visible_message("[user] delivers a heavy hit to [H]'s head, knocking [H.p_them()] out cold!", \
"[user] knocks you unconscious!")
H.SetSleeping(30)
diff --git a/code/modules/mining/ore.dm b/code/modules/mining/ore.dm
index 08b81e1fd78..dda5fb47f78 100644
--- a/code/modules/mining/ore.dm
+++ b/code/modules/mining/ore.dm
@@ -52,7 +52,7 @@
F.attackby(OB, AM)
return ..()
-/obj/item/stack/ore/fire_act()
+/obj/item/stack/ore/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
..()
if(isnull(refined_type))
return
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 7d396a7e7ea..923c81c53b1 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -49,7 +49,7 @@ var/list/image/ghost_darkness_images = list() //this is a list of images for thi
T = get_turf(body) //Where is the body located?
attack_log = body.attack_log //preserve our attack logs by copying them to our ghost
- var/mutable_appearance/MA = copy_appearance(body)
+ var/mutable_appearance/MA = copy_appearance(body)
if(body.mind && body.mind.name)
MA.name = body.mind.name
else if(body.real_name)
@@ -148,6 +148,8 @@ Works together with spawning an observer, noted above.
/mob/proc/ghostize(var/flags = GHOST_CAN_REENTER)
if(key)
+ if(player_logged) //if they have disconnected we want to remove their SSD overlay
+ overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow")
if(GLOB.non_respawnable_keys[ckey])
flags &= ~GHOST_CAN_REENTER
var/mob/dead/observer/ghost = new(src, flags) //Transfer safety to observer spawning proc.
@@ -177,30 +179,44 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(P)
if(TOO_EARLY_TO_GHOST)
warningmsg = "It's too early in the shift to enter cryo"
- // If it's not too early, we'll skip straight to ghosting out without penalty
else if(suiciding && TOO_EARLY_TO_GHOST)
warningmsg = "You have committed suicide too early in the round"
else if(stat != DEAD)
warningmsg = "You are alive"
+ if(isAI(src))
+ warningmsg = "You are a living AI! You should probably use OOC -> Wipe Core instead."
else if(GLOB.non_respawnable_keys[ckey])
warningmsg = "You have lost your right to respawn"
- if(!warningmsg)
- ghostize(1)
- else
+ if(warningmsg)
var/response
var/alertmsg = "Are you -sure- you want to ghost?\n([warningmsg]. If you ghost now, you probably won't be able to rejoin the round! You can't change your mind, so choose wisely!)"
response = alert(src, alertmsg,"Are you sure you want to ghost?","Stay in body","Ghost")
if(response != "Ghost")
- return //didn't want to ghost after-all
- StartResting()
- var/mob/dead/observer/ghost = ghostize(0) //0 parameter is so we can never re-enter our body, "Charlie, you can never come baaaack~" :3
- ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly.
+ return
+
+ if(stat == CONSCIOUS)
+ if(!is_admin_level(z))
+ player_ghosted = 1
+ if(mind && mind.special_role)
+ message_admins("[key_name_admin(src)] has ghosted while alive, with special_role: [mind.special_role]")
+
+ if(warningmsg)
+ // Not respawnable
+ var/mob/dead/observer/ghost = ghostize(0) // 0 parameter stops them re-entering their body
+ ghost.timeofdeath = world.time // Because the living mob won't have a time of death and we want the respawn timer to work properly.
+ else
+ // Respawnable
+ ghostize(1)
+
+ // If mob in morgue tray, update tray
var/obj/structure/morgue/Morgue = locate() in M.loc
if(istype(M.loc, /obj/structure/morgue))
Morgue = M.loc
if(Morgue)
Morgue.update()
+
+ // If mob in cryopod, despawn mob
if(P)
if(!P.control_computer)
P.find_control_computer(urgent=1)
@@ -208,7 +224,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
P.despawn_occupant()
return
-
/mob/dead/observer/Move(NewLoc, direct)
following = null
dir = direct
@@ -235,9 +250,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
..()
-/mob/dead/observer/experience_pressure_difference()
- return 0
-
/mob/dead/observer/can_use_hands() return 0
/mob/dead/observer/Stat()
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index e53e3c9fd4d..471f82c1511 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -35,7 +35,7 @@
/mob/proc/put_in_l_hand(var/obj/item/W)
if(!put_in_hand_check(W))
return 0
- if(!l_hand)
+ if(!l_hand && has_left_hand())
W.forceMove(src) //TODO: move to equipped?
l_hand = W
W.layer = 20 //TODO: move to equipped?
@@ -51,7 +51,7 @@
/mob/proc/put_in_r_hand(var/obj/item/W)
if(!put_in_hand_check(W))
return 0
- if(!r_hand)
+ if(!r_hand && has_right_hand())
W.forceMove(src)
r_hand = W
W.layer = 20
diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm
index fa5ba4a62ad..8a7c017818a 100644
--- a/code/modules/mob/language.dm
+++ b/code/modules/mob/language.dm
@@ -246,8 +246,8 @@
syllables = list("hs","zt","kr","st","sh")
/datum/language/diona/get_random_name()
- var/new_name = "[pick(list("To Sleep Beneath", "Wind Over", "Embrace of", "Dreams of", "Witnessing", "To Walk Beneath", "Approaching the", "Glimmer of", "The Ripple of", "Colors of", "The Still of", "Silence of", "Gentle Breeze of", "Glistening Waters under", "Child of", "Blessed Plant-ling of", "Grass-Walker of", "Element of", "Spawn of"))]"
- new_name += " [pick(list("the Void", "the Sky", "Encroaching Night", "Planetsong", "Starsong", "the Wandering Star", "the Empty Day", "Daybreak", "Nightfall", "the Rain", "the Stars", "the Waves", "Dusk", "Night", "the Wind", "the Summer Wind", "the Blazing Sun", "the Scorching Sun", "Eternal Fields", "the Soothing Plains", "the Undying Fiona", "Mother Nature's Bousum"))]"
+ var/new_name = "[pick(list("To Sleep Beneath", "Wind Over", "Embrace Of", "Dreams Of", "Witnessing", "To Walk Beneath", "Approaching The", "Glimmer Of", "The Ripple Of", "Colors Of", "The Still Of", "Silence Of", "Gentle Breeze Of", "Glistening Waters Under", "Child Of", "Blessed Plant-Ling Of", "Grass-Walker Of", "Element Of", "Spawn Of"))]"
+ new_name += " [pick(list("The Void", "The Sky", "Encroaching Night", "Planetsong", "Starsong", "The Wandering Star", "The Empty Day", "Daybreak", "Nightfall", "The Rain", "The Stars", "The Waves", "Dusk", "Night", "The Wind", "The Summer Wind", "The Blazing Sun", "The Scorching Sun", "Eternal Fields", "The Soothing Plains", "The Undying Fiona", "Mother Nature's Bousum"))]"
return new_name
/datum/language/trinary
diff --git a/code/modules/mob/living/carbon/_defines.dm b/code/modules/mob/living/carbon/_defines.dm
index 163ce8f7c8d..a5a524f86ed 100644
--- a/code/modules/mob/living/carbon/_defines.dm
+++ b/code/modules/mob/living/carbon/_defines.dm
@@ -1,10 +1,9 @@
-//NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick!
-#define HUMAN_MAX_OXYLOSS 3 //Defines how much oxyloss humans can get per tick. A tile with no air at all (such as space) applies this value, otherwise it's a percentage of it.
-#define HUMAN_CRIT_MAX_OXYLOSS ( (tickerProcess.getLastTickerTimeDuration()) / 3) //The amount of damage you'll get when in critical condition. We want this to be a 5 minute deal = 300s. There are 100HP to get through, so (1/3)*last_tick_duration per second. Breaths however only happen every 4 ticks.
+//NOTE: Breathing happens once EVERY OTHER TICK.
+#define HUMAN_MAX_OXYLOSS 5 //Defines how much oxyloss humans can get per tick. A tile with no air at all (such as space) applies this value, otherwise it's a percentage of it.
#define HEAT_DAMAGE_LEVEL_1 2 //Amount of damage applied when your body temperature just passes the 360.15k safety point
#define HEAT_DAMAGE_LEVEL_2 3 //Amount of damage applied when your body temperature passes the 400K point
-#define HEAT_DAMAGE_LEVEL_3 10 //Amount of damage applied when your body temperature passes the 1000K point
+#define HEAT_DAMAGE_LEVEL_3 5 //Amount of damage applied when your body temperature passes the 1000K point
#define COLD_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when your body temperature just passes the 260.15k safety point
#define COLD_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when your body temperature passes the 200K point
diff --git a/code/modules/mob/living/carbon/alien/humanoid/life.dm b/code/modules/mob/living/carbon/alien/humanoid/life.dm
index 6012a8fb7f3..3af2250bbbd 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/life.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/life.dm
@@ -46,13 +46,13 @@
if(stat == DEAD) //DEAD. BROWN BREAD. SWIMMING WITH THE SPESS CARP
SetSilence(0)
else //ALIVE. LIGHTS ARE ON
- if(health < config.health_threshold_dead || !get_int_organ(/obj/item/organ/internal/brain))
+ if(health < HEALTH_THRESHOLD_DEAD && check_death_method() || !get_int_organ(/obj/item/organ/internal/brain))
death()
SetSilence(0)
return 1
//UNCONSCIOUS. NO-ONE IS HOME
- if((getOxyLoss() > 50) || (config.health_threshold_crit >= health))
+ if((getOxyLoss() > 50) || (HEALTH_THRESHOLD_CRIT >= health && check_death_method()))
if(health <= 20 && prob(1))
emote("gasp")
if(!reagents.has_reagent("epinephrine"))
diff --git a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
index 44287493718..bdc2ee31f77 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
@@ -18,7 +18,7 @@
if(stat == DEAD)
//If we mostly took damage from fire
- if(fireloss > 125)
+ if(getFireLoss() > 125)
icon_state = "alien[caste]_husked"
pixel_y = 0
else
diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm
index a64750ad93d..5ebaaffac0c 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva.dm
@@ -93,6 +93,9 @@
/mob/living/carbon/alien/larva/show_inv(mob/user as mob)
return
+/mob/living/carbon/alien/larva/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
+ return FALSE
+
/* Commented out because it's duplicated in life.dm
/mob/living/carbon/alien/larva/proc/grow() // Larvae can grow into full fledged Xenos if they survive long enough -- TLE
if(icon_state == "larva_l" && !canmove) // This is a shit death check. It is made of shit and death. Fix later.
diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm
index a4b783e08fb..a0668db8327 100644
--- a/code/modules/mob/living/carbon/alien/larva/life.dm
+++ b/code/modules/mob/living/carbon/alien/larva/life.dm
@@ -19,7 +19,7 @@
return 1
//UNCONSCIOUS. NO-ONE IS HOME
- if( (getOxyLoss() > 25) || (config.health_threshold_crit >= health) )
+ if((getOxyLoss() > 25) || (HEALTH_THRESHOLD_CRIT >= health && check_death_method()))
//if( health <= 20 && prob(1) )
// spawn(0)
// emote("gasp")
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index 5294e3bda91..04dcb0c60ef 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -65,9 +65,9 @@ var/const/MAX_ACTIVE_TIME = 400
return
/obj/item/clothing/mask/facehugger/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ ..()
if(exposed_temperature > 300)
Die()
- return
/obj/item/clothing/mask/facehugger/equipped(mob/M)
Attach(M)
diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/carbon/brain/life.dm
index 2ac3b3c4d6b..d0cf06f1bf7 100644
--- a/code/modules/mob/living/carbon/brain/life.dm
+++ b/code/modules/mob/living/carbon/brain/life.dm
@@ -32,7 +32,7 @@
. = ..()
if(.)
- if(!container && (health < config.health_threshold_dead || ((world.time - timeofhostdeath) > config.revival_brain_life)))
+ if(!container && (health < HEALTH_THRESHOLD_DEAD && check_death_method() || ((world.time - timeofhostdeath) > config.revival_brain_life)))
death()
return 0
diff --git a/code/modules/mob/living/carbon/brain/robotic_brain.dm b/code/modules/mob/living/carbon/brain/robotic_brain.dm
index c294a11c999..6528d9c252e 100644
--- a/code/modules/mob/living/carbon/brain/robotic_brain.dm
+++ b/code/modules/mob/living/carbon/brain/robotic_brain.dm
@@ -161,7 +161,7 @@
if(jobban_isbanned(O, "Cyborg") || jobban_isbanned(O,"nonhumandept"))
to_chat(O, "You are job banned from this role.")
return
- to_chat(O., "You've been added to the list of ghosts that may become this [src]. Click again to unvolunteer.")
+ to_chat(O, "You've been added to the list of ghosts that may become this [src]. Click again to unvolunteer.")
ghost_volunteers.Add(O)
diff --git a/code/modules/mob/living/carbon/brain/update_status.dm b/code/modules/mob/living/carbon/brain/update_status.dm
index 431d1eea0c3..6fec51bb07b 100644
--- a/code/modules/mob/living/carbon/brain/update_status.dm
+++ b/code/modules/mob/living/carbon/brain/update_status.dm
@@ -3,12 +3,12 @@
return
// if(health <= min_health)
if(stat == DEAD)
- if(container && health > config.health_threshold_dead)
+ if(container && health > HEALTH_THRESHOLD_DEAD)
update_revive()
create_debug_log("revived, trigger reason: [reason]")
return
else
- if(!container || health <= config.health_threshold_dead)
+ if(!container || health <= HEALTH_THRESHOLD_DEAD && check_death_method())
// Considered "dead" without any external apparatus
death()
create_debug_log("died, trigger reason: [reason]")
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 0e921e7953e..0f1c5d91df1 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -209,7 +209,7 @@
/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
add_attack_logs(M, src, "Shaked", ATKLOG_ALL)
- if(health >= config.health_threshold_crit)
+ if(health >= HEALTH_THRESHOLD_CRIT)
if(src == M && ishuman(src))
var/mob/living/carbon/human/H = src
visible_message( \
@@ -442,6 +442,10 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
if(!do_after(src, 45, target = src))
return
+ if(buckled)
+ to_chat(src, "You cannot crawl into a vent while buckled to something!")
+ return
+
if(!client)
return
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 5d816ed625e..4ecd81e1338 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -22,9 +22,8 @@
var/wetlevel = 0 //how wet the mob is
- var/failed_last_breath = FALSE //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks.
var/co2overloadtime = null
var/dreaming = 0 //How many dream images we have left to send
var/nightmare = 0
- blood_volume = BLOOD_VOLUME_NORMAL
+ blood_volume = BLOOD_VOLUME_NORMAL
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/give.dm b/code/modules/mob/living/carbon/give.dm
index 473715367b4..c0dba9b77e5 100644
--- a/code/modules/mob/living/carbon/give.dm
+++ b/code/modules/mob/living/carbon/give.dm
@@ -4,22 +4,15 @@
if(!iscarbon(target)) //something is bypassing the give arguments, no clue what, adding a sanity check JIC
to_chat(usr, "Wait a second... \the [target] HAS NO HANDS! AHH!")//cheesy messages ftw
+ return
+ if(target.incapacitated() || usr.incapacitated() || target.client == null)
return
- if(target.stat == 2 || usr.stat == 2|| target.client == null)
- return
- var/obj/item/I
- if(!usr.hand && usr.r_hand == null)
- to_chat(usr, " You don't have anything in your right hand to give to [target.name]")
- return
- if(usr.hand && usr.l_hand == null)
- to_chat(usr, " You don't have anything in your left hand to give to [target.name]")
- return
- if(usr.hand)
- I = usr.l_hand
- else if(!usr.hand)
- I = usr.r_hand
+
+ var/obj/item/I = get_active_hand()
+
if(!I)
+ to_chat(usr, " You don't have anything in your hand to give to [target.name]")
return
if((I.flags & NODROP) || (I.flags & ABSTRACT))
to_chat(usr, "That's not exactly something you can give.")
@@ -29,35 +22,30 @@
if("Yes")
if(!I)
return
+ if(target.incapacitated() || usr.incapacitated())
+ return
if(!Adjacent(target))
to_chat(usr, " You need to stay in reaching distance while giving an object.")
to_chat(target, " [usr.name] moved too far away.")
return
- if((usr.hand && usr.l_hand != I) || (!usr.hand && usr.r_hand != I))
+ if((I.flags & NODROP) || (I.flags & ABSTRACT))
+ to_chat(usr, "[I] stays stuck to your hand when you try to give it!")
+ to_chat(target, "[I] stays stuck to [usr.name]'s hand when you try to take it!")
+ return
+ if(I != get_active_hand())
to_chat(usr, " You need to keep the item in your active hand.")
- to_chat(target, " [usr.name] seem to have given up on giving \the [I.name] to you.")
+ to_chat(target, " [usr.name] seem to have given up on giving [I] to you.")
return
if(target.r_hand != null && target.l_hand != null)
to_chat(target, " Your hands are full.")
to_chat(usr, " Their hands are full.")
return
- else
- usr.drop_item()
- if(target.r_hand == null)
- target.r_hand = I
- else
- target.l_hand = I
- I.loc = target
- I.layer = 20
- I.plane = HUD_PLANE
+ usr.unEquip(I)
+ target.put_in_hands(I)
I.add_fingerprint(target)
- src.update_inv_l_hand()
- src.update_inv_r_hand()
- target.update_inv_l_hand()
- target.update_inv_r_hand()
- target.visible_message(" [usr.name] handed \the [I.name] to [target.name].")
+ target.visible_message(" [usr.name] handed [I] to [target.name].")
I.on_give(usr, target)
if("No")
- target.visible_message(" [usr.name] tried to hand [I.name] to [target.name] but [target.name] didn't want it.")
+ target.visible_message(" [usr.name] tried to hand [I] to [target.name] but [target.name] didn't want it.")
else
to_chat(usr, " [target.name]'s hands are full.")
diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm
index 3e1c874a067..442d7aaf044 100644
--- a/code/modules/mob/living/carbon/human/emote.dm
+++ b/code/modules/mob/living/carbon/human/emote.dm
@@ -680,6 +680,14 @@
message = "[src] trembles."
m_type = 1
+ if("shudder", "shudders")
+ message = "[src] shudders."
+ m_type = 1
+
+ if("bshake", "bshakes")
+ message = "[src] shakes."
+ m_type = 1
+
if("sneeze", "sneezes")
if(miming)
message = "[src] sneezes."
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 03726353022..aa714f0d527 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -363,7 +363,7 @@
for(var/datum/data/record/R in data_core.security)
if(R.fields["id"] == E.fields["id"])
criminal = R.fields["criminal"]
- var/criminal_status = hasHUD(user, "read_only_security") ? "\[[criminal]\]" : "\[[criminal]\]"
+ var/criminal_status = hasHUD(user, "read_only_security") ? "\[[criminal]\]" : "\[[criminal]\]"
msg += "Criminal status: [criminal_status]\n"
msg += "Security records: \[View\] \[Add comment\]\n"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 5550378984a..09787bbf73b 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1651,6 +1651,9 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
..()
/mob/living/carbon/human/proc/do_cpr(mob/living/carbon/human/H)
+ if(H == src)
+ to_chat(src, "You cannot perform CPR on yourself!")
+ return
if(H.stat == DEAD || (H.status_flags & FAKEDEATH))
to_chat(src, "[H.name] is dead!")
return
@@ -1662,25 +1665,29 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
return
if((head && (head.flags_cover & HEADCOVERSMOUTH)) || (wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH) && !wear_mask.mask_adjusted))
to_chat(src, "Remove your mask first!")
- return 0
+ return
if((H.head && (H.head.flags_cover & HEADCOVERSMOUTH)) || (H.wear_mask && (H.wear_mask.flags_cover & MASKCOVERSMOUTH) && !H.wear_mask.mask_adjusted))
to_chat(src, "Remove [H.p_their()] mask first!")
- return 0
- visible_message("[src] is trying to perform CPR on [H.name]!", \
- "You try to perform CPR on [H.name]!")
+ return
+ if(H.receiving_cpr) // To prevent spam stacking
+ to_chat(src, "They are already receiving CPR!")
+ return
+ visible_message("[src] is trying to perform CPR on [H.name]!", "You try to perform CPR on [H.name]!")
+ H.receiving_cpr = TRUE
if(do_mob(src, H, 40))
- if(H.health > config.health_threshold_dead && H.health <= config.health_threshold_crit)
- var/suff = min(H.getOxyLoss(), 7)
- H.adjustOxyLoss(-suff)
+ if(H.health <= HEALTH_THRESHOLD_CRIT)
+ H.adjustOxyLoss(-15)
+ H.SetLoseBreath(0)
+ H.AdjustParalysis(-1)
H.updatehealth("cpr")
- visible_message("[src] performs CPR on [H.name]!", \
- "You perform CPR on [H.name].")
+ visible_message("[src] performs CPR on [H.name]!", "You perform CPR on [H.name].")
to_chat(H, "You feel a breath of fresh air enter your lungs. It feels good.")
- to_chat(src, "Repeat at least every 7 seconds.")
+ H.receiving_cpr = FALSE
add_attack_logs(src, H, "CPRed", ATKLOG_ALL)
- return 1
+ return TRUE
else
+ H.receiving_cpr = FALSE
to_chat(src, "You need to stay still while performing CPR!")
/mob/living/carbon/human/canBeHandcuffed()
@@ -1696,7 +1703,7 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
return FALSE
/mob/living/carbon/human/InCritical()
- return (health <= config.health_threshold_crit && stat == UNCONSCIOUS)
+ return (health <= HEALTH_THRESHOLD_CRIT && stat == UNCONSCIOUS)
/mob/living/carbon/human/IsAdvancedToolUser()
@@ -2000,4 +2007,4 @@ Eyes need to have significantly high darksight to shine unless the mob has the X
var/obj/item/organ/internal/lantern/O = get_int_organ(/obj/item/organ/internal/lantern)
if(O && O.glowing)
O.toggle_biolum(TRUE)
- visible_message("[src] is engulfed in shadows and fades into the darkness.", "A sense of dread washes over you as you suddenly dim dark.")
+ visible_message("[src] is engulfed in shadows and fades into the darkness.", "A sense of dread washes over you as you suddenly dim dark.")
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index b858cca130a..7e9739a816d 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -15,7 +15,7 @@
health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
//TODO: fix husking
- if(((maxHealth - total_burn) < config.health_threshold_dead) && stat == DEAD)
+ if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD)
ChangeToHusk()
update_stat("updatehealth([reason])")
med_hud_set_health()
@@ -171,11 +171,17 @@
// Defined here solely to take species flags into account without having to recast at mob/living level.
/mob/living/carbon/human/adjustOxyLoss(amount)
+ if(NO_BREATHE in dna.species.species_traits)
+ oxyloss = 0
+ return FALSE
if(dna.species && amount > 0)
amount = amount * dna.species.oxy_mod
. = ..()
/mob/living/carbon/human/setOxyLoss(amount)
+ if(NO_BREATHE in dna.species.species_traits)
+ oxyloss = 0
+ return FALSE
if(dna.species && amount > 0)
amount = amount * dna.species.oxy_mod
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 965a2c81ab2..84764bfddaa 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -513,3 +513,12 @@ emp_act
return TRUE
if(check_mask && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH))
return TRUE
+
+/mob/living/carbon/human/proc/reagent_safety_check(hot = TRUE)
+ if(wear_mask)
+ to_chat(src, "Your [wear_mask.name] protects you from the [hot ? "hot" : "cold"] liquid!")
+ return FALSE
+ if(head)
+ to_chat(src, "Your [head.name] protects you from the [hot ? "hot" : "cold"] liquid!")
+ return FALSE
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 22a9d40f6fd..9bd463b73bc 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -64,6 +64,7 @@ var/global/default_martial_art = new/datum/martial_art
var/check_mutations=0 // Check mutations on next life tick
var/heartbeat = 0
+ var/receiving_cpr = FALSE
var/fire_dmi = 'icons/mob/OnFire.dmi'
var/fire_sprite = "Standing"
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 7d83c7eaa1d..79b41e47cc3 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -434,11 +434,11 @@
if(slot_l_hand)
if(l_hand)
return 0
- return 1
+ return !incapacitated()
if(slot_r_hand)
if(r_hand)
return 0
- return 1
+ return !incapacitated()
if(slot_wear_mask)
if(wear_mask)
return 0
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 8d0261528ed..3571deb392a 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -10,10 +10,8 @@
update_mutations()
check_mutations=0
- handle_shock()
handle_pain()
handle_heartbeat()
- handle_heartattack()
handle_drunk()
dna.species.handle_life(src)
@@ -39,6 +37,17 @@
if(life_tick == 1)
regenerate_icons() // Make sure the inventory updates
+ handle_ghosted()
+
+/mob/living/carbon/human/proc/handle_ghosted()
+ if(player_ghosted > 0 && stat == CONSCIOUS && job && !restrained())
+ if(key)
+ player_ghosted = 0
+ else
+ player_ghosted++
+ if(player_ghosted % 150 == 0)
+ force_cryo_human(src)
+
/mob/living/carbon/human/calculate_affecting_pressure(var/pressure)
..()
var/pressure_difference = abs( pressure - ONE_ATMOSPHERE )
@@ -141,15 +150,6 @@
if(3)
emote("drool")
- if(getBrainLoss() >= 100 && stat != DEAD) //you lapse into a coma and die without immediate aid; RIP. -Fox
- Weaken(20)
- AdjustLoseBreath(10)
- AdjustSilence(2)
-
- if(getBrainLoss() >= 120 && stat != DEAD) //they died from stupidity--literally. -Fox
- visible_message("[src] goes limp, [p_their()] facial expression utterly blank.")
- death()
-
/mob/living/carbon/human/handle_mutations_and_radiation()
for(var/datum/dna/gene/gene in dna_genes)
if(!gene.block)
@@ -242,12 +242,10 @@
var/obj/item/organ/internal/L = get_organ_slot("lungs")
if(!L || L && (L.status & ORGAN_DEAD))
- if(health >= config.health_threshold_crit)
+ if(health >= HEALTH_THRESHOLD_CRIT)
adjustOxyLoss(HUMAN_MAX_OXYLOSS + 1)
else if(!(NOCRITDAMAGE in dna.species.species_traits))
- adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS)
-
- failed_last_breath = TRUE
+ adjustOxyLoss(HUMAN_MAX_OXYLOSS)
if(dna.species)
var/datum/species/S = dna.species
@@ -270,7 +268,7 @@
// USED IN DEATHWHISPERS
/mob/living/carbon/human/proc/isInCrit()
// Health is in deep shit and we're not already dead
- return health <= 0 && stat != 2
+ return health <= HEALTH_THRESHOLD_CRIT && stat != DEAD
/mob/living/carbon/human/get_breath_from_internal(volume_needed) //making this call the parent would be far too complicated
@@ -791,6 +789,70 @@
handle_organs()
+ if(getBrainLoss() >= 120 || (health + (getOxyLoss() / 2)) <= -500)
+ visible_message("[src] goes limp, their facial expression utterly blank.")
+ death()
+ return
+
+ if(getBrainLoss() >= 100) // braindeath
+ AdjustLoseBreath(10, bound_lower = 0, bound_upper = 25)
+ Weaken(30)
+
+ if(!check_death_method())
+ if(health <= HEALTH_THRESHOLD_DEAD)
+ var/deathchance = min(99, ((getBrainLoss() * -5) + (health + (getOxyLoss() / 2))) * -0.01)
+ if(prob(deathchance))
+ death()
+ return
+
+ if(health <= HEALTH_THRESHOLD_CRIT)
+ if(prob(5))
+ emote(pick("faint", "collapse", "cry", "moan", "gasp", "shudder", "shiver"))
+ AdjustStuttering(5, bound_lower = 0, bound_upper = 5)
+ EyeBlurry(5)
+ if(prob(7))
+ AdjustConfused(2)
+ if(prob(5))
+ Paralyse(2)
+ switch(health)
+ if(-INFINITY to -100)
+ adjustOxyLoss(1)
+ if(prob(health * -0.1))
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ H.set_heartattack(TRUE)
+ if(prob(health * -0.2))
+ var/datum/disease/D = new /datum/disease/critical/heart_failure
+ ForceContractDisease(D)
+ Paralyse(5)
+ if(-99 to -80)
+ adjustOxyLoss(1)
+ if(prob(4))
+ to_chat(src, "Your chest hurts...")
+ Paralyse(2)
+ var/datum/disease/D = new /datum/disease/critical/heart_failure
+ ForceContractDisease(D)
+ if(-79 to -50)
+ adjustOxyLoss(1)
+ if(prob(10))
+ var/datum/disease/D = new /datum/disease/critical/shock
+ ForceContractDisease(D)
+ if(prob(health * -0.08))
+ var/datum/disease/D = new /datum/disease/critical/heart_failure
+ ForceContractDisease(D)
+ if(prob(6))
+ to_chat(src, "You feel [pick("horrible pain", "awful", "like shit", "absolutely awful", "like death", "like you are dying", "nothing", "warm", "sweaty", "tingly", "really, really bad", "horrible")]!")
+ Weaken(3)
+ if(prob(3))
+ Paralyse(2)
+ if(-49 to 0)
+ adjustOxyLoss(1)
+ if(prob(3))
+ var/datum/disease/D = new /datum/disease/critical/shock
+ ForceContractDisease(D)
+ if(prob(5))
+ to_chat(src, "You feel [pick("terrible", "awful", "like shit", "sick", "numb", "cold", "sweaty", "tingly", "horrible")]!")
+ Weaken(3)
else //dead
SetSilence(0)
@@ -962,7 +1024,7 @@
return
if(H.is_robotic()) //Handle robotic hearts specially with a wuuuubb. This also applies to machine-people.
- if(shock_stage >= 10 || istype(get_turf(src), /turf/space))
+ if(isinspace())
//PULSE_THREADY - maximum value for pulse, currently it 5.
//High pulse value corresponds to a fast rate of heartbeat.
//Divided by 2, otherwise it is too slow.
@@ -980,7 +1042,7 @@
if(pulse == PULSE_NONE)
return
- if(pulse >= PULSE_2FAST || shock_stage >= 10 || istype(get_turf(src), /turf/space))
+ if(pulse >= PULSE_2FAST || isinspace())
//PULSE_THREADY - maximum value for pulse, currently it 5.
//High pulse value corresponds to a fast rate of heartbeat.
//Divided by 2, otherwise it is too slow.
@@ -999,7 +1061,7 @@
*/
/mob/living/carbon/human/proc/can_heartattack()
- if(NO_BLOOD in dna.species.species_traits)
+ if((NO_BLOOD in dna.species.species_traits) && !dna.species.forced_heartattack)
return FALSE
if(NO_INTORGANS in dna.species.species_traits)
return FALSE
@@ -1026,16 +1088,19 @@
heart.beating = !status
-/mob/living/carbon/human/proc/handle_heartattack()
+/mob/living/carbon/human/handle_heartattack()
if(!can_heartattack() || !undergoing_cardiac_arrest() || reagents.has_reagent("corazone"))
return
- AdjustLoseBreath(2, bound_lower = 0, bound_upper = 3)
- adjustOxyLoss(5)
- Paralyse(4)
- adjustBruteLoss(2)
+ if(getOxyLoss())
+ adjustBrainLoss(3)
+ else if(prob(10))
+ adjustBrainLoss(1)
+ Weaken(5)
+ AdjustLoseBreath(20, bound_lower = 0, bound_upper = 25)
+ adjustOxyLoss(20)
// Need this in species.
//#undef HUMAN_MAX_OXYLOSS
-//#undef HUMAN_CRIT_MAX_OXYLOSS
+//#undef HUMAN_CRIT_MAX_OXYLOSS
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/login.dm b/code/modules/mob/living/carbon/human/login.dm
index e16c67a56d0..2964166e68f 100644
--- a/code/modules/mob/living/carbon/human/login.dm
+++ b/code/modules/mob/living/carbon/human/login.dm
@@ -1,4 +1,6 @@
/mob/living/carbon/human/Login()
+ if(player_logged)
+ overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow")
..()
if(dna.species && dna.species.ventcrawler)
diff --git a/code/modules/mob/living/carbon/human/logout.dm b/code/modules/mob/living/carbon/human/logout.dm
new file mode 100644
index 00000000000..2dae7ea5b9a
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/logout.dm
@@ -0,0 +1,4 @@
+/mob/living/carbon/human/Logout()
+ ..()
+ if(mind && mind.active && stat != DEAD)
+ overlays += image('icons/effects/effects.dmi', icon_state = "zzz_glow")
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index ff8083f8093..1be6fc60a25 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -91,7 +91,7 @@
var/obj/item/organ/internal/L = get_organ_slot("lungs")
if((breathes && !L) || breathes && L && (L.status & ORGAN_DEAD))
return FALSE
- if(oxyloss > 10 || losebreath >= 4)
+ if(getOxyLoss() > 10 || losebreath >= 4)
emote("gasp")
return FALSE
if(mind)
diff --git a/code/modules/mob/living/carbon/human/shock.dm b/code/modules/mob/living/carbon/human/shock.dm
deleted file mode 100644
index e2d5dd79cec..00000000000
--- a/code/modules/mob/living/carbon/human/shock.dm
+++ /dev/null
@@ -1,75 +0,0 @@
-/mob/living/carbon/human/var/traumatic_shock = 0
-/mob/living/carbon/human/var/shock_stage = 0
-
-// proc to find out in how much pain the mob is at the moment
-/mob/living/carbon/human/proc/updateshock()
- traumatic_shock = getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss()
-
- // broken or ripped off organs will add quite a bit of pain
- for(var/thing in bodyparts)
- var/obj/item/organ/external/BP = thing
- if(BP.status & ORGAN_BROKEN && !(BP.status & ORGAN_SPLINTED) || BP.open)
- traumatic_shock += 15
-
- if(reagents)
- for(var/datum/reagent/R in reagents.reagent_list)
- if(R.shock_reduction)
- traumatic_shock = max(0, traumatic_shock - R.shock_reduction) // now you too can varedit cyanide to reduce shock by 1000 - Iamgoofball
- if(drunk)
- traumatic_shock = max(0, traumatic_shock - 10)
-
- return traumatic_shock
-
-/mob/living/carbon/human/proc/handle_shock()
- if(status_flags & GODMODE) //godmode
- return
- if(NO_PAIN in dna.species.species_traits)
- return
-
- updateshock()
-
- if(health <= config.health_threshold_softcrit)// health 0 makes you immediately collapse
- shock_stage = max(shock_stage, 61)
-
- if(traumatic_shock >= 100)
- shock_stage += 1
- else
- shock_stage = min(shock_stage, 160)
- shock_stage = max(shock_stage-1, 0)
- return
-
- if(shock_stage == 10)
- to_chat(src, ""+pick("It hurts so much!", "You really need some painkillers..", "Dear god, the pain!"))
-
- if(shock_stage >= 30)
- if(shock_stage == 30)
- custom_emote(1,"is having trouble keeping [p_their()] eyes open.")
- EyeBlurry(2)
- Stuttering(5)
-
- if(shock_stage == 40)
- to_chat(src, ""+pick("The pain is excrutiating!", "Please, just end the pain!", "Your whole body is going numb!"))
-
- if(shock_stage >=60)
- if(shock_stage == 60)
- custom_emote(1,"falls limp.")
- if(prob(2))
- to_chat(src, ""+pick("The pain is excrutiating!", "Please, just end the pain!", "Your whole body is going numb!"))
- Weaken(20)
-
- if(shock_stage >= 80)
- if(prob(5))
- to_chat(src, ""+pick("The pain is excrutiating!", "Please, just end the pain!", "Your whole body is going numb!"))
- Weaken(20)
-
- if(shock_stage >= 120)
- if(prob(2))
- to_chat(src, ""+pick("You black out!", "You feel like you could die any moment now.", "You're about to lose consciousness."))
- Paralyse(5)
-
- if(shock_stage == 150)
- custom_emote(1,"can no longer stand, collapsing!")
- Weaken(20)
-
- if(shock_stage >= 150)
- Weaken(20)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm
index 1335c8e2d57..e9a88fdb033 100644
--- a/code/modules/mob/living/carbon/human/species/_species.dm
+++ b/code/modules/mob/living/carbon/human/species/_species.dm
@@ -91,6 +91,8 @@
var/is_small
var/show_ssd = 1
+ var/forced_heartattack = FALSE //Some species have blood, but we still want them to have heart attacks
+ var/dies_at_threshold = FALSE // Do they die or get knocked out at specific thresholds, or do they go through complex crit?
var/can_revive_by_healing // Determines whether or not this species can be revived by simply healing them
var/has_gender = TRUE
var/blacklisted = FALSE
@@ -255,8 +257,6 @@
. += (health_deficiency / 75)
else
. += (health_deficiency / 25)
- if(H.shock_stage >= 10)
- . += 3
. += 2 * H.stance_damage //damaged/missing feet or legs is slow
if((hungry >= 70) && !flight)
@@ -298,11 +298,8 @@
// (Slime People changing color based on the reagents they consume)
/datum/species/proc/handle_life(mob/living/carbon/human/H)
if((NO_BREATHE in species_traits) || (BREATHLESS in H.mutations))
- H.setOxyLoss(0)
- H.SetLoseBreath(0)
-
var/takes_crit_damage = (!(NOCRITDAMAGE in species_traits))
- if((H.health <= config.health_threshold_crit) && takes_crit_damage)
+ if((H.health <= HEALTH_THRESHOLD_CRIT) && takes_crit_damage)
H.adjustBruteLoss(1)
return
@@ -315,7 +312,7 @@
/datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(attacker_style && attacker_style.help_act(user, target))//adminfu only...
return TRUE
- if(target.health >= config.health_threshold_crit && !(target.status_flags & FAKEDEATH))
+ if(target.health >= HEALTH_THRESHOLD_CRIT && !(target.status_flags & FAKEDEATH))
target.help_shake_act(user)
return TRUE
else
@@ -539,7 +536,7 @@
return FALSE
/datum/species/proc/get_perceived_trauma(mob/living/carbon/human/H)
- return 100 - ((NO_PAIN in species_traits) ? 0 : H.traumatic_shock) - H.getStaminaLoss()
+ return H.health - H.getStaminaLoss()
/datum/species/proc/handle_hud_icons(mob/living/carbon/human/H)
if(!H.client)
diff --git a/code/modules/mob/living/carbon/human/species/abductor.dm b/code/modules/mob/living/carbon/human/species/abductor.dm
index cf1492e8408..64c5a4aa0b3 100644
--- a/code/modules/mob/living/carbon/human/species/abductor.dm
+++ b/code/modules/mob/living/carbon/human/species/abductor.dm
@@ -16,8 +16,7 @@
)
species_traits = list(NO_BLOOD, NO_BREATHE, VIRUSIMMUNE, NOGUNS, NO_EXAMINE)
-
- oxy_mod = 0
+ dies_at_threshold = TRUE
clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS
dietflags = DIET_OMNI
diff --git a/code/modules/mob/living/carbon/human/species/diona.dm b/code/modules/mob/living/carbon/human/species/diona.dm
index 82def809a4b..bccbeb6c5a7 100644
--- a/code/modules/mob/living/carbon/human/species/diona.dm
+++ b/code/modules/mob/living/carbon/human/species/diona.dm
@@ -32,6 +32,7 @@
water and other radiation."
species_traits = list(NO_BREATHE, RADIMMUNE, IS_PLANT, NO_BLOOD, NO_PAIN)
+ dies_at_threshold = TRUE
clothing_flags = HAS_SOCKS
default_hair_colour = "#000000"
has_gender = FALSE
@@ -39,8 +40,6 @@
taste_sensitivity = TASTE_SENSITIVITY_NO_TASTE
skinned_type = /obj/item/stack/sheet/wood
- oxy_mod = 0
-
body_temperature = T0C + 15 //make the plant people have a bit lower body temperature, why not
blood_color = "#004400"
flesh_color = "#907E4A"
diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm
index 032af8ea3b9..e790181188e 100644
--- a/code/modules/mob/living/carbon/human/species/golem.dm
+++ b/code/modules/mob/living/carbon/human/species/golem.dm
@@ -6,10 +6,10 @@
deform = 'icons/mob/human_races/r_golem.dmi'
species_traits = list(NO_BREATHE, NO_BLOOD, NO_PAIN, RADIMMUNE, VIRUSIMMUNE, NOGUNS)
+ dies_at_threshold = TRUE
brute_mod = 0.45 //55% damage reduction
burn_mod = 0.45
tox_mod = 0.45
- oxy_mod = 0
dietflags = DIET_OMNI //golems can eat anything because they are magic or something
reagent_tag = PROCESS_ORG
@@ -163,6 +163,8 @@
if(H.bodytemperature > 850 && H.on_fire && prob(25))
explosion(get_turf(H), 1, 2, 4, flame_range = 5)
+ msg_admin_attack("Plasma Golem ([H.name]) exploded with radius 1, 2, 4 (flame_range: 5) at ([H.x],[H.y],[H.z]). User Ckey: [key_name_admin(H)]", ATKLOG_FEW)
+ log_game("Plasma Golem ([H.name]) exploded with radius 1, 2, 4 (flame_range: 5) at ([H.x],[H.y],[H.z]). User Ckey: [key_name_admin(H)]", ATKLOG_FEW)
if(H)
H.gib()
if(H.fire_stacks < 2) //flammable
@@ -533,23 +535,26 @@
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "blink"
icon_icon = 'icons/mob/actions/actions.dmi'
+ var/activated = FALSE // To prevent spamming
var/cooldown = 150
var/last_teleport = 0
var/tele_range = 6
/datum/action/innate/unstable_teleport/IsAvailable()
if(..())
- if(world.time > last_teleport + cooldown)
+ if(world.time > last_teleport + cooldown && !activated)
return 1
return 0
/datum/action/innate/unstable_teleport/Activate()
+ activated = TRUE
var/mob/living/carbon/human/H = owner
H.visible_message("[H] starts vibrating!", "You start charging your bluespace core...")
playsound(get_turf(H), 'sound/weapons/flash.ogg', 25, 1)
addtimer(CALLBACK(src, .proc/teleport, H), 15)
/datum/action/innate/unstable_teleport/proc/teleport(mob/living/carbon/human/H)
+ activated = FALSE
H.visible_message("[H] teleports!", "You teleport!")
var/list/turfs = new/list()
for(var/turf/T in orange(tele_range, H))
diff --git a/code/modules/mob/living/carbon/human/species/grey.dm b/code/modules/mob/living/carbon/human/species/grey.dm
index 31fb5db6661..e5492e60293 100644
--- a/code/modules/mob/living/carbon/human/species/grey.dm
+++ b/code/modules/mob/living/carbon/human/species/grey.dm
@@ -8,10 +8,10 @@
butt_sprite = "grey"
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
- "lungs" = /obj/item/organ/internal/lungs,
+ "heart" = /obj/item/organ/internal/heart/grey,
+ "lungs" = /obj/item/organ/internal/lungs/grey,
"liver" = /obj/item/organ/internal/liver/grey,
- "kidneys" = /obj/item/organ/internal/kidneys,
+ "kidneys" = /obj/item/organ/internal/kidneys/grey,
"brain" = /obj/item/organ/internal/brain/grey,
"appendix" = /obj/item/organ/internal/appendix,
"eyes" = /obj/item/organ/internal/eyes/grey //5 darksight.
diff --git a/code/modules/mob/living/carbon/human/species/kidan.dm b/code/modules/mob/living/carbon/human/species/kidan.dm
index 583e098054b..a1d2fb6624d 100644
--- a/code/modules/mob/living/carbon/human/species/kidan.dm
+++ b/code/modules/mob/living/carbon/human/species/kidan.dm
@@ -20,13 +20,13 @@
butt_sprite = "kidan"
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
- "lungs" = /obj/item/organ/internal/lungs,
+ "heart" = /obj/item/organ/internal/heart/kidan,
+ "lungs" = /obj/item/organ/internal/lungs/kidan,
"liver" = /obj/item/organ/internal/liver/kidan,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
+ "kidneys" = /obj/item/organ/internal/kidneys/kidan,
+ "brain" = /obj/item/organ/internal/brain/kidan,
"appendix" = /obj/item/organ/internal/appendix,
- "eyes" = /obj/item/organ/internal/eyes, //Default darksight of 2.
+ "eyes" = /obj/item/organ/internal/eyes/kidan, //Default darksight of 2.
"lantern" = /obj/item/organ/internal/lantern
)
diff --git a/code/modules/mob/living/carbon/human/species/machine.dm b/code/modules/mob/living/carbon/human/species/machine.dm
index 88ed0a626cb..4f5a65c82a2 100644
--- a/code/modules/mob/living/carbon/human/species/machine.dm
+++ b/code/modules/mob/living/carbon/human/species/machine.dm
@@ -19,7 +19,6 @@
burn_mod = 2.28 // So they take 50% extra damage from brute/burn overall
tox_mod = 0
clone_mod = 0
- oxy_mod = 0
death_message = "gives one shrill beep before falling limp, their monitor flashing blue before completely shutting off..."
species_traits = list(IS_WHITELISTED, NO_BREATHE, NO_SCAN, NO_INTORGANS, NO_PAIN, NO_DNA, RADIMMUNE, VIRUSIMMUNE, NOTRANSSTING)
@@ -36,6 +35,7 @@
//Default styles for created mobs.
default_hair = "Blue IPC Screen"
+ dies_at_threshold = TRUE
can_revive_by_healing = 1
has_gender = FALSE
reagent_tag = PROCESS_SYN
diff --git a/code/modules/mob/living/carbon/human/species/monkey.dm b/code/modules/mob/living/carbon/human/species/monkey.dm
index 5e926a23870..cac42a29cd2 100644
--- a/code/modules/mob/living/carbon/human/species/monkey.dm
+++ b/code/modules/mob/living/carbon/human/species/monkey.dm
@@ -108,11 +108,11 @@
tail = "farwatail"
reagent_tag = PROCESS_ORG
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
- "lungs" = /obj/item/organ/internal/lungs,
+ "heart" = /obj/item/organ/internal/heart/tajaran,
+ "lungs" = /obj/item/organ/internal/lungs/tajaran,
"liver" = /obj/item/organ/internal/liver/tajaran,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
+ "kidneys" = /obj/item/organ/internal/kidneys/tajaran,
+ "brain" = /obj/item/organ/internal/brain/tajaran,
"appendix" = /obj/item/organ/internal/appendix,
"eyes" = /obj/item/organ/internal/eyes/tajaran/farwa //Tajara monkey-forms are uniquely colourblind and have excellent darksight, which is why they need a subtype of their greater-form's organ..
)
@@ -132,11 +132,11 @@
tail = "wolpintail"
reagent_tag = PROCESS_ORG
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
- "lungs" = /obj/item/organ/internal/lungs,
+ "heart" = /obj/item/organ/internal/heart/vulpkanin,
+ "lungs" = /obj/item/organ/internal/lungs/vulpkanin,
"liver" = /obj/item/organ/internal/liver/vulpkanin,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
+ "kidneys" = /obj/item/organ/internal/kidneys/vulpkanin,
+ "brain" = /obj/item/organ/internal/brain/vulpkanin,
"appendix" = /obj/item/organ/internal/appendix,
"eyes" = /obj/item/organ/internal/eyes/vulpkanin/wolpin //Vulpkanin monkey-forms are uniquely colourblind and have excellent darksight, which is why they need a subtype of their greater-form's organ..
)
@@ -156,6 +156,16 @@
reagent_tag = PROCESS_ORG
tail = null
+ has_organ = list(
+ "heart" = /obj/item/organ/internal/heart/skrell,
+ "lungs" = /obj/item/organ/internal/lungs/skrell,
+ "liver" = /obj/item/organ/internal/liver/skrell,
+ "kidneys" = /obj/item/organ/internal/kidneys/skrell,
+ "brain" = /obj/item/organ/internal/brain/skrell,
+ "appendix" = /obj/item/organ/internal/appendix,
+ "eyes" = /obj/item/organ/internal/eyes/skrell //Tajara monkey-forms are uniquely colourblind and have excellent darksight, which is why they need a subtype of their greater-form's organ..
+ )
+
/datum/species/monkey/unathi
name = "Stok"
name_plural = "Stok"
@@ -171,3 +181,13 @@
reagent_tag = PROCESS_ORG
bodyflags = HAS_TAIL
+
+ has_organ = list(
+ "heart" = /obj/item/organ/internal/heart/unathi,
+ "lungs" = /obj/item/organ/internal/lungs/unathi,
+ "liver" = /obj/item/organ/internal/liver/unathi,
+ "kidneys" = /obj/item/organ/internal/kidneys/unathi,
+ "brain" = /obj/item/organ/internal/brain/unathi,
+ "appendix" = /obj/item/organ/internal/appendix,
+ "eyes" = /obj/item/organ/internal/eyes/unathi
+ )
diff --git a/code/modules/mob/living/carbon/human/species/nucleation.dm b/code/modules/mob/living/carbon/human/species/nucleation.dm
index 21d8a5c0012..fe8a5587017 100644
--- a/code/modules/mob/living/carbon/human/species/nucleation.dm
+++ b/code/modules/mob/living/carbon/human/species/nucleation.dm
@@ -13,8 +13,8 @@
language = "Sol Common"
burn_mod = 4 // holy shite, poor guys wont survive half a second cooking smores
brute_mod = 2 // damn, double wham, double dam
- oxy_mod = 0
species_traits = list(LIPS, IS_WHITELISTED, NO_BREATHE, NO_BLOOD, NO_PAIN, NO_SCAN, RADIMMUNE)
+ dies_at_threshold = TRUE
dietflags = DIET_OMNI //still human at their core, so they maintain their eating habits and diet
//Default styles for created mobs.
diff --git a/code/modules/mob/living/carbon/human/species/plasmaman.dm b/code/modules/mob/living/carbon/human/species/plasmaman.dm
index df2359af3df..ba249edb5a8 100644
--- a/code/modules/mob/living/carbon/human/species/plasmaman.dm
+++ b/code/modules/mob/living/carbon/human/species/plasmaman.dm
@@ -7,6 +7,7 @@
//language = "Clatter"
species_traits = list(IS_WHITELISTED, NO_BLOOD, NOTRANSSTING)
+ forced_heartattack = TRUE // Plasmamen have no blood, but they should still get heart-attacks
skinned_type = /obj/item/stack/sheet/mineral/plasma // We're low on plasma, R&D! *eyes plasmaman co-worker intently*
dietflags = DIET_OMNI
reagent_tag = PROCESS_ORG
@@ -30,13 +31,13 @@
"shows their true colors, which happens to be the color of plasma!")
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
+ "heart" = /obj/item/organ/internal/heart/plasmaman,
"lungs" = /obj/item/organ/internal/lungs/plasmaman,
- "liver" = /obj/item/organ/internal/liver,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
+ "liver" = /obj/item/organ/internal/liver/plasmaman,
+ "kidneys" = /obj/item/organ/internal/kidneys/plasmaman,
+ "brain" = /obj/item/organ/internal/brain/plasmaman,
"appendix" = /obj/item/organ/internal/appendix,
- "eyes" = /obj/item/organ/internal/eyes
+ "eyes" = /obj/item/organ/internal/eyes/plasmaman
)
speciesbox = /obj/item/storage/box/survival_plasmaman
diff --git a/code/modules/mob/living/carbon/human/species/shadow.dm b/code/modules/mob/living/carbon/human/species/shadow.dm
index df1ecd61484..fb7fd2ebda1 100644
--- a/code/modules/mob/living/carbon/human/species/shadow.dm
+++ b/code/modules/mob/living/carbon/human/species/shadow.dm
@@ -18,8 +18,7 @@
)
species_traits = list(NO_BREATHE, NO_BLOOD, RADIMMUNE, VIRUSIMMUNE)
-
- oxy_mod = 0
+ dies_at_threshold = TRUE
dietflags = DIET_OMNI //the mutation process allowed you to now digest all foods regardless of initial race
reagent_tag = PROCESS_ORG
diff --git a/code/modules/mob/living/carbon/human/species/shadowling.dm b/code/modules/mob/living/carbon/human/species/shadowling.dm
index 1ce7b5cd0e0..f65aedb530b 100644
--- a/code/modules/mob/living/carbon/human/species/shadowling.dm
+++ b/code/modules/mob/living/carbon/human/species/shadowling.dm
@@ -11,7 +11,6 @@
species_traits = list(NO_BLOOD, NO_BREATHE, RADIMMUNE, NOGUNS, NO_EXAMINE) //Can't use guns due to muzzle flash
burn_mod = 1.5 //1.5x burn damage, 2x is excessive
- oxy_mod = 0
heatmod = 1.5
silent_steps = 1
@@ -63,7 +62,6 @@
species_traits = list(NO_BLOOD, NO_BREATHE, RADIMMUNE, NO_EXAMINE)
burn_mod = 1.1
- oxy_mod = 0
heatmod = 1.1
/datum/species/shadow/ling/lesser/handle_life(mob/living/carbon/human/H)
diff --git a/code/modules/mob/living/carbon/human/species/skeleton.dm b/code/modules/mob/living/carbon/human/species/skeleton.dm
index 6a2b74fb671..50920798d70 100644
--- a/code/modules/mob/living/carbon/human/species/skeleton.dm
+++ b/code/modules/mob/living/carbon/human/species/skeleton.dm
@@ -11,10 +11,9 @@
flesh_color = "#E6E6C6"
species_traits = list(NO_BREATHE, NO_BLOOD, RADIMMUNE, VIRUSIMMUNE)
+ dies_at_threshold = TRUE
skinned_type = /obj/item/stack/sheet/bone
- oxy_mod = 0
-
dietflags = DIET_OMNI
reagent_tag = PROCESS_ORG
diff --git a/code/modules/mob/living/carbon/human/species/skrell.dm b/code/modules/mob/living/carbon/human/species/skrell.dm
index a7c24cd338c..009514f4902 100644
--- a/code/modules/mob/living/carbon/human/species/skrell.dm
+++ b/code/modules/mob/living/carbon/human/species/skrell.dm
@@ -28,13 +28,13 @@
butt_sprite = "skrell"
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
- "lungs" = /obj/item/organ/internal/lungs,
+ "heart" = /obj/item/organ/internal/heart/skrell,
+ "lungs" = /obj/item/organ/internal/lungs/skrell,
"liver" = /obj/item/organ/internal/liver/skrell,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
+ "kidneys" = /obj/item/organ/internal/kidneys/skrell,
+ "brain" = /obj/item/organ/internal/brain/skrell,
"appendix" = /obj/item/organ/internal/appendix,
- "eyes" = /obj/item/organ/internal/eyes, //Default darksight of 2.
+ "eyes" = /obj/item/organ/internal/eyes/skrell, //Default darksight of 2.
"headpocket" = /obj/item/organ/internal/headpocket
)
diff --git a/code/modules/mob/living/carbon/human/species/slime.dm b/code/modules/mob/living/carbon/human/species/slime.dm
index 5631f600afc..b33ebc1f048 100644
--- a/code/modules/mob/living/carbon/human/species/slime.dm
+++ b/code/modules/mob/living/carbon/human/species/slime.dm
@@ -20,13 +20,13 @@
cold_level_3 = 200
coldmod = 3
- oxy_mod = 0
brain_mod = 2.5
male_cough_sounds = list('sound/effects/slime_squish.ogg')
female_cough_sounds = list('sound/effects/slime_squish.ogg')
species_traits = list(LIPS, IS_WHITELISTED, NO_BREATHE, NO_INTORGANS, NO_SCAN)
+ dies_at_threshold = TRUE
clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS
bodyflags = HAS_SKIN_COLOR | NO_EYES
dietflags = DIET_CARN
@@ -83,7 +83,7 @@
H.update_body()
..()
-/datum/species/slime/can_hear() // fucking snowflakes
+/datum/species/slime/can_hear() // fucking snowflakes
. = TRUE
/datum/action/innate/slimecolor
diff --git a/code/modules/mob/living/carbon/human/species/tajaran.dm b/code/modules/mob/living/carbon/human/species/tajaran.dm
index d4cdaf95944..2b0c65aa821 100644
--- a/code/modules/mob/living/carbon/human/species/tajaran.dm
+++ b/code/modules/mob/living/carbon/human/species/tajaran.dm
@@ -30,16 +30,17 @@
dietflags = DIET_OMNI
taste_sensitivity = TASTE_SENSITIVITY_SHARP
reagent_tag = PROCESS_ORG
+
flesh_color = "#AFA59E"
base_color = "#424242"
butt_sprite = "tajaran"
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
- "lungs" = /obj/item/organ/internal/lungs,
+ "heart" = /obj/item/organ/internal/heart/tajaran,
+ "lungs" = /obj/item/organ/internal/lungs/tajaran,
"liver" = /obj/item/organ/internal/liver/tajaran,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
+ "kidneys" = /obj/item/organ/internal/kidneys/tajaran,
+ "brain" = /obj/item/organ/internal/brain/tajaran,
"appendix" = /obj/item/organ/internal/appendix,
"eyes" = /obj/item/organ/internal/eyes/tajaran /*Most Tajara see in full colour as a result of genetic augmentation, although it cost them their darksight (darksight = 2)
unless they choose otherwise by selecting the colourblind disability in character creation (darksight = 8 but colourblind).*/
diff --git a/code/modules/mob/living/carbon/human/species/unathi.dm b/code/modules/mob/living/carbon/human/species/unathi.dm
index bcad7d9342e..f255091a7d6 100644
--- a/code/modules/mob/living/carbon/human/species/unathi.dm
+++ b/code/modules/mob/living/carbon/human/species/unathi.dm
@@ -38,11 +38,11 @@
brute_mod = 1.05
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
- "lungs" = /obj/item/organ/internal/lungs,
+ "heart" = /obj/item/organ/internal/heart/unathi,
+ "lungs" = /obj/item/organ/internal/lungs/unathi,
"liver" = /obj/item/organ/internal/liver/unathi,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
+ "kidneys" = /obj/item/organ/internal/kidneys/unathi,
+ "brain" = /obj/item/organ/internal/brain/unathi,
"appendix" = /obj/item/organ/internal/appendix,
"eyes" = /obj/item/organ/internal/eyes/unathi //3 darksight.
)
diff --git a/code/modules/mob/living/carbon/human/species/vox.dm b/code/modules/mob/living/carbon/human/species/vox.dm
index b3ac08580aa..436c3d32b3b 100644
--- a/code/modules/mob/living/carbon/human/species/vox.dm
+++ b/code/modules/mob/living/carbon/human/species/vox.dm
@@ -62,13 +62,13 @@
)
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
+ "heart" = /obj/item/organ/internal/heart/vox,
"lungs" = /obj/item/organ/internal/lungs/vox,
"liver" = /obj/item/organ/internal/liver/vox,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
+ "kidneys" = /obj/item/organ/internal/kidneys/vox,
+ "brain" = /obj/item/organ/internal/brain/vox,
"appendix" = /obj/item/organ/internal/appendix,
- "eyes" = /obj/item/organ/internal/eyes, //Default darksight of 2.
+ "eyes" = /obj/item/organ/internal/eyes/vox, //Default darksight of 2.
"stack" = /obj/item/organ/internal/stack //Not the same as the cortical stack implant Vox Raiders spawn with. The cortical stack implant is used
) //for determining the success of the heist game-mode's 'leave nobody behind' objective, while this is just an organ.
@@ -173,6 +173,7 @@
eyes = "blank_eyes"
species_traits = list(NO_SCAN, NO_BLOOD, NO_PAIN, IS_WHITELISTED)
+ dies_at_threshold = TRUE
bodyflags = HAS_TAIL
dietflags = DIET_OMNI //should inherit this from vox, this is here just in case
diff --git a/code/modules/mob/living/carbon/human/species/vulpkanin.dm b/code/modules/mob/living/carbon/human/species/vulpkanin.dm
index 3e6ebc1d41d..2ff707ee020 100644
--- a/code/modules/mob/living/carbon/human/species/vulpkanin.dm
+++ b/code/modules/mob/living/carbon/human/species/vulpkanin.dm
@@ -22,6 +22,7 @@
hunger_drain = 0.11
taste_sensitivity = TASTE_SENSITIVITY_SHARP
reagent_tag = PROCESS_ORG
+
flesh_color = "#966464"
base_color = "#CF4D2F"
butt_sprite = "vulp"
@@ -29,11 +30,11 @@
scream_verb = "yelps"
has_organ = list(
- "heart" = /obj/item/organ/internal/heart,
- "lungs" = /obj/item/organ/internal/lungs,
+ "heart" = /obj/item/organ/internal/heart/vulpkanin,
+ "lungs" = /obj/item/organ/internal/lungs/vulpkanin,
"liver" = /obj/item/organ/internal/liver/vulpkanin,
- "kidneys" = /obj/item/organ/internal/kidneys,
- "brain" = /obj/item/organ/internal/brain,
+ "kidneys" = /obj/item/organ/internal/kidneys/vulpkanin,
+ "brain" = /obj/item/organ/internal/brain/vulpkanin,
"appendix" = /obj/item/organ/internal/appendix,
"eyes" = /obj/item/organ/internal/eyes/vulpkanin /*Most Vulpkanin see in full colour as a result of genetic augmentation, although it cost them their darksight (darksight = 2)
unless they choose otherwise by selecting the colourblind disability in character creation (darksight = 8 but colourblind).*/
diff --git a/code/modules/mob/living/carbon/human/species/wryn.dm b/code/modules/mob/living/carbon/human/species/wryn.dm
index 8c576f9e30e..6069da28f84 100644
--- a/code/modules/mob/living/carbon/human/species/wryn.dm
+++ b/code/modules/mob/living/carbon/human/species/wryn.dm
@@ -39,7 +39,7 @@
clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS
dietflags = DIET_HERB //bees feed off nectar, so bee people feed off plants too
- oxy_mod = 0
+ dies_at_threshold = TRUE
reagent_tag = PROCESS_ORG
base_color = "#704300"
diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm
index e7a65129017..30653023751 100644
--- a/code/modules/mob/living/carbon/human/status_procs.dm
+++ b/code/modules/mob/living/carbon/human/status_procs.dm
@@ -1,3 +1,9 @@
+/mob/living/carbon/human/SetLoseBreath(amount)
+ if(NO_BREATHE in dna.species.species_traits)
+ losebreath = 0
+ return FALSE
+ . = ..()
+
/mob/living/carbon/human/SetStunned(amount, updating = 1, force = 0)
if(dna.species)
amount = amount * dna.species.stun_mod
diff --git a/code/modules/mob/living/carbon/human/update_stat.dm b/code/modules/mob/living/carbon/human/update_stat.dm
index d8c26a91964..5dfd98c0b63 100644
--- a/code/modules/mob/living/carbon/human/update_stat.dm
+++ b/code/modules/mob/living/carbon/human/update_stat.dm
@@ -15,7 +15,7 @@
if(dna.species && dna.species.can_revive_by_healing)
var/obj/item/organ/internal/brain/B = get_int_organ(/obj/item/organ/internal/brain)
if(B)
- if((health >= (config.health_threshold_dead + config.health_threshold_crit) * 0.5) && getBrainLoss()<120)
+ if((health >= (HEALTH_THRESHOLD_DEAD + HEALTH_THRESHOLD_CRIT) * 0.5) && getBrainLoss() < 120)
update_revive()
create_debug_log("revived from healing, trigger reason: [reason]")
@@ -30,4 +30,7 @@
/mob/living/carbon/human/can_hear()
. = TRUE // Fallback if we don't have a species
if(dna.species)
- . = dna.species.can_hear(src)
\ No newline at end of file
+ . = dna.species.can_hear(src)
+
+/mob/living/carbon/human/check_death_method()
+ return dna.species.dies_at_threshold
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 18e42c98d08..48d8137092a 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -27,8 +27,8 @@
//Start of a breath chain, calls breathe()
/mob/living/carbon/handle_breathing(times_fired)
- if(times_fired % 4 == 2 || failed_last_breath)
- breathe() //Breathe per 4 ticks, unless suffocating
+ if(times_fired % 2 == 1)
+ breathe() //Breathe every other tick, unless suffocating
else
if(istype(loc, /obj/))
var/obj/location_as_object = loc
@@ -47,13 +47,13 @@
var/datum/gas_mixture/breath
- if(health <= config.health_threshold_crit)
+ if(health <= HEALTH_THRESHOLD_CRIT && check_death_method())
AdjustLoseBreath(1)
//Suffocate
if(losebreath > 0)
AdjustLoseBreath(-1)
- if(prob(10))
+ if(prob(75))
emote("gasp")
if(istype(loc, /obj/))
var/obj/loc_as_obj = loc
@@ -97,7 +97,6 @@
//CRIT
if(!breath || (breath.total_moles() == 0) || !lungs)
adjustOxyLoss(1)
- failed_last_breath = TRUE
throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
return FALSE
@@ -121,15 +120,12 @@
if(O2_partialpressure > 0)
var/ratio = 1 - O2_partialpressure/safe_oxy_min
adjustOxyLoss(min(5*ratio, 3))
- failed_last_breath = TRUE
oxygen_used = breath.oxygen*ratio
else
adjustOxyLoss(3)
- failed_last_breath = TRUE
throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
else //Enough oxygen
- failed_last_breath = FALSE
adjustOxyLoss(-5)
oxygen_used = breath.oxygen
clear_alert("not_enough_oxy")
@@ -406,35 +402,54 @@
handle_hud_icons_health_overlay()
/mob/living/carbon/proc/handle_hud_icons_health_overlay()
- if(stat == UNCONSCIOUS && health <= config.health_threshold_crit)
- var/severity = 0
- switch(health)
- if(-20 to -10) severity = 1
- if(-30 to -20) severity = 2
- if(-40 to -30) severity = 3
- if(-50 to -40) severity = 4
- if(-60 to -50) severity = 5
- if(-70 to -60) severity = 6
- if(-80 to -70) severity = 7
- if(-90 to -80) severity = 8
- if(-95 to -90) severity = 9
- if(-INFINITY to -95) severity = 10
- overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity)
- else if(stat == CONSCIOUS)
- clear_fullscreen("crit")
- if(oxyloss)
+ if(stat == UNCONSCIOUS && health <= HEALTH_THRESHOLD_CRIT)
+ if(check_death_method())
var/severity = 0
- switch(oxyloss)
- if(10 to 20) severity = 1
- if(20 to 25) severity = 2
- if(25 to 30) severity = 3
- if(30 to 35) severity = 4
- if(35 to 40) severity = 5
- if(40 to 45) severity = 6
- if(45 to INFINITY) severity = 7
- overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity)
- else
- clear_fullscreen("oxy")
+ switch(health)
+ if(-20 to -10)
+ severity = 1
+ if(-30 to -20)
+ severity = 2
+ if(-40 to -30)
+ severity = 3
+ if(-50 to -40)
+ severity = 4
+ if(-60 to -50)
+ severity = 5
+ if(-70 to -60)
+ severity = 6
+ if(-80 to -70)
+ severity = 7
+ if(-90 to -80)
+ severity = 8
+ if(-95 to -90)
+ severity = 9
+ if(-INFINITY to -95)
+ severity = 10
+ overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity)
+ else if(stat == CONSCIOUS)
+ if(check_death_method())
+ clear_fullscreen("crit")
+ if(getOxyLoss())
+ var/severity = 0
+ switch(getOxyLoss())
+ if(10 to 20)
+ severity = 1
+ if(20 to 25)
+ severity = 2
+ if(25 to 30)
+ severity = 3
+ if(30 to 35)
+ severity = 4
+ if(35 to 40)
+ severity = 5
+ if(40 to 45)
+ severity = 6
+ if(45 to INFINITY)
+ severity = 7
+ overlay_fullscreen("oxy", /obj/screen/fullscreen/oxy, severity)
+ else
+ clear_fullscreen("oxy")
//Fire and Brute damage overlay (BSSR)
var/hurtdamage = getBruteLoss() + getFireLoss() + damageoverlaytemp
@@ -450,4 +465,4 @@
if(85 to INFINITY) severity = 6
overlay_fullscreen("brute", /obj/screen/fullscreen/brute, severity)
else
- clear_fullscreen("brute")
+ clear_fullscreen("brute")
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/slime/life.dm b/code/modules/mob/living/carbon/slime/life.dm
index 649ec7b3f00..e3bfcb74431 100644
--- a/code/modules/mob/living/carbon/slime/life.dm
+++ b/code/modules/mob/living/carbon/slime/life.dm
@@ -174,11 +174,11 @@
else
health = 150 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
- if(health < config.health_threshold_dead && stat != 2)
+ if(health < HEALTH_THRESHOLD_DEAD && check_death_method() && stat != DEAD)
death()
return
- else if(src.health <= config.health_threshold_crit)
+ else if(src.health <= HEALTH_THRESHOLD_CRIT && check_death_method())
if(!src.reagents.has_reagent("epinephrine"))
src.adjustOxyLoss(10)
diff --git a/code/modules/mob/living/carbon/update_status.dm b/code/modules/mob/living/carbon/update_status.dm
index 22030c78f4b..58c6e09764b 100644
--- a/code/modules/mob/living/carbon/update_status.dm
+++ b/code/modules/mob/living/carbon/update_status.dm
@@ -3,12 +3,12 @@
return
if(stat != DEAD)
// if(health <= min_health)
- if(health <= config.health_threshold_dead)
+ if(health <= HEALTH_THRESHOLD_DEAD && check_death_method())
death()
create_debug_log("died of damage, trigger reason: [reason]")
return
// if(paralysis || sleeping || getOxyLoss() > low_oxy_ko || (status_flags & FAKEDEATH) || health <= crit_health)
- if(paralysis || sleeping || getOxyLoss() > 50 || (status_flags & FAKEDEATH) || health <= config.health_threshold_crit)
+ if(paralysis || sleeping || (check_death_method() && getOxyLoss() > 50) || (status_flags & FAKEDEATH) || health <= HEALTH_THRESHOLD_CRIT && check_death_method())
if(stat == CONSCIOUS)
KnockOut()
create_debug_log("fell unconscious, trigger reason: [reason]")
@@ -21,7 +21,7 @@
..()
if(staminaloss)
var/total_health = (health - staminaloss)
- if(total_health <= config.health_threshold_softcrit && !stat)
+ if(total_health <= HEALTH_THRESHOLD_CRIT && !stat)
to_chat(src, "You're too exhausted to keep going...")
Weaken(5)
setStaminaLoss(health - 2)
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index 734dd556b48..afca9ad8798 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -104,11 +104,11 @@
/mob/living/proc/getBruteLoss()
return bruteloss
-/mob/living/proc/adjustBruteLoss(var/amount, updating_health = TRUE)
+/mob/living/proc/adjustBruteLoss(amount, updating_health = TRUE)
if(status_flags & GODMODE)
return FALSE //godmode
var/old_bruteloss = bruteloss
- bruteloss = min(max(bruteloss + amount, 0),(maxHealth*2))
+ bruteloss = max(bruteloss + amount, 0)
if(old_bruteloss == bruteloss)
updating_health = FALSE
. = STATUS_UPDATE_NONE
@@ -120,11 +120,15 @@
/mob/living/proc/getOxyLoss()
return oxyloss
-/mob/living/proc/adjustOxyLoss(var/amount, updating_health = TRUE)
+/mob/living/proc/adjustOxyLoss(amount, updating_health = TRUE)
if(status_flags & GODMODE)
+ oxyloss = 0
return FALSE //godmode
+ if(BREATHLESS in mutations)
+ oxyloss = 0
+ return FALSE
var/old_oxyloss = oxyloss
- oxyloss = min(max(oxyloss + amount, 0),(maxHealth*2))
+ oxyloss = max(oxyloss + amount, 0)
if(old_oxyloss == oxyloss)
updating_health = FALSE
. = STATUS_UPDATE_NONE
@@ -135,7 +139,11 @@
/mob/living/proc/setOxyLoss(amount, updating_health = TRUE)
if(status_flags & GODMODE)
+ oxyloss = 0
return FALSE //godmode
+ if(BREATHLESS in mutations)
+ oxyloss = 0
+ return FALSE
var/old_oxyloss = oxyloss
oxyloss = amount
if(old_oxyloss == oxyloss)
@@ -149,11 +157,11 @@
/mob/living/proc/getToxLoss()
return toxloss
-/mob/living/proc/adjustToxLoss(var/amount, updating_health = TRUE)
+/mob/living/proc/adjustToxLoss(amount, updating_health = TRUE)
if(status_flags & GODMODE)
return FALSE //godmode
var/old_toxloss = toxloss
- toxloss = min(max(toxloss + amount, 0),(maxHealth*2))
+ toxloss = max(toxloss + amount, 0)
if(old_toxloss == toxloss)
updating_health = FALSE
. = STATUS_UPDATE_NONE
@@ -162,7 +170,7 @@
if(updating_health)
updatehealth("adjustToxLoss")
-/mob/living/proc/setToxLoss(var/amount, updating_health = TRUE)
+/mob/living/proc/setToxLoss(amount, updating_health = TRUE)
if(status_flags & GODMODE)
return FALSE //godmode
var/old_toxloss = toxloss
@@ -178,11 +186,11 @@
/mob/living/proc/getFireLoss()
return fireloss
-/mob/living/proc/adjustFireLoss(var/amount, updating_health = TRUE)
+/mob/living/proc/adjustFireLoss(amount, updating_health = TRUE)
if(status_flags & GODMODE)
return FALSE //godmode
var/old_fireloss = fireloss
- fireloss = min(max(fireloss + amount, 0),(maxHealth*2))
+ fireloss = max(fireloss + amount, 0)
if(old_fireloss == fireloss)
updating_health = FALSE
. = STATUS_UPDATE_NONE
@@ -194,11 +202,11 @@
/mob/living/proc/getCloneLoss()
return cloneloss
-/mob/living/proc/adjustCloneLoss(var/amount, updating_health = TRUE)
+/mob/living/proc/adjustCloneLoss(amount, updating_health = TRUE)
if(status_flags & GODMODE)
return FALSE //godmode
var/old_cloneloss = cloneloss
- cloneloss = min(max(cloneloss + amount, 0),(maxHealth*2))
+ cloneloss = max(cloneloss + amount, 0)
if(old_cloneloss == cloneloss)
updating_health = FALSE
. = STATUS_UPDATE_NONE
@@ -207,8 +215,9 @@
if(updating_health)
updatehealth("adjustCloneLoss")
-/mob/living/proc/setCloneLoss(var/amount, updating_health = TRUE)
- if(status_flags & GODMODE) return 0 //godmode
+/mob/living/proc/setCloneLoss(amount, updating_health = TRUE)
+ if(status_flags & GODMODE)
+ return FALSE //godmode
var/old_cloneloss = cloneloss
cloneloss = amount
if(old_cloneloss == cloneloss)
@@ -235,7 +244,7 @@
if(status_flags & GODMODE)
return FALSE
var/old_stamloss = staminaloss
- staminaloss = min(max(staminaloss + amount, 0),(maxHealth*2))
+ staminaloss = max(staminaloss + amount, 0)
if(old_stamloss == staminaloss)
updating = FALSE
. = STATUS_UPDATE_NONE
@@ -300,4 +309,4 @@
updatehealth("take overall damage")
/mob/living/proc/has_organic_damage()
- return (maxHealth - health)
+ return (maxHealth - health)
\ No newline at end of file
diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm
index 43a811dc3a3..003b5c3d4fe 100644
--- a/code/modules/mob/living/death.dm
+++ b/code/modules/mob/living/death.dm
@@ -59,7 +59,7 @@
if(!gibbed && deathgasp_on_death)
emote("deathgasp")
- if(suiciding)
+ if(mind && suiciding)
mind.suicided = TRUE
clear_fullscreens()
update_sight()
@@ -96,3 +96,9 @@
// u no we dead
return TRUE
+
+/mob/living/proc/delayed_gib()
+ visible_message("[src] starts convulsing violently!", "You feel as if your body is tearing itself apart!")
+ Weaken(15)
+ do_jitter_animation(1000, -1)
+ addtimer(CALLBACK(src, .proc/gib), rand(20, 100))
\ No newline at end of file
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 66f3eec1683..0569c944382 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -25,6 +25,10 @@
handle_diseases()
+ //Heart Attack, if applicable
+ if(stat != DEAD)
+ handle_heartattack()
+
//Handle temperature/pressure differences between body and environment
if(environment)
handle_environment(environment)
@@ -56,6 +60,9 @@
/mob/living/proc/handle_breathing(times_fired)
return
+/mob/living/proc/handle_heartattack()
+ return
+
/mob/living/proc/handle_mutations_and_radiation()
radiation = 0 //so radiation don't accumulate in simple animals
return
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index bf933f568d4..52fde3d0d9e 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -246,17 +246,18 @@
set hidden = 1
if(InCritical())
create_attack_log("[src] has ["succumbed to death"] with [round(health, 0.1)] points of health!")
- adjustOxyLoss(health - config.health_threshold_dead)
+ adjustOxyLoss(health - HEALTH_THRESHOLD_DEAD)
// super check for weird mobs, including ones that adjust hp
// we don't want to go overboard and gib them, though
for(var/i = 1 to 5)
- if(health < config.health_threshold_dead)
+ if(health < HEALTH_THRESHOLD_DEAD)
break
- take_overall_damage(max(5, health - config.health_threshold_dead), 0)
+ take_overall_damage(max(5, health - HEALTH_THRESHOLD_DEAD), 0)
+ death()
to_chat(src, "You have given up life and succumbed to death.")
/mob/living/proc/InCritical()
- return (health < 0 && health > -95.0 && stat == UNCONSCIOUS)
+ return (health < HEALTH_THRESHOLD_CRIT && health > HEALTH_THRESHOLD_DEAD && stat == UNCONSCIOUS)
/mob/living/ex_act(severity)
..()
@@ -462,7 +463,6 @@
human_mob = src
human_mob.set_heartattack(FALSE)
human_mob.restore_blood()
- human_mob.shock_stage = 0
human_mob.decaylevel = 0
human_mob.remove_all_embedded_objects()
@@ -759,7 +759,7 @@
if(!silent)
visible_message("[src] tries to put [what] on [who].")
if(do_mob(src, who, what.put_on_delay))
- if(what && Adjacent(who))
+ if(what && Adjacent(who) && !(what.flags & NODROP))
unEquip(what)
who.equip_to_slot_if_possible(what, where, 0, 1)
add_attack_logs(src, who, "Equipped [what]")
@@ -786,11 +786,11 @@
..()
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
-/mob/living/proc/do_jitter_animation(jitteriness)
+/mob/living/proc/do_jitter_animation(jitteriness, loop_amount = 6)
var/amplitude = min(4, (jitteriness/100) + 1)
var/pixel_x_diff = rand(-amplitude, amplitude)
var/pixel_y_diff = rand(-amplitude/3, amplitude/3)
- animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff , time = 2, loop = 6)
+ animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff , time = 2, loop = loop_amount)
animate(pixel_x = initial(pixel_x) , pixel_y = initial(pixel_y) , time = 2)
floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index f65faaba70d..0641ce380f5 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -179,7 +179,8 @@
var/turf/location = get_turf(src)
location.hotspot_expose(700, 50, 1)
-/mob/living/fire_act()
+/mob/living/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
+ ..()
adjust_fire_stacks(3)
IgniteMob()
diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm
index 57e5623cbbf..dcc046f7b00 100644
--- a/code/modules/mob/living/login.dm
+++ b/code/modules/mob/living/login.dm
@@ -7,7 +7,6 @@
//If they're SSD, remove it so they can wake back up.
player_logged = 0
-
//Vents
if(ventcrawler)
to_chat(src, "You can ventcrawl! Use alt+click on vents to quickly travel about the station.")
diff --git a/code/modules/mob/living/logout.dm b/code/modules/mob/living/logout.dm
index 910a72aeca3..87384669a7c 100644
--- a/code/modules/mob/living/logout.dm
+++ b/code/modules/mob/living/logout.dm
@@ -9,4 +9,4 @@
if(mind.active)
Sleeping(2)
player_logged = 1
- last_logout = world.time
+ last_logout = world.time
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 5f0397becfe..ccf319b0884 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -38,7 +38,7 @@ var/list/ai_verbs_default = list(
name = "AI"
icon = 'icons/mob/ai.dmi'//
icon_state = "ai"
- move_resist = MOVE_FORCE_VERY_STRONG
+ move_resist = MOVE_FORCE_NORMAL
density = 1
status_flags = CANSTUN|CANPARALYSE|CANPUSH
mob_size = MOB_SIZE_LARGE
@@ -534,14 +534,12 @@ var/list/ai_verbs_default = list(
if(!isturf(loc)) // if their location isn't a turf
return // stop
- var/is_anchored = FALSE
- if(move_resist == MOVE_FORCE_VERY_STRONG)
- move_resist = MOVE_FORCE_VERY_STRONG
+ if(anchored)
+ anchored = FALSE
else
- is_anchored = TRUE
- move_resist = MOVE_FORCE_NORMAL
+ anchored = TRUE
- to_chat(src, "[is_anchored ? "You are now anchored." : "You are now unanchored."]")
+ to_chat(src, "[anchored ? "You are now anchored." : "You are now unanchored."]")
/mob/living/silicon/ai/update_canmove()
return FALSE
@@ -1113,7 +1111,7 @@ var/list/ai_verbs_default = list(
user.visible_message("\The [user] decides not to unbolt \the [src].")
return
user.visible_message("\The [user] finishes unfastening \the [src]!")
- anchored = 0
+ anchored = FALSE
return
else
user.visible_message("\The [user] starts to bolt \the [src] to the plating...")
@@ -1121,7 +1119,7 @@ var/list/ai_verbs_default = list(
user.visible_message("\The [user] decides not to bolt \the [src].")
return
user.visible_message("\The [user] finishes fastening down \the [src]!")
- anchored = 1
+ anchored = TRUE
return
else
return ..()
diff --git a/code/modules/mob/living/silicon/ai/update_status.dm b/code/modules/mob/living/silicon/ai/update_status.dm
index 18a35534db8..fd001956c67 100644
--- a/code/modules/mob/living/silicon/ai/update_status.dm
+++ b/code/modules/mob/living/silicon/ai/update_status.dm
@@ -2,7 +2,7 @@
if(status_flags & GODMODE)
return
if(stat != DEAD)
- if(health <= config.health_threshold_dead)
+ if(health <= HEALTH_THRESHOLD_DEAD && check_death_method())
death()
create_debug_log("died of damage, trigger reason: [reason]")
return
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 752cdc0f631..5f37177f674 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -230,7 +230,7 @@
if(on_fire)
overlays += image("icon"='icons/mob/OnFire.dmi', "icon_state"="Generic_mob_burning")
-/mob/living/silicon/robot/fire_act()
+/mob/living/silicon/robot/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
IgniteMob()
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 5cbdf9f3fa8..a84af2c8254 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -144,6 +144,7 @@
modules += new /obj/item/robotanalyzer(src)
modules += new /obj/item/reagent_scanner/adv(src)
modules += new /obj/item/borg_defib(src)
+ modules += new /obj/item/handheld_defibrillator(src)
modules += new /obj/item/roller_holder(src)
modules += new /obj/item/reagent_containers/borghypo(src)
modules += new /obj/item/reagent_containers/glass/beaker/large(src)
@@ -412,6 +413,7 @@
modules += new /obj/item/reagent_scanner/adv(src)
modules += new /obj/item/bodyanalyzer/borg/syndicate(src)
modules += new /obj/item/borg_defib(src)
+ modules += new /obj/item/handheld_defibrillator(src)
modules += new /obj/item/roller_holder(src)
modules += new /obj/item/reagent_containers/borghypo/syndicate(src)
modules += new /obj/item/extinguisher/mini(src)
@@ -427,6 +429,7 @@
modules += new /obj/item/bonesetter(src)
modules += new /obj/item/surgicaldrill(src)
modules += new /obj/item/gripper/medical(src)
+ modules += new /obj/item/gun/medbeam(src)
modules += new /obj/item/melee/energy/sword/cyborg/saw(src) //Energy saw -- primary weapon
modules += new /obj/item/card/emag(src)
modules += new /obj/item/crowbar/cyborg(src)
diff --git a/code/modules/mob/living/simple_animal/bot/emote.dm b/code/modules/mob/living/simple_animal/bot/emote.dm
index 2ea085464a7..eb6a18e8657 100644
--- a/code/modules/mob/living/simple_animal/bot/emote.dm
+++ b/code/modules/mob/living/simple_animal/bot/emote.dm
@@ -1,4 +1,4 @@
-/mob/living/simple_animal/bot/emote(var/act, var/m_type=1, var/message = null)
+/mob/living/simple_animal/bot/emote(act, m_type=1, message = null)
var/param = null
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
@@ -69,4 +69,6 @@
playsound(src.loc, 'sound/goonstation/voice/robot_scream.ogg', 80, 0)
m_type = 2
+ if("help")
+ to_chat(src, "scream(s), yes, no, beep, buzz, ping")
..(act, m_type, message)
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index c37b54938ac..9532daabab8 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -11,6 +11,7 @@
speak_emote = list("purrs", "meows")
emote_hear = list("meows", "mews")
emote_see = list("shakes its head", "shivers")
+ var/meow_sound = 'sound/creatures/cat_meow.ogg' //Used in emote.
speak_chance = 1
turns_per_move = 5
see_in_dark = 6
@@ -146,6 +147,40 @@
stop_automated_movement = 1
walk_to(src,movement_target,0,3)
+/mob/living/simple_animal/pet/cat/emote(act, m_type=1, message = null)
+ if(stat != CONSCIOUS)
+ return
+
+ var/on_CD = 0
+ act = lowertext(act)
+ switch(act)
+ if("meow")
+ on_CD = handle_emote_CD()
+ if("hiss")
+ on_CD = handle_emote_CD()
+ if("purr")
+ on_CD = handle_emote_CD()
+ else
+ on_CD = 0
+
+ if(on_CD == 1)
+ return
+
+ switch(act)
+ if("meow")
+ message = "[src] [pick(emote_hear)]!"
+ m_type = 2 //audible
+ playsound(src, meow_sound, 50, 0.75)
+ if("hiss")
+ message = "[src] hisses!"
+ m_type = 2
+ if("purr")
+ message = "[src] purrs."
+ m_type = 2
+ if("help")
+ to_chat(src, "scream, meow, hiss, purr")
+
+ ..()
/mob/living/simple_animal/pet/cat/Proc
name = "Proc"
@@ -168,6 +203,7 @@
icon_living = "Syndicat"
icon_dead = "Syndicat_dead"
icon_resting = "Syndicat_rest"
+ meow_sound = null //Need robo-meow.
gender = FEMALE
mutations = list(BREATHLESS)
faction = list("syndicate")
diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm
index 4d7ff459563..832d92c9d8f 100644
--- a/code/modules/mob/living/simple_animal/friendly/corgi.dm
+++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm
@@ -13,6 +13,8 @@
speak_emote = list("barks", "woofs")
emote_hear = list("barks", "woofs", "yaps","pants")
emote_see = list("shakes its head", "shivers")
+ var/bark_sound = list('sound/creatures/dog_bark1.ogg','sound/creatures/dog_bark2.ogg') //Used in emote.
+ var/yelp_sound = 'sound/creatures/dog_yelp.ogg' //Used on death.
speak_chance = 1
turns_per_move = 10
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/corgi = 3)
@@ -401,6 +403,40 @@
return valid
+/mob/living/simple_animal/pet/corgi/death(gibbed)
+ playsound(src, yelp_sound, 75, 1)
+ ..()
+
+/mob/living/simple_animal/pet/corgi/emote(act, m_type=1, message = null)
+ if(stat != CONSCIOUS)
+ return
+
+ var/on_CD = 0
+ act = lowertext(act)
+ switch(act)
+ if("bark")
+ on_CD = handle_emote_CD()
+ if("growl")
+ on_CD = handle_emote_CD()
+ else
+ on_CD = 0
+
+ if(on_CD == 1)
+ return
+
+ switch(act)
+ if("bark")
+ message = "[src] [pick(src.speak_emote)]!"
+ m_type = 2 //audible
+ playsound(src, pick(src.bark_sound), 50, 0.85)
+ if("growl")
+ message = "[src] growls!"
+ m_type = 2 //audible
+ if("help")
+ to_chat(src, "scream, bark, growl")
+
+ ..()
+
//IAN! SQUEEEEEEEEE~
/mob/living/simple_animal/pet/corgi/Ian
@@ -574,6 +610,8 @@
desc = "It's a borgi."
icon_state = "borgi"
icon_living = "borgi"
+ bark_sound = null //No robo-bjork...
+ yelp_sound = null //Or robo-Yelp.
var/emagged = 0
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
diff --git a/code/modules/mob/living/simple_animal/friendly/crab.dm b/code/modules/mob/living/simple_animal/friendly/crab.dm
index 6e49437455e..94ecb71703b 100644
--- a/code/modules/mob/living/simple_animal/friendly/crab.dm
+++ b/code/modules/mob/living/simple_animal/friendly/crab.dm
@@ -11,9 +11,9 @@
speak_chance = 1
turns_per_move = 5
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat = 1)
- response_help = "pets the"
- response_disarm = "gently pushes aside the"
- response_harm = "stomps the"
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "stomps"
stop_automated_movement = 1
friendly = "pinches"
ventcrawler = 2
diff --git a/code/modules/mob/living/simple_animal/friendly/diona.dm b/code/modules/mob/living/simple_animal/friendly/diona.dm
index d4f40c6cf43..07a5fcf0131 100644
--- a/code/modules/mob/living/simple_animal/friendly/diona.dm
+++ b/code/modules/mob/living/simple_animal/friendly/diona.dm
@@ -32,7 +32,7 @@
melee_damage_upper = 8
attacktext = "bites"
attack_sound = 'sound/weapons/bite.ogg'
- var/chirp_sound = 'sound/misc/nymphchirp.ogg' //used in emote
+ var/chirp_sound = 'sound/creatures/nymphchirp.ogg' //used in emote
speed = 0
stop_automated_movement = 0
@@ -109,6 +109,8 @@
forceMove(M)
else
get_scooped(M)
+ else
+ ..()
/mob/living/simple_animal/diona/proc/merge()
if(stat != CONSCIOUS)
@@ -278,5 +280,7 @@
message = "\The [src] chirps!"
m_type = 2 //audible
playsound(src, chirp_sound, 40, 1, 1)
+ if("help")
+ to_chat(src, "scream, chirp")
..(act, m_type, message)
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index d8a3f793d3a..03f353754fe 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -13,9 +13,9 @@
turns_per_move = 5
see_in_dark = 6
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat = 4)
- response_help = "pets the"
- response_disarm = "gently pushes aside the"
- response_harm = "kicks the"
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
faction = list("neutral")
attack_same = 1
attacktext = "kicks"
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 228b67beecc..c84947c7363 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -10,16 +10,16 @@
speak_emote = list("squeeks","squeaks","squiks")
emote_hear = list("squeeks","squeaks","squiks")
emote_see = list("runs in a circle", "shakes", "scritches at something")
- var/squeak_sound = 'sound/effects/mousesqueek.ogg'
+ var/squeak_sound = 'sound/creatures/mousesqueak.ogg'
speak_chance = 1
turns_per_move = 5
see_in_dark = 6
maxHealth = 5
health = 5
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat = 1)
- response_help = "pets the"
- response_disarm = "gently pushes aside the"
- response_harm = "stamps on the"
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "stamps on"
density = 0
ventcrawler = 2
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
@@ -74,7 +74,6 @@
desc = "It's a small [mouse_color] rodent, often seen hiding in maintenance areas and making a nuisance of itself."
/mob/living/simple_animal/mouse/proc/splat()
- playsound(src, squeak_sound, 40, 1)
src.health = 0
src.stat = DEAD
src.icon_dead = "mouse_[mouse_color]_splat"
@@ -102,6 +101,7 @@
/mob/living/simple_animal/mouse/death(gibbed)
// Only execute the below if we successfully died
+ playsound(src, squeak_sound, 40, 1)
. = ..(gibbed)
if(!.)
return FALSE
@@ -126,7 +126,7 @@
switch(act)
if("squeak")
- message = "\The [src] squeaks!"
+ message = "\The [src] [pick(emote_hear)]!"
m_type = 2 //audible
playsound(src, squeak_sound, 40, 1)
if("help")
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index 4516a44a935..5ebefeba405 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -11,7 +11,7 @@
/mob/living/simple_animal/hostile/poison/bees
name = "bee"
- desc = "buzzy buzzy bee, stingy sti- Ouch!"
+ desc = "Buzzy buzzy bee, stingy sti- Ouch!"
icon_state = ""
icon_living = ""
icon = 'icons/mob/bees.dmi'
@@ -33,25 +33,28 @@
environment_smash = 0
mouse_opacity = MOUSE_OPACITY_OPAQUE
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
- flying = 1
- search_objects = 1 //have to find those plant trays!
- density = 0
+ density = FALSE
mob_size = MOB_SIZE_TINY
+ flying = TRUE
+ search_objects = TRUE //have to find those plant trays!
//Spaceborn beings don't get hurt by space
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
- del_on_death = 1
+ del_on_death = TRUE
var/datum/reagent/beegent = null //hehe, beegent
var/obj/structure/beebox/beehome = null
- var/isqueen = FALSE
var/idle = 0
+ var/isqueen = FALSE
+ var/bee_syndicate = FALSE
var/icon_base = "bee"
var/static/list/bee_icons = list()
+ var/static/beehometypecache = typecacheof(/obj/structure/beebox)
+ var/static/hydroponicstypecache = typecacheof(/obj/machinery/hydroponics)
/mob/living/simple_animal/hostile/poison/bees/Process_Spacemove(movement_dir = 0)
- return 1
+ return TRUE
/mob/living/simple_animal/hostile/poison/bees/New()
..()
@@ -65,6 +68,20 @@
beehome = null
return ..()
+/mob/living/simple_animal/hostile/poison/bees/death(gibbed)
+ . = ..()
+ if(!.)
+ return
+ if(beehome)
+ if(beehome.bees)
+ beehome.bees.Remove(src)
+ beehome = null
+
+/mob/living/simple_animal/hostile/poison/bees/examine(mob/user)
+ ..()
+ if(!bee_syndicate && !beehome)
+ to_chat(user, "This bee is homeless!")
+
/mob/living/simple_animal/hostile/poison/bees/proc/generate_bee_visuals()
overlays.Cut()
@@ -94,21 +111,45 @@
//We don't attack beekeepers/people dressed as bees//Todo: bee costume
/mob/living/simple_animal/hostile/poison/bees/CanAttack(atom/the_target)
. = ..()
- return .
+ if(!.)
+ return FALSE
+ if(!bee_syndicate && isliving(the_target))
+ var/mob/living/H = the_target
+ return !H.bee_friendly()
/mob/living/simple_animal/hostile/poison/bees/Found(atom/A)
if(isliving(A))
- var/mob/living/L = A
- return !L.bee_friendly()
- return 0
+ var/mob/living/H = A
+ return !H.bee_friendly()
+ if(istype(A, /obj/machinery/hydroponics))
+ var/obj/machinery/hydroponics/Hydro = A
+ if(Hydro.myseed && !Hydro.dead && !Hydro.recent_bee_visit)
+ wanted_objects |= hydroponicstypecache //so we only hunt them while they're alive/seeded/not visisted
+ return TRUE
+ return FALSE
/mob/living/simple_animal/hostile/poison/bees/AttackingTarget()
- if(beegent && isliving(target))
- var/mob/living/L = target
- if(!isnull(target.reagents))
- beegent.reaction_mob(L, INGEST)
- L.reagents.add_reagent(beegent.id, rand(1,5))
- target.attack_animal(src)
+ //Pollinate
+ if(istype(target, /obj/machinery/hydroponics))
+ var/obj/machinery/hydroponics/Hydro = target
+ pollinate(Hydro)
+ else if(istype(target, /obj/structure/beebox))
+ if(target == beehome)
+ var/obj/structure/beebox/BB = target
+ forceMove(BB)
+ target = null
+ wanted_objects -= beehometypecache //so we don't attack beeboxes when not going home
+ return //no don't attack the goddamm box
+ else
+ ..()
+ if(isliving(target))
+ var/mob/living/L = target
+ if(L.reagents)
+ if(beegent)
+ beegent.reaction_mob(L, INGEST)
+ L.reagents.add_reagent(beegent.id, rand(1, 5))
+ else
+ L.reagents.add_reagent("spidertoxin", 5)
/mob/living/simple_animal/hostile/poison/bees/proc/assign_reagent(datum/reagent/R)
if(istype(R))
@@ -116,81 +157,13 @@
name = "[initial(name)] ([R.name])"
generate_bee_visuals()
-/mob/living/simple_animal/hostile/poison/bees/handle_automated_action()
- . = ..()
- if(!.)
- return
-
-/mob/living/simple_animal/hostile/poison/bees/proc/reagent_incompatible(mob/living/simple_animal/hostile/poison/bees/B)
- if(!B)
- return 0
- if(B.beegent && beegent && B.beegent.id != beegent.id || B.beegent && !beegent || !B.beegent && beegent)
- return 1
- return 0
-
-//Botany Worker Bees
-/mob/living/simple_animal/hostile/poison/bees/worker
- //Blank type define in case we need to give them special stuff later, plus organization (currently they are same as base type bee)
-
-
-/mob/living/simple_animal/hostile/poison/bees/worker/Destroy()
- if(beehome)
- if(beehome.bees)
- beehome.bees.Remove(src)
- beehome = null
- return ..()
-
-/mob/living/simple_animal/hostile/poison/bees/worker/death(gibbed)
- . = ..()
- if(!.)
- return
- if(beehome)
- if(beehome.bees)
- beehome.bees.Remove(src)
- beehome = null
-
-/mob/living/simple_animal/hostile/poison/bees/worker/examine(mob/user)
- ..()
-
- if(!beehome)
- to_chat(user, "This bee is homeless!")
-
-/mob/living/simple_animal/hostile/poison/bees/worker/Found(atom/A)
- if(istype(A, /obj/machinery/hydroponics))
- var/obj/machinery/hydroponics/Hydro = A
- if(Hydro.myseed && !Hydro.dead && !Hydro.recent_bee_visit && !Hydro.lid_state)
- wanted_objects |= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted and uncovered
- return 1
- ..()
-
-/mob/living/simple_animal/hostile/poison/bees/worker/CanAttack(atom/the_target)
- . = ..()
- if(!.)
- return 0
- if(isliving(the_target)) //Should ignore ghosts and camera mobs already, but just in case
- var/mob/living/L = the_target
- return !L.bee_friendly()
-
-/mob/living/simple_animal/hostile/poison/bees/worker/AttackingTarget()
- //Pollinate
- if(istype(target, /obj/machinery/hydroponics))
- var/obj/machinery/hydroponics/Hydro = target
- pollinate(Hydro)
- else if(target == beehome)
- var/obj/structure/beebox/BB = target
- forceMove(BB)
- target = null
- wanted_objects -= /obj/structure/beebox //so we don't attack beeboxes when not going home
- else
- ..()
-
-/mob/living/simple_animal/hostile/poison/bees/worker/proc/pollinate(obj/machinery/hydroponics/Hydro)
+/mob/living/simple_animal/hostile/poison/bees/proc/pollinate(obj/machinery/hydroponics/Hydro)
if(!istype(Hydro) || !Hydro.myseed || Hydro.dead || Hydro.recent_bee_visit || Hydro.lid_state)
target = null
return
target = null //so we pick a new hydro tray next FindTarget(), instead of loving the same plant for eternity
- wanted_objects -= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted and uncovered
+ wanted_objects -= hydroponicstypecache //so we only hunt them while they're alive/seeded/not visisted
Hydro.recent_bee_visit = TRUE
spawn(BEE_TRAY_RECENT_VISIT)
if(Hydro)
@@ -210,68 +183,79 @@
if(beehome)
beehome.bee_resources = min(beehome.bee_resources + growth, 100)
-/mob/living/simple_animal/hostile/poison/bees/worker/handle_automated_action()
+/mob/living/simple_animal/hostile/poison/bees/handle_automated_action()
. = ..()
if(!.)
return
- if(!isqueen)
- if(loc == beehome)
- idle = min(100, ++idle)
- if(idle >= BEE_IDLE_ROAMING && prob(BEE_PROB_GOROAM))
- forceMove(get_turf(beehome))
- else
- idle = max(0, --idle)
- if(idle <= BEE_IDLE_GOHOME && prob(BEE_PROB_GOHOME))
- if(!FindTarget())
- wanted_objects += /obj/structure/beebox //so we don't attack beeboxes when not going home
- target = beehome
- if(!beehome) //add outselves to a beebox (of the same reagent) if we have no home
- for(var/obj/structure/beebox/BB in view(vision_range, src))
- if(reagent_incompatible(BB.queen_bee) || BB.bees.len >= BB.get_max_bees())
- continue
- BB.bees |= src
- beehome = BB
-
+ if(!bee_syndicate)
+ if(!isqueen)
+ if(loc == beehome)
+ idle = min(100, ++idle)
+ if(idle >= BEE_IDLE_ROAMING && prob(BEE_PROB_GOROAM))
+ forceMove(beehome.drop_location())
+ else
+ idle = max(0, --idle)
+ if(idle <= BEE_IDLE_GOHOME && prob(BEE_PROB_GOHOME))
+ if(!FindTarget())
+ wanted_objects |= beehometypecache //so we don't attack beeboxes when not going home
+ target = beehome
+ if(!beehome) //add ourselves to a beebox (of the same reagent) if we have no home
+ for(var/obj/structure/beebox/BB in view(vision_range, src))
+ if(reagent_incompatible(BB.queen_bee) || BB.bees.len >= BB.get_max_bees())
+ continue
+ BB.bees |= src
+ beehome = BB
+ break // End loop after the first compatible find.
//Botany Queen Bee
/mob/living/simple_animal/hostile/poison/bees/queen
name = "queen bee"
- desc = "she's the queen of bees, BZZ BZZ"
+ desc = "She's the queen of bees, BZZ BZZ"
icon_base = "queen"
isqueen = TRUE
- //the Queen doesn't leave the box on her own, and she CERTAINLY doesn't pollinate by herself
+//the Queen doesn't leave the box on her own, and she CERTAINLY doesn't pollinate by herself
/mob/living/simple_animal/hostile/poison/bees/queen/Found(atom/A)
- return 0
+ return FALSE
+
+//leave pollination for the peasent bees
+/mob/living/simple_animal/hostile/poison/bees/queen/AttackingTarget()
+ ..()
+ if(beegent && isliving(target))
+ var/mob/living/L = target
+ beegent.reaction_mob(L, TOUCH)
+ L.reagents.add_reagent(beegent.id, rand(1, 5))
+
+//PEASENT BEES
+/mob/living/simple_animal/hostile/poison/bees/queen/pollinate()
+ return
+
+/mob/living/simple_animal/hostile/poison/bees/proc/reagent_incompatible(mob/living/simple_animal/hostile/poison/bees/B)
+ if(!B)
+ return FALSE
+ if(B.beegent && beegent && B.beegent.id != beegent.id || B.beegent && !beegent || !B.beegent && beegent)
+ return TRUE
+ return FALSE
-/mob/living/simple_animal/hostile/poison/bees/queen/CanAttack(atom/the_target)
- . = ..()
- if(!.)
- return 0
- if(isliving(the_target)) //Should ignore ghosts and camera mobs already, but just in case
- var/mob/living/L = the_target
- return !L.bee_friendly()
/obj/item/queen_bee
name = "queen bee"
- desc = "she's the queen of bees, BZZ BZZ"
+ desc = "She's the queen of bees, BZZ BZZ"
icon_state = "queen_item"
item_state = ""
icon = 'icons/mob/bees.dmi'
var/mob/living/simple_animal/hostile/poison/bees/queen/queen
+
/obj/item/queen_bee/attackby(obj/item/I, mob/user, params)
- if(istype(I,/obj/item/reagent_containers/syringe))
+ if(istype(I, /obj/item/reagent_containers/syringe))
var/obj/item/reagent_containers/syringe/S = I
if(S.reagents.has_reagent("royal_bee_jelly")) //checked twice, because I really don't want royal bee jelly to be duped
- if(S.reagents.has_reagent("royal_bee_jelly",5))
+ if(S.reagents.has_reagent("royal_bee_jelly", 5))
S.reagents.remove_reagent("royal_bee_jelly", 5)
- if(!queen.beegent.can_synth)
- to_chat(user, "You inject [src] with the royal bee jelly. It's ineffective! Maybe it's something to do with the [src] reagent.")
- return
- var/obj/item/queen_bee/qb = new(get_turf(user))
+ var/obj/item/queen_bee/qb = new(user.drop_location())
qb.queen = new(qb)
if(queen && queen.beegent)
qb.queen.assign_reagent(queen.beegent) //Bees use the global singleton instances of reagents, so we don't need to worry about one bee being deleted and her copies losing their reagents.
@@ -282,16 +266,17 @@
else
var/datum/reagent/R = GLOB.chemical_reagents_list[S.reagents.get_master_reagent_id()]
if(R && S.reagents.has_reagent(R.id, 5))
- S.reagents.remove_reagent(R.id,5)
+ S.reagents.remove_reagent(R.id, 5)
queen.assign_reagent(R)
- user.visible_message("[user] injects [src]'s genome with [R.name], mutating it's DNA!","You inject [src]'s genome with [R.name], mutating it's DNA!")
+ user.visible_message("[user] injects [src]'s genome with [R.name], mutating its DNA!", "You inject [src]'s genome with [R.name], mutating its DNA!")
name = queen.name
else
to_chat(user, "You don't have enough units of that chemical to modify the bee's DNA!")
- ..()
+ else
+ return ..()
-/obj/item/queen_bee/bought/New()
- ..()
+/obj/item/queen_bee/bought/Initialize(mapload)
+ . = ..()
queen = new(src)
/obj/item/queen_bee/Destroy()
@@ -299,7 +284,6 @@
return ..()
-
//Syndicate Bees
/mob/living/simple_animal/hostile/poison/bees/syndi
name = "syndi-bee"
@@ -309,10 +293,14 @@
maxHealth = 25
health = 25
faction = list("hostile", "syndicate")
- search_objects = 0 //these bees don't care about trivial things like plants, especially when there is havoc to sow
- beegent = new /datum/reagent/facid() //prepare to die
+ search_objects = FALSE //these bees don't care about trivial things like plants, especially when there is havoc to sow
+ bee_syndicate = TRUE
var/list/master_and_friends = list()
+/mob/living/simple_animal/hostile/poison/bees/syndi/New()
+ beegent = GLOB.chemical_reagents_list["facid"] //Prepare to die
+ ..()
+
/mob/living/simple_animal/hostile/poison/bees/syndi/Destroy()
master_and_friends.Cut()
return ..()
@@ -320,24 +308,27 @@
/mob/living/simple_animal/hostile/poison/bees/syndi/assign_reagent(datum/reagent/R)
return
-/mob/living/simple_animal/hostile/poison/bees/syndi/Found(atom/A)
- return CanAttack(A)
+/mob/living/simple_animal/hostile/poison/bees/syndi/pollinate() // No Pollination
+ return
+
+/mob/living/simple_animal/hostile/poison/bees/syndi/Found(atom/A) //Typical usual hostile mob targeting list
+ return
/mob/living/simple_animal/hostile/poison/bees/syndi/CanAttack(atom/the_target)
. = ..()
if(!.)
- return 0
+ return FALSE
if(isliving(the_target))
var/mob/living/L = the_target
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(H in master_and_friends)
- return 0
- return 1
+ return FALSE
+ return TRUE
/mob/living/simple_animal/hostile/poison/bees/syndi/AttackingTarget()
..()
if(target && isliving(target))
var/mob/living/L = target
if(L.stat)
- LoseTarget()
+ LoseTarget()
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/hellhound.dm b/code/modules/mob/living/simple_animal/hostile/hellhound.dm
index 450f6767892..f3e110d0099 100644
--- a/code/modules/mob/living/simple_animal/hostile/hellhound.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hellhound.dm
@@ -71,7 +71,7 @@
else if(health > (maxHealth*0.25))
msgs += "It is covered in wounds!"
if(resting)
- if(bruteloss > 0 || fireloss > 0)
+ if(getBruteLoss() || getFireLoss())
msgs += "It is currently licking its wounds, regenerating the damage to its body!"
else
msgs += "It is currently resting."
@@ -79,7 +79,7 @@
/mob/living/simple_animal/hostile/hellhound/Life(seconds, times_fired)
. = ..()
- if(stat != DEAD && resting && (bruteloss > 0) || (fireloss > 0))
+ if(stat != DEAD && resting && (getBruteLoss() || getFireLoss()))
if(life_regen_cycles >= life_regen_cycle_trigger)
life_regen_cycles = 0
to_chat(src, "You lick your wounds, helping them close.")
@@ -91,7 +91,7 @@
/mob/living/simple_animal/hostile/hellhound/proc/wants_to_rest()
if(target)
return FALSE
- if(bruteloss > 0 || fireloss > 0)
+ if(getBruteLoss() || getFireLoss())
return TRUE
return FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index ccbd37f2f4c..50568fb37d0 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -53,6 +53,7 @@
if(!targets_from)
targets_from = src
environment_target_typecache = typecacheof(environment_target_typecache)
+ wanted_objects = typecacheof(wanted_objects)
/mob/living/simple_animal/hostile/Destroy()
targets_from = null
@@ -205,7 +206,7 @@
return 0
return 1
if(isobj(the_target))
- if(is_type_in_list(the_target, wanted_objects))
+ if(is_type_in_typecache(the_target, wanted_objects))
return 1
return 0
diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
index 4041e95c6c7..74a28c58c3f 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
@@ -98,7 +98,7 @@
/obj/item/organ/internal/hivelord_core/on_life()
..()
- if(owner.health < config.health_threshold_crit)
+ if(owner.health < HEALTH_THRESHOLD_CRIT)
ui_action_click()
/obj/item/organ/internal/hivelord_core/afterattack(atom/target, mob/user, proximity_flag)
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
index 0f37482b3e2..81b384f56b7 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
@@ -238,8 +238,8 @@
if(istype(target, /obj/item/clothing/suit/space/hardsuit/mining) || istype(target, /obj/item/clothing/head/helmet/space/hardsuit/mining) || istype(target, /obj/item/clothing/suit/space/eva/plasmaman/miner) || istype(target, /obj/item/clothing/head/helmet/space/eva/plasmaman/miner))
var/obj/item/clothing/C = target
var/current_armor = C.armor
- if(current_armor.["melee"] < 60)
- current_armor.["melee"] = min(current_armor.["melee"] + 10, 60)
+ if(current_armor["melee"] < 60)
+ current_armor["melee"] = min(current_armor["melee"] + 10, 60)
to_chat(user, "You strengthen [target], improving its resistance against melee attacks.")
qdel(src)
else
@@ -260,7 +260,7 @@
qdel(src)
D.overlays += image("icon"="mecha.dmi", "icon_state"="ripley-g-open")
D.desc = "Autonomous Power Loader Unit. Its armour is enhanced with some goliath hide plates."
- if(damage_absorption.["brute"] == 0.3)
+ if(damage_absorption["brute"] == 0.3)
D.overlays += image("icon"="mecha.dmi", "icon_state"="ripley-g-full-open")
D.desc = "Autonomous Power Loader Unit. It's wearing a fearsome carapace entirely composed of goliath hide plates - the pilot must be an experienced monster hunter."
else
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm
index 51028a69111..14353c4dfd0 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm
@@ -24,6 +24,12 @@
canlay = 1000
spider_tier = TS_TIER_5
projectiletype = /obj/item/projectile/terrorqueenspit/empress
+ icon = 'icons/mob/terrorspider64.dmi'
+ pixel_x = -16
+ mob_size = MOB_SIZE_LARGE
+ icon_state = "terror_empress"
+ icon_living = "terror_empress"
+ icon_dead = "terror_empress_dead"
var/datum/action/innate/terrorspider/queen/empress/empresslings/empresslings_action
var/datum/action/innate/terrorspider/queen/empress/empresserase/empresserase_action
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
@@ -42,7 +48,7 @@
queenfakelings_action.button.name = "Empress Lings"
/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/LayQueenEggs()
- var/eggtype = input("What kind of eggs?") as null|anything in list(TS_DESC_QUEEN, TS_DESC_MOTHER, TS_DESC_PRINCE, TS_DESC_PRINCESS, TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE, TS_DESC_WHITE)
+ var/eggtype = input("What kind of eggs?") as null|anything in list(TS_DESC_QUEEN, TS_DESC_MOTHER, TS_DESC_PRINCE, TS_DESC_PRINCESS, TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE, TS_DESC_WHITE, TS_DESC_BROWN)
var/numlings = input("How many in the batch?") as null|anything in list(1, 2, 3, 4, 5, 10, 15, 20, 30, 40, 50)
if(eggtype == null || numlings == null)
to_chat(src, "Cancelled.")
@@ -60,6 +66,8 @@
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings)
if(TS_DESC_WHITE)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, numlings)
+ if(TS_DESC_BROWN)
+ DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, numlings)
if(TS_DESC_PRINCE)
DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, numlings)
if(TS_DESC_PRINCESS)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm
index 354f99db8af..d1e171d2f55 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/mother.dm
@@ -38,6 +38,8 @@
if(can_die())
if(spider_awaymission && !is_away_level(z))
canspawn = FALSE
+ if(degenerate)
+ canspawn = FALSE
if(canspawn)
canspawn = FALSE
for(var/i in 0 to spawn_count)
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
index ed2ea164634..2839dedb237 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm
@@ -142,9 +142,8 @@
visible_message("\The [src] looks around warily - then seeks a better nesting ground.")
path_to_vent = 1
else
- visible_message("\The [src] looks around, searching for the vent that should be there, but isn't. A bluespace portal forms on her, and she is gone.")
- qdel(src)
- new /obj/effect/portal(get_turf(loc))
+ neststep = -1
+ message_admins("Warning: [key_name_admin(src)] was spawned in an area without a vent! This is likely a mapping/spawn mistake. This mob's AI has been permanently deactivated.")
if(1)
// No nest, and we should create one. Start NestMode(), then advance to step 2.
if(world.time > (lastnestsetup + nestfrequency))
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
index 562c90588f8..39c03feb928 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm
@@ -71,6 +71,9 @@ var/global/list/ts_spiderling_list = list()
speak_emote = list("hisses")
emote_hear = list("hisses")
+ // Sentience Type
+ sentience_type = SENTIENCE_OTHER
+
// Languages are handled in terror_spider/New()
// Interaction keywords
@@ -313,12 +316,12 @@ var/global/list/ts_spiderling_list = list()
adjustToxLoss(rand(1,10))
if(regen_points < regen_points_max)
regen_points += regen_points_per_tick
- if((bruteloss > 0) || (fireloss > 0))
+ if(getBruteLoss() || getFireLoss())
if(regen_points > regen_points_per_hp)
- if(bruteloss > 0)
+ if(getBruteLoss())
adjustBruteLoss(-1)
regen_points -= regen_points_per_hp
- else if(fireloss > 0)
+ else if(getFireLoss())
adjustFireLoss(-1)
regen_points -= regen_points_per_hp
if(prob(5))
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 27e544e56d6..02f15a59709 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -266,6 +266,8 @@
if("scream")
message = "\The [src] whimpers."
m_type = 2
+ if("help")
+ to_chat(src, "scream")
..(act, m_type, message)
diff --git a/code/modules/mob/living/stat_states.dm b/code/modules/mob/living/stat_states.dm
index fa5530091c9..70cced62aab 100644
--- a/code/modules/mob/living/stat_states.dm
+++ b/code/modules/mob/living/stat_states.dm
@@ -33,7 +33,7 @@
/mob/living/proc/can_be_revived()
. = TRUE
// if(health <= min_health)
- if(health <= config.health_threshold_dead)
+ if(health <= HEALTH_THRESHOLD_DEAD)
return FALSE
// death() is used to make a mob die
@@ -71,3 +71,6 @@
spell.updateButtonIcon()
return 1
+
+/mob/living/proc/check_death_method()
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 4e5c778b7fb..d47f21b8d46 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -297,6 +297,9 @@
SetLoseBreath(max(losebreath, amount))
/mob/living/SetLoseBreath(amount)
+ if(BREATHLESS in mutations)
+ losebreath = 0
+ return FALSE
losebreath = max(amount, 0)
/mob/living/AdjustLoseBreath(amount, bound_lower = 0, bound_upper = INFINITY)
diff --git a/code/modules/mob/living/update_status.dm b/code/modules/mob/living/update_status.dm
index daf058bb41b..bec41f68698 100644
--- a/code/modules/mob/living/update_status.dm
+++ b/code/modules/mob/living/update_status.dm
@@ -110,7 +110,7 @@
if(status_flags & GODMODE)
return
if(stat != DEAD)
- if(health <= config.health_threshold_dead)
+ if(health <= HEALTH_THRESHOLD_DEAD && check_death_method())
death()
create_debug_log("died of damage, trigger reason: [reason]")
else if(paralysis || status_flags & FAKEDEATH)
diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm
index 762607bd501..f409d184340 100644
--- a/code/modules/mob/logout.dm
+++ b/code/modules/mob/logout.dm
@@ -16,7 +16,5 @@
send2irc(config.admin_notify_irc, "[key_name(src)] logged out - No active admins, [admincounter[2]] non-admin staff, [admincounter[3]] inactive staff.")
..()
-
callHook("mob_logout", list("client" = client, "mob" = src))
-
return 1
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index e0d20f01a48..ee04e624f02 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -580,6 +580,10 @@ var/list/slot_equipment_priority = list( \
to_chat(src, "Something is there but you can't see it.")
return 1
+ var/is_antag = (isAntag(src) || isobserver(src)) //ghosts don't have minds
+ if(client)
+ client.update_description_holders(A, is_antag)
+
face_atom(A)
A.examine(src)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 77c74c4396e..3e9ff0b7ba6 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -173,6 +173,9 @@
//SSD var, changed it up some so people can have special things happen for different mobs when SSD.
var/player_logged = 0
+ //Ghosted var, set only if a player has manually ghosted out of this mob.
+ var/player_ghosted = 0
+
var/turf/listed_turf = null //the current turf being examined in the stat panel
var/list/shouldnt_see = list(/atom/movable/lighting_overlay) //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes
diff --git a/code/modules/mob/new_player/sprite_accessories/human/human_hair.dm b/code/modules/mob/new_player/sprite_accessories/human/human_hair.dm
index 720243eaada..bc9931a8782 100644
--- a/code/modules/mob/new_player/sprite_accessories/human/human_hair.dm
+++ b/code/modules/mob/new_player/sprite_accessories/human/human_hair.dm
@@ -684,6 +684,73 @@
//////END POLARIS HAIRSTYLES///////
//////////////////////////////////
+//////////////////////
+////Ume hairstyles////
+//////////////////////
+
+/datum/sprite_accessory/hair/eighties_ponytail
+ name = "80's ponytail"
+ icon_state = "80_ponytail"
+
+/datum/sprite_accessory/hair/eighties_ponytailalt
+ name = "80's ponytail alt"
+ icon_state = "80_ponytail_alt"
+
+/datum/sprite_accessory/hair/big_bow
+ name = "Big bow"
+ icon_state = "big_bow"
+
+/datum/sprite_accessory/hair/buns
+ name = "Buns"
+ icon_state = "buns"
+
+/datum/sprite_accessory/hair/himecut_long
+ name = "Himecut long"
+ icon_state = "himecut_long"
+
+/datum/sprite_accessory/hair/himecut_long_ponytail
+ name = "Himecut long ponytail"
+ icon_state = "himecut_long_ponytail"
+
+/datum/sprite_accessory/hair/himecut_ponytail
+ name = "Himecut ponytail"
+ icon_state = "himecut_ponytail"
+
+/datum/sprite_accessory/hair/ombre_twintails
+ name = "Ombre twintails"
+ icon_state = "ombre_twintails"
+
+/datum/sprite_accessory/hair/ombre_twintails_alt
+ name = "Ombre twintails alt"
+ icon_state = "ombre_twintails_alt"
+
+/datum/sprite_accessory/hair/sailor
+ name = "Sailor"
+ icon_state = "sailor"
+
+/datum/sprite_accessory/hair/amanita_short
+ name = "Amanita short"
+ icon_state = "amanita_short"
+
+/datum/sprite_accessory/hair/long_curls
+ name = "Long curls"
+ icon_state = "long_curls"
+
+/datum/sprite_accessory/hair/long_curls_alt
+ name = "Long curls alt"
+ icon_state = "long_curls_alt"
+
+/datum/sprite_accessory/hair/long_buns
+ name = "Long buns"
+ icon_state = "long_buns"
+
+/datum/sprite_accessory/hair/low_twins
+ name = "Low twins"
+ icon_state = "low_twins"
+
+///Ume hairs end here///
+
+
///Fluff HairStyles//
/datum/sprite_accessory/hair/fluff/pinapple_fluff_hair //Pineapple Salad hair fluff its for a slime..has to go under human
name = "Sasook Hair"
diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm
index 9c6c8f2fa73..9ad5449ee8b 100644
--- a/code/modules/mob/typing_indicator.dm
+++ b/code/modules/mob/typing_indicator.dm
@@ -39,7 +39,7 @@ var/global/image/typing_indicator
set_typing_indicator(1)
hud_typing = 1
- var/message = input("","say (text)") as null|text
+ var/message = typing_input(src, "", "say (text)")
hud_typing = 0
set_typing_indicator(0)
if(message)
@@ -49,9 +49,10 @@ var/global/image/typing_indicator
set name = ".Me"
set hidden = 1
+
set_typing_indicator(1)
hud_typing = 1
- var/message = input("","me (text)") as null|text
+ var/message = typing_input(src, "", "me (text)")
hud_typing = 0
set_typing_indicator(0)
if(message)
diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm
index 68cc26725cf..c1124bee744 100644
--- a/code/modules/paperwork/contract.dm
+++ b/code/modules/paperwork/contract.dm
@@ -15,7 +15,7 @@
/obj/item/paper/contract/employment
- icon_state = "paper_words"
+ icon_state = "good_contract"
signed = TRUE
/obj/item/paper/contract/employment/New(atom/loc, mob/living/nOwner)
@@ -37,7 +37,6 @@
Further, SLAVE agrees to transfer ownership of his or her soul to the loyalty department of the omnipresent and helpful watcher of humanity.\
Should transfership of a soul not be possible, a lien shall be placed instead. Signed, [target]"
-
/obj/item/paper/contract/employment/attack(mob/living/M, mob/living/carbon/human/user)
var/deconvert = 0
if(M.mind == target && target.soulOwner != target)
@@ -58,7 +57,7 @@
var/contractType = 0
burn_state = LAVA_PROOF
var/datum/mind/owner
- icon_state = "paper_onfire"
+ icon_state = "evil_contract"
/obj/item/paper/contract/infernal/power
name = "paper- contract for infernal power"
@@ -105,7 +104,7 @@
H.visible_message("[H] holds up a contract claiming his soul, then immediately catches fire. It looks like \he's trying to commit suicide!")
H.adjust_fire_stacks(20)
H.IgniteMob()
- return(FIRELOSS)
+ return FIRELOSS
else
..()
diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm
index f4808f46d53..13d85941a79 100644
--- a/code/modules/paperwork/faxmachine.dm
+++ b/code/modules/paperwork/faxmachine.dm
@@ -283,34 +283,25 @@ var/global/list/fax_blacklist = list()
use_power(200)
- var/obj/item/rcvdcopy
- if(istype(copyitem, /obj/item/paper))
- rcvdcopy = copy(copyitem)
- else if(istype(copyitem, /obj/item/photo))
- rcvdcopy = photocopy(copyitem)
- else if(istype(copyitem, /obj/item/paper_bundle))
- rcvdcopy = bundlecopy(copyitem)
- else
+ if(!(istype(copyitem, /obj/item/paper) || istype(copyitem, /obj/item/paper_bundle) || istype(copyitem, /obj/item/photo)))
visible_message("[src] beeps, \"Error transmitting message.\"")
return
- rcvdcopy.loc = null //hopefully this shouldn't cause trouble
-
var/datum/fax/admin/A = new /datum/fax/admin()
- A.name = rcvdcopy.name
+ A.name = copyitem.name
A.from_department = department
A.to_department = destination
A.origin = src
- A.message = rcvdcopy
+ A.message = copyitem
A.sent_by = sender
A.sent_at = world.time
//message badmins that a fax has arrived
switch(destination)
if("Central Command")
- message_admins(sender, "CENTCOM FAX", destination, rcvdcopy, "#006100")
+ message_admins(sender, "CENTCOM FAX", destination, copyitem, "#006100")
if("Syndicate")
- message_admins(sender, "SYNDICATE FAX", destination, rcvdcopy, "#DC143C")
+ message_admins(sender, "SYNDICATE FAX", destination, copyitem, "#DC143C")
for(var/obj/machinery/photocopier/faxmachine/F in allfaxes)
if(F.department == destination)
F.receivefax(copyitem)
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 36af97b0972..d5ca6b0b0f8 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -401,7 +401,7 @@
add_fingerprint(user)
-/obj/item/paper/fire_act()
+/obj/item/paper/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
..()
if(burn_state >= FLAMMABLE) //Only render paper that's burnable to be hard to read.
info = "[stars(info)]"
@@ -711,7 +711,7 @@
H.reagents.add_reagent(contact_poison, contact_poison_volume)
contact_poison = null
add_attack_logs(src, user, "Picked up [src], the paper poisoned by [contact_poison_poisoner]")
- ..()
+ . = ..()
/obj/item/paper/researchnotes
name = "paper - 'Research Notes'"
diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm
index da241a9c007..01974ad3694 100644
--- a/code/modules/paperwork/paper_bundle.dm
+++ b/code/modules/paperwork/paper_bundle.dm
@@ -131,7 +131,7 @@
usr << browse(dat + "[P.name]" \
+ "" \
+ "  Written on the back: [P.scribble]" : ]"\
+ + "[P.scribble ? " Written on the back: [P.scribble]" : ""]"\
+ "", "window=[name]")
/obj/item/paper_bundle/attack_self(mob/user as mob)
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index a3f41c0ac25..e8643c97cff 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -12,7 +12,7 @@
var/amount = 30 //How much paper is in the bin.
var/list/papers = list() //List of papers put in the bin for reference.
-/obj/item/paper_bin/fire_act()
+/obj/item/paper_bin/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
if(!amount)
return
..()
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index 83897e5cbd3..302f2e02342 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -26,7 +26,7 @@
/obj/item/pen/suicide_act(mob/user)
to_chat(viewers(user), " [user] starts scribbling numbers over [user.p_them()]self with the [name]! It looks like [user.p_theyre()] trying to commit sudoku.")
- return (BRUTELOSS)
+ return BRUTELOSS
/obj/item/pen/blue
name = "blue-ink pen"
diff --git a/code/modules/paperwork/stamps.dm b/code/modules/paperwork/stamps.dm
index 9bb3a09ebb0..8e78f0ce230 100644
--- a/code/modules/paperwork/stamps.dm
+++ b/code/modules/paperwork/stamps.dm
@@ -15,7 +15,7 @@
/obj/item/stamp/suicide_act(mob/user)
user.visible_message(" [user] stamps 'VOID' on [user.p_their()] forehead, then promptly falls over, dead.")
- return (OXYLOSS)
+ return OXYLOSS
/obj/item/stamp/qm
name = "Quartermaster's rubber stamp"
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 410b91bdf48..238d2e43599 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -504,7 +504,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list(
user.visible_message(" [user] is making a noose with the [name]! It looks like [user.p_theyre()] trying to commit suicide.")
else
user.visible_message(" [user] is strangling [user.p_them()]self with the [name]! It looks like [user.p_theyre()] trying to commit suicide.")
- return(OXYLOSS)
+ return OXYLOSS
/obj/item/stack/cable_coil/New(loc, length = MAXCOIL, paramcolor = null)
..()
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 3bc2b5bc39b..192ef9d792e 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -90,7 +90,7 @@
/obj/item/stock_parts/cell/suicide_act(mob/user)
to_chat(viewers(user), " [user] is licking the electrodes of the [src]! It looks like [user.p_theyre()] trying to commit suicide.")
- return (FIRELOSS)
+ return FIRELOSS
/obj/item/stock_parts/cell/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/reagent_containers/syringe))
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index dcd884da879..8dda1ed8731 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -586,6 +586,7 @@
// called when on fire
/obj/machinery/light/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ ..()
if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C
broken()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 5178c8ff173..d5dfb454e09 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -311,7 +311,7 @@ obj/item/gun/proc/newshot()
visible_message(" [src]'s light fades and turns off.")
/obj/item/gun/pickup(mob/user)
- ..()
+ . = ..()
if(azoom)
azoom.Grant(user)
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 795b5942845..8c9b0cf66f8 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -154,14 +154,14 @@
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
power_supply.use(shot.e_cost)
update_icon()
- return(FIRELOSS)
+ return FIRELOSS
else
user.visible_message(" [user] panics and starts choking to death!")
- return(OXYLOSS)
+ return OXYLOSS
else
user.visible_message(" [user] is pretending to blow [user.p_their()] brains out with the [name]! It looks like [user.p_theyre()] trying to commit suicide!")
playsound(loc, 'sound/weapons/empty.ogg', 50, 1, -1)
- return (OXYLOSS)
+ return OXYLOSS
/obj/item/gun/energy/vv_edit_var(var_name, var_value)
switch(var_name)
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 74ab90fcbc4..623986f5837 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -137,7 +137,7 @@
playsound(loc, 'sound/weapons/kenetic_reload.ogg', 60, 1)
user.visible_message(" [user] cocks the [name] and pretends to blow [user.p_their()] brains out! It looks like [user.p_theyre()] trying to commit suicide!")
shoot_live_shot()
- return (OXYLOSS)
+ return OXYLOSS
// Plasma Cutters //
/obj/item/gun/energy/plasmacutter
diff --git a/code/modules/projectiles/guns/medbeam.dm b/code/modules/projectiles/guns/medbeam.dm
index d77621051e2..face61e79c3 100644
--- a/code/modules/projectiles/guns/medbeam.dm
+++ b/code/modules/projectiles/guns/medbeam.dm
@@ -54,8 +54,8 @@
feedback_add_details("gun_fired","[type]")
/obj/item/gun/medbeam/process()
- var/mob/living/carbon/human/H = loc
- if(!istype(H))
+ var/source = loc
+ if(!ishuman(source) && !isrobot(source))
LoseTarget()
return
@@ -68,9 +68,9 @@
last_check = world.time
- if(get_dist(H,current_target)>max_range || !los_check(H,current_target))
+ if(get_dist(source,current_target)>max_range || !los_check(source,current_target))
LoseTarget()
- to_chat(H, " You lose control of the beam!")
+ to_chat(source, " You lose control of the beam!")
return
if(current_target)
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index 6e558dedbd1..9defe7637d4 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -55,7 +55,7 @@
/obj/item/gun/projectile/proc/can_reload()
return !magazine
-/obj/item/gun/projectile/proc/reload(obj/item/ammo_box/magazine/AM, mob/user as mob)
+/obj/item/gun/projectile/proc/reload(obj/item/ammo_box/magazine/AM, mob/user as mob)
user.remove_from_mob(AM)
magazine = AM
magazine.loc = src
@@ -81,7 +81,7 @@
to_chat(user, " You perform a tactical reload on \the [src], replacing the magazine.")
magazine.loc = get_turf(loc)
magazine.update_icon()
- magazine = null
+ magazine = null
reload(AM, user)
return TRUE
else
@@ -165,14 +165,14 @@
if(user.l_hand == src || user.r_hand == src)
process_fire(user, user, 0, zone_override = "head")
user.visible_message(" [user] blows [user.p_their()] brains out with the [name]!")
- return(BRUTELOSS)
+ return BRUTELOSS
else
user.visible_message(" [user] panics and starts choking to death!")
- return(OXYLOSS)
+ return OXYLOSS
else
user.visible_message(" [user] is pretending to blow [user.p_their()] brains out with the [name]! It looks like [user.p_theyre()] trying to commit suicide!")
playsound(loc, 'sound/weapons/empty.ogg', 50, 1, -1)
- return (OXYLOSS)
+ return OXYLOSS
/obj/item/gun/projectile/proc/sawoff(mob/user)
if(sawn_state == SAWN_OFF)
diff --git a/code/modules/reagents/chem_splash.dm b/code/modules/reagents/chem_splash.dm
index e586e6f806b..c73ffc72ced 100644
--- a/code/modules/reagents/chem_splash.dm
+++ b/code/modules/reagents/chem_splash.dm
@@ -25,8 +25,7 @@
for(var/datum/reagents/R in reactants)
R.trans_to(splash_holder, R.total_volume, threatscale, 1, 1)
total_temp += R.chem_temp
- splash_holder.chem_temp = (total_temp/reactants.len) + extra_heat // Average temperature of reagents + extra heat.
- splash_holder.handle_reactions() // React them now.
+ splash_holder.set_reagent_temp((total_temp / reactants.len) + extra_heat) // Average temperature of reagents + extra heat.
if(splash_holder.total_volume && affected_range >= 0) //The possible reactions didnt use up all reagents, so we spread it around.
var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread()
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index fa2a8d71a9a..66f010b86e3 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -9,7 +9,7 @@ var/const/INGEST = 2
var/total_volume = 0
var/maximum_volume = 100
var/atom/my_atom = null
- var/chem_temp = 300
+ var/chem_temp = T20C
var/list/datum/reagent/addiction_list = new/list()
var/flags
@@ -166,6 +166,30 @@ var/const/INGEST = 2
handle_reactions()
return amount
+/datum/reagents/proc/set_reagent_temp(new_temp = T0C, react = TRUE)
+ chem_temp = new_temp
+ if(react)
+ temperature_react()
+ handle_reactions()
+
+/datum/reagents/proc/temperature_react() //Calls the temperature reaction procs without changing the temp.
+ for(var/datum/reagent/current_reagent in reagent_list)
+ current_reagent.reaction_temperature(chem_temp, 100)
+
+/datum/reagents/proc/temperature_reagents(exposed_temperature, divisor = 35, change_cap = 15) //This is what you use to change the temp of a reagent holder.
+ //Do not manually change the reagent unless you know what youre doing.
+ var/difference = abs(chem_temp - exposed_temperature)
+ var/change = min(max((difference / divisor), 1), change_cap)
+ if(exposed_temperature > chem_temp)
+ chem_temp += change
+ else if(exposed_temperature < chem_temp)
+ chem_temp -= change
+
+ chem_temp = max(min(chem_temp, 10000), 0) //Cap for the moment.
+ temperature_react()
+
+ handle_reactions()
+
/datum/reagents/proc/trans_id_to(obj/target, reagent, amount=1, preserve_data=1)//Not sure why this proc didn't exist before. It does now! /N
if(!target)
return
@@ -194,8 +218,7 @@ var/const/INGEST = 2
/datum/reagents/proc/metabolize(mob/living/M)
if(M)
- chem_temp = M.bodytemperature
- handle_reactions()
+ set_reagent_temp(M.bodytemperature)
// a bitfield filled in by each reagent's `on_mob_life` to find out which states to update
var/update_flags = STATUS_UPDATE_NONE
@@ -269,6 +292,8 @@ var/const/INGEST = 2
if(prob(20) && (world.timeofday > (R.last_addiction_dose + ADDICTION_TIME))) //Each addiction lasts 8 minutes before it can end
to_chat(M, " You no longer feel reliant on [R.name]!")
addiction_list.Remove(R)
+ qdel(R)
+
if(update_flags & STATUS_UPDATE_HEALTH)
M.updatehealth("reagent metabolism")
else if(update_flags & STATUS_UPDATE_STAT)
@@ -440,8 +465,8 @@ var/const/INGEST = 2
add_reagent(S, C.result_amount * C.secondary_results[S] * multiplier)
var/list/seen = viewers(4, get_turf(my_atom))
- for(var/mob/M in seen)
- if(!C.no_message)
+ for(var/mob/living/M in seen)
+ if(C.mix_message)
to_chat(M, " [bicon(my_atom)] [C.mix_message]")
if(istype(my_atom, /obj/item/slime_extract))
@@ -453,7 +478,8 @@ var/const/INGEST = 2
ME2.name = "used slime extract"
ME2.desc = "This extract has been used up."
- playsound(get_turf(my_atom), C.mix_sound, 80, 1)
+ if(C.mix_sound)
+ playsound(get_turf(my_atom), C.mix_sound, 80, 1)
C.on_reaction(src, created_volume)
reaction_occured = 1
@@ -531,6 +557,35 @@ var/const/INGEST = 2
react_type = "OBJ"
else
return
+
+ if(react_type == "LIVING" && ishuman(A))
+ var/mob/living/carbon/human/H = A
+ if(method == TOUCH)
+ var/obj/item/organ/external/head/affecting = H.get_organ("head")
+ if(affecting)
+ if(chem_temp > H.dna.species.heat_level_1)
+ if(H.reagent_safety_check())
+ to_chat(H, " You are scalded by the hot chemicals!")
+ affecting.receive_damage(0, round(log(chem_temp / 50) * 10))
+ H.emote("scream")
+ H.adjust_bodytemperature(min(max((chem_temp - T0C) - 20, 5), 500))
+ else if(chem_temp < H.dna.species.cold_level_1)
+ if(H.reagent_safety_check(FALSE))
+ to_chat(H, " You are frostbitten by the freezing cold chemicals!")
+ affecting.receive_damage(0, round(log(T0C - chem_temp / 50) * 10))
+ H.emote("scream")
+ H.adjust_bodytemperature(- min(max(T0C - chem_temp - 20, 5), 500))
+
+ if(method == INGEST)
+ if(chem_temp > H.dna.species.heat_level_1)
+ to_chat(H, " You scald yourself trying to consume the boiling hot substance!")
+ H.adjustFireLoss(7)
+ H.adjust_bodytemperature(min(max((chem_temp - T0C) - 20, 5), 700))
+ else if(chem_temp < H.dna.species.cold_level_1)
+ to_chat(H, " You frostburn yourself trying to consume the freezing cold substance!")
+ H.adjustFireLoss(7)
+ H.adjust_bodytemperature(- min(max((T0C - chem_temp) - 20, 5), 700))
+
for(var/datum/reagent/R in reagent_list)
switch(react_type)
if("LIVING")
@@ -548,14 +603,14 @@ var/const/INGEST = 2
var/amt = list_reagents[r_id]
add_reagent(r_id, amt, data)
-/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0)
+/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = T20C, no_react = 0)
if(!isnum(amount))
return 1
update_total()
if(total_volume + amount > maximum_volume) amount = (maximum_volume - total_volume) //Doesnt fit in. Make it disappear. Shouldnt happen. Will happen.
if(amount <= 0)
return 0
- chem_temp = round(((amount * reagtemp) + (total_volume * chem_temp)) / (total_volume + amount)) //equalize with new chems
+ chem_temp = (chem_temp * total_volume + reagtemp * amount) / (total_volume + amount) //equalize with new chems
for(var/A in reagent_list)
@@ -567,6 +622,7 @@ var/const/INGEST = 2
my_atom.on_reagent_change()
R.on_merge(data)
if(!no_react)
+ temperature_react()
handle_reactions()
return 0
@@ -585,6 +641,7 @@ var/const/INGEST = 2
if(my_atom)
my_atom.on_reagent_change()
if(!no_react)
+ temperature_react()
handle_reactions()
return 0
else
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index e827d282e21..258237f0ddd 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -1,38 +1,80 @@
/obj/machinery/chem_dispenser
name = "chem dispenser"
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
icon = 'icons/obj/chemical.dmi'
icon_state = "dispenser"
- use_power = NO_POWER_USE
+ use_power = IDLE_POWER_USE
idle_power_usage = 40
var/ui_title = "Chem Dispenser 5000"
- var/energy = 100
- var/max_energy = 100
- var/amount = 30
+ var/cell_type = /obj/item/stock_parts/cell/high
+ var/obj/item/stock_parts/cell/cell
+ var/powerefficiency = 0.1
+ var/amount = 10
+ var/recharge_amount = 100
+ var/recharge_counter = 0
+ var/hackedcheck = FALSE
var/obj/item/reagent_containers/beaker = null
- var/recharged = 0
- var/hackedcheck = 0
+ var/image/icon_beaker = null //cached overlay
var/list/dispensable_reagents = list("hydrogen", "lithium", "carbon", "nitrogen", "oxygen", "fluorine",
"sodium", "aluminum", "silicon", "phosphorus", "sulfur", "chlorine", "potassium", "iron",
"copper", "mercury", "plasma", "radium", "water", "ethanol", "sugar", "iodine", "bromine", "silver")
+ var/list/upgrade_reagents = list("oil", "ash", "acetone", "saltpetre", "ammonia", "diethylamine", "fuel")
var/list/hacked_reagents = list("toxin")
var/hack_message = "You disable the safety safeguards, enabling the \"Mad Scientist\" mode."
var/unhack_message = "You re-enable the safety safeguards, enabling the \"NT Standard\" mode."
- var/list/broken_requirements = list()
- var/broken_on_spawn = 0
- var/recharge_delay = 5
- var/image/icon_beaker = null //cached overlay
+
+/obj/machinery/chem_dispenser/New()
+ ..()
+ component_parts = list()
+ component_parts += new /obj/item/circuitboard/chem_dispenser(null)
+ component_parts += new /obj/item/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/stock_parts/matter_bin(null)
+ component_parts += new /obj/item/stock_parts/capacitor(null)
+ component_parts += new /obj/item/stock_parts/manipulator(null)
+ component_parts += new /obj/item/stock_parts/console_screen(null)
+ component_parts += new cell_type(null)
+ RefreshParts()
+ dispensable_reagents = sortList(dispensable_reagents)
+
+/obj/machinery/chem_dispenser/RefreshParts()
+ recharge_amount = initial(recharge_amount)
+ var/newpowereff = 0.0666666
+ for(var/obj/item/stock_parts/cell/P in component_parts)
+ cell = P
+ for(var/obj/item/stock_parts/matter_bin/M in component_parts)
+ newpowereff += 0.0166666666 * M.rating
+ for(var/obj/item/stock_parts/capacitor/C in component_parts)
+ recharge_amount *= C.rating
+ for(var/obj/item/stock_parts/manipulator/M in component_parts)
+ if(M.rating > 3)
+ dispensable_reagents |= upgrade_reagents
+ powerefficiency = round(newpowereff, 0.01)
+
+/obj/machinery/chem_dispenser/Destroy()
+ QDEL_NULL(beaker)
+ QDEL_NULL(cell)
+ return ..()
+
+/obj/machinery/chem_dispenser/examine(mob/user)
+ ..()
+ if(panel_open)
+ to_chat(user, " [src]'s maintenance hatch is open!")
+ if(in_range(user, src) || isobserver(user))
+ to_chat(user, " The status display reads: Recharging [recharge_amount] power units per interval. Power efficiency increased by [round((powerefficiency * 1000) - 100, 1)]%.")
-/obj/machinery/chem_dispenser/proc/recharge()
- if(stat & (BROKEN|NOPOWER)) return
- var/addenergy = 1
- var/oldenergy = energy
- energy = min(energy + addenergy, max_energy)
- if(energy != oldenergy)
- use_power(1500) // This thing uses up alot of power (this is still low as shit for creating reagents from thin air)
- SSnanoui.update_uis(src) // update all UIs attached to src
+/obj/machinery/chem_dispenser/process()
+ if(recharge_counter >= 4)
+ if(!is_operational())
+ return
+ var/usedpower = cell.give(recharge_amount)
+ if(usedpower)
+ use_power(15 * recharge_amount)
+ SSnanoui.update_uis(src) // update all UIs attached to src
+ recharge_counter = 0
+ return
+ recharge_counter++
/obj/machinery/chem_dispenser/power_change()
if(powered())
@@ -42,72 +84,19 @@
stat |= NOPOWER
SSnanoui.update_uis(src) // update all UIs attached to src
-/obj/machinery/chem_dispenser/process()
-
- if(recharged < 0)
- recharge()
- recharged = recharge_delay
- else
- recharged -= 1
-
-/obj/machinery/chem_dispenser/New()
- ..()
- recharge()
- dispensable_reagents = sortList(dispensable_reagents)
-
- if(broken_on_spawn)
- overlays.Cut()
- var/amount = pick(3,3,4)
- var/list/options = list()
- options[/obj/item/stock_parts/capacitor/adv] = "Add an advanced capacitor to fix it."
- options[/obj/item/stock_parts/console_screen] = "Replace the console screen to fix it."
- options[/obj/item/stock_parts/manipulator/pico] = "Upgrade to a pico manipulator to fix it."
- options[/obj/item/stock_parts/matter_bin/super] = "Give it a super matter bin to fix it."
- options[/obj/item/stock_parts/cell/super] = "Replace the reagent synthesizer with a super capacity cell to fix it."
- options[/obj/item/reagent_scanner/adv] = "Replace the reagent scanner with an advanced reagent scanner to fix it"
- options[/obj/item/stock_parts/micro_laser/high] = "Repair the reagent synthesizer with an high-power micro-laser to fix it"
- options[/obj/item/reagent_scanner/adv] = "Replace the reagent scanner with an advanced reagent scanner to fix it"
- options[/obj/item/stack/nanopaste] = "Apply some nanopaste to the broken nozzles to fix it."
- options[/obj/item/stack/sheet/plasteel] = "Surround the outside with a plasteel cover to fix it."
- options[/obj/item/stack/sheet/rglass] = "Insert a pane of reinforced glass to fix it."
-
- while(amount > 0)
- amount -= 1
-
- var/index = pick(options)
- broken_requirements[index] = options[index]
- options -= index
-
-
/obj/machinery/chem_dispenser/ex_act(severity)
switch(severity)
- if(1.0)
+ if(1)
qdel(src)
- return
- if(2.0)
+ if(2)
if(prob(50))
qdel(src)
- return
/obj/machinery/chem_dispenser/blob_act()
if(prob(50))
qdel(src)
- /**
- * The ui_interact proc is used to open and update Nano UIs
- * If ui_interact is not used then the UI will not update correctly
- * ui_interact is currently defined for /atom/movable
- *
- * @param user /mob The mob who is interacting with this ui
- * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
- *
- * @return nothing
- */
/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
- if(broken_requirements.len)
- to_chat(user, "[src] is broken. [broken_requirements[broken_requirements[1]]]")
- return
-
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
@@ -121,8 +110,8 @@
var/data[0]
data["amount"] = amount
- data["energy"] = round(energy)
- data["maxEnergy"] = round(max_energy)
+ data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI.
+ data["maxEnergy"] = cell.maxcharge * powerefficiency
data["isBeakerLoaded"] = beaker ? 1 : 0
var/beakerContents[0]
@@ -151,26 +140,32 @@
/obj/machinery/chem_dispenser/Topic(href, href_list)
if(..())
- return 1
+ return TRUE
if(href_list["amount"])
- amount = round(text2num(href_list["amount"]), 5) // round to nearest 5
+ amount = round(text2num(href_list["amount"]), 1) // round to nearest 1
if(amount < 0) // Since the user can actually type the commands himself, some sanity checking
amount = 0
if(amount > 100)
amount = 100
if(href_list["dispense"])
- if(dispensable_reagents.Find(href_list["dispense"]) && beaker != null)
- var/obj/item/reagent_containers/glass/B = beaker
- var/datum/reagents/R = B.reagents
- var/space = R.maximum_volume - R.total_volume
+ if(!is_operational() || QDELETED(cell))
+ return
+ if(beaker && dispensable_reagents.Find(href_list["dispense"]))
+ var/datum/reagents/R = beaker.reagents
+ var/free = R.maximum_volume - R.total_volume
+ var/actual = min(amount, (cell.charge * powerefficiency) * 10, free)
- R.add_reagent(href_list["dispense"], min(amount, energy * 10, space))
- energy = max(energy - min(amount, energy * 10, space) / 10, 0)
+ if(!cell.use(actual / powerefficiency))
+ atom_say("Not enough energy to complete operation!")
+ return
+
+ R.add_reagent(href_list["dispense"], actual)
overlays.Cut()
- icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
- icon_beaker.pixel_x = rand(-10,5)
+ if(!icon_beaker)
+ icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
+ icon_beaker.pixel_x = rand(-10, 5)
overlays += icon_beaker
if(href_list["remove"])
@@ -178,75 +173,96 @@
if(href_list["removeamount"])
var/amount = text2num(href_list["removeamount"])
if(isnum(amount) && (amount > 0))
- var/obj/item/reagent_containers/glass/B = beaker
- var/datum/reagents/R = B.reagents
+ var/datum/reagents/R = beaker.reagents
var/id = href_list["remove"]
R.remove_reagent(id, amount)
+ else if(isnum(amount) && (amount == -1)) //Isolate instead
+ var/datum/reagents/R = beaker.reagents
+ var/id = href_list["remove"]
+ R.isolate_reagent(id)
if(href_list["ejectBeaker"])
if(beaker)
- var/obj/item/reagent_containers/glass/B = beaker
- B.forceMove(loc)
+ beaker.forceMove(loc)
beaker = null
overlays.Cut()
- add_fingerprint(usr)
- return 1 // update UIs attached to this object
-/obj/machinery/chem_dispenser/attackby(obj/item/reagent_containers/B, mob/user, params)
- if(isrobot(user))
+ add_fingerprint(usr)
+ return TRUE // update UIs attached to this object
+
+/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
+ if(ismultitool(I))
+ if(!hackedcheck)
+ to_chat(user, hack_message)
+ dispensable_reagents += hacked_reagents
+ hackedcheck = TRUE
+ else
+ to_chat(user, unhack_message)
+ dispensable_reagents -= hacked_reagents
+ hackedcheck = FALSE
+ SSnanoui.update_uis(src)
return
- if(broken_requirements.len && B.type == broken_requirements[1])
- if(istype(B,/obj/item/stack))
- var/obj/item/stack/S = B
- S.use(1)
- else
- if(!user.drop_item())
- to_chat(user, "[B] is stuck to you!")
- return
- qdel(B)
- broken_requirements -= broken_requirements[1]
- to_chat(user, "You fix [src].")
+ if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", "[initial(icon_state)]", I))
+ return
+
+ if(exchange_parts(user, I))
+ SSnanoui.update_uis(src)
+ return
+
+ if(iswrench(I))
+ playsound(src, I.usesound, 50, 1)
+ if(anchored)
+ anchored = FALSE
+ to_chat(user, "[src] can now be moved.")
+ else if(!anchored)
+ anchored = TRUE
+ to_chat(user, "[src] is now secured.")
+ return
+
+ if(panel_open)
+ if(iscrowbar(I))
+ if(beaker)
+ beaker.forceMove(loc)
+ beaker = null
+ if(cell)
+ cell.forceMove(loc)
+ cell = null
+ default_deconstruction_crowbar(I)
+ return TRUE
+
+ if(isrobot(user))
return
if(beaker)
to_chat(user, "Something is already loaded into the machine.")
return
- if(istype(B, /obj/item/reagent_containers/glass) || istype(B, /obj/item/reagent_containers/food/drinks))
- beaker = B
- if(!user.drop_item())
- to_chat(user, "[B] is stuck to you!")
+ if(istype(I, /obj/item/reagent_containers/glass) || istype(I, /obj/item/reagent_containers/food/drinks))
+ if(panel_open)
+ to_chat(user, "Close the maintenance panel first.")
return
- B.forceMove(src)
- to_chat(user, "You set [B] on the machine.")
+ if(!user.drop_item())
+ to_chat(user, "[I] is stuck to you!")
+ return
+ beaker = I
+ I.forceMove(src)
+ to_chat(user, "You set [I] on the machine.")
SSnanoui.update_uis(src) // update all UIs attached to src
if(!icon_beaker)
icon_beaker = image('icons/obj/chemical.dmi', src, "disp_beaker") //randomize beaker overlay position.
- icon_beaker.pixel_x = rand(-10,5)
+ icon_beaker.pixel_x = rand(-10, 5)
overlays += icon_beaker
return
+ return ..()
-/obj/machinery/chem_dispenser/attackby(obj/item/B, mob/user, params)
- ..()
- if(istype(B, /obj/item/multitool))
- if(hackedcheck == 0)
- to_chat(user, hack_message)
- dispensable_reagents += hacked_reagents
- hackedcheck = 1
- return
-
- else
- to_chat(user, unhack_message)
- dispensable_reagents -= hacked_reagents
- hackedcheck = 0
- return
/obj/machinery/chem_dispenser/attack_ai(mob/user)
return attack_hand(user)
/obj/machinery/chem_dispenser/attack_ghost(mob/user)
- return attack_hand(user)
+ if(user.can_admin_interact())
+ return attack_hand(user)
/obj/machinery/chem_dispenser/attack_hand(mob/user)
if(stat & BROKEN)
@@ -259,245 +275,45 @@
name = "soda fountain"
desc = "A drink fabricating machine, capable of producing many sugary drinks with just one touch."
ui_title = "Soda Dispens-o-matic"
- energy = 100
- max_energy = 100
dispensable_reagents = list("water", "ice", "milk", "soymilk", "coffee", "tea", "hot_coco", "cola", "spacemountainwind", "dr_gibb", "space_up",
"tonic", "sodawater", "lemon_lime", "grapejuice", "sugar", "orangejuice", "lemonjuice", "limejuice", "tomatojuice", "banana",
"watermelonjuice", "carrotjuice", "potato", "berryjuice")
- var/list/special_reagents2 = list(list(""),
- list("bananahonk", "milkshake", "cafe_latte", "cafe_mocha"),
- list("triple_citrus", "icecoffe","icetea"))
+ upgrade_reagents = list("bananahonk", "milkshake", "cafe_latte", "cafe_mocha", "triple_citrus", "icecoffe","icetea")
+ hacked_reagents = list("thirteenloko")
hack_message = "You change the mode from 'McNano' to 'Pizza King'."
unhack_message = "You change the mode from 'Pizza King' to 'McNano'."
- hacked_reagents = list("thirteenloko")
/obj/machinery/chem_dispenser/soda/New()
..()
- component_parts = list()
- component_parts += new /obj/item/circuitboard/soda(null)
+ QDEL_LIST(component_parts)
+ component_parts += new /obj/item/circuitboard/chem_dispenser/soda(null)
component_parts += new /obj/item/stock_parts/matter_bin(null)
component_parts += new /obj/item/stock_parts/matter_bin(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
component_parts += new /obj/item/stock_parts/capacitor(null)
component_parts += new /obj/item/stock_parts/console_screen(null)
- component_parts += new /obj/item/stock_parts/cell/super(null)
+ component_parts += new cell_type(null)
RefreshParts()
-/obj/machinery/chem_dispenser/soda/upgraded/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/circuitboard/soda(null)
- component_parts += new /obj/item/stock_parts/matter_bin/super(null)
- component_parts += new /obj/item/stock_parts/matter_bin/super(null)
- component_parts += new /obj/item/stock_parts/manipulator/pico(null)
- component_parts += new /obj/item/stock_parts/capacitor/super(null)
- component_parts += new /obj/item/stock_parts/console_screen(null)
- component_parts += new /obj/item/stock_parts/cell/hyper(null)
- RefreshParts()
-
-/obj/machinery/chem_dispenser/soda/RefreshParts()
- for(var/obj/item/stock_parts/manipulator/M in component_parts)
- for(var/i in 1 to M.rating)
- dispensable_reagents = sortList(dispensable_reagents | special_reagents2[i])
-
-/obj/machinery/chem_dispenser/soda/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/reagent_containers/glass))
- if(panel_open)
- to_chat(user, "Close the maintenance panel first.")
- return
- return ..()
- else
- ..()
-
- if(default_deconstruction_screwdriver(user, "minidispenser-o", "minidispenser", I))
- return
-
- if(exchange_parts(user, I))
- return
-
- if(iswrench(I))
- playsound(src, I.usesound, 50, 1)
- if(anchored)
- anchored = FALSE
- to_chat(user, "[src] can now be moved.")
- else if(!anchored)
- anchored = TRUE
- to_chat(user, "[src] is now secured.")
-
- if(panel_open)
- if(iscrowbar(I))
- if(beaker)
- var/obj/item/reagent_containers/glass/B = beaker
- B.forceMove(loc)
- beaker = null
- default_deconstruction_crowbar(I)
- return TRUE
-
-
/obj/machinery/chem_dispenser/beer
icon_state = "booze_dispenser"
name = "booze dispenser"
ui_title = "Booze Portal 9001"
- energy = 100
- max_energy = 100
desc = "A technological marvel, supposedly able to mix just the mixture you'd like to drink the moment you ask for one."
dispensable_reagents = list("ice", "cream", "cider", "beer", "kahlua", "whiskey", "wine", "vodka", "gin", "rum", "tequila", "vermouth", "cognac", "ale", "mead", "synthanol")
- var/list/special_reagents3 = list(list("iced_beer"),
- list("irishcream", "manhattan",),
- list("antihol", "synthignon", "bravebull"))
+ upgrade_reagents = list("iced_beer", "irishcream", "manhattan", "antihol", "synthignon", "bravebull")
+ hacked_reagents = list("goldschlager", "patron", "absinthe", "ethanol", "nothing", "sake")
hack_message = "You disable the 'nanotrasen-are-cheap-bastards' lock, enabling hidden and very expensive boozes."
unhack_message = "You re-enable the 'nanotrasen-are-cheap-bastards' lock, disabling hidden and very expensive boozes."
- hacked_reagents = list("goldschlager", "patron", "absinthe", "ethanol", "nothing", "sake")
/obj/machinery/chem_dispenser/beer/New()
..()
- component_parts = list()
- component_parts += new /obj/item/circuitboard/beer(null)
+ QDEL_LIST(component_parts)
+ component_parts += new /obj/item/circuitboard/chem_dispenser/beer(null)
component_parts += new /obj/item/stock_parts/matter_bin(null)
component_parts += new /obj/item/stock_parts/matter_bin(null)
- component_parts += new /obj/item/stock_parts/manipulator(null)
component_parts += new /obj/item/stock_parts/capacitor(null)
- component_parts += new /obj/item/stock_parts/console_screen(null)
- component_parts += new /obj/item/stock_parts/cell/super(null)
- RefreshParts()
-
-/obj/machinery/chem_dispenser/beer/upgraded/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/circuitboard/beer(null)
- component_parts += new /obj/item/stock_parts/matter_bin/super(null)
- component_parts += new /obj/item/stock_parts/matter_bin/super(null)
- component_parts += new /obj/item/stock_parts/manipulator/pico(null)
- component_parts += new /obj/item/stock_parts/capacitor/super(null)
- component_parts += new /obj/item/stock_parts/console_screen(null)
- component_parts += new /obj/item/stock_parts/cell/hyper(null)
- RefreshParts()
-
-/obj/machinery/chem_dispenser/beer/RefreshParts()
- for(var/obj/item/stock_parts/manipulator/M in component_parts)
- for(var/i in 1 to M.rating)
- dispensable_reagents = sortList(dispensable_reagents | special_reagents3[i])
-
-/obj/machinery/chem_dispenser/beer/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/reagent_containers/glass))
- if(panel_open)
- to_chat(user, "Close the maintenance panel first.")
- return
- return ..()
- else
- ..()
-
- if(default_deconstruction_screwdriver(user, "minidispenser-o", "minidispenser", I))
- return
-
- if(exchange_parts(user, I))
- return
-
- if(iswrench(I))
- playsound(src, I.usesound, 50, 1)
- if(anchored)
- anchored = FALSE
- to_chat(user, "[src] can now be moved.")
- else if(!anchored)
- anchored = TRUE
- to_chat(user, "[src] is now secured.")
-
- if(panel_open)
- if(iscrowbar(I))
- if(beaker)
- var/obj/item/reagent_containers/glass/B = beaker
- B.forceMove(loc)
- beaker = null
- default_deconstruction_crowbar(I)
- return TRUE
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/obj/machinery/chem_dispenser/constructable
- name = "portable chem dispenser"
- icon = 'icons/obj/chemical.dmi'
- icon_state = "minidispenser"
- energy = 5
- max_energy = 5
- amount = 5
- recharge_delay = 10
- dispensable_reagents = list()
- var/list/special_reagents = list(list("hydrogen", "oxygen", "silicon", "phosphorus", "sulfur", "carbon", "nitrogen", "water"),
- list("lithium", "sugar", "copper", "mercury", "sodium","iodine","bromine"),
- list("ethanol", "chlorine", "potassium", "aluminum","plasma", "radium", "fluorine", "iron", "silver"),
- list("oil", "ash", "acetone", "saltpetre", "ammonia", "diethylamine", "fuel"))
-
-/obj/machinery/chem_dispenser/constructable/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/circuitboard/chem_dispenser(null)
- component_parts += new /obj/item/stock_parts/matter_bin(null)
- component_parts += new /obj/item/stock_parts/matter_bin(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
- component_parts += new /obj/item/stock_parts/capacitor(null)
component_parts += new /obj/item/stock_parts/console_screen(null)
- component_parts += new /obj/item/stock_parts/cell/super(null)
- RefreshParts()
-
-/obj/machinery/chem_dispenser/constructable/upgraded/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/circuitboard/chem_dispenser(null)
- component_parts += new /obj/item/stock_parts/matter_bin/super(null)
- component_parts += new /obj/item/stock_parts/matter_bin/super(null)
- component_parts += new /obj/item/stock_parts/manipulator/pico(null)
- component_parts += new /obj/item/stock_parts/capacitor/super(null)
- component_parts += new /obj/item/stock_parts/console_screen(null)
- component_parts += new /obj/item/stock_parts/cell/hyper(null)
- RefreshParts()
-
-/obj/machinery/chem_dispenser/constructable/RefreshParts()
- var/time = 0
- var/temp_energy = 0
- var/i
- for(var/obj/item/stock_parts/matter_bin/M in component_parts)
- temp_energy += M.rating
- temp_energy--
- max_energy = temp_energy * 5 //max energy = (bin1.rating + bin2.rating - 1) * 5, 5 on lowest 25 on highest
- for(var/obj/item/stock_parts/capacitor/C in component_parts)
- time += C.rating
- for(var/obj/item/stock_parts/cell/P in component_parts)
- time += round(P.maxcharge, 10000) / 10000
- recharge_delay = 10 / (time/2) //delay between recharges, double the usual time on lowest 33% less than usual on highest
- for(var/obj/item/stock_parts/manipulator/M in component_parts)
- for(i=1, i<=M.rating, i++)
- dispensable_reagents = sortList(dispensable_reagents | special_reagents[i])
-
-/obj/machinery/chem_dispenser/constructable/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/reagent_containers/glass))
- if(panel_open)
- to_chat(user, "Close the maintenance panel first.")
- return
- ..()
- else
- ..()
-
- if(default_deconstruction_screwdriver(user, "minidispenser-o", "minidispenser", I))
- return
-
- if(exchange_parts(user, I))
- return
-
- if(istype(I, /obj/item/wrench))
- playsound(src, I.usesound, 50, 1)
- if(anchored)
- anchored = 0
- to_chat(user, "[src] can now be moved.")
- else if(!anchored)
- anchored = 1
- to_chat(user, "[src] is now secured.")
-
- if(panel_open)
- if(istype(I, /obj/item/crowbar))
- if(beaker)
- var/obj/item/reagent_containers/glass/B = beaker
- B.forceMove(loc)
- beaker = null
- default_deconstruction_crowbar(I)
- return 1
+ component_parts += new cell_type(null)
+ RefreshParts()
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm
index 1b84afb3d74..848c1ca4ecd 100644
--- a/code/modules/reagents/chemistry/machinery/chem_heater.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm
@@ -7,8 +7,7 @@
use_power = IDLE_POWER_USE
idle_power_usage = 40
var/obj/item/reagent_containers/beaker = null
- var/desired_temp = 300
- var/heater_coefficient = 0.03
+ var/desired_temp = T0C
var/on = FALSE
/obj/machinery/chem_heater/New()
@@ -19,34 +18,22 @@
component_parts += new /obj/item/stock_parts/console_screen(null)
RefreshParts()
-/obj/machinery/chem_heater/upgraded/New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/circuitboard/chem_heater(null)
- component_parts += new /obj/item/stock_parts/micro_laser/ultra(null)
- component_parts += new /obj/item/stock_parts/console_screen(null)
- RefreshParts()
-
-/obj/machinery/chem_heater/RefreshParts()
- heater_coefficient = 0.03
- for(var/obj/item/stock_parts/micro_laser/M in component_parts)
- heater_coefficient *= M.rating
-
/obj/machinery/chem_heater/process()
..()
if(stat & NOPOWER)
return
- var/state_change = 0
+ var/state_change = FALSE
if(on)
if(beaker)
- if(beaker.reagents.chem_temp > desired_temp)
- beaker.reagents.chem_temp += min(-1, max((desired_temp - beaker.reagents.chem_temp) * heater_coefficient, -15))
- if(beaker.reagents.chem_temp < desired_temp)
- beaker.reagents.chem_temp += max(1, min((desired_temp - beaker.reagents.chem_temp) * heater_coefficient, 15))
- beaker.reagents.chem_temp = round(beaker.reagents.chem_temp) //stops stuff like 456.12312312302
-
- beaker.reagents.handle_reactions()
- state_change = 1
+ if(!beaker.reagents.total_volume)
+ on = FALSE
+ SSnanoui.update_uis(src)
+ return
+ beaker.reagents.temperature_reagents(desired_temp)
+ beaker.reagents.temperature_reagents(desired_temp)
+ if(abs(beaker.reagents.chem_temp - desired_temp) <= 3)
+ on = FALSE
+ state_change = TRUE
if(state_change)
SSnanoui.update_uis(src)
@@ -54,7 +41,6 @@
/obj/machinery/chem_heater/proc/eject_beaker()
if(beaker)
beaker.forceMove(get_turf(src))
- beaker.reagents.handle_reactions()
beaker = null
icon_state = "mixer0b"
on = FALSE
@@ -102,15 +88,21 @@
/obj/machinery/chem_heater/attack_hand(mob/user)
ui_interact(user)
+/obj/machinery/chem_heater/attack_ghost(mob/user)
+ if(user.can_admin_interact())
+ return attack_hand(user)
+
/obj/machinery/chem_heater/attack_ai(mob/user)
add_hiddenprint(user)
return attack_hand(user)
/obj/machinery/chem_heater/Topic(href, href_list)
if(..())
- return 0
+ return FALSE
if(href_list["toggle_on"])
+ if(!beaker.reagents.total_volume)
+ return FALSE
on = !on
. = 1
@@ -122,7 +114,7 @@
var/target = input("Please input the target temperature", name) as num
desired_temp = Clamp(target, 0, 1000)
else
- return 0
+ return FALSE
. = 1
if(href_list["eject_beaker"])
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index 2bd9f6d4af8..ffd3ae57bd5 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -1,7 +1,7 @@
/obj/machinery/chem_master
name = "\improper ChemMaster 3000"
- density = 1
- anchored = 1
+ density = TRUE
+ anchored = TRUE
icon = 'icons/obj/chemical.dmi'
icon_state = "mixer0"
use_power = IDLE_POWER_USE
@@ -9,28 +9,44 @@
var/obj/item/reagent_containers/beaker = null
var/obj/item/storage/pill_bottle/loaded_pill_bottle = null
var/mode = 0
- var/condi = 0
+ var/condi = FALSE
var/useramount = 30 // Last used amount
var/pillamount = 10
var/patchamount = 10
var/bottlesprite = "bottle"
var/pillsprite = "1"
var/client/has_sprites = list()
- var/printing = null
+ var/printing = FALSE
/obj/machinery/chem_master/New()
+ ..()
create_reagents(100)
+ component_parts = list()
+ component_parts += new /obj/item/circuitboard/chem_master(null)
+ component_parts += new /obj/item/stock_parts/manipulator(null)
+ component_parts += new /obj/item/stock_parts/console_screen(null)
+ component_parts += new /obj/item/reagent_containers/glass/beaker(null)
+ component_parts += new /obj/item/reagent_containers/glass/beaker(null)
+ RefreshParts()
update_icon()
+/obj/machinery/chem_master/Destroy()
+ QDEL_NULL(beaker)
+ QDEL_NULL(loaded_pill_bottle)
+ return ..()
+
+/obj/machinery/chem_master/RefreshParts()
+ reagents.maximum_volume = 0
+ for(var/obj/item/reagent_containers/glass/beaker/B in component_parts)
+ reagents.maximum_volume += B.reagents.maximum_volume
+
/obj/machinery/chem_master/ex_act(severity)
switch(severity)
- if(1.0)
+ if(1)
qdel(src)
- return
- if(2.0)
+ if(2)
if(prob(50))
qdel(src)
- return
/obj/machinery/chem_master/update_icon()
overlays.Cut()
@@ -50,43 +66,64 @@
stat |= NOPOWER
update_icon()
-/obj/machinery/chem_master/attackby(obj/item/B, mob/user, params)
- if(default_unfasten_wrench(user, B))
+/obj/machinery/chem_master/attackby(obj/item/I, mob/user, params)
+ if(default_deconstruction_screwdriver(user, "mixer0_nopower", "mixer0", I))
+ if(beaker)
+ beaker.forceMove(get_turf(src))
+ beaker = null
+ reagents.clear_reagents()
+ if(loaded_pill_bottle)
+ loaded_pill_bottle.forceMove(get_turf(src))
+ loaded_pill_bottle = null
+ return
+
+ if(exchange_parts(user, I))
+ return
+
+ if(panel_open)
+ if(iscrowbar(I))
+ default_deconstruction_crowbar(I)
+ return TRUE
+ else
+ to_chat(user, "You can't use the [name] while it's panel is opened!")
+ return TRUE
+
+ if(default_unfasten_wrench(user, I))
power_change()
return
- if(istype(B, /obj/item/reagent_containers/glass) || istype(B, /obj/item/reagent_containers/food/drinks/drinkingglass))
-
+ if(istype(I, /obj/item/reagent_containers/glass) || istype(I, /obj/item/reagent_containers/food/drinks/drinkingglass))
if(beaker)
to_chat(user, "A beaker is already loaded into the machine.")
return
if(!user.drop_item())
- to_chat(user, "[B] is stuck to you!")
+ to_chat(user, "[I] is stuck to you!")
return
- beaker = B
- B.forceMove(src)
+ beaker = I
+ I.forceMove(src)
to_chat(user, "You add the beaker to the machine!")
SSnanoui.update_uis(src)
update_icon()
- else if(istype(B, /obj/item/storage/pill_bottle))
-
+ else if(istype(I, /obj/item/storage/pill_bottle))
if(loaded_pill_bottle)
- to_chat(user, "A pill bottle is already loaded into the machine.")
+ to_chat(user, "A [loaded_pill_bottle] is already loaded into the machine.")
return
if(!user.drop_item())
- to_chat(user, "[B] is stuck to you!")
+ to_chat(user, "[I] is stuck to you!")
return
- loaded_pill_bottle = B
- B.forceMove(src)
- to_chat(user, "You add the pill bottle into the dispenser slot!")
+
+ loaded_pill_bottle = I
+ I.forceMove(src)
+ to_chat(user, "You add [I] into the dispenser slot!")
SSnanoui.update_uis(src)
- return
+ else
+ return ..()
/obj/machinery/chem_master/Topic(href, href_list)
if(..())
- return 1
+ return TRUE
add_fingerprint(usr)
usr.set_machine(src)
@@ -103,8 +140,8 @@
return
if(href_list["print_p"])
- if(!(printing))
- printing = 1
+ if(!printing)
+ printing = TRUE
visible_message("[src] rattles and prints out a sheet of paper.")
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
var/obj/item/paper/P = new /obj/item/paper(loc)
@@ -125,7 +162,7 @@
P.info += "Description: [href_list["desc"]]"
P.info += "
Notes: "
P.name = "Chemical Analysis - [href_list["name"]]"
- printing = null
+ printing = FALSE
if(beaker)
var/datum/reagents/R = beaker.reagents
@@ -203,10 +240,13 @@
if(count == null)
return
count = isgoodnumber(count)
- if(count > 20) count = 20 //Pevent people from creating huge stacks of pills easily. Maybe move the number to defines?
- if(count <= 0) return
- var/amount_per_pill = reagents.total_volume/count
- if(amount_per_pill > 50) amount_per_pill = 50
+ if(count > 20)
+ count = 20 //Pevent people from creating huge stacks of pills easily. Maybe move the number to defines?
+ if(count <= 0)
+ return
+ var/amount_per_pill = reagents.total_volume / count
+ if(amount_per_pill > 100)
+ amount_per_pill = 100
var/name = input(usr,"Name:","Name your pill!","[reagents.get_master_reagent_name()] ([amount_per_pill]u)") as text|null
if(!name)
return
@@ -216,18 +256,19 @@
to_chat(usr, "Not enough reagents to create these pills!")
return
var/obj/item/reagent_containers/food/pill/P = new/obj/item/reagent_containers/food/pill(loc)
- if(!name) name = reagents.get_master_reagent_name()
+ if(!name)
+ name = reagents.get_master_reagent_name()
P.name = "[name] pill"
P.pixel_x = rand(-7, 7) //random position
P.pixel_y = rand(-7, 7)
P.icon_state = "pill"+pillsprite
- reagents.trans_to(P,amount_per_pill)
- if(loaded_pill_bottle)
+ reagents.trans_to(P, amount_per_pill)
+ if(loaded_pill_bottle && loaded_pill_bottle.type == /obj/item/storage/pill_bottle)
if(loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots)
P.forceMove(loaded_pill_bottle)
updateUsrDialog()
else
- var/name = input(usr,"Name:","Name your bag!",reagents.get_master_reagent_name()) as text|null
+ var/name = input(usr, "Name:", "Name your bag!", reagents.get_master_reagent_name()) as text|null
if(!name)
return
name = reject_bad_text(name)
@@ -236,7 +277,7 @@
P.originalname = name
P.name = "[name] pack"
P.desc = "A small condiment pack. The label says it contains [name]."
- reagents.trans_to(P,10)
+ reagents.trans_to(P, 10)
else if(href_list["createpatch"] || href_list["createpatch_multiple"])
if(!condi)
var/count = 1
@@ -247,10 +288,12 @@
count = isgoodnumber(count)
if(!count || count <= 0)
return
- if(count > 20) count = 20 //Pevent people from creating huge stacks of patches easily. Maybe move the number to defines?
+ if(count > 20)
+ count = 20 //Pevent people from creating huge stacks of patches easily. Maybe move the number to defines?
var/amount_per_patch = reagents.total_volume/count
- if(amount_per_patch > 40) amount_per_patch = 40
- var/name = input(usr,"Name:","Name your patch!","[reagents.get_master_reagent_name()] ([amount_per_patch]u)") as text|null
+ if(amount_per_patch > 40)
+ amount_per_patch = 40
+ var/name = input(usr, "Name:", "Name your patch!", "[reagents.get_master_reagent_name()] ([amount_per_patch]u)") as text|null
if(!name)
return
name = reject_bad_text(name)
@@ -263,24 +306,30 @@
P.pixel_y = rand(-7, 7)
reagents.trans_to(P,amount_per_patch)
if(is_medical_patch)
- P.instant_application = 1
+ P.instant_application = TRUE
P.icon_state = "bandaid_med"
+ if(loaded_pill_bottle && loaded_pill_bottle.type == /obj/item/storage/pill_bottle/patch_pack)
+ if(loaded_pill_bottle.contents.len < loaded_pill_bottle.storage_slots)
+ P.forceMove(loaded_pill_bottle)
+ updateUsrDialog()
+
else if(href_list["createbottle"])
if(!condi)
- var/name = input(usr,"Name:","Name your bottle!",reagents.get_master_reagent_name()) as text|null
+ var/name = input(usr, "Name:", "Name your bottle!", reagents.get_master_reagent_name()) as text|null
if(!name)
return
name = reject_bad_text(name)
- var/obj/item/reagent_containers/glass/bottle/P = new/obj/item/reagent_containers/glass/bottle(loc)
- if(!name) name = reagents.get_master_reagent_name()
+ var/obj/item/reagent_containers/glass/bottle/reagent/P = new/obj/item/reagent_containers/glass/bottle/reagent(loc)
+ if(!name)
+ name = reagents.get_master_reagent_name()
P.name = "[name] bottle"
P.pixel_x = rand(-7, 7) //random position
P.pixel_y = rand(-7, 7)
P.icon_state = bottlesprite
- reagents.trans_to(P,30)
+ reagents.trans_to(P, 50)
else
var/obj/item/reagent_containers/food/condiment/P = new/obj/item/reagent_containers/food/condiment(loc)
- reagents.trans_to(P,50)
+ reagents.trans_to(P, 50)
else if(href_list["change_pill"])
#define MAX_PILL_SPRITE 20 //max icon state of the pill sprites
var/dat = ""
@@ -299,7 +348,7 @@
else if(href_list["change_bottle"])
var/dat = ""
var/j = 0
- for(var/i in list("bottle", "small_bottle", "wide_bottle", "round_bottle"))
+ for(var/i in list("bottle", "small_bottle", "wide_bottle", "round_bottle", "reagent_bottle"))
j++
if(j == 1)
dat += ""
@@ -318,21 +367,20 @@
usr << browse(null, "window=chem_master_iconsel")
SSnanoui.update_uis(src)
- return
/obj/machinery/chem_master/attack_ai(mob/user)
return attack_hand(user)
/obj/machinery/chem_master/attack_ghost(mob/user)
- return attack_hand(user)
+ if(user.can_admin_interact())
+ return attack_hand(user)
/obj/machinery/chem_master/attack_hand(mob/user)
if(..())
- return 1
+ return TRUE
ui_interact(user)
- return
-/obj/machinery/chem_master/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
+/obj/machinery/chem_master/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = TRUE)
var/datum/asset/chem_master/assets = get_asset_datum(/datum/asset/chem_master)
assets.send(user)
@@ -380,50 +428,22 @@
return 0
/obj/machinery/chem_master/proc/chemical_safety_check(datum/reagents/R)
- var/all_safe = 1
+ var/all_safe = TRUE
for(var/datum/reagent/A in R.reagent_list)
if(!GLOB.safe_chem_list.Find(A.id))
- all_safe = 0
+ all_safe = FALSE
return all_safe
/obj/machinery/chem_master/condimaster
name = "\improper CondiMaster 3000"
- condi = 1
+ condi = TRUE
-/obj/machinery/chem_master/constructable
- name = "ChemMaster 2999"
- desc = "Used to seperate chemicals and distribute them in a variety of forms."
-
-/obj/machinery/chem_master/constructable/New()
+/obj/machinery/chem_master/condimaster/New()
..()
- component_parts = list()
- component_parts += new /obj/item/circuitboard/chem_master(null)
+ QDEL_LIST(component_parts)
+ component_parts += new /obj/item/circuitboard/chem_master/condi_master(null)
component_parts += new /obj/item/stock_parts/manipulator(null)
component_parts += new /obj/item/stock_parts/console_screen(null)
component_parts += new /obj/item/reagent_containers/glass/beaker(null)
component_parts += new /obj/item/reagent_containers/glass/beaker(null)
-
-/obj/machinery/chem_master/constructable/attackby(obj/item/B, mob/user, params)
-
- if(default_deconstruction_screwdriver(user, "mixer0_nopower", "mixer0", B))
- if(beaker)
- beaker.forceMove(get_turf(src))
- beaker = null
- reagents.clear_reagents()
- if(loaded_pill_bottle)
- loaded_pill_bottle.forceMove(get_turf(src))
- loaded_pill_bottle = null
- return
-
- if(exchange_parts(user, B))
- return
-
- if(panel_open)
- if(istype(B, /obj/item/crowbar))
- default_deconstruction_crowbar(B)
- return 1
- else
- to_chat(user, "You can't use the [name] while it's panel is opened!")
- return 1
- else
- ..()
+ RefreshParts()
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm
index 7e76217fe15..a2ecc811e6a 100644
--- a/code/modules/reagents/chemistry/reagents.dm
+++ b/code/modules/reagents/chemistry/reagents.dm
@@ -32,6 +32,12 @@
/datum/reagent/Destroy()
. = ..()
holder = null
+ if(islist(data))
+ data.Cut()
+ data = null
+
+/datum/reagent/proc/reaction_temperature(exposed_temperature, exposed_volume) //By default we do nothing.
+ return
/datum/reagent/proc/reaction_mob(mob/living/M, method = TOUCH, volume) //Some reagents transfer on touch, others don't; dependent on if they penetrate the skin or not.
if(holder) //for catching rare runtimes
diff --git a/code/modules/reagents/chemistry/reagents/alcohol.dm b/code/modules/reagents/chemistry/reagents/alcohol.dm
index 88e2d685f57..6c22360face 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol.dm
@@ -765,7 +765,7 @@
/datum/reagent/consumable/ethanol/sbiten/on_mob_life(mob/living/M)
if(M.bodytemperature < 360)
M.bodytemperature = min(360, M.bodytemperature + (50 * TEMPERATURE_DAMAGE_COEFFICIENT)) //310 is the normal bodytemp. 310.055
- ..()
+ return ..()
/datum/reagent/consumable/ethanol/devilskiss
name = "Devils Kiss"
@@ -819,7 +819,7 @@
/datum/reagent/consumable/ethanol/iced_beer/on_mob_life(mob/living/M)
if(M.bodytemperature > 270)
M.bodytemperature = max(270, M.bodytemperature - (20 * TEMPERATURE_DAMAGE_COEFFICIENT)) //310 is the normal bodytemp. 310.055
- ..()
+ return ..()
/datum/reagent/consumable/ethanol/grog
name = "Grog"
@@ -1126,7 +1126,7 @@
/datum/reagent/consumable/ethanol/dragons_breath/reaction_mob(mob/living/M, method=TOUCH, volume)
if(method == INGEST && prob(20))
if(M.on_fire)
- M.adjust_fire_stacks(3)
+ M.adjust_fire_stacks(6)
/datum/reagent/consumable/ethanol/dragons_breath/on_mob_life(mob/living/M)
var/update_flags = STATUS_UPDATE_NONE
@@ -1148,7 +1148,7 @@
if(prob(2 * volume))
to_chat(M, "OH GOD OH GOD PLEASE NO!!")
if(M.on_fire)
- M.adjust_fire_stacks(5)
+ M.adjust_fire_stacks(20)
if(prob(50))
to_chat(M, "IT BURNS!!!!")
M.visible_message("[M] is consumed in flames!")
@@ -1178,7 +1178,7 @@
if(prob(25))
holder.remove_reagent(id, 15)
M.fakevomit()
- ..()
+ return ..()
/datum/reagent/consumable/ethanol/synthanol/reaction_mob(mob/living/M, method=TOUCH, volume)
if(M.isSynthetic())
diff --git a/code/modules/reagents/chemistry/reagents/blob.dm b/code/modules/reagents/chemistry/reagents/blob.dm
index c7dd046664c..1dcd414b702 100644
--- a/code/modules/reagents/chemistry/reagents/blob.dm
+++ b/code/modules/reagents/chemistry/reagents/blob.dm
@@ -2,6 +2,7 @@
// The 4 damage
/datum/reagent/blob
description = ""
+ var/complementary_color = "#000000"
var/message = "The blob strikes you" //message sent to any mob hit by the blob
var/message_living = null //extension to first mob sent to only living mobs i.e. silicons have no skin to be burnt
can_synth = FALSE
@@ -11,8 +12,10 @@
/datum/reagent/blob/ripping_tendrils //does brute and a little stamina damage
name = "Ripping Tendrils"
+ description = "Deals High Brute damage, as well as Stamina damage."
id = "ripping_tendrils"
color = "#7F0000"
+ complementary_color = "#a15656"
message_living = ", and you feel your skin ripping and tearing off"
/datum/reagent/blob/ripping_tendrils/reaction_mob(mob/living/M, method=TOUCH, volume)
@@ -25,8 +28,10 @@
/datum/reagent/blob/boiling_oil //sets you on fire, does burn damage
name = "Boiling Oil"
+ description = "Deals High Burn damage, and sets the victim aflame."
id = "boiling_oil"
color = "#B68D00"
+ complementary_color = "#c0a856"
message = "The blob splashes you with burning oil"
message_living = ", and you feel your skin char and melt"
@@ -40,8 +45,10 @@
/datum/reagent/blob/envenomed_filaments //toxin, hallucination, and some bonus spore toxin
name = "Envenomed Filaments"
+ description = "Deals High Toxin damage, causes Hallucinations, and injects Spores into the bloodstream."
id = "envenomed_filaments"
color = "#9ACD32"
+ complementary_color = "#b0cd73"
message_living = ", and you feel sick and nauseated"
/datum/reagent/blob/envenomed_filaments/reaction_mob(mob/living/M, method=TOUCH, volume)
@@ -53,8 +60,10 @@
/datum/reagent/blob/lexorin_jelly //does tons of oxygen damage and a little brute
name = "Lexorin Jelly"
+ description = "Deals Medium Brute damage, but massive amounts of Respiration Damage."
id = "lexorin_jelly"
color = "#00FFC5"
+ complementary_color = "#56ebc9"
message_living = ", and your lungs feel heavy and weak"
/datum/reagent/blob/lexorin_jelly/reaction_mob(mob/living/M, method=TOUCH, volume)
@@ -67,8 +76,10 @@
/datum/reagent/blob/kinetic //does semi-random brute damage
name = "Kinetic Gelatin"
+ description = "Deals Randomized damage, between 0.33 to 2.33 times the standard amount."
id = "kinetic"
color = "#FFA500"
+ complementary_color = "#ebb756"
message = "The blob pummels you"
/datum/reagent/blob/kinetic/reaction_mob(mob/living/M, method=TOUCH, volume)
@@ -79,8 +90,10 @@
/datum/reagent/blob/cryogenic_liquid //does low burn damage and stamina damage and cools targets down
name = "Cryogenic Liquid"
+ description = "Deals Medium Brute damage, Stamina Damage, and injects Frost Oil into its victims, freezing them to death."
id = "cryogenic_liquid"
color = "#8BA6E9"
+ complementary_color = "#a8b7df"
message = "The blob splashes you with an icy liquid"
message_living = ", and you feel cold and tired"
@@ -91,23 +104,12 @@
M.adjustStaminaLoss(0.4*volume)
M.reagents.add_reagent("frostoil", 0.4*volume)
-/datum/reagent/blob/dark_matter
- name = "Dark Matter"
- id = "dark_matter"
- color = "#61407E"
- message = "You feel a thrum as the blob strikes you, and everything flies at you"
-
-/datum/reagent/blob/dark_matter/reaction_mob(mob/living/M, method=TOUCH, volume)
- if(method == TOUCH)
- reagent_vortex(M, 0, volume)
- volume = ..()
- M.apply_damage(0.6*volume, BRUTE)
-
-
/datum/reagent/blob/b_sorium
name = "Sorium"
+ description = "Deals High Brute damage, and sends people flying away."
id = "b_sorium"
color = "#808000"
+ complementary_color = "#a2a256"
message = "The blob slams into you, and sends you flying"
/datum/reagent/blob/b_sorium/reaction_mob(mob/living/M, method=TOUCH, volume)
diff --git a/code/modules/reagents/chemistry/reagents/disease.dm b/code/modules/reagents/chemistry/reagents/disease.dm
index a9cbbe87691..9ce636b466a 100644
--- a/code/modules/reagents/chemistry/reagents/disease.dm
+++ b/code/modules/reagents/chemistry/reagents/disease.dm
@@ -114,6 +114,19 @@
M.ForceContractDisease(new /datum/disease/vampire(0))
return ..()
+/datum/reagent/bacon_grease
+ name = "pure bacon grease"
+ id = "bacon_grease"
+ description = "Hook me up to an IV of that sweet, sweet stuff!"
+ reagent_state = LIQUID
+ color = "#F7E6B1"
+ can_synth = FALSE
+
+/datum/reagent/bacon_grease/on_mob_life(mob/living/carbon/M)
+ if(volume > 4.5)
+ M.ForceContractDisease(new /datum/disease/critical/heart_failure(0))
+ return ..()
+
/datum/reagent/heartworms
name = "Space heartworms"
id = "heartworms"
diff --git a/code/modules/reagents/chemistry/reagents/drink_cold.dm b/code/modules/reagents/chemistry/reagents/drink_cold.dm
index 8e902f014f3..707aab07b54 100644
--- a/code/modules/reagents/chemistry/reagents/drink_cold.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_cold.dm
@@ -42,7 +42,7 @@
/datum/reagent/consumable/drink/cold/ice/on_mob_life(mob/living/M)
M.bodytemperature = max(M.bodytemperature - 5 * TEMPERATURE_DAMAGE_COEFFICIENT, 0)
- ..()
+ return ..()
/datum/reagent/consumable/drink/cold/space_cola
name = "Cola"
diff --git a/code/modules/reagents/chemistry/reagents/food.dm b/code/modules/reagents/chemistry/reagents/food.dm
index c4434a92c5e..9b1aca91f8d 100644
--- a/code/modules/reagents/chemistry/reagents/food.dm
+++ b/code/modules/reagents/chemistry/reagents/food.dm
@@ -448,7 +448,7 @@
/datum/reagent/consumable/egg/on_mob_life(mob/living/M)
if(prob(3))
M.reagents.add_reagent("cholesterol", rand(1,2))
- ..()
+ return ..()
/datum/reagent/consumable/corn_starch
name = "Corn Starch"
@@ -643,9 +643,6 @@
color = "#684435"
taste_message = "burritos"
-/datum/reagent/consumable/beans/on_mob_life(mob/living/M)
- return ..()
-
/datum/reagent/consumable/bread
name = "Bread"
id = "bread"
@@ -845,10 +842,7 @@
to_chat(M, "Your chest is burning with pain!")
update_flags |= M.Stun(1, FALSE)
update_flags |= M.Weaken(1, FALSE)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(!H.undergoing_cardiac_arrest())
- H.set_heartattack(TRUE)
+ M.ForceContractDisease(new /datum/disease/critical/heart_failure(0))
return ..() | update_flags
/datum/reagent/fungus
diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm
index 804904723ea..d9c1591a4dc 100644
--- a/code/modules/reagents/chemistry/reagents/medicine.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine.dm
@@ -5,6 +5,7 @@
/datum/reagent/medicine/on_mob_life(mob/living/M)
current_cycle++
holder.remove_reagent(id, (metabolization_rate / M.metabolism_efficiency) * M.digestion_ratio) //medicine reagents stay longer if you have a better metabolism
+ return STATUS_UPDATE_NONE
/datum/reagent/medicine/hydrocodone
name = "Hydrocodone"
@@ -16,13 +17,6 @@
shock_reduction = 200
taste_message = "numbness"
-/datum/reagent/medicine/hydrocodone/on_mob_life(mob/living/M)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.traumatic_shock < 100)
- H.shock_stage = 0
- return ..()
-
/datum/reagent/medicine/sterilizine
name = "Sterilizine"
id = "sterilizine"
@@ -412,10 +406,6 @@
var/update_flags = STATUS_UPDATE_NONE
if(prob(55))
update_flags |= M.adjustBruteLoss(-2*REAGENTS_EFFECT_MULTIPLIER, FALSE)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.traumatic_shock < 100)
- H.shock_stage = 0
return ..() | update_flags
/datum/reagent/medicine/salbutamol
@@ -472,7 +462,7 @@
update_flags |= M.AdjustWeakened(-1, FALSE)
update_flags |= M.adjustStaminaLoss(-1*REAGENTS_EFFECT_MULTIPLIER, FALSE)
M.AdjustLoseBreath(-1, bound_lower = 5)
- if(M.oxyloss > 75)
+ if(M.getOxyLoss() > 75)
update_flags |= M.adjustOxyLoss(-1, FALSE)
if(M.health < 0 || M.health > 0 && prob(33))
update_flags |= M.adjustToxLoss(-1, FALSE)
@@ -537,6 +527,7 @@
taste_message = "a delightful numbing"
/datum/reagent/medicine/morphine/on_mob_life(mob/living/M)
+ var/update_flags = STATUS_UPDATE_NONE
M.AdjustJitter(-25)
switch(current_cycle)
if(1 to 15)
@@ -545,13 +536,9 @@
if(16 to 35)
M.Drowsy(20)
if(36 to INFINITY)
- M.Paralyse(15)
+ update_flags |= M.Paralyse(15, FALSE)
M.Drowsy(20)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.traumatic_shock < 100)
- H.shock_stage = 0
- ..()
+ return ..() | update_flags
/datum/reagent/medicine/oculine
name = "Oculine"
@@ -600,7 +587,7 @@
if(prob(4))
M.emote("collapse")
M.AdjustLoseBreath(-5, bound_lower = 5)
- if(M.oxyloss > 65)
+ if(M.getOxyLoss() > 65)
update_flags |= M.adjustOxyLoss(-10*REAGENTS_EFFECT_MULTIPLIER, FALSE)
if(M.health < -25)
update_flags |= M.adjustToxLoss(-1, FALSE)
@@ -636,7 +623,7 @@
update_flags |= M.adjustBrainLoss(-1, FALSE)
holder.remove_reagent("histamine", 15)
M.AdjustLoseBreath(-1, bound_lower = 3)
- if(M.oxyloss > 35)
+ if(M.getOxyLoss() > 35)
update_flags |= M.adjustOxyLoss(-10*REAGENTS_EFFECT_MULTIPLIER, FALSE)
if(M.health < -10 && M.health > -65)
update_flags |= M.adjustToxLoss(-1*REAGENTS_EFFECT_MULTIPLIER, FALSE)
@@ -700,8 +687,7 @@
if(method == INGEST)
if(M.stat == DEAD)
if(M.getBruteLoss()+M.getFireLoss()+M.getCloneLoss() >= 150)
- M.visible_message("[M]'s body starts convulsing!")
- M.gib()
+ M.delayed_gib()
return
var/mob/dead/observer/ghost = M.get_ghost()
if(ghost)
@@ -775,7 +761,7 @@
if(ishuman(M))
var/mob/living/carbon/human/H = M
H.update_mutations()
- ..()
+ return ..()
/datum/reagent/medicine/antihol
name = "Antihol"
@@ -789,7 +775,7 @@
M.SetSlur(0)
M.AdjustDrunk(-4)
M.reagents.remove_all_type(/datum/reagent/consumable/ethanol, 8, 0, 1)
- if(M.toxloss <= 25)
+ if(M.getToxLoss() <= 25)
update_flags |= M.adjustToxLoss(-2.0, FALSE)
return ..() | update_flags
@@ -873,6 +859,7 @@
/datum/reagent/medicine/insulin/on_mob_life(mob/living/M)
M.reagents.remove_reagent("sugar", 5)
+ return ..()
/datum/reagent/medicine/teporone
name = "Teporone"
@@ -889,7 +876,7 @@
M.bodytemperature = max(310, M.bodytemperature - (40 * TEMPERATURE_DAMAGE_COEFFICIENT))
else if(M.bodytemperature < 311)
M.bodytemperature = min(310, M.bodytemperature + (40 * TEMPERATURE_DAMAGE_COEFFICIENT))
- ..()
+ return ..()
/datum/reagent/medicine/haloperidol
name = "Haloperidol"
@@ -932,6 +919,7 @@
taste_message = "sleepiness"
/datum/reagent/medicine/ether/on_mob_life(mob/living/M)
+ var/update_flags = STATUS_UPDATE_NONE
M.AdjustJitter(-25)
switch(current_cycle)
if(1 to 30)
@@ -940,9 +928,9 @@
if(31 to 40)
M.Drowsy(20)
if(41 to INFINITY)
- M.Paralyse(15)
+ update_flags |= M.Paralyse(15, FALSE)
M.Drowsy(20)
- ..()
+ return ..() | update_flags
/datum/reagent/medicine/syndicate_nanites //Used exclusively by Syndicate medical cyborgs
name = "Restorative Nanites"
diff --git a/code/modules/reagents/chemistry/reagents/misc.dm b/code/modules/reagents/chemistry/reagents/misc.dm
index 7e015a006e8..7d92080ae6b 100644
--- a/code/modules/reagents/chemistry/reagents/misc.dm
+++ b/code/modules/reagents/chemistry/reagents/misc.dm
@@ -162,7 +162,7 @@
if(!H.dna.species.exotic_blood && !(NO_BLOOD in H.dna.species.species_traits))
if(H.blood_volume < BLOOD_VOLUME_NORMAL)
H.blood_volume += 0.8
- ..()
+ return ..()
/datum/reagent/iron/reaction_mob(mob/living/M, method=TOUCH, volume)
if(M.has_bane(BANE_IRON) && holder && holder.chem_temp < 150) //If the target is weak to cold iron, then poison them.
@@ -205,6 +205,18 @@
taste_message = "motor oil"
process_flags = ORGANIC | SYNTHETIC
+/datum/reagent/oil/reaction_temperature(exposed_temperature, exposed_volume)
+ if(exposed_temperature > T0C + 600)
+ var/turf/T = get_turf(holder.my_atom)
+ holder.my_atom.visible_message("The oil burns!")
+ fireflash(T, min(max(0, volume / 40), 8))
+ var/datum/effect_system/smoke_spread/bad/BS = new
+ BS.set_up(1, 0, T)
+ BS.start()
+ if(holder)
+ holder.add_reagent("ash", round(volume * 0.5))
+ holder.del_reagent(id)
+
/datum/reagent/oil/reaction_turf(turf/T, volume)
if(volume >= 3 && !isspaceturf(T) && !locate(/obj/effect/decal/cleanable/blood/oil) in T)
new /obj/effect/decal/cleanable/blood/oil(T)
diff --git a/code/modules/reagents/chemistry/reagents/paradise_pop.dm b/code/modules/reagents/chemistry/reagents/paradise_pop.dm
index 08f01bdd381..2294088e54a 100644
--- a/code/modules/reagents/chemistry/reagents/paradise_pop.dm
+++ b/code/modules/reagents/chemistry/reagents/paradise_pop.dm
@@ -29,9 +29,9 @@
/datum/reagent/consumable/drink/apple_pocalypse/on_mob_life(mob/living/M)
if(prob(1))
var/turf/simulated/T = get_turf(M)
- goonchem_vortex(T, 0, 2, 1)
+ goonchem_vortex(T, 1, 0)
to_chat(M, "You briefly feel super-massive, like a black hole. Probably just your imagination...")
- ..()
+ return ..()
//Berry Banned: This one is tasty and safe to drink, might have a low chance of healing a random damage type?
/datum/reagent/consumable/drink/berry_banned
@@ -119,7 +119,7 @@
/datum/reagent/consumable/drink/grape_granade/on_mob_life(mob/living/M)
if(prob(1))
var/turf/simulated/T = get_turf(M)
- goonchem_vortex(T, 1, 1, 2)
+ goonchem_vortex(T, 0, 0)
M.emote("burp")
to_chat(M, "You feel ready to burst! Oh wait, just a burp...")
else if(prob(25))
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
index 857b15330d4..d91a76da7fc 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
@@ -1,3 +1,80 @@
+/datum/reagent/phlogiston
+ name = "phlogiston"
+ id = "phlogiston"
+ description = "It appears to be liquid fire."
+ reagent_state = LIQUID
+ color = "#FFAF00"
+ process_flags = ORGANIC | SYNTHETIC
+ var/temp_fire = 4000
+ var/temp_deviance = 1000
+ var/size_divisor = 40
+ var/mob_burning = 6.6 // 33
+
+/datum/reagent/phlogiston/reaction_turf(turf/T, volume)
+ if(holder.chem_temp <= T0C - 50)
+ return
+ var/radius = min(max(0, volume / size_divisor), 8)
+ fireflash_sm(T, radius, rand(temp_fire - temp_deviance, temp_fire + temp_deviance), 500)
+
+/datum/reagent/phlogiston/reaction_mob(mob/living/M, method = TOUCH, volume)
+ if(holder.chem_temp <= T0C - 50)
+ return
+ M.adjust_fire_stacks(mob_burning)
+ M.IgniteMob()
+ if(method == INGEST)
+ M.adjustFireLoss(min(max(15, volume * 3), 45))
+ to_chat(M, "It burns!")
+ M.emote("scream")
+
+/datum/reagent/phlogiston/on_mob_life(mob/living/M)
+ if(holder.chem_temp <= T0C - 50)
+ return
+ M.adjust_fire_stacks(0.4)
+ M.IgniteMob()
+ return ..()
+
+/datum/reagent/phlogiston/firedust
+ name = "phlogiston dust"
+ id = "phlogiston_dust"
+ description = "And this is solid fire. However that works."
+ temp_fire = 1500
+ temp_deviance = 500
+ size_divisor = 80
+ mob_burning = 3 // 15
+
+/datum/reagent/napalm
+ name = "napalm"
+ id = "napalm"
+ description = "A highly flammable jellied fuel."
+ reagent_state = LIQUID
+ process_flags = ORGANIC | SYNTHETIC
+ color = "#C86432"
+
+/datum/reagent/napalm/reaction_temperature(exposed_temperature, exposed_volume)
+ if(exposed_temperature > T0C + 100)
+ var/radius = min(max(0, volume * 0.15), 8)
+ fireflash_sm(get_turf(holder.my_atom), radius, rand(3000, 6000), 500)
+ if(holder)
+ holder.del_reagent(id)
+
+/datum/reagent/napalm/reaction_turf(turf/T, volume)
+ if(isspaceturf(T))
+ return
+ if(!T.reagents)
+ T.create_reagents(volume)
+ T.reagents.add_reagent("napalm", volume)
+
+/datum/reagent/napalm/reaction_mob(mob/living/M, method = TOUCH, volume)
+ if(method == TOUCH)
+ if(M.on_fire)
+ M.adjust_fire_stacks(14)
+ M.emote("scream")
+
+/datum/reagent/napalm/on_mob_life(mob/living/M)
+ if(M.on_fire)
+ M.adjust_fire_stacks(2)
+ return ..()
+
/datum/reagent/fuel
name = "Welding fuel"
id = "fuel"
@@ -8,12 +85,54 @@
drink_name = "Glass of welder fuel"
drink_desc = "Unless you are an industrial tool, this is probably not safe for consumption."
taste_message = "mistakes"
+ process_flags = ORGANIC | SYNTHETIC
+ var/max_radius = 7
+ var/min_radius = 0
+ var/volume_radius_modifier = -0.15
+ var/volume_radius_multiplier = 0.09
+ var/explosion_threshold = 100
+ var/min_explosion_radius = 0
+ var/max_explosion_radius = 4
+ var/volume_explosion_radius_multiplier = 0.005
+ var/volume_explosion_radius_modifier = 0
+ var/combustion_temp = T0C + 200
+
+/datum/reagent/fuel/on_mob_life(mob/living/M)
+ if(M.on_fire)
+ M.adjust_fire_stacks(0.4)
+ return ..()
+
+/datum/reagent/fuel/reaction_temperature(exposed_temperature, exposed_volume)
+ if(exposed_temperature > combustion_temp)
+ if(volume < 1)
+ if(holder)
+ holder.del_reagent(id)
+ return
+ var/turf/T = get_turf(holder.my_atom)
+ var/radius = min(max(min_radius, volume * volume_radius_multiplier + volume_radius_modifier), max_radius)
+ fireflash_sm(T, radius, 2200 + radius * 250, radius * 50)
+ if(holder && volume >= explosion_threshold)
+ if(holder.my_atom)
+ holder.my_atom.visible_message("[holder.my_atom] explodes!")
+ message_admins("Fuel explosion ([holder.my_atom], reagent type: [id]) at [COORD(holder.my_atom.loc)]. Last touched by: [holder.my_atom.fingerprintslast ? "[holder.my_atom.fingerprintslast]" : "*null*"].")
+ log_game("Fuel explosion ([holder.my_atom], reagent type: [id]) at [COORD(holder.my_atom.loc)]. Last touched by: [holder.my_atom.fingerprintslast ? "[holder.my_atom.fingerprintslast]" : "*null*"].")
+ holder.my_atom.investigate_log("A fuel explosion, last touched by [holder.my_atom.fingerprintslast ? "[holder.my_atom.fingerprintslast]" : "*null*"], triggered at [COORD(holder.my_atom.loc)].", INVESTIGATE_BOMB)
+ var/boomrange = min(max(min_explosion_radius, round(volume * volume_explosion_radius_multiplier + volume_explosion_radius_modifier)), max_explosion_radius)
+ explosion(T, -1, -1, boomrange, 1)
+ if(holder)
+ holder.del_reagent(id)
+
+/datum/reagent/fuel/reaction_turf(turf/T, volume) //Don't spill the fuel, or you'll regret it
+ if(isspaceturf(T))
+ return
+ if(!T.reagents)
+ T.create_reagents(50)
+ T.reagents.add_reagent("fuel", volume)
/datum/reagent/fuel/reaction_mob(mob/living/M, method=TOUCH, volume)//Splashing people with welding fuel to make them easy to ignite!
if(method == TOUCH)
- M.adjust_fire_stacks(volume / 10)
- return
- ..()
+ if(M.on_fire)
+ M.adjust_fire_stacks(6)
/datum/reagent/plasma
name = "Plasma"
@@ -23,6 +142,12 @@
color = "#7A2B94"
taste_message = "corporate assets going to waste"
+/datum/reagent/plasma/reaction_temperature(exposed_temperature, exposed_volume)
+ if(exposed_temperature >= T0C + 100)
+ fireflash(get_turf(holder.my_atom), min(max(0, volume / 10), 8))
+ if(holder)
+ holder.del_reagent(id)
+
/datum/reagent/plasma/on_mob_life(mob/living/M)
var/update_flags = STATUS_UPDATE_NONE
update_flags |= M.adjustToxLoss(1*REAGENTS_EFFECT_MULTIPLIER, FALSE)
@@ -33,10 +158,10 @@
C.adjustPlasma(10)
return ..() | update_flags
-/datum/reagent/plasma/reaction_mob(mob/living/M, method=TOUCH, volume)//Splashing people with plasma is stronger than fuel!
+/datum/reagent/plasma/reaction_mob(mob/living/M, method = TOUCH, volume)//Splashing people with plasma is stronger than fuel!
if(method == TOUCH)
- M.adjust_fire_stacks(volume / 5)
- ..()
+ if(M.on_fire)
+ M.adjust_fire_stacks(6)
/datum/reagent/thermite
@@ -48,11 +173,32 @@
process_flags = ORGANIC | SYNTHETIC
taste_message = "rust"
-/datum/reagent/thermite/reaction_turf(turf/simulated/wall/W, volume)
- if(volume >= 5 && istype(W))
- W.thermite = 1
- W.overlays.Cut()
- W.overlays = image('icons/effects/effects.dmi', icon_state = "thermite")
+/datum/reagent/thermite/reaction_mob(mob/living/M, method= TOUCH, volume)
+ if(method == TOUCH)
+ if(M.on_fire)
+ M.adjust_fire_stacks(20)
+
+/datum/reagent/thermite/reaction_temperature(exposed_temperature, exposed_volume)
+ var/turf/simulated/S = holder.my_atom
+ if(!istype(S))
+ return
+
+ if(exposed_temperature >= T0C + 100)
+ var/datum/reagents/Holder = holder
+ var/Id = id
+ var/Volume = volume
+ Holder.del_reagent(Id)
+ fireflash_sm(S, 0, rand(20000, 25000) + Volume * 2500, 0, 0, 1)
+
+/datum/reagent/thermite/reaction_turf(turf/simulated/S, volume)
+ if(istype(S))
+ if(!S.reagents)
+ S.create_reagents(volume)
+ S.reagents.add_reagent("thermite", volume)
+ S.overlays.Cut()
+ S.overlays = image('icons/effects/effects.dmi', icon_state = "thermite")
+ if(S.active_hotspot)
+ S.reagents.temperature_reagents(S.active_hotspot.temperature, 10, 300)
/datum/reagent/glycerol
name = "Glycerol"
@@ -81,33 +227,24 @@
taste_message = null
/datum/reagent/clf3/on_mob_life(mob/living/M)
- var/update_flags = STATUS_UPDATE_NONE
- M.adjust_fire_stacks(2)
- var/burndmg = max(0.3*M.fire_stacks, 0.3)
- update_flags |= M.adjustFireLoss(burndmg, FALSE)
- return ..() | update_flags
+ if(M.on_fire)
+ M.adjust_fire_stacks(1)
+ return ..()
-/datum/reagent/clf3/reaction_turf(turf/simulated/T, volume)
- if(prob(1) && istype(T, /turf/simulated/floor/plating))
- var/turf/simulated/floor/plating/F = T
- F.ChangeTurf(/turf/space)
- if(istype(T, /turf/simulated/floor))
- var/turf/simulated/floor/F = T
- if(prob(volume/10))
- F.make_plating()
- if(istype(F, /turf/simulated/floor))
- new /obj/effect/hotspot(F)
- if(prob(volume/10) && istype(T, /turf/simulated/wall))
- var/turf/simulated/wall/W = T
- W.ChangeTurf(/turf/simulated/floor)
- if(istype(T, /turf/simulated/shuttle))
- new /obj/effect/hotspot(T)
+/datum/reagent/clf3/reaction_turf(turf/T, volume)
+ if(volume < 3)
+ return
+ var/radius = min((volume - 3) * 0.15, 3)
+ fireflash_sm(T, radius, 4500 + volume * 500, 350)
-/datum/reagent/clf3/reaction_mob(mob/living/M, method=TOUCH, volume)
- if(method == TOUCH)
- M.adjust_fire_stacks(min(volume/5, 10))
+/datum/reagent/clf3/reaction_mob(mob/living/M, method = TOUCH, volume)
+ if(method == TOUCH || method == INGEST)
+ M.adjust_fire_stacks(10)
M.IgniteMob()
- M.bodytemperature += 30
+ if(method == INGEST)
+ M.adjustFireLoss(min(max(30, volume * 6), 90))
+ to_chat(M, "It burns!")
+ M.emote("scream")
/datum/reagent/sorium
name = "Sorium"
@@ -116,11 +253,14 @@
reagent_state = LIQUID
color = "#FFA500"
-/datum/reagent/sorium_vortex
- name = "sorium_vortex"
- id = "sorium_vortex"
- reagent_state = LIQUID
- color = "#FFA500"
+/datum/reagent/sorium/reaction_turf(turf/T, volume) // oh no
+ if(prob(75))
+ return
+ if(isspaceturf(T))
+ return
+ if(!T.reagents)
+ T.create_reagents(50)
+ T.reagents.add_reagent("sorium", 5)
/datum/reagent/liquid_dark_matter
name = "Liquid Dark Matter"
@@ -130,11 +270,14 @@
color = "#800080"
taste_message = "the end of the world"
-/datum/reagent/ldm_vortex
- name = "LDM Vortex"
- id = "ldm_vortex"
- reagent_state = LIQUID
- color = "#800080"
+/datum/reagent/liquid_dark_matter/reaction_turf(turf/T, volume) //Oh gosh, why
+ if(prob(75))
+ return
+ if(isspaceturf(T))
+ return
+ if(!T.reagents)
+ T.create_reagents(50)
+ T.reagents.add_reagent("liquid_dark_matter", 5)
/datum/reagent/blackpowder
name = "Black Powder"
@@ -157,6 +300,7 @@
description = "Makes a very bright flash."
reagent_state = LIQUID
color = "#FFFF00"
+ penetrates_skin = TRUE
/datum/reagent/smoke_powder
name = "Smoke Powder"
@@ -171,42 +315,7 @@
description = "Makes a deafening noise."
reagent_state = LIQUID
color = "#0000FF"
-
-/datum/reagent/phlogiston
- name = "Phlogiston"
- id = "phlogiston"
- description = "Catches you on fire and makes you ignite."
- reagent_state = LIQUID
- color = "#FF9999"
- process_flags = ORGANIC | SYNTHETIC
-
-/datum/reagent/phlogiston/on_mob_life(mob/living/M)
- var/update_flags = STATUS_UPDATE_NONE
- M.adjust_fire_stacks(1)
- var/burndmg = max(0.3*M.fire_stacks, 0.3)
- update_flags |= M.adjustFireLoss(burndmg, FALSE)
- return ..() | update_flags
-
-/datum/reagent/phlogiston/reaction_mob(mob/living/M, method=TOUCH, volume)
- M.adjust_fire_stacks(1)
- M.IgniteMob()
- ..()
-
-/datum/reagent/napalm
- name = "Napalm"
- id = "napalm"
- description = "Very flammable."
- reagent_state = LIQUID
- color = "#FF9999"
- process_flags = ORGANIC | SYNTHETIC
-
-/datum/reagent/napalm/on_mob_life(mob/living/M)
- M.adjust_fire_stacks(1)
- return ..()
-
-/datum/reagent/napalm/reaction_mob(mob/living/M, method=TOUCH, volume)
- if(method == TOUCH)
- M.adjust_fire_stacks(min(volume/4, 20))
+ penetrates_skin = TRUE
/datum/reagent/cryostylane
name = "Cryostylane"
@@ -223,11 +332,16 @@
/datum/reagent/cryostylane/on_tick()
if(holder.has_reagent("oxygen"))
- holder.remove_reagent("oxygen", 1)
- holder.chem_temp -= 10
- holder.handle_reactions()
+ holder.remove_reagent("oxygen", 2)
+ holder.remove_reagent("cryostylane", 2)
+ holder.temperature_reagents(holder.chem_temp - 200)
+ holder.temperature_reagents(holder.chem_temp - 200)
..()
+/datum/reagent/cryostylane/reaction_mob(mob/living/M, method = TOUCH, volume)
+ if(method == TOUCH)
+ M.ExtinguishMob()
+
/datum/reagent/cryostylane/reaction_turf(turf/T, volume)
if(volume >= 5)
for(var/mob/living/carbon/slime/M in T)
@@ -248,9 +362,10 @@
/datum/reagent/pyrosium/on_tick()
if(holder.has_reagent("oxygen"))
- holder.remove_reagent("oxygen", 1)
- holder.chem_temp += 10
- holder.handle_reactions()
+ holder.remove_reagent("oxygen", 2)
+ holder.remove_reagent("pyrosium", 2)
+ holder.temperature_reagents(holder.chem_temp + 200)
+ holder.temperature_reagents(holder.chem_temp + 200)
..()
/datum/reagent/firefighting_foam
@@ -264,8 +379,7 @@
/datum/reagent/firefighting_foam/reaction_mob(mob/living/M, method=TOUCH, volume)
// Put out fire
if(method == TOUCH)
- M.adjust_fire_stacks(-(volume / 5)) // more effective than water
- M.ExtinguishMob()
+ M.adjust_fire_stacks(-10) // more effective than water
/datum/reagent/firefighting_foam/reaction_obj(obj/O, volume)
O.extinguish()
@@ -290,6 +404,12 @@
color = "#500064" // rgb: 80, 0, 100
taste_message = "corporate assets going to waste"
+/datum/reagent/plasma_dust/reaction_temperature(exposed_temperature, exposed_volume)
+ if(exposed_temperature >= T0C + 100)
+ fireflash(get_turf(holder.my_atom), min(max(0, volume / 10), 8))
+ if(holder)
+ holder.del_reagent(id)
+
/datum/reagent/plasma_dust/on_mob_life(mob/living/M)
var/update_flags = STATUS_UPDATE_NONE
update_flags |= M.adjustToxLoss(3, FALSE)
diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm
index 510f3ca1368..d337d2a421b 100644
--- a/code/modules/reagents/chemistry/reagents/toxins.dm
+++ b/code/modules/reagents/chemistry/reagents/toxins.dm
@@ -506,19 +506,11 @@
M.fakevomit()
update_flags |= M.adjustToxLoss(2, FALSE)
update_flags |= M.adjustBruteLoss(2, FALSE)
+ if(volume > 40 && prob(4))
+ M.delayed_gib()
+ return
return ..() | update_flags
-/datum/reagent/venom/overdose_process(mob/living/M)
- var/update_flags = STATUS_UPDATE_NONE
- if(volume >= 40)
- if(prob(4))
- M.visible_message("[M] starts convulsing violently!", "You feel as if your body is tearing itself apart!")
- update_flags |= M.Weaken(15, FALSE)
- M.AdjustJitter(1000)
- spawn(rand(20, 100))
- M.gib()
- return list(0, update_flags)
-
/datum/reagent/neurotoxin2
name = "Neurotoxin"
id = "neurotoxin2"
@@ -1057,6 +1049,11 @@
update_flags |= M.adjustToxLoss(1, FALSE)
return ..() | update_flags
+/datum/reagent/pestkiller/reaction_obj(obj/O, volume)
+ if(istype(O, /obj/effect/decal/ants))
+ O.visible_message("The ants die.")
+ qdel(O)
+
/datum/reagent/pestkiller/reaction_mob(mob/living/M, method=TOUCH, volume)
if(iscarbon(M))
var/mob/living/carbon/C = M
@@ -1159,12 +1156,16 @@
M.apply_effect(2, IRRADIATE, 0, negate_armor = 1)
if(!M.dna)
return
+ var/did_mutation = FALSE
if(prob(15))
randmutb(M)
+ did_mutation = TRUE
if(prob(3))
randmutg(M)
- domutcheck(M, null)
- M.UpdateAppearance()
+ did_mutation = TRUE
+ if(did_mutation)
+ domutcheck(M, null)
+ M.UpdateAppearance()
return ..()
/datum/reagent/ants
diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm
index 6d8ea272cfe..5623023659b 100644
--- a/code/modules/reagents/chemistry/reagents/water.dm
+++ b/code/modules/reagents/chemistry/reagents/water.dm
@@ -23,8 +23,7 @@
/datum/reagent/water/reaction_mob(mob/living/M, method=TOUCH, volume)
if(method == TOUCH)
// Put out fire
- M.adjust_fire_stacks(-(volume / 10))
- M.ExtinguishMob()
+ M.adjust_fire_stacks(-(volume * 0.2))
if(ishuman(M))
var/mob/living/carbon/human/H = M
diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm
index 3464b145f6a..a881f191594 100644
--- a/code/modules/reagents/chemistry/recipes.dm
+++ b/code/modules/reagents/chemistry/recipes.dm
@@ -11,13 +11,11 @@
var/required_other = 0 // an integer required for the reaction to happen
var/result_amount = 0
- var/secondary = 0 // set to nonzero if secondary reaction
var/list/secondary_results = list() //additional reagents produced by the reaction
var/min_temp = 0 //Minimum temperature required for the reaction to occur (heat to/above this). min_temp = 0 means no requirement
var/max_temp = 9999 //Maximum temperature allowed for the reaction to occur (cool to/below this).
var/mix_message = "The solution begins to bubble."
var/mix_sound = 'sound/effects/bubbles.ogg'
- var/no_message = 0
/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume)
return
@@ -65,17 +63,18 @@ var/list/chemical_mob_spawn_nicecritters = list() // and possible friendly mobs
for(var/j = 1, j <= rand(1, 3), j++)
step(C, pick(NORTH,SOUTH,EAST,WEST))
-/proc/goonchem_vortex(turf/simulated/T, setting_type, range, pull_times)
- for(var/atom/movable/X in orange(range, T))
+/proc/goonchem_vortex(turf/T, setting_type, volume)
+ if(setting_type)
+ new /obj/effect/temp_visual/implosion(T)
+ playsound(T, 'sound/effects/whoosh.ogg', 25, 1) //credit to Robinhood76 of Freesound.org for this.
+ else
+ new /obj/effect/temp_visual/shockwave(T)
+ playsound(T, 'sound/effects/bang.ogg', 25, 1)
+ for(var/atom/movable/X in view(2 + setting_type + (volume > 30 ? 1 : 0), T))
if(istype(X, /obj/effect))
continue //stop pulling smoke and hotspots please
- if(istype(X, /atom/movable))
- if((X) && !X.anchored && X.move_resist <= MOVE_FORCE_DEFAULT)
- if(setting_type)
- playsound(T, 'sound/effects/bang.ogg', 25, 1)
- for(var/i = 0, i < pull_times, i++)
- step_away(X,T)
- else
- playsound(T, 'sound/effects/whoosh.ogg', 25, 1) //credit to Robinhood76 of Freesound.org for this.
- for(var/i = 0, i < pull_times, i++)
- step_towards(X,T)
\ No newline at end of file
+ if(X && !X.anchored && X.move_resist <= MOVE_FORCE_DEFAULT)
+ if(setting_type)
+ X.throw_at(T, 20 + round(volume * 2), 1 + round(volume / 10))
+ else
+ X.throw_at(get_edge_target_turf(T, get_dir(T, X)), 20 + round(volume * 2), 1 + round(volume / 10))
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/recipes/drinks.dm b/code/modules/reagents/chemistry/recipes/drinks.dm
index c348db060ff..2f3eda996b0 100644
--- a/code/modules/reagents/chemistry/recipes/drinks.dm
+++ b/code/modules/reagents/chemistry/recipes/drinks.dm
@@ -229,7 +229,7 @@
id = "flamingmoe"
result = "flamingmoe"
required_reagents = list("vodka" = 1, "gin" = 1, "cognac" = 1, "tequila" = 1, "salglu_solution" = 1) //Close enough
- min_temp = 374 //Fire makes it good!
+ min_temp = T0C + 100 //Fire makes it good!
result_amount = 5
mix_sound = 'sound/goonstation/misc/drinkfizz.ogg'
mix_message = "The concoction bursts into flame!"
@@ -701,7 +701,7 @@
id = "applejack"
result = "applejack"
required_reagents = list("cider" = 2)
- max_temp = 270
+ max_temp = T0C
result_amount = 1
mix_message = "The drink darkens as the water freezes, leaving the concentrated cider behind."
mix_sound = null
diff --git a/code/modules/reagents/chemistry/recipes/drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm
index e44ace8f511..d2499a06c54 100644
--- a/code/modules/reagents/chemistry/recipes/drugs.dm
+++ b/code/modules/reagents/chemistry/recipes/drugs.dm
@@ -15,13 +15,12 @@
result_amount = 5
mix_message = "The mixture violently reacts, leaving behind a few crystalline shards."
mix_sound = 'sound/goonstation/effects/crystalshatter.ogg'
- min_temp = 390
+ min_temp = T0C + 100
/datum/chemical_reaction/crank/on_reaction(datum/reagents/holder, created_volume)
var/turf/T = get_turf(holder.my_atom)
- for(var/turf/turf in range(1,T))
- new /obj/effect/hotspot(turf)
- explosion(T,0,0,2)
+ fireflash(holder.my_atom, 1)
+ explosion(T, 0, 0, 2)
/datum/chemical_reaction/krokodil
name = "Krokodil"
@@ -30,7 +29,7 @@
required_reagents = list("diphenhydramine" = 1, "morphine" = 1, "cleaner" = 1, "potassium" = 1, "phosphorus" = 1, "fuel" = 1)
result_amount = 6
mix_message = "The mixture dries into a pale blue powder."
- min_temp = 380
+ min_temp = T0C + 100
mix_sound = 'sound/goonstation/misc/fuse.ogg'
/datum/chemical_reaction/methamphetamine
@@ -39,7 +38,7 @@
result = "methamphetamine"
required_reagents = list("ephedrine" = 1, "iodine" = 1, "phosphorus" = 1, "hydrogen" = 1)
result_amount = 4
- min_temp = 374
+ min_temp = T0C + 100
/datum/chemical_reaction/methamphetamine/on_reaction(datum/reagents/holder)
var/turf/T = get_turf(holder.my_atom)
@@ -57,7 +56,7 @@
result = "bath_salts"
required_reagents = list("????" = 1, "saltpetre" = 1, "msg" = 1, "cleaner" = 1, "enzyme" = 1, "mugwort" = 1, "mercury" = 1)
result_amount = 6
- min_temp = 374
+ min_temp = T0C + 100
mix_message = "Tiny cubic crystals precipitate out of the mixture. Huh."
mix_sound = 'sound/goonstation/misc/fuse.ogg'
diff --git a/code/modules/reagents/chemistry/recipes/food.dm b/code/modules/reagents/chemistry/recipes/food.dm
index ec732bba858..5b5efc105d6 100644
--- a/code/modules/reagents/chemistry/recipes/food.dm
+++ b/code/modules/reagents/chemistry/recipes/food.dm
@@ -124,7 +124,7 @@
result = "corn_syrup"
required_reagents = list("corn_starch" = 1, "sacid" = 1)
result_amount = 2
- min_temp = 374
+ min_temp = T0C + 100
mix_message = "The mixture forms a viscous, clear fluid!"
/datum/chemical_reaction/vhfcs
@@ -176,7 +176,7 @@
result = "hydrogenated_soybeanoil"
required_reagents = list("soybeanoil" = 1, "hydrogen" = 1)
result_amount = 2
- min_temp = 520
+ min_temp = T0C + 250
mix_message = "The mixture emits a burnt, oily smell."
/datum/chemical_reaction/meatslurry
@@ -194,7 +194,7 @@
result = "gravy"
required_reagents = list("porktonium" = 1, "corn_starch" = 1, "milk" = 1)
result_amount = 3
- min_temp = 374
+ min_temp = T0C + 100
mix_message = "The substance thickens and takes on a meaty odor."
/datum/chemical_reaction/beff
@@ -221,7 +221,7 @@
result = "enzyme"
required_reagents = list("vomit" = 1, "sugar" = 1)
result_amount = 2
- min_temp = 750
+ min_temp = T0C + 480
mix_message = "The mixture emits a horrible smell as you heat up the contents. Luckily, enzymes don't stink."
mix_sound = 'sound/goonstation/misc/fuse.ogg'
@@ -231,6 +231,6 @@
result = "enzyme"
required_reagents = list("green_vomit" = 1, "sugar" = 1)
result_amount = 2
- min_temp = 750
+ min_temp = T0C + 480
mix_message = "The mixture emits a horrible smell as you heat up the contents. Luckily, enzymes don't stink."
mix_sound = 'sound/goonstation/misc/fuse.ogg'
diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm
index 864733f6555..b523bbafb45 100644
--- a/code/modules/reagents/chemistry/recipes/medicine.dm
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -50,7 +50,7 @@
required_reagents = list("ash" = 1, "sodiumchloride" = 1)
result_amount = 2
mix_message = "The mixture yields a fine black powder."
- min_temp = 380
+ min_temp = T0C + 100
mix_sound = 'sound/goonstation/misc/fuse.ogg'
/datum/chemical_reaction/silver_sulfadiazine
@@ -92,7 +92,7 @@
result = "calomel"
required_reagents = list("mercury" = 1, "chlorine" = 1)
result_amount = 2
- min_temp = 374
+ min_temp = T0C + 100
mix_message = "Stinging vapors rise from the solution."
/datum/chemical_reaction/potass_iodide
@@ -135,7 +135,7 @@
result = "perfluorodecalin"
required_reagents = list("hydrogen" = 1, "fluorine" = 1, "oil" = 1)
result_amount = 3
- min_temp = 370
+ min_temp = T0C + 100
mix_message = "The mixture rapidly turns into a dense pink liquid."
mix_sound = 'sound/goonstation/misc/drinkfizz.ogg'
@@ -195,7 +195,7 @@
result = null
required_reagents = list("strange_reagent" = 1, "synthflesh" = 1, "blood" = 1)
result_amount = 3
- min_temp = 374
+ min_temp = T0C + 100
/datum/chemical_reaction/life/on_reaction(datum/reagents/holder, created_volume)
chemical_mob_spawn(holder, 1, "Life")
@@ -263,12 +263,5 @@
result = "liquid_solder"
required_reagents = list("ethanol" = 1, "copper" = 1, "silver" = 1)
result_amount = 3
- min_temp = 370
- mix_message = "The solution gently swirls with a metallic sheen."
-
-/datum/chemical_reaction/corazone
- name = "Corazone"
- id = "corazone"
- result = "corazone"
- result_amount = 3
- required_reagents = list("phenol" = 2, "lithium" = 1)
+ min_temp = T0C + 100
+ mix_message = "The solution gently swirls with a metallic sheen."
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index 0259ed89e86..c40c1213793 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -74,7 +74,7 @@
result = "diethylamine"
required_reagents = list ("ammonia" = 1, "ethanol" = 1)
result_amount = 2
- min_temp = 374
+ min_temp = T0C + 100
mix_message = "A horrible smell pours forth from the mixture."
/datum/chemical_reaction/space_cleaner
@@ -98,7 +98,7 @@
id = "plastic_polymers"
result = null
required_reagents = list("oil" = 5, "sacid" = 2, "ash" = 3)
- min_temp = 374
+ min_temp = T0C + 100
result_amount = 1
/datum/chemical_reaction/plastic_polymers/on_reaction(datum/reagents/holder, created_volume)
@@ -171,16 +171,6 @@
mix_message = "The mixture bubbles and gives off an unpleasant medicinal odor."
mix_sound = 'sound/goonstation/misc/drinkfizz.ogg'
-/datum/chemical_reaction/ash
- name = "Ash"
- id = "ash"
- result = "ash"
- required_reagents = list("oil" = 1)
- result_amount = 0.5
- min_temp = 480
- mix_sound = null
- no_message = 1
-
/datum/chemical_reaction/colorful_reagent
name = "colorful_reagent"
id = "colorful_reagent"
@@ -195,7 +185,7 @@
result = null
required_reagents = list("nutriment" = 1, "colorful_reagent" = 1, "strange_reagent" = 1, "blood" = 1)
result_amount = 3
- min_temp = 374
+ min_temp = T0C + 100
/datum/chemical_reaction/corgium/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
@@ -208,7 +198,7 @@
result = null
required_reagents = list("egg" = 1, "colorful_reagent" = 1, "chicken_soup" = 1, "strange_reagent" = 1, "blood" = 1)
result_amount = 5
- min_temp = 374
+ min_temp = T0C + 100
mix_message = "The substance turns an airy sky-blue and foams up into a new shape."
/datum/chemical_reaction/flaptonium/on_reaction(datum/reagents/holder, created_volume)
@@ -244,7 +234,7 @@
id = "soapification"
result = null
required_reagents = list("liquidgibs" = 10, "lye" = 10) // requires two scooped gib tiles
- min_temp = 374
+ min_temp = T0C + 100
result_amount = 1
@@ -257,7 +247,7 @@
id = "candlefication"
result = null
required_reagents = list("liquidgibs" = 5, "oxygen" = 5) //
- min_temp = 374
+ min_temp = T0C + 100
result_amount = 1
/datum/chemical_reaction/candlefication/on_reaction(datum/reagents/holder, created_volume)
@@ -295,7 +285,7 @@
id = "jestosterone"
result = "jestosterone"
required_reagents = list("blood" = 1, "sodiumchloride" = 1, "banana" = 1, "lube" = 1, "space_drugs" = 1) //Or one freshly-squeezed clown
- min_temp = 374
+ min_temp = T0C + 100
result_amount = 5
mix_message = "The substance quickly shifts colour, cycling from red, to yellow, to green, to blue, and finally settles at a vibrant fuchsia."
@@ -338,7 +328,7 @@
result = "ice"
required_reagents = list("water" = 1)
result_amount = 1
- max_temp = 273
+ max_temp = T0C
mix_message = "Ice forms as the water freezes."
mix_sound = null
@@ -348,7 +338,7 @@
result = "water"
required_reagents = list("ice" = 1)
result_amount = 1
- min_temp = 301 // In Space.....ice melts at 82F...don't ask
+ min_temp = T0C + 29 // In Space.....ice melts at 82F...don't ask
mix_message = "Water pools as the ice melts."
mix_sound = null
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 362aebfcc10..a21a7fcf1c2 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -80,66 +80,68 @@
result = "clf3"
required_reagents = list("chlorine" = 1, "fluorine" = 3)
result_amount = 2
- min_temp = 424
+ min_temp = T0C + 150
/datum/chemical_reaction/clf3/on_reaction(datum/reagents/holder, created_volume)
- var/turf/T = get_turf(holder.my_atom)
- for(var/turf/turf in range(1,T))
- new /obj/effect/hotspot(turf)
+ fireflash(holder.my_atom, 1, 7000)
/datum/chemical_reaction/sorium
name = "Sorium"
id = "sorium"
result = "sorium"
- required_reagents = list("mercury" = 1, "oxygen" = 1, "nitrogen" = 1, "carbon" = 1)
+ required_reagents = list("mercury" = 1, "carbon" = 1, "nitrogen" = 1, "oxygen" = 1, "stabilizing_agent" = 1)
result_amount = 4
+ mix_message = "The mixture pops and crackles before settling down."
-/datum/chemical_reaction/sorium/on_reaction(datum/reagents/holder, created_volume)
- if(holder.has_reagent("stabilizing_agent"))
+/datum/chemical_reaction/sorium_explosion
+ name = "Sorium Explosion"
+ id = "sorium_explosion"
+ required_reagents = list("mercury" = 1, "carbon" = 1, "nitrogen" = 1, "oxygen" = 1)
+ result_amount = 1
+ mix_message = "The mixture explodes with a big bang."
+
+/datum/chemical_reaction/sorium_explosion/on_reaction(datum/reagents/holder, created_volume)
+ var/turf/T = get_turf(holder.my_atom)
+ if(!T)
return
- var/turf/simulated/T = get_turf(holder.my_atom)
- goonchem_vortex(T, 1, min(10, created_volume), min(11, created_volume + 1))
- holder.remove_reagent("sorium", created_volume)
+ goonchem_vortex(T, 0, created_volume)
-/datum/chemical_reaction/sorium_vortex
+/datum/chemical_reaction/sorium_explosion/sorium
name = "sorium_vortex"
id = "sorium_vortex"
- result = "sorium_vortex"
required_reagents = list("sorium" = 1)
- result_amount = 1
- min_temp = 474
-
-/datum/chemical_reaction/sorium_vortex/on_reaction(datum/reagents/holder, created_volume)
- var/turf/simulated/T = get_turf(holder.my_atom)
- goonchem_vortex(T, 1, min(10, created_volume), min(11, created_volume + 1))
- holder.remove_reagent("sorium_vortex", created_volume)
+ min_temp = T0C + 200
+ mix_sound = null
+ mix_message = null
/datum/chemical_reaction/liquid_dark_matter
name = "Liquid Dark Matter"
id = "liquid_dark_matter"
result = "liquid_dark_matter"
+ required_reagents = list("plasma" = 1, "radium" = 1, "carbon" = 1, "stabilizing_agent" = 1)
+ result_amount = 4
+ mix_message = "The mixture begins to glow in a dark purple."
+
+/datum/chemical_reaction/ldm_implosion
+ name = "Implosion"
+ id = "implosion"
required_reagents = list("plasma" = 1, "radium" = 1, "carbon" = 1)
- result_amount = 3
+ result_amount = 1
+ mix_message = "The mixture implodes suddenly."
-/datum/chemical_reaction/liquid_dark_matter/on_reaction(datum/reagents/holder, created_volume)
- if(holder.has_reagent("stabilizing_agent"))
- return
+/datum/chemical_reaction/ldm_implosion/on_reaction(datum/reagents/holder, created_volume)
var/turf/simulated/T = get_turf(holder.my_atom)
- goonchem_vortex(T, 0, min(10, created_volume), min(11, created_volume + 1))
- holder.remove_reagent("liquid_dark_matter", created_volume)
+ if(!T)
+ return
+ goonchem_vortex(T, 1, created_volume)
-/datum/chemical_reaction/ldm_vortex
+/datum/chemical_reaction/ldm_implosion/liquid_dark_matter
name = "LDM Vortex"
id = "ldm_vortex"
- result = "ldm_vortex"
required_reagents = list("liquid_dark_matter" = 1)
- result_amount = 1
- min_temp = 474
-
-/datum/chemical_reaction/ldm_vortex/on_reaction(datum/reagents/holder, created_volume)
- var/turf/simulated/T = get_turf(holder.my_atom)
- goonchem_vortex(T, 0, min(10, created_volume), min(11, created_volume + 1))
- holder.remove_reagent("ldm_vortex", created_volume)
+ min_temp = T0C + 200
+ mix_sound = null
+ mix_message = null
/datum/chemical_reaction/blackpowder
name = "Black Powder"
@@ -155,70 +157,97 @@
result = null
required_reagents = list("blackpowder" = 1)
result_amount = 1
- min_temp = 474
- no_message = 1
+ min_temp = T0C + 200
+ mix_message = null
mix_sound = null
/datum/chemical_reaction/blackpowder_explosion/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
do_sparks(2, 1, location)
- sleep(rand(20,30))
- blackpowder_detonate(holder, created_volume)
+ spawn(rand(5, 15))
+ blackpowder_detonate(holder, created_volume)
/proc/blackpowder_detonate(datum/reagents/holder, created_volume)
- var/turf/simulated/T = get_turf(holder.my_atom)
+ var/turf/T = get_turf(holder.my_atom)
var/ex_severe = round(created_volume / 100)
var/ex_heavy = round(created_volume / 42)
var/ex_light = round(created_volume / 20)
var/ex_flash = round(created_volume / 8)
- explosion(T,ex_severe,ex_heavy,ex_light,ex_flash, 1)
+ explosion(T, ex_severe, ex_heavy,ex_light, ex_flash, 1)
// If this black powder is in a decal, remove the decal, because it just exploded
if(istype(holder.my_atom, /obj/effect/decal/cleanable/dirt/blackpowder))
spawn(0)
qdel(holder.my_atom)
-datum/chemical_reaction/flash_powder
+/datum/chemical_reaction/flash_powder
name = "Flash powder"
id = "flash_powder"
result = "flash_powder"
- required_reagents = list("aluminum" = 1, "potassium" = 1, "sulfur" = 1, "chlorine" = 1)
- result_amount = 3
+ required_reagents = list("aluminum" = 1, "potassium" = 1, "sulfur" = 1, "chlorine" = 1, "stabilizing_agent" = 1)
+ result_amount = 5
+ mix_message = "The chemicals hiss and fizz briefly before falling still."
-/datum/chemical_reaction/flash_powder/on_reaction(datum/reagents/holder, created_volume)
- if(holder.has_reagent("stabilizing_agent"))
- return
- var/location = get_turf(holder.my_atom)
- do_sparks(2, 1, location)
- for(var/mob/living/carbon/C in viewers(5, location))
- if(C.flash_eyes())
- if(get_dist(C, location) < 4)
- C.Weaken(5)
- continue
- C.Stun(5)
- holder.remove_reagent("flash_powder", created_volume)
-
-/datum/chemical_reaction/flash_powder_flash
- name = "Flash powder activation"
- id = "flash_powder_flash"
+/datum/chemical_reaction/flash
+ name = "Flash"
+ id = "flash"
result = null
- required_reagents = list("flash_powder" = 1)
- min_temp = 374
+ required_reagents = list("aluminum" = 1, "potassium" = 1, "sulfur" = 1, "chlorine" = 1)
+ mix_message = "The chemicals catch fire, burning brightly and violently!"
+ mix_sound = 'sound/effects/bang.ogg'
-/datum/chemical_reaction/flash_powder_flash/on_reaction(datum/reagents/holder, created_volume)
+/datum/chemical_reaction/flash/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
+ if(!location)
+ return
do_sparks(2, 1, location)
- for(var/mob/living/carbon/C in viewers(5, location))
- if(C.flash_eyes())
- if(get_dist(C, location) < 4)
- C.Weaken(5)
- continue
- C.Stun(5)
+ bang(location, holder.my_atom, 5, flash = TRUE, bang = FALSE)
+
+/datum/chemical_reaction/flash/flash_powder
+ name = "flash_powder_flash"
+ id = "flash_powder_flash"
+ required_reagents = list("flash_powder" = 1)
+ min_temp = T0C + 100
+ mix_message = null
+
+/datum/chemical_reaction/phlogiston
+ name = "Phlogiston"
+ id = "phlogiston"
+ result = "phlogiston"
+ required_reagents = list("phosphorus" = 1, "plasma" = 1, "sacid" = 1, "stabilizing_agent" = 1)
+ result_amount = 4
+ mix_message = "The substance becomes sticky and extremely warm."
+
+/datum/chemical_reaction/phlogiston_dust
+ name = "Phlogiston Dust"
+ id = "phlogiston_dust"
+ result = "phlogiston_dust"
+ required_reagents = list("phlogiston" = 1, "charcoal" = 1, "phosphorus" = 1, "sulfur" = 1)
+ result_amount = 2
+ mix_message = "The substance becomes a pile of burning dust."
+
+/datum/chemical_reaction/phlogiston_fire //This MUST be above the smoke recipe.
+ name = "Phlogiston Fire"
+ id = "phlogiston_fire"
+ result = "phlogiston"
+ required_reagents = list("phosphorus" = 1, "plasma" = 1, "sacid" = 1)
+ mix_message = "The substance erupts into wild flames."
+
+/datum/chemical_reaction/phlogiston_fire/on_reaction(datum/reagents/holder, created_volume)
+ fireflash(get_turf(holder.my_atom), min(max(2, round(created_volume / 10)), 8))
+
+/datum/chemical_reaction/napalm
+ name = "Napalm"
+ id = "napalm"
+ result = "napalm"
+ required_reagents = list("fuel" = 1, "sugar" = 1, "ethanol" = 1)
+ result_amount = 3
+ mix_message = "The mixture congeals into a sticky gel."
/datum/chemical_reaction/smoke_powder
name = "smoke_powder"
id = "smoke_powder"
result = "smoke_powder"
- required_reagents = list("stabilizing_agent" = 1, "potassium" = 1, "sugar" = 1, "phosphorus" = 1)
+ required_reagents = list("potassium" = 1, "sugar" = 1, "phosphorus" = 1, "stabilizing_agent" = 1)
result_amount = 3
mix_message = "The mixture sets into a greyish powder!"
@@ -233,14 +262,12 @@ datum/chemical_reaction/flash_powder
/datum/chemical_reaction/smoke/on_reaction(datum/reagents/holder, created_volume)
for(var/f_reagent in forbidden_reagents)
- if(holder.has_reagent(f_reagent))
- holder.remove_reagent(f_reagent, holder.get_reagent_amount(f_reagent))
+ holder.del_reagent(f_reagent)
var/location = get_turf(holder.my_atom)
var/datum/effect_system/smoke_spread/chem/S = new
- S.attach(location)
playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3)
if(S)
- S.set_up(holder, 10, 0, location)
+ S.set_up(holder, location)
if(created_volume < 5)
S.start(1)
if(created_volume >=5 && created_volume < 10)
@@ -249,15 +276,12 @@ datum/chemical_reaction/flash_powder
S.start(3)
if(created_volume >=15)
S.start(4)
- if(holder && holder.my_atom)
- holder.clear_reagents()
/datum/chemical_reaction/smoke/smoke_powder
name = "smoke_powder_smoke"
id = "smoke_powder_smoke"
required_reagents = list("smoke_powder" = 1)
- min_temp = 374
- secondary = 1
+ min_temp = T0C + 100
result_amount = 1
forbidden_reagents = list("stimulants")
mix_sound = null
@@ -266,100 +290,30 @@ datum/chemical_reaction/flash_powder
name = "sonic_powder"
id = "sonic_powder"
result = "sonic_powder"
+ required_reagents = list("oxygen" = 1, "cola" = 1, "phosphorus" = 1, "stabilizing_agent" = 1)
+ result_amount = 2
+ mix_message = "The mixture begins to bubble slighly!"
+
+/datum/chemical_reaction/sonic_deafen
+ name = "sonic_deafen"
+ id = "sonic_deafen"
+ result = null
required_reagents = list("oxygen" = 1, "cola" = 1, "phosphorus" = 1)
- result_amount = 3
+ mix_message = "The mixture begins to bubble furiously!"
+ mix_sound = 'sound/effects/bang.ogg'
-/datum/chemical_reaction/sonic_powder/on_reaction(datum/reagents/holder, created_volume)
- if(holder.has_reagent("stabilizing_agent"))
- return
+/datum/chemical_reaction/sonic_deafen/on_reaction(datum/reagents/holder, created_volume)
var/location = get_turf(holder.my_atom)
- playsound(location, 'sound/effects/bang.ogg', 25, 1)
- for(var/mob/living/M in hearers(5, location))
- var/ear_safety = 0
- var/distance = max(1,get_dist(src,T))
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- if((H.r_ear && (H.r_ear.flags & EARBANGPROTECT)) || (H.l_ear && (H.l_ear.flags & EARBANGPROTECT)) || (H.head && (H.head.flags & HEADBANGPROTECT)))
- ear_safety++
- to_chat(C, "BANG")
- if(!ear_safety)
- M.Stun(max(10/distance, 3))
- M.Weaken(max(10/distance, 3))
- M.AdjustEarDamage(rand(0, 5), 15)
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- var/obj/item/organ/internal/ears/ears = C.get_int_organ(/obj/item/organ/internal/ears)
- if(istype(ears))
- if(ears.ear_damage >= 15)
- to_chat(M, "Your ears start to ring badly!")
- if(prob(ears.ear_damage - 5))
- to_chat(M, "You can't hear anything!")
- M.BecomeDeaf()
- else
- if(ears.ear_damage >= 5)
- to_chat(M, "Your ears start to ring!")
- holder.remove_reagent("sonic_powder", created_volume)
+ if(!location)
+ return
+ bang(location, holder.my_atom, 5, flash = FALSE, bang = TRUE)
-/datum/chemical_reaction/sonic_powder_deafen
+/datum/chemical_reaction/sonic_deafen/sonic_powder
name = "sonic_powder_deafen"
id = "sonic_powder_deafen"
- result = null
required_reagents = list("sonic_powder" = 1)
- min_temp = 374
-
-/datum/chemical_reaction/sonic_powder_deafen/on_reaction(datum/reagents/holder, created_volume)
- var/location = get_turf(holder.my_atom)
- playsound(location, 'sound/effects/bang.ogg', 25, 1)
- for(var/mob/living/M in hearers(5, location))
- var/ear_safety = 0
- var/distance = max(1,get_dist(src,T))
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- if((H.r_ear && (H.r_ear.flags & EARBANGPROTECT)) || (H.l_ear && (H.l_ear.flags & EARBANGPROTECT)) || (H.head && (H.head.flags & HEADBANGPROTECT)))
- ear_safety++
- to_chat(M, "BANG")
- if(!ear_safety)
- M.Stun(max(10/distance, 3))
- M.Weaken(max(10/distance, 3))
- M.AdjustEarDamage(rand(0, 5), 15)
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- var/obj/item/organ/internal/ears/ears = C.get_int_organ(/obj/item/organ/internal/ears)
- if(istype(ears))
- if(ears.ear_damage >= 15)
- to_chat(M, "Your ears start to ring badly!")
- if(prob(ears.ear_damage - 5))
- to_chat(M, "You can't hear anything!")
- M.BecomeDeaf()
- else
- if(ears.ear_damage >= 5)
- to_chat(M, "Your ears start to ring!")
-
-
-/datum/chemical_reaction/phlogiston
- name = "phlogiston"
- id = "phlogiston"
- result = "phlogiston"
- required_reagents = list("phosphorus" = 1, "sacid" = 1, "plasma" = 1)
- result_amount = 3
-
-/datum/chemical_reaction/phlogiston/on_reaction(datum/reagents/holder, created_volume)
- if(holder.has_reagent("stabilizing_agent"))
- return
- var/turf/simulated/T = get_turf(holder.my_atom)
- for(var/turf/simulated/turf in range(min(created_volume/10,4),T))
- new /obj/effect/hotspot(turf)
-
-/datum/chemical_reaction/napalm
- name = "Napalm"
- id = "napalm"
- result = "napalm"
- required_reagents = list("sugar" = 1, "fuel" = 1, "ethanol" = 1 )
- result_amount = 1
+ min_temp = T0C + 100
+ mix_message = null
/datum/chemical_reaction/cryostylane
name = "cryostylane"
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index aa457938afc..afbc94a9455 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -250,7 +250,7 @@
/datum/chemical_reaction/slimestabilizer/on_reaction(datum/reagents/holder)
feedback_add_details("slime_cores_used","[type]")
- var/obj/item/slimepotion/stabilizer/P = new /obj/item/slimepotion/stabilizer
+ var/obj/item/slimepotion/slime/stabilizer/P = new /obj/item/slimepotion/slime/stabilizer
P.forceMove(get_turf(holder.my_atom))
//Dark Blue
@@ -380,7 +380,7 @@
/datum/chemical_reaction/slimepsteroid/on_reaction(datum/reagents/holder)
feedback_add_details("slime_cores_used","[type]")
- var/obj/item/slimepotion/steroid/P = new /obj/item/slimepotion/steroid
+ var/obj/item/slimepotion/slime/steroid/P = new /obj/item/slimepotion/slime/steroid
P.forceMove(get_turf(holder.my_atom))
/datum/chemical_reaction/slimejam
@@ -423,7 +423,7 @@
/datum/chemical_reaction/slimemutator/on_reaction(datum/reagents/holder)
feedback_add_details("slime_cores_used","[type]")
- var/obj/item/slimepotion/mutator/P = new /obj/item/slimepotion/mutator
+ var/obj/item/slimepotion/slime/mutator/P = new /obj/item/slimepotion/slime/mutator
P.forceMove(get_turf(holder.my_atom))
/datum/chemical_reaction/slimebloodlust
@@ -469,7 +469,7 @@
/datum/chemical_reaction/docility/on_reaction(datum/reagents/holder)
feedback_add_details("slime_cores_used","[type]")
- var/obj/item/slimepotion/docility/P = new /obj/item/slimepotion/docility
+ var/obj/item/slimepotion/slime/docility/P = new /obj/item/slimepotion/slime/docility
P.forceMove(get_turf(holder.my_atom))
diff --git a/code/modules/reagents/chemistry/recipes/toxins.dm b/code/modules/reagents/chemistry/recipes/toxins.dm
index 1531c80542a..cdc10bcbcc5 100644
--- a/code/modules/reagents/chemistry/recipes/toxins.dm
+++ b/code/modules/reagents/chemistry/recipes/toxins.dm
@@ -4,7 +4,7 @@
result = "formaldehyde"
required_reagents = list("ethanol" = 1, "oxygen" = 1, "silver" = 1)
result_amount = 3
- min_temp = 420
+ min_temp = T0C + 150
mix_message = "Ugh, it smells like the morgue in here."
/datum/chemical_reaction/neurotoxin2
@@ -13,9 +13,9 @@
result = "neurotoxin2"
required_reagents = list("space_drugs" = 1)
result_amount = 1
- min_temp = 674
+ min_temp = T0C + 400
mix_sound = null
- no_message = 1
+ mix_message = null
/datum/chemical_reaction/cyanide
name = "Cyanide"
@@ -23,7 +23,7 @@
result = "cyanide"
required_reagents = list("oil" = 1, "ammonia" = 1, "oxygen" = 1)
result_amount = 3
- min_temp = 380
+ min_temp = T0C + 100
mix_message = "The mixture gives off a faint scent of almonds."
mix_sound = 'sound/goonstation/misc/drinkfizz.ogg'
@@ -49,7 +49,7 @@
result = "facid"
required_reagents = list("sacid" = 1, "fluorine" = 1, "hydrogen" = 1, "potassium" = 1)
result_amount = 4
- min_temp = 380
+ min_temp = T0C + 100
mix_message = "The mixture deepens to a dark blue, and slowly begins to corrode its container."
/datum/chemical_reaction/initropidril
@@ -83,7 +83,7 @@
required_reagents = list("chlorine" = 1, "fuel" = 1, "oxygen" = 1, "phosphorus" = 1, "fluorine" = 1, "hydrogen" = 1, "acetone" = 1, "atrazine" = 1)
result_amount = 3
mix_message = "The mixture yields a colorless, odorless liquid."
- min_temp = 374
+ min_temp = T0C + 100
mix_sound = 'sound/goonstation/misc/drinkfizz.ogg'
/datum/chemical_reaction/sarin/on_reaction(datum/reagents/holder)
@@ -139,7 +139,7 @@
required_reagents = list("plasma" = 1, "silver" = 1, "blackpowder" = 1)
result_amount = 3
mix_message = "A jet of sparks flies from the mixture as it merges into a flickering slurry."
- min_temp = 400
+ min_temp = T0C + 50
mix_sound = null
/datum/chemical_reaction/teslium/on_reaction(datum/reagents/holder, created_volume)
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 6d58e42d539..a350d75a4b4 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -44,11 +44,6 @@
R.on_ex_act()
..()
-/obj/item/reagent_containers/fire_act()
- reagents.chem_temp += 30
- reagents.handle_reactions()
- ..()
-
/obj/item/reagent_containers/attack_self(mob/user)
if(has_lid)
if(is_open_container())
diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm
index 3a9ee271ab5..6aeafd92cf0 100644
--- a/code/modules/reagents/reagent_containers/bottle.dm
+++ b/code/modules/reagents/reagent_containers/bottle.dm
@@ -44,10 +44,28 @@
/obj/item/reagent_containers/glass/bottle/toxin
name = "toxin bottle"
- desc = "A small bottle of toxins. Do not drink, it is poisonous."
+ desc = "A small bottle containing toxic compounds."
icon_state = "small_bottle"
list_reagents = list("toxin" = 30)
+/obj/item/reagent_containers/glass/bottle/atropine
+ name = "atropine bottle"
+ desc = "A small bottle containing atropine, used for cardiac emergencies."
+ icon_state = "small_bottle"
+ list_reagents = list("atropine" = 30)
+
+/obj/item/reagent_containers/glass/bottle/saline
+ name = "saline-glucose bottle"
+ desc = "A small bottle containing saline-glucose solution."
+ icon_state = "small_bottle"
+ list_reagents = list("salglu_solution" = 30)
+
+/obj/item/reagent_containers/glass/bottle/salicylic
+ name = "salicylic acid bottle"
+ desc = "A small bottle containing medicine for pain and fevers."
+ icon_state = "small_bottle"
+ list_reagents = list("sal_acid" = 30)
+
/obj/item/reagent_containers/glass/bottle/cyanide
name = "cyanide bottle"
desc = "A small bottle of cyanide. Bitter almonds?"
@@ -99,25 +117,25 @@
/obj/item/reagent_containers/glass/bottle/morphine
name = "Morphine Bottle"
- desc = "A small bottle. Contains morphine."
- icon_state = "round_bottle"
+ desc = "A small bottle of morphine, a powerful painkiller."
+ icon_state = "bottle"
list_reagents = list("morphine" = 30)
/obj/item/reagent_containers/glass/bottle/ether
name = "Ether Bottle"
- desc = "A small bottle. Contains ether."
+ desc = "A small bottle of an ether, a strong anesthetic and sedative."
icon_state = "round_bottle"
list_reagents = list("ether" = 30)
/obj/item/reagent_containers/glass/bottle/charcoal
name = "Charcoal Bottle"
desc = "A small bottle. Contains charcoal."
- icon_state = "round_bottle"
+ icon_state = "wide_bottle"
list_reagents = list("charcoal" = 30)
/obj/item/reagent_containers/glass/bottle/epinephrine
name = "Epinephrine Bottle"
- desc = "A small bottle. Contains epinephrine."
+ desc = "A small bottle. Contains epinephrine - used to stabilize patients."
icon_state = "round_bottle"
list_reagents = list("epinephrine" = 30)
@@ -236,9 +254,21 @@
/obj/item/reagent_containers/glass/bottle/diphenhydramine
name = "diphenhydramine bottle"
desc = "A small bottle of diphenhydramine."
- icon_state = "bottle"
+ icon_state = "round_bottle"
list_reagents = list("diphenhydramine" = 30)
+/obj/item/reagent_containers/glass/bottle/oculine
+ name = "oculine bottle"
+ desc = "A small bottle of combined eye and ear medication."
+ icon_state = "round_bottle"
+ list_reagents = list("oculine" = 30)
+
+/obj/item/reagent_containers/glass/bottle/potassium_iodide
+ name = "potassium iodide bottle"
+ desc = "A small bottle of potassium iodide."
+ icon_state = "wide_bottle"
+ list_reagents = list("potass_iodide" = 30)
+
/obj/item/reagent_containers/glass/bottle/flu_virion
name = "Flu virion culture bottle"
desc = "A small bottle. Contains H13N1 flu virion culture in synthblood medium."
diff --git a/code/modules/reagents/reagent_containers/glass_containers.dm b/code/modules/reagents/reagent_containers/glass_containers.dm
index 23ec5f5cadb..4bd5d25ed3c 100644
--- a/code/modules/reagents/reagent_containers/glass_containers.dm
+++ b/code/modules/reagents/reagent_containers/glass_containers.dm
@@ -113,7 +113,7 @@
to_chat(user, "You cannot fill [target] while it is sealed.")
return
- else if(istype(target, /obj/effect/decal/cleanable)) //stops splashing while scooping up fluids
+ else if(istype(target, /obj/effect/decal)) //stops splashing while scooping up fluids
return
else if(reagents.total_volume)
@@ -124,13 +124,6 @@
/obj/item/reagent_containers/glass/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/clothing/mask/cigarette)) //ciggies are weird
- return
- if(is_hot(I))
- if(reagents)
- reagents.chem_temp += 15
- to_chat(user, "You heat [src] with [I].")
- reagents.handle_reactions()
if(istype(I, /obj/item/pen) || istype(I, /obj/item/flashlight/pen))
var/tmp_label = sanitize(input(user, "Enter a label for [name]","Label",label_text))
if(length(tmp_label) > MAX_NAME_LEN)
@@ -210,8 +203,7 @@
/obj/item/reagent_containers/glass/beaker/proc/heat_beaker()
if(reagents)
- reagents.chem_temp += 30
- reagents.handle_reactions()
+ reagents.temperature_reagents(4000)
/obj/item/reagent_containers/glass/beaker/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/assembly_holder) && can_assembly)
diff --git a/code/modules/reagents/reagent_containers/iv_bag.dm b/code/modules/reagents/reagent_containers/iv_bag.dm
index 413621d8257..709b20f070f 100644
--- a/code/modules/reagents/reagent_containers/iv_bag.dm
+++ b/code/modules/reagents/reagent_containers/iv_bag.dm
@@ -24,7 +24,7 @@
update_icon()
/obj/item/reagent_containers/iv_bag/pickup(mob/user)
- ..()
+ . = ..()
update_icon()
/obj/item/reagent_containers/iv_bag/dropped(mob/user)
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 71b0532650b..4b66482cf1d 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -8,9 +8,10 @@
icon_state = null
item_state = "pill"
possible_transfer_amounts = null
- volume = 50
+ volume = 100
consume_sound = null
taste = FALSE
+ antable = FALSE
/obj/item/reagent_containers/food/pill/New()
..()
@@ -103,7 +104,7 @@
name = "Charcoal pill"
desc = "Neutralizes many common toxins."
icon_state = "pill17"
- list_reagents = list("charcoal" = 25)
+ list_reagents = list("charcoal" = 50)
/obj/item/reagent_containers/food/pill/salicylic
name = "Salicylic Acid pill"
@@ -121,4 +122,22 @@
name = "Hydrocodone pill"
desc = "Used to treat extreme pain."
icon_state = "pill6"
- list_reagents = list("hydrocodone" = 15)
\ No newline at end of file
+ list_reagents = list("hydrocodone" = 15)
+
+/obj/item/reagent_containers/food/pill/calomel
+ name = "calomel pill"
+ desc = "Can be used to purge impurities, but is highly toxic itself."
+ icon_state = "pill3"
+ list_reagents = list("calomel" = 15)
+
+/obj/item/reagent_containers/food/pill/mutadone
+ name = "mutadone pill"
+ desc = "Used to cure genetic abnormalities."
+ icon_state = "pill18"
+ list_reagents = list("mutadone" = 20)
+
+/obj/item/reagent_containers/food/pill/mannitol
+ name = "mannitol pill"
+ desc = "Used to treat cranial swelling."
+ icon_state = "pill19"
+ list_reagents = list("mannitol" = 20)
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 654dff53b5e..e28ec4c0cff 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -31,7 +31,7 @@
update_icon()
/obj/item/reagent_containers/syringe/pickup(mob/user)
- ..()
+ . = ..()
update_icon()
/obj/item/reagent_containers/syringe/dropped(mob/user)
@@ -197,7 +197,7 @@
update_icon()
/obj/item/reagent_containers/ld50_syringe/pickup(mob/user)
- ..()
+ . = ..()
update_icon()
/obj/item/reagent_containers/ld50_syringe/dropped(mob/user)
@@ -318,6 +318,11 @@
desc = "Contains insulin - used to treat diabetes."
list_reagents = list("insulin" = 15)
+/obj/item/reagent_containers/syringe/calomel
+ name = "Syringe (calomel)"
+ desc = "Contains calomel, which be used to purge impurities, but is highly toxic itself."
+ list_reagents = list("calomel" = 15)
+
/obj/item/reagent_containers/syringe/bioterror
name = "bioterror syringe"
desc = "Contains several paralyzing reagents."
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index da9f408a7c3..b3c98f82b54 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -22,6 +22,13 @@
reagents.add_reagent(reagent_id, tank_volume)
..()
+/obj/structure/reagent_dispensers/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ ..()
+ if(reagents)
+ for(var/i in 1 to 8)
+ if(reagents)
+ reagents.temperature_reagents(exposed_temperature)
+
/obj/structure/reagent_dispensers/proc/boom()
visible_message("[src] ruptures!")
chem_splash(loc, 5, list(reagents))
@@ -68,6 +75,7 @@
desc = "A tank full of industrial welding fuel. Do not consume."
icon_state = "fuel"
reagent_id = "fuel"
+ tank_volume = 4000
var/obj/item/assembly_holder/rig = null
var/accepts_rig = 1
@@ -84,14 +92,14 @@
investigate_log("[key_name(P.firer)] triggered a fueltank explosion with [P.name] at [COORD(loc)]", INVESTIGATE_BOMB)
boom()
-/obj/structure/reagent_dispensers/fueltank/boom(var/rigtrigger = FALSE) // Prevent case where someone who rigged the tank is blamed for the explosion when the rig isn't what triggered the explosion
- if(reagents.has_reagent("fuel"))
- if(rigtrigger == TRUE) // If the explosion is triggered by an assembly holder
- message_admins("A fueltank, last rigged by [lastrigger], exploded at [COORD(loc)]") // Then admin is informed of the last person who rigged the fuel tank
- log_game("A fueltank, last rigged by [lastrigger], exploded at [COORD(loc)]")
- investigate_log("A fueltank, last rigged by [lastrigger], exploded at [COORD(loc)]", INVESTIGATE_BOMB)
- explosion(loc, 0, 1, 5, 7, 10, flame_range = 5)
- qdel(src)
+/obj/structure/reagent_dispensers/fueltank/boom(rigtrigger = FALSE) // Prevent case where someone who rigged the tank is blamed for the explosion when the rig isn't what triggered the explosion
+ if(rigtrigger) // If the explosion is triggered by an assembly holder
+ message_admins("A fueltank, last rigged by [lastrigger], was triggered at [COORD(loc)]") // Then admin is informed of the last person who rigged the fuel tank
+ log_game("A fueltank, last rigged by [lastrigger], triggered at [COORD(loc)]")
+ investigate_log("A fueltank, last rigged by [lastrigger], triggered at [COORD(loc)]", INVESTIGATE_BOMB)
+ if(reagents)
+ reagents.set_reagent_temp(1000) //uh-oh
+ qdel(src)
/obj/structure/reagent_dispensers/fueltank/blob_act()
boom()
@@ -99,7 +107,8 @@
/obj/structure/reagent_dispensers/fueltank/ex_act()
boom()
-/obj/structure/reagent_dispensers/fueltank/fire_act()
+/obj/structure/reagent_dispensers/fueltank/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
+ ..()
boom()
/obj/structure/reagent_dispensers/fueltank/tesla_act()
@@ -167,7 +176,7 @@
investigate_log("[key_name(user)] triggered a fueltank explosion at [COORD(loc)]", INVESTIGATE_BOMB)
boom()
else
- ..()
+ return ..()
/obj/structure/reagent_dispensers/fueltank/Move()
..()
@@ -295,3 +304,4 @@
anchored = 1
density = 0
accepts_rig = 0
+ tank_volume = 1000
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index 8cf0f52d847..239cb71328e 100755
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -177,7 +177,9 @@
var/obj/structure/closet/crate/O = target
if(O.opened)
return
- if(use(3))
+ if(amount >= 3 && do_after_once(user, 15, target = target))
+ if(O.opened || !use(3))
+ return
var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
P.icon_state = "deliverycrate"
P.wrapped = O
@@ -189,7 +191,9 @@
var/obj/structure/closet/O = target
if(O.opened)
return
- if(use(3))
+ if(amount >= 3 && do_after_once(user, 15, target = target))
+ if(O.opened || !use(3))
+ return
var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
P.wrapped = O
P.init_welded = O.welded
diff --git a/code/modules/research/designs/comp_board_designs.dm b/code/modules/research/designs/comp_board_designs.dm
index 57da7142b7c..9d555d8cf32 100644
--- a/code/modules/research/designs/comp_board_designs.dm
+++ b/code/modules/research/designs/comp_board_designs.dm
@@ -212,6 +212,16 @@
build_path = /obj/item/circuitboard/prisoner
category = list("Computer Boards")
+/datum/design/brigcells
+ name = "Console Board (Brig Cell Management Console)"
+ desc = "Allows for the construction of circuit boards used to build a brig cell management console."
+ id = "brigcells"
+ req_tech = list("programming" = 2)
+ build_type = IMPRINTER
+ materials = list(MAT_GLASS = 1000)
+ build_path = /obj/item/circuitboard/brigcells
+ category = list("Computer Boards")
+
/datum/design/rdconsole
name = "Console Board (R&D Console)"
desc = "Allows for the construction of circuit boards used to build a new R&D console. Can be swiped with a Scientist level ID to manage access levels."
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index cc6305319c7..a23378f5513 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -163,8 +163,8 @@
category = list("Medical Machinery")
/datum/design/chem_dispenser
- name = "Machine Board (Portable Chem Dispenser)"
- desc = "The circuit board for a Portable Chem Dispenser."
+ name = "Machine Board (Chem Dispenser)"
+ desc = "The circuit board for a Chem Dispenser."
id = "chem_dispenser"
req_tech = list("programming" = 5, "biotech" = 3, "materials" = 4, "plasmatech" = 4)
build_type = IMPRINTER
@@ -173,8 +173,8 @@
category = list("Medical Machinery")
/datum/design/chem_master
- name = "Machine Design (Chem Master Board)"
- desc = "The circuit board for a Chem Master 2999."
+ name = "Machine Design (ChemMaster Board)"
+ desc = "The circuit board for a ChemMaster 3000."
id = "chem_master"
req_tech = list("biotech" = 3, "materials" = 3, "programming" = 2)
build_type = IMPRINTER
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index d5434765e30..d945722770e 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -52,6 +52,16 @@
build_path = /obj/item/healthupgrade
category = list("Medical")
+/datum/design/handheld_defib
+ name = "Handheld Defibrillator"
+ desc = "A smaller defibrillator only capable of treating cardiac arrest."
+ id = "handheld_defib"
+ req_tech = list("biotech" = 2, "magnets" = 3)
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 20, MAT_GLASS = 20)
+ build_path = /obj/item/handheld_defibrillator
+ category = list("Medical")
+
/datum/design/defib
name = "Defibrillator"
desc = "A device that delivers powerful shocks to detachable paddles that resuscitate incapacitated patients."
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 2ae4e3ac828..dad2b6698ad 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -318,7 +318,7 @@
R.add_reagent(chosenchem , 15)
investigate_log("Experimentor has released [chosenchem] smoke.", "experimentor")
var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, 1, 0, src, 0, silent = 1)
+ smoke.set_up(R, src, TRUE)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start()
qdel(R)
@@ -330,7 +330,7 @@
R.my_atom = src
R.add_reagent(chosenchem , 15)
var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, 1, 0, src, 0, silent = 1)
+ smoke.set_up(R, src, TRUE)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start()
qdel(R)
@@ -417,7 +417,7 @@
R.add_reagent("frostoil" , 15)
investigate_log("Experimentor has released frostoil gas.", "experimentor")
var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, 1, 0, src, 0, silent = 1)
+ smoke.set_up(R, src, TRUE)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start()
qdel(R)
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index 29a3cd26600..b695ca3a1b4 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -26,14 +26,33 @@
var/datum/action/innate/slime_pick_up/slime_up_action = new
var/datum/action/innate/feed_slime/feed_slime_action = new
var/datum/action/innate/monkey_recycle/monkey_recycle_action = new
+ var/datum/action/innate/slime_scan/scan_action = new
+ var/datum/action/innate/feed_potion/potion_action = new
+ var/datum/action/innate/hotkey_help/hotkey_help = new
var/list/stored_slimes = list()
var/max_slimes = 5
var/monkeys = 0
+ var/obj/item/slimepotion/slime/current_potion
+ var/obj/machinery/monkey_recycler/connected_recycler
icon_screen = "slime_comp"
icon_keyboard = "rd_key"
+/obj/machinery/computer/camera_advanced/xenobio/New()
+ ..()
+ for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers)
+ if(get_area(recycler.loc) == get_area(loc))
+ connected_recycler = recycler
+ connected_recycler.connected += src
+
+/obj/machinery/computer/camera_advanced/xenobio/Destroy()
+ QDEL_NULL(current_potion)
+ for(var/mob/living/carbon/slime/S in stored_slimes)
+ S.forceMove(drop_location())
+ stored_slimes.Cut()
+ return ..()
+
/obj/machinery/computer/camera_advanced/xenobio/CreateEye()
eyeobj = new /mob/camera/aiEye/remote/xenobio(get_turf(src))
eyeobj.origin = src
@@ -43,26 +62,63 @@
/obj/machinery/computer/camera_advanced/xenobio/GrantActions(mob/living/carbon/user)
..()
+
if(slime_up_action)
slime_up_action.target = src
slime_up_action.Grant(user)
actions += slime_up_action
-
+
if(slime_place_action)
slime_place_action.target = src
slime_place_action.Grant(user)
actions += slime_place_action
-
+
if(feed_slime_action)
feed_slime_action.target = src
feed_slime_action.Grant(user)
actions += feed_slime_action
-
+
if(monkey_recycle_action)
monkey_recycle_action.target = src
monkey_recycle_action.Grant(user)
actions += monkey_recycle_action
+ if(scan_action)
+ scan_action.target = src
+ scan_action.Grant(user)
+ actions += scan_action
+
+ if(potion_action)
+ potion_action.target = src
+ potion_action.Grant(user)
+ actions += potion_action
+
+ if(hotkey_help)
+ hotkey_help.target = src
+ hotkey_help.Grant(user)
+ actions += hotkey_help
+
+ RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, .proc/XenoSlimeClickCtrl)
+ RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, .proc/XenoSlimeClickAlt)
+ RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, .proc/XenoSlimeClickShift)
+ RegisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT, .proc/XenoTurfClickShift)
+ RegisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL, .proc/XenoTurfClickCtrl)
+ RegisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL, .proc/XenoMonkeyClickCtrl)
+
+ if(!connected_recycler)
+ for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers)
+ if(get_area(recycler.loc) == get_area(loc))
+ connected_recycler = recycler
+ connected_recycler.connected += src
+
+/obj/machinery/computer/camera_advanced/xenobio/remove_eye_control(mob/living/user)
+ UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL)
+ UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT)
+ UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT)
+ UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT)
+ UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL)
+ UnregisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL)
+ ..()
/obj/machinery/computer/camera_advanced/xenobio/attack_hand(mob/user)
if(!ishuman(user)) //AIs using it might be weird
@@ -71,11 +127,20 @@
/obj/machinery/computer/camera_advanced/xenobio/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/reagent_containers/food/snacks/monkeycube))
- monkeys++
- to_chat(user, "You feed [O] to [src]. It now has [monkeys] monkey cubes stored.")
- user.drop_item()
- qdel(O)
- return
+ if(user.drop_item())
+ monkeys++
+ to_chat(user, "You feed [O] to [src]. It now has [monkeys] monkey cubes stored.")
+ qdel(O)
+ return
+ else if(istype(O, /obj/item/slimepotion/slime))
+ var/replaced = FALSE
+ if(user.drop_item())
+ if(!QDELETED(current_potion))
+ current_potion.forceMove(drop_location())
+ replaced = TRUE
+ current_potion = O
+ to_chat(user, "You load [O] in the console's potion slot[replaced ? ", replacing the one that was there before" : ""].")
+ return
else if(istype(O, /obj/item/storage/bag))
var/obj/item/storage/P = O
var/loaded = 0
@@ -87,6 +152,13 @@
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(ismultitool(O))
+ var/obj/item/multitool/I = O
+ if(istype(I.buffer, /obj/machinery/monkey_recycler))
+ to_chat(user, "You link [src] with [I.buffer] in [I] buffer.")
+ connected_recycler = I.buffer
+ connected_recycler.connected += src
+ return
..()
/datum/action/innate/slime_place
@@ -163,12 +235,201 @@
var/mob/living/carbon/human/C = owner
var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
var/obj/machinery/computer/camera_advanced/xenobio/X = target
-
+ var/obj/machinery/monkey_recycler/recycler = X.connected_recycler
+
+ if(!recycler)
+ to_chat(owner, "There is no connected monkey recycler. Use a multitool to link one.")
+ return
if(cameranet.checkTurfVis(remote_eye.loc))
for(var/mob/living/carbon/human/M in remote_eye.loc)
if(issmall(M) && M.stat)
M.visible_message("[M] vanishes as [M.p_theyre()] reclaimed for recycling!")
- X.monkeys = round(X.monkeys + 0.2,0.1)
+ recycler.use_power(500)
+ X.monkeys = round(X.monkeys + recycler.cube_production/recycler.required_grind, 0.1)
qdel(M)
else
- to_chat(owner, "Target is not near a camera. Cannot proceed.")
\ No newline at end of file
+ to_chat(owner, "Target is not near a camera. Cannot proceed.")
+
+/datum/action/innate/slime_scan
+ name = "Scan Slime"
+ button_icon_state = "slime_scan"
+
+/datum/action/innate/slime_scan/Activate()
+ if(!target || !isliving(owner))
+ return
+ var/mob/living/C = owner
+ var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
+
+ if(cameranet.checkTurfVis(remote_eye.loc))
+ for(var/mob/living/carbon/slime/S in remote_eye.loc)
+ slime_scan(S, C)
+ else
+ to_chat(owner, "Target is not near a camera. Cannot proceed.")
+
+/datum/action/innate/feed_potion
+ name = "Apply Potion"
+ button_icon_state = "slime_potion"
+
+/datum/action/innate/feed_potion/Activate()
+ if(!target || !ishuman(owner))
+ return
+
+ var/mob/living/carbon/human/C = owner
+ var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
+ var/obj/machinery/computer/camera_advanced/xenobio/X = target
+
+ if(QDELETED(X.current_potion))
+ to_chat(owner, "No potion loaded.")
+ return
+
+ if(cameranet.checkTurfVis(remote_eye.loc))
+ for(var/mob/living/carbon/slime/S in remote_eye.loc)
+ X.current_potion.attack(S, C)
+ break
+ else
+ to_chat(owner, "Target is not near a camera. Cannot proceed.")
+
+/datum/action/innate/hotkey_help
+ name = "Hotkey Help"
+ button_icon_state = "hotkey_help"
+
+/datum/action/innate/hotkey_help/Activate()
+ if(!target || !isliving(owner))
+ return
+ to_chat(owner, "Click shortcuts:")
+ to_chat(owner, "Shift-click a slime to pick it up, or the floor to drop all held slimes.")
+ to_chat(owner, "Ctrl-click a slime to scan it.")
+ to_chat(owner, "Alt-click a slime to feed it a potion.")
+ to_chat(owner, "Ctrl-click or a dead monkey to recycle it, or the floor to place a new monkey.")
+
+//
+// Alternate clicks for slime, monkey and open turf if using a xenobio console
+
+// Scans slime
+/mob/living/carbon/slime/CtrlClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_CTRL, src)
+ ..()
+
+//Feeds a potion to slime
+/mob/living/carbon/slime/AltClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_ALT, src)
+ ..()
+
+//Picks up slime
+/mob/living/carbon/slime/ShiftClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_SLIME_CLICK_SHIFT, src)
+ ..()
+
+//Place slimes
+/turf/simulated/ShiftClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_TURF_CLICK_SHIFT, src)
+ ..()
+
+//Place monkey
+/turf/simulated/CtrlClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_TURF_CLICK_CTRL, src)
+ ..()
+
+//Pick up monkey
+/mob/living/carbon/monkey/CtrlClick(mob/user)
+ SEND_SIGNAL(user, COMSIG_XENO_MONKEY_CLICK_CTRL, src)
+ ..()
+
+// Scans slime
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickCtrl(mob/living/user, mob/living/carbon/slime/S)
+ if(!cameranet.checkTurfVis(S.loc))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
+ return
+ var/mob/living/C = user
+ var/mob/camera/aiEye/remote/xenobio/E = C.remote_control
+ var/area/mobarea = get_area(S.loc)
+ if(mobarea.name == E.allowed_area || mobarea.xenobiology_compatible)
+ slime_scan(S, C)
+
+//Feeds a potion to slime
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickAlt(mob/living/user, mob/living/carbon/slime/S)
+ if(!cameranet.checkTurfVis(S.loc))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
+ return
+ var/mob/living/C = user
+ var/mob/camera/aiEye/remote/xenobio/E = C.remote_control
+ var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
+ var/area/mobarea = get_area(S.loc)
+ if(QDELETED(X.current_potion))
+ to_chat(C, "No potion loaded.")
+ return
+ if(mobarea.name == E.allowed_area || mobarea.xenobiology_compatible)
+ X.current_potion.attack(S, C)
+
+//Picks up slime
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoSlimeClickShift(mob/living/user, mob/living/carbon/slime/S)
+ if(!cameranet.checkTurfVis(S.loc))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
+ return
+ var/mob/living/C = user
+ var/mob/camera/aiEye/remote/xenobio/E = C.remote_control
+ var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
+ var/area/mobarea = get_area(S.loc)
+ if(mobarea.name == E.allowed_area || mobarea.xenobiology_compatible)
+ if(X.stored_slimes.len >= X.max_slimes)
+ return
+ if(!S.ckey)
+ if(S.buckled)
+ S.buckled.unbuckle_mob()
+ S.Feedstop()
+ S.visible_message("[S] vanishes in a flash of light!")
+ S.forceMove(X)
+ X.stored_slimes += S
+
+//Place slimes
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoTurfClickShift(mob/living/user, turf/T)
+ if(!cameranet.checkTurfVis(T))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
+ return
+ var/mob/living/C = user
+ var/mob/camera/aiEye/remote/xenobio/E = C.remote_control
+ var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
+ var/area/turfarea = get_area(T)
+ if(turfarea.name == E.allowed_area || turfarea.xenobiology_compatible)
+ for(var/mob/living/carbon/slime/S in X.stored_slimes)
+ S.forceMove(T)
+ S.visible_message("[S] warps in!")
+ X.stored_slimes -= S
+
+//Place monkey
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoTurfClickCtrl(mob/living/user, turf/T)
+ if(!cameranet.checkTurfVis(T))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
+ return
+ var/mob/living/C = user
+ var/mob/camera/aiEye/remote/xenobio/E = C.remote_control
+ var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
+ var/area/turfarea = get_area(T)
+
+ if(turfarea.name == E.allowed_area || turfarea.xenobiology_compatible)
+ if(X.monkeys >= 1)
+ var/mob/living/carbon/human/monkey/food = new /mob/living/carbon/human/monkey(T)
+ food.LAssailant = C
+ X.monkeys --
+ X.monkeys = round(X.monkeys, 0.1)
+ to_chat(user, "[X] now has [X.monkeys] monkeys left.")
+
+//Pick up monkey
+/obj/machinery/computer/camera_advanced/xenobio/proc/XenoMonkeyClickCtrl(mob/living/user, mob/living/carbon/monkey/M)
+ if(!cameranet.checkTurfVis(M.loc))
+ to_chat(user, "Target is not near a camera. Cannot proceed.")
+ return
+ var/mob/living/C = user
+ var/mob/camera/aiEye/remote/xenobio/E = C.remote_control
+ var/obj/machinery/computer/camera_advanced/xenobio/X = E.origin
+ var/area/mobarea = get_area(M.loc)
+ var/obj/machinery/monkey_recycler/recycler = X.connected_recycler
+ if(!recycler)
+ to_chat(C, "There is no connected monkey recycler. Use a multitool to link one.")
+ return
+ if(mobarea.name == E.allowed_area || mobarea.xenobiology_compatible)
+ if(issmall(M) && M.stat)
+ M.visible_message("[M] vanishes as [M.p_theyre()] reclaimed for recycling!")
+ recycler.use_power(500)
+ X.monkeys = round(X.monkeys + recycler.cube_production/recycler.required_grind, 0.1)
+ qdel(M)
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 02e6b155025..f60954a83a6 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -132,14 +132,14 @@
to_chat(user, "You cannot transfer [src] to [target]! It appears the potion must be given directly to a slime to absorb.") // le fluff faec
return
-/obj/item/slimepotion/docility
+/obj/item/slimepotion/slime/docility
name = "docility potion"
desc = "A potent chemical mix that nullifies a slime's hunger, causing it to become docile and tame."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
var/being_used = 0
-/obj/item/slimepotion/docility/attack(mob/living/carbon/slime/M, mob/user)
+/obj/item/slimepotion/slime/docility/attack(mob/living/carbon/slime/M, mob/user)
if(!isslime(M))
to_chat(user, "The potion only works on slimes!")
return
@@ -205,6 +205,7 @@
SM.faction = user.faction
SM.master_commander = user
SM.sentience_act()
+ SM.can_collar = 1
to_chat(SM, "All at once it makes sense: you know what you are and who you are! Self awareness is yours!")
to_chat(SM, "You are grateful to be self aware and owe [user] a great debt. Serve [user], and assist [user.p_them()] in completing [user.p_their()] goals at any cost.")
if(SM.flags_2 & HOLOGRAM_2) //Check to see if it's a holodeck creature
@@ -254,19 +255,20 @@
SM.universal_speak = 1
SM.faction = user.faction
SM.sentience_act() //Same deal here as with sentience
+ SM.can_collar = 1
user.death()
to_chat(SM, "In a quick flash, you feel your consciousness flow into [SM]!")
to_chat(SM, "You are now [SM]. Your allegiances, alliances, and roles are still the same as they were prior to consciousness transfer!")
SM.name = "[SM.name] as [user.real_name]"
qdel(src)
-/obj/item/slimepotion/steroid
+/obj/item/slimepotion/slime/steroid
name = "slime steroid"
desc = "A potent chemical mix that will cause a baby slime to generate more extract."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle16"
-/obj/item/slimepotion/steroid/attack(mob/living/carbon/slime/M, mob/user)
+/obj/item/slimepotion/slime/steroid/attack(mob/living/carbon/slime/M, mob/user)
if(!isslime(M))//If target is not a slime.
to_chat(user, "The steroid only works on baby slimes!")
return ..()
@@ -290,13 +292,13 @@
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle17"
-/obj/item/slimepotion/stabilizer
+/obj/item/slimepotion/slime/stabilizer
name = "slime stabilizer"
desc = "A potent chemical mix that will reduce the chance of a slime mutating."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle15"
-/obj/item/slimepotion/stabilizer/attack(mob/living/carbon/slime/M, mob/user)
+/obj/item/slimepotion/slime/stabilizer/attack(mob/living/carbon/slime/M, mob/user)
if(!isslime(M))
to_chat(user, "The stabilizer only works on slimes!")
return ..()
@@ -311,13 +313,13 @@
M.mutation_chance = Clamp(M.mutation_chance-15,0,100)
qdel(src)
-/obj/item/slimepotion/mutator
+/obj/item/slimepotion/slime/mutator
name = "slime mutator"
desc = "A potent chemical mix that will increase the chance of a slime mutating."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle3"
-/obj/item/slimepotion/mutator/attack(mob/living/carbon/slime/M, mob/user)
+/obj/item/slimepotion/slime/mutator/attack(mob/living/carbon/slime/M, mob/user)
if(!isslime(M))
to_chat(user, "The mutator only works on slimes!")
return ..()
diff --git a/code/modules/response_team/ert_outfits.dm b/code/modules/response_team/ert_outfits.dm
index 368868770c7..b287643901d 100644
--- a/code/modules/response_team/ert_outfits.dm
+++ b/code/modules/response_team/ert_outfits.dm
@@ -306,7 +306,8 @@
/obj/item/roller = 1,
/obj/item/storage/pill_bottle/ert = 1,
/obj/item/flashlight = 1,
- /obj/item/healthupgrade = 1
+ /obj/item/healthupgrade = 1,
+ /obj/item/handheld_defibrillator = 1
)
/datum/outfit/job/centcom/response_team/medic/red
@@ -335,7 +336,8 @@
/obj/item/roller = 1,
/obj/item/clothing/shoes/magboots = 1,
/obj/item/bodyanalyzer = 1,
- /obj/item/healthupgrade = 1
+ /obj/item/healthupgrade = 1,
+ /obj/item/handheld_defibrillator = 1
)
/datum/outfit/job/centcom/response_team/medic/gamma
@@ -357,7 +359,8 @@
/obj/item/bodyanalyzer/advanced = 1,
/obj/item/extinguisher/mini = 1,
/obj/item/roller = 1,
- /obj/item/healthanalyzer/advanced = 1
+ /obj/item/healthanalyzer/advanced = 1,
+ /obj/item/handheld_defibrillator = 1
)
diff --git a/code/modules/security_levels/security levels.dm b/code/modules/security_levels/security levels.dm
index f5d3fe7e1bf..050326891fb 100644
--- a/code/modules/security_levels/security levels.dm
+++ b/code/modules/security_levels/security levels.dm
@@ -77,7 +77,7 @@
FA.overlays += image('icons/obj/monitors.dmi', "overlay_red")
if(SEC_LEVEL_GAMMA)
- security_announcement_up.Announce("Central Command has ordered the Gamma security level on the station. Security is to have weapons equipped at all times, and all civilians are to immediately seek their nearest head for transportation to a secure location. The station's Gamma armory has been unlocked and is ready for use.","Attention! Gamma security level activated!")
+ security_announcement_up.Announce("Central Command has ordered the Gamma security level on the station. Security is to have weapons equipped at all times, and all civilians are to immediately seek their nearest head for transportation to a secure location. The station's Gamma armory has been unlocked and is ready for use.","Attention! Gamma security level activated!", new_sound = sound('sound/effects/new_siren.ogg'))
security_level = SEC_LEVEL_GAMMA
move_gamma_ship()
@@ -102,7 +102,7 @@
FA.update_icon()
if(SEC_LEVEL_EPSILON)
- security_announcement_up.Announce("Central Command has ordered the Epsilon security level on the station. Consider all contracts terminated.","Attention! Epsilon security level activated!")
+ security_announcement_up.Announce("Central Command has ordered the Epsilon security level on the station. Consider all contracts terminated.","Attention! Epsilon security level activated!", new_sound = sound('sound/effects/purge_siren.ogg'))
security_level = SEC_LEVEL_EPSILON
post_status("alert", "epsilonalert")
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index dfa54f086d1..06e0c2336f0 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -714,6 +714,8 @@
possible_destinations = C.possible_destinations
shuttleId = C.shuttleId
+/obj/machinery/computer/shuttle/Initialize(mapload)
+ . = ..()
connect()
/obj/machinery/computer/shuttle/proc/connect()
diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm
index 0ff4273daa1..d2d758529aa 100644
--- a/code/modules/surgery/organs/blood.dm
+++ b/code/modules/surgery/organs/blood.dm
@@ -18,23 +18,11 @@
// Takes care blood loss and regeneration
/mob/living/carbon/human/handle_blood()
- var/list/blood_data = get_blood_data(get_blood_id())//PROCCEPTION
-
if(NO_BLOOD in dna.species.species_traits)
bleed_rate = 0
return
if(bodytemperature >= 225 && !(NOCLONE in mutations)) //cryosleep or husked people do not pump the blood.
-
- //Blood regeneration if there is some space
- if(blood_volume < max_blood && blood_volume)
- if(mind) //Handles vampires "eating" blood that isn't their own.
- if(mind in ticker.mode.vampires)
- if(nutrition >= NUTRITION_LEVEL_WELL_FED)
- return //We don't want blood tranfusions making vampires fat.
- if(blood_data["donor"] != src)
- nutrition += (15 * REAGENTS_METABOLISM)
- return //Only process one blood per tick, to maintain the same metabolism as nutriment for non-vampires.
if(blood_volume < BLOOD_VOLUME_NORMAL)
blood_volume += 0.1 // regenerate blood VERY slowly
@@ -56,7 +44,7 @@
if(prob(15))
Paralyse(rand(1,3))
to_chat(src, "You feel extremely [word].")
- if(0 to BLOOD_VOLUME_SURVIVE)
+ if(-INFINITY to BLOOD_VOLUME_SURVIVE)
death()
var/temp_bleed = 0
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index 04626864b94..512de9de9e9 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -160,6 +160,7 @@
/obj/item/organ/internal/heart/cybernetic/upgraded/on_life()
if(!ishuman(owner))
return
+
if(!(status & ORGAN_DEAD) && !attempted_restart && !beating)
to_chat(owner, "Your [name] detects a cardiac event and attempts to return to its normal rhythm!")
if(prob(20) && emagged)
@@ -180,6 +181,28 @@
addtimer(CALLBACK(src, .proc/recharge), 300)
addtimer(CALLBACK(src, .proc/message_to_owner, owner, "Your [name] fails to return to its normal rhythm!"), 30)
+ if(!(status & ORGAN_DEAD) && !attempted_restart && owner.HasDisease(new /datum/disease/critical/heart_failure(0)))
+ to_chat(owner, "Your [name] detects a cardiac event and attempts to return to its normal rhythm!")
+ if(prob(40) && emagged)
+ attempted_restart = TRUE
+ for(var/datum/disease/critical/heart_failure/HF in owner.viruses)
+ HF.cure()
+ addtimer(CALLBACK(src, .proc/message_to_owner, owner, "Your [name] returns to its normal rhythm!"), 30)
+ addtimer(CALLBACK(src, .proc/recharge), 200)
+ else if(prob(25))
+ attempted_restart = TRUE
+ for(var/datum/disease/critical/heart_failure/HF in owner.viruses)
+ HF.cure()
+ addtimer(CALLBACK(src, .proc/message_to_owner, owner, "Your [name] returns to its normal rhythm!"), 30)
+ addtimer(CALLBACK(src, .proc/recharge), 200)
+ else
+ attempted_restart = TRUE
+ if(emagged)
+ addtimer(CALLBACK(src, .proc/recharge), 200)
+ else
+ addtimer(CALLBACK(src, .proc/recharge), 300)
+ addtimer(CALLBACK(src, .proc/message_to_owner, owner, "Your [name] fails to return to its normal rhythm!"), 30)
+
if(!(status & ORGAN_DEAD))
var/boost = emagged ? 2 : 1
owner.AdjustDrowsy(-4 * boost)
@@ -230,7 +253,7 @@
owner.adjustFireLoss(numHigh)
if(prob(numMid))
to_chat(owner, "Your [name] lurches awkwardly!")
- Stop()
+ owner.ForceContractDisease(new /datum/disease/critical/heart_failure(0))
if(prob(numMid))
to_chat(owner, "Your [name] stops beating!")
Stop()
@@ -246,4 +269,4 @@
owner.adjustFireLoss(numMid)
if(prob(numLow))
to_chat(owner, "Your [name] lurches awkwardly!")
- Stop()
\ No newline at end of file
+ owner.ForceContractDisease(new /datum/disease/critical/heart_failure(0))
\ No newline at end of file
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index 9e437f415a9..47fa74969d0 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -19,20 +19,16 @@
var/safe_toxins_max = 0.05
var/SA_para_min = 1 //Sleeping agent
var/SA_sleep_min = 5 //Sleeping agent
- var/gas_toxicity_multiplier = 100
- var/oxy_breath_dam_min = MIN_TOXIC_GAS_DAMAGE
- var/oxy_breath_dam_max = MAX_TOXIC_GAS_DAMAGE
+
var/oxy_damage_type = OXY
- var/nitro_breath_dam_min = MIN_TOXIC_GAS_DAMAGE
- var/nitro_breath_dam_max = MAX_TOXIC_GAS_DAMAGE
+ var/oxy_breath_dam_multiplier = 1
var/nitro_damage_type = OXY
- var/co2_breath_dam_min = MIN_TOXIC_GAS_DAMAGE
- var/co2_breath_dam_max = MAX_TOXIC_GAS_DAMAGE
+ var/nitro_breath_dam_multiplier = 1
var/co2_damage_type = OXY
- var/tox_breath_dam_min = MIN_TOXIC_GAS_DAMAGE
- var/tox_breath_dam_max = MAX_TOXIC_GAS_DAMAGE
+ var/co2_breath_dam_multiplier = 1
var/tox_damage_type = TOX
+ var/tox_breath_dam_multiplier = 1
var/cold_message = "your face freezing and an icicle forming"
var/cold_level_1_threshold = 260
@@ -88,12 +84,11 @@
return
if(!breath || (breath.total_moles() == 0))
- if(H.health >= config.health_threshold_crit)
- H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
- else if(!(NOCRITDAMAGE in H.dna.species.species_traits))
- H.adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS)
+ if(isspaceturf(loc))
+ H.adjustOxyLoss(10)
+ else
+ H.adjustOxyLoss(5)
- H.failed_last_breath = TRUE
if(safe_oxygen_min)
H.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
else if(safe_toxins_min)
@@ -104,6 +99,10 @@
H.throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro)
return FALSE
+
+ if(H.health < HEALTH_THRESHOLD_CRIT)
+ return FALSE
+
var/gas_breathed = 0
//Partial pressures in our breath
@@ -118,8 +117,8 @@
//Too much oxygen! //Yes, some species may not like it.
if(safe_oxygen_max)
if(O2_pp > safe_oxygen_max)
- var/ratio = (breath.oxygen/safe_oxygen_max) * gas_toxicity_multiplier
- H.apply_damage_type(Clamp(ratio, oxy_breath_dam_min, oxy_breath_dam_max), oxy_damage_type)
+ var/ratio = breath.oxygen/safe_oxygen_max
+ H.apply_damage_type(ratio * 325 * oxy_breath_dam_multiplier, oxy_damage_type)
H.throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy)
else
H.clear_alert("too_much_oxy")
@@ -130,8 +129,7 @@
gas_breathed = handle_too_little_breath(H, O2_pp, safe_oxygen_min, breath.oxygen)
H.throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
else
- H.failed_last_breath = FALSE
- H.adjustOxyLoss(-5)
+ H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS)
gas_breathed = breath.oxygen
H.clear_alert("not_enough_oxy")
@@ -145,8 +143,8 @@
//Too much nitrogen!
if(safe_nitro_max)
if(N2_pp > safe_nitro_max)
- var/ratio = (breath.nitrogen/safe_nitro_max) * gas_toxicity_multiplier
- H.apply_damage_type(Clamp(ratio, nitro_breath_dam_min, nitro_breath_dam_max), nitro_damage_type)
+ var/ratio = breath.nitrogen/safe_nitro_max
+ H.apply_damage_type(ratio * 325 * nitro_breath_dam_multiplier, nitro_damage_type)
H.throw_alert("too_much_nitro", /obj/screen/alert/too_much_nitro)
else
H.clear_alert("too_much_nitro")
@@ -157,8 +155,7 @@
gas_breathed = handle_too_little_breath(H, N2_pp, safe_nitro_min, breath.nitrogen)
H.throw_alert("not_enough_nitro", /obj/screen/alert/not_enough_nitro)
else
- H.failed_last_breath = FALSE
- H.adjustOxyLoss(-5)
+ H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS)
gas_breathed = breath.nitrogen
H.clear_alert("not_enough_nitro")
@@ -176,9 +173,9 @@
H.co2overloadtime = world.time
else if(world.time - H.co2overloadtime > 120)
H.Paralyse(3)
- H.apply_damage_type(3, co2_damage_type) // Lets hurt em a little, let them know we mean business
+ H.apply_damage_type(HUMAN_MAX_OXYLOSS * co2_breath_dam_multiplier, co2_damage_type) // Lets hurt em a little, let them know we mean business
if(world.time - H.co2overloadtime > 300) // They've been in here 30s now, lets start to kill them for their own good!
- H.apply_damage_type(8, co2_damage_type)
+ H.apply_damage_type(15 * co2_breath_dam_multiplier, co2_damage_type)
H.throw_alert("too_much_co2", /obj/screen/alert/too_much_co2)
if(prob(20)) // Lets give them some chance to know somethings not right though I guess.
H.emote("cough")
@@ -193,8 +190,7 @@
gas_breathed = handle_too_little_breath(H, CO2_pp, safe_co2_min, breath.carbon_dioxide)
H.throw_alert("not_enough_co2", /obj/screen/alert/not_enough_co2)
else
- H.failed_last_breath = FALSE
- H.adjustOxyLoss(-5)
+ H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS)
gas_breathed = breath.carbon_dioxide
H.clear_alert("not_enough_co2")
@@ -209,8 +205,8 @@
//Too much toxins!
if(safe_toxins_max)
if(Toxins_pp > safe_toxins_max)
- var/ratio = (breath.toxins/safe_toxins_max) * gas_toxicity_multiplier
- H.apply_damage_type(Clamp(ratio, tox_breath_dam_min, tox_breath_dam_max), tox_damage_type)
+ var/ratio = breath.toxins/safe_toxins_max
+ H.apply_damage_type(ratio * 325 * tox_breath_dam_multiplier, tox_damage_type)
H.throw_alert("too_much_tox", /obj/screen/alert/too_much_tox)
else
H.clear_alert("too_much_tox")
@@ -222,8 +218,7 @@
gas_breathed = handle_too_little_breath(H, Toxins_pp, safe_toxins_min, breath.toxins)
H.throw_alert("not_enough_tox", /obj/screen/alert/not_enough_tox)
else
- H.failed_last_breath = FALSE
- H.adjustOxyLoss(-5)
+ H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS)
gas_breathed = breath.toxins
H.clear_alert("not_enough_tox")
@@ -261,11 +256,9 @@
if(breath_pp > 0)
var/ratio = safe_breath_min/breath_pp
H.adjustOxyLoss(min(5*ratio, HUMAN_MAX_OXYLOSS)) // Don't fuck them up too fast (space only does HUMAN_MAX_OXYLOSS after all!
- H.failed_last_breath = TRUE
. = true_pp*ratio/6
else
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
- H.failed_last_breath = TRUE
/obj/item/organ/internal/lungs/proc/handle_breath_temperature(datum/gas_mixture/breath, mob/living/carbon/human/H) // called by human/life, handles temperatures
@@ -315,7 +308,8 @@
/obj/item/organ/internal/lungs/plasmaman
name = "plasma filter"
desc = "A spongy rib-shaped mass for filtering plasma from the air."
- icon_state = "lungs-plasma"
+ icon = 'icons/obj/species_organs/plasmaman.dmi'
+ icon_state = "lungs"
safe_oxygen_min = 0 //We don't breath this
safe_toxins_min = 16 //We breathe THIS!
@@ -324,21 +318,24 @@
/obj/item/organ/internal/lungs/vox
name = "Vox lungs"
desc = "They're filled with dust....wow."
+ icon = 'icons/obj/species_organs/vox.dmi'
+ icon_state = "lungs"
safe_oxygen_min = 0 //We don't breathe this
safe_oxygen_max = 0.05 //This is toxic to us
safe_nitro_min = 16 //We breathe THIS!
oxy_damage_type = TOX //And it poisons us
+ oxy_breath_dam_multiplier = 0.16
/obj/item/organ/internal/lungs/drask
- icon = 'icons/obj/surgery_drask.dmi'
+ icon = 'icons/obj/species_organs/drask.dmi'
cold_message = "an invigorating coldness"
cold_level_3_threshold = 60
cold_level_1_damage = -COLD_GAS_DAMAGE_LEVEL_1 //They heal when the air is cold
cold_level_2_damage = -COLD_GAS_DAMAGE_LEVEL_2
cold_level_3_damage = -COLD_GAS_DAMAGE_LEVEL_3
- cold_damage_types = list(BRUTE = 1, BURN = 0.5)
+ cold_damage_types = list(BRUTE = 0.5, BURN = 0.25)
/obj/item/organ/internal/lungs/cybernetic
name = "cybernetic lungs"
diff --git a/code/modules/surgery/organs/parasites.dm b/code/modules/surgery/organs/parasites.dm
index 536ca7a4f37..f330df260eb 100644
--- a/code/modules/surgery/organs/parasites.dm
+++ b/code/modules/surgery/organs/parasites.dm
@@ -52,10 +52,11 @@
var/egg_progress = 0 // # of on_life() cycles completed, unlike cycle_num this is reset on each hatch event
var/egg_progress_per_hatch = 90 // if egg_progress > this, chance to hatch and reset egg_progress
var/eggs_hatched = 0 // num of hatch events completed
- var/eggs_max = 3 // max possible spiderlings you can get from a single infection if its left to run for a very long time
var/awaymission_checked = FALSE
var/awaymission_infection = FALSE // TRUE if infection occurred inside gateway
- var/list/types_basic = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray, /mob/living/simple_animal/hostile/poison/terror_spider/green)
+ var/list/types_basic = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray)
+ var/list/types_adv = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray, /mob/living/simple_animal/hostile/poison/terror_spider/green)
+
/obj/item/organ/internal/body_egg/terror_eggs/on_life()
// Safety first.
@@ -78,19 +79,11 @@
qdel(src)
return
- // Detect dying hosts, and try to keep them alive (so spiderlings can hatch) at the cost of some growth progress.
- if(owner.health < -25)
- to_chat(owner,"You feel a strange, blissful senstation.")
- owner.adjustBruteLoss(-5)
- owner.adjustFireLoss(-5)
- owner.adjustToxLoss(-5)
- egg_progress += 10
-
// Once at least one egg has hatched from you, you'll need help to reach medbay.
if(eggs_hatched >= 1)
owner.Confused(2)
- if(egg_progress > egg_progress_per_hatch && eggs_hatched < eggs_max)
+ if(egg_progress > egg_progress_per_hatch)
egg_progress -= egg_progress_per_hatch
hatch_egg()
@@ -107,15 +100,22 @@
return extra_progress
/obj/item/organ/internal/body_egg/terror_eggs/proc/hatch_egg()
+ var/infection_completed = FALSE
var/obj/structure/spider/spiderling/terror_spiderling/S = new(get_turf(owner))
- if(eggs_hatched >= 2) // on the third egg...
- S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/princess
- else
- S.grow_as = pick(types_basic)
+ switch(eggs_hatched)
+ if(0) // First spiderling
+ S.grow_as = pick(types_basic)
+ if(1) // Second
+ S.grow_as = pick(types_adv)
+ if(2) // Last
+ S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/princess
+ infection_completed = TRUE
S.immediate_ventcrawl = TRUE
eggs_hatched++
to_chat(owner, "A strange prickling sensation moves across your skin... then suddenly the whole world seems to spin around you!")
owner.Paralyse(10)
+ if(infection_completed && !QDELETED(src))
+ qdel(src)
/obj/item/organ/internal/body_egg/terror_eggs/remove(var/mob/living/carbon/M, var/special = 0)
..()
diff --git a/code/modules/surgery/organs/subtypes/drask.dm b/code/modules/surgery/organs/subtypes/drask.dm
index 6e11cf2993e..e457c4cddaa 100644
--- a/code/modules/surgery/organs/subtypes/drask.dm
+++ b/code/modules/surgery/organs/subtypes/drask.dm
@@ -1,29 +1,29 @@
//DRASK ORGAN
/obj/item/organ/internal/drask
name = "drask organ"
- icon = 'icons/obj/surgery_drask.dmi'
+ icon = 'icons/obj/species_organs/drask.dmi'
icon_state = "innards"
desc = "A greenish, slightly translucent organ. It is extremely cold."
/obj/item/organ/internal/heart/drask
name = "drask heart"
- icon = 'icons/obj/surgery_drask.dmi'
+ icon = 'icons/obj/species_organs/drask.dmi'
parent_organ = "head"
/obj/item/organ/internal/liver/drask
name = "metabolic strainer"
- icon = 'icons/obj/surgery_drask.dmi'
+ icon = 'icons/obj/species_organs/drask.dmi'
icon_state = "kidneys"
alcohol_intensity = 0.8
/obj/item/organ/internal/brain/drask
- icon = 'icons/obj/surgery_drask.dmi'
+ icon = 'icons/obj/species_organs/drask.dmi'
icon_state = "brain2"
- mmi_icon = 'icons/obj/surgery_drask.dmi'
+ mmi_icon = 'icons/obj/species_organs/drask.dmi'
mmi_icon_state = "mmi_full"
/obj/item/organ/internal/eyes/drask
name = "drask eyeballs"
- icon = 'icons/obj/surgery_drask.dmi'
+ icon = 'icons/obj/species_organs/drask.dmi'
desc = "Drask eyes. They look even stranger disembodied"
dark_view = 5
\ No newline at end of file
diff --git a/code/modules/surgery/organs/subtypes/grey.dm b/code/modules/surgery/organs/subtypes/grey.dm
index 177e4ae5be1..3e7598fa06f 100644
--- a/code/modules/surgery/organs/subtypes/grey.dm
+++ b/code/modules/surgery/organs/subtypes/grey.dm
@@ -1,9 +1,15 @@
/obj/item/organ/internal/liver/grey
+ name = "grey liver"
+ desc = "A small, odd looking liver"
+ icon = 'icons/obj/species_organs/grey.dmi'
alcohol_intensity = 1.6
/obj/item/organ/internal/brain/grey
- icon_state = "brain-x"
- mmi_icon_state = "mmi_alien"
+ desc = "A large brain"
+ icon = 'icons/obj/species_organs/grey.dmi'
+ icon_state = "brain2"
+ mmi_icon = 'icons/obj/species_organs/grey.dmi'
+ mmi_icon_state = "mmi_full"
/obj/item/organ/internal/brain/grey/insert(var/mob/living/carbon/M, var/special = 0)
..()
@@ -15,4 +21,18 @@
/obj/item/organ/internal/eyes/grey
name = "grey eyeballs"
- dark_view = 5
\ No newline at end of file
+ desc = "They still look creepy and emotionless"
+ icon = 'icons/obj/species_organs/grey.dmi'
+ dark_view = 5
+
+/obj/item/organ/internal/heart/grey
+ name = "grey heart"
+ icon = 'icons/obj/species_organs/grey.dmi'
+
+/obj/item/organ/internal/lungs/grey
+ name = "grey lungs"
+ icon = 'icons/obj/species_organs/grey.dmi'
+
+/obj/item/organ/internal/kidneys/grey
+ name = "grey kidneys"
+ icon = 'icons/obj/species_organs/grey.dmi'
\ No newline at end of file
diff --git a/code/modules/surgery/organs/subtypes/kidan.dm b/code/modules/surgery/organs/subtypes/kidan.dm
index 72290fd624b..3778a7204cc 100644
--- a/code/modules/surgery/organs/subtypes/kidan.dm
+++ b/code/modules/surgery/organs/subtypes/kidan.dm
@@ -1,6 +1,9 @@
/obj/item/organ/internal/liver/kidan
+ name = "kidan liver"
+ icon = 'icons/obj/species_organs/kidan.dmi'
alcohol_intensity = 0.5
+
#define KIDAN_LANTERN_HUNGERCOST 0.5
#define KIDAN_LANTERN_MINHUNGER 150
#define KIDAN_LANTERN_LIGHT 5
@@ -8,6 +11,7 @@
/obj/item/organ/internal/lantern
name = "Bioluminescent Lantern"
desc = "A specialized tissue that reacts with oxygen, nutriment and blood to produce light in Kidan."
+ icon = 'icons/obj/species_organs/kidan.dmi'
icon_state = "kid_lantern"
origin_tech = "biotech=2"
w_class = WEIGHT_CLASS_TINY
@@ -107,6 +111,28 @@
. = ..()
+/obj/item/organ/internal/eyes/kidan
+ name = "kidan eyeballs"
+ icon = 'icons/obj/species_organs/kidan.dmi'
+
+/obj/item/organ/internal/heart/kidan
+ name = "kidan heart"
+ icon = 'icons/obj/species_organs/kidan.dmi'
+
+/obj/item/organ/internal/brain/kidan
+ icon = 'icons/obj/species_organs/kidan.dmi'
+ icon_state = "brain2"
+ mmi_icon = 'icons/obj/species_organs/kidan.dmi'
+ mmi_icon_state = "mmi_full"
+
+/obj/item/organ/internal/lungs/kidan
+ name = "kidan lungs"
+ icon = 'icons/obj/species_organs/kidan.dmi'
+
+/obj/item/organ/internal/kidneys/kidan
+ name = "kidan kidneys"
+ icon = 'icons/obj/species_organs/kidan.dmi'
+
#undef KIDAN_LANTERN_HUNGERCOST
#undef KIDAN_LANTERN_MINHUNGER
#undef KIDAN_LANTERN_LIGHT
\ No newline at end of file
diff --git a/code/modules/surgery/organs/subtypes/plasmaman.dm b/code/modules/surgery/organs/subtypes/plasmaman.dm
new file mode 100644
index 00000000000..3fd59189fb0
--- /dev/null
+++ b/code/modules/surgery/organs/subtypes/plasmaman.dm
@@ -0,0 +1,21 @@
+/obj/item/organ/internal/liver/plasmaman
+ name = "plasmaman liver"
+ icon = 'icons/obj/species_organs/plasmaman.dmi'
+
+/obj/item/organ/internal/eyes/plasmaman
+ name = "plasmaman eyeballs"
+ icon = 'icons/obj/species_organs/plasmaman.dmi'
+
+/obj/item/organ/internal/heart/plasmaman
+ name = "plasmaman heart"
+ icon = 'icons/obj/species_organs/plasmaman.dmi'
+
+/obj/item/organ/internal/brain/plasmaman
+ icon = 'icons/obj/species_organs/plasmaman.dmi'
+ icon_state = "brain2"
+ mmi_icon = 'icons/obj/species_organs/plasmaman.dmi'
+ mmi_icon_state = "mmi_full"
+
+/obj/item/organ/internal/kidneys/plasmaman
+ name = "plasmaman kidneys"
+ icon = 'icons/obj/species_organs/plasmaman.dmi'
\ No newline at end of file
diff --git a/code/modules/surgery/organs/subtypes/skrell.dm b/code/modules/surgery/organs/subtypes/skrell.dm
index 20eae88139c..0443fa4f49f 100644
--- a/code/modules/surgery/organs/subtypes/skrell.dm
+++ b/code/modules/surgery/organs/subtypes/skrell.dm
@@ -1,9 +1,12 @@
/obj/item/organ/internal/liver/skrell
+ name = "skrell liver"
+ icon = 'icons/obj/species_organs/skrell.dmi'
alcohol_intensity = 4
/obj/item/organ/internal/headpocket
name = "headpocket"
desc = "Allows Skrell to hide tiny objects within their head tentacles."
+ icon = 'icons/obj/species_organs/skrell.dmi'
icon_state = "skrell_headpocket"
origin_tech = "biotech=2"
w_class = WEIGHT_CLASS_TINY
@@ -59,3 +62,28 @@
/obj/item/organ/internal/headpocket/hear_message(mob/living/M as mob, msg)
pocket.hear_message(M, msg)
..()
+
+/obj/item/organ/internal/heart/skrell
+ name = "skrell heart"
+ desc = "A stream lined heart"
+ icon = 'icons/obj/species_organs/skrell.dmi'
+
+/obj/item/organ/internal/brain/skrell
+ icon = 'icons/obj/species_organs/skrell.dmi'
+ desc = "A brain with a odd division in the middle."
+ icon_state = "brain2"
+ mmi_icon = 'icons/obj/species_organs/skrell.dmi'
+ mmi_icon_state = "mmi_full"
+
+/obj/item/organ/internal/lungs/skrell
+ name = "skrell lungs"
+ icon = 'icons/obj/species_organs/skrell.dmi'
+
+/obj/item/organ/internal/kidneys/skrell
+ name = "skrell kidneys"
+ icon = 'icons/obj/species_organs/skrell.dmi'
+ desc = "The smallest kidneys you have ever seen, it probably doesn't even work."
+
+/obj/item/organ/internal/eyes/skrell
+ name = "skrell eyeballs"
+ icon = 'icons/obj/species_organs/skrell.dmi'
\ No newline at end of file
diff --git a/code/modules/surgery/organs/subtypes/tajaran.dm b/code/modules/surgery/organs/subtypes/tajaran.dm
index 1857fc5e45a..d6202a377e6 100644
--- a/code/modules/surgery/organs/subtypes/tajaran.dm
+++ b/code/modules/surgery/organs/subtypes/tajaran.dm
@@ -1,7 +1,10 @@
/obj/item/organ/internal/liver/tajaran
+ name = "tajaran liver"
+ icon = 'icons/obj/species_organs/tajaran.dmi'
alcohol_intensity = 1.4
/obj/item/organ/internal/eyes/tajaran
+ icon = 'icons/obj/species_organs/tajaran.dmi'
name = "tajaran eyeballs"
colourblind_matrix = MATRIX_TAJ_CBLIND //The colour matrix and darksight parameters that the mob will recieve when they get the disability.
replace_colours = LIST_TAJ_REPLACE
@@ -12,3 +15,21 @@
colourmatrix = MATRIX_TAJ_CBLIND
dark_view = 8
replace_colours = LIST_TAJ_REPLACE
+
+/obj/item/organ/internal/heart/tajaran
+ name = "tajaran heart"
+ icon = 'icons/obj/species_organs/tajaran.dmi'
+
+/obj/item/organ/internal/brain/tajaran
+ icon = 'icons/obj/species_organs/tajaran.dmi'
+ icon_state = "brain2"
+ mmi_icon = 'icons/obj/species_organs/tajaran.dmi'
+ mmi_icon_state = "mmi_full"
+
+/obj/item/organ/internal/lungs/tajaran
+ name = "tajaran lungs"
+ icon = 'icons/obj/species_organs/tajaran.dmi'
+
+/obj/item/organ/internal/kidneys/tajaran
+ name = "tajaran kidneys"
+ icon = 'icons/obj/species_organs/tajaran.dmi'
\ No newline at end of file
diff --git a/code/modules/surgery/organs/subtypes/unathi.dm b/code/modules/surgery/organs/subtypes/unathi.dm
index 219ef0447e6..26ad86d4700 100644
--- a/code/modules/surgery/organs/subtypes/unathi.dm
+++ b/code/modules/surgery/organs/subtypes/unathi.dm
@@ -1,6 +1,30 @@
/obj/item/organ/internal/liver/unathi
+ name = "unathi liver"
+ icon = 'icons/obj/species_organs/unathi.dmi'
+ desc = "A large looking liver"
alcohol_intensity = 0.8
/obj/item/organ/internal/eyes/unathi
name = "unathi eyeballs"
- dark_view = 3
\ No newline at end of file
+ icon = 'icons/obj/species_organs/unathi.dmi'
+ dark_view = 3
+
+/obj/item/organ/internal/heart/unathi
+ name = "unathi heart"
+ desc = "A large looking heart"
+ icon = 'icons/obj/species_organs/unathi.dmi'
+
+/obj/item/organ/internal/brain/unathi
+ icon = 'icons/obj/species_organs/unathi.dmi'
+ desc = "A smallish looking brain."
+ icon_state = "brain2"
+ mmi_icon = 'icons/obj/species_organs/unathi.dmi'
+ mmi_icon_state = "mmi_full"
+
+/obj/item/organ/internal/lungs/unathi
+ name = "unathi lungs"
+ icon = 'icons/obj/species_organs/unathi.dmi'
+
+/obj/item/organ/internal/kidneys/unathi
+ name = "unathi kidneys"
+ icon = 'icons/obj/species_organs/unathi.dmi'
\ No newline at end of file
diff --git a/code/modules/surgery/organs/subtypes/vox.dm b/code/modules/surgery/organs/subtypes/vox.dm
index 8af6f8bf740..e71393b964d 100644
--- a/code/modules/surgery/organs/subtypes/vox.dm
+++ b/code/modules/surgery/organs/subtypes/vox.dm
@@ -1,9 +1,12 @@
/obj/item/organ/internal/liver/vox
+ name = "vox liver"
+ icon = 'icons/obj/species_organs/vox.dmi'
alcohol_intensity = 1.6
/obj/item/organ/internal/stack
name = "cortical stack"
+ icon = 'icons/obj/species_organs/vox.dmi'
icon_state = "cortical-stack"
parent_organ = "head"
organ_tag = "stack"
@@ -29,4 +32,23 @@
owner.AdjustConfused(4)
if(!stackdamaged)
stackdamaged = TRUE
- ..()
\ No newline at end of file
+ ..()
+
+/obj/item/organ/internal/eyes/vox
+ name = "vox eyeballs"
+ icon = 'icons/obj/species_organs/vox.dmi'
+
+/obj/item/organ/internal/heart/vox
+ name = "vox heart"
+ icon = 'icons/obj/species_organs/vox.dmi'
+
+/obj/item/organ/internal/brain/vox
+ icon = 'icons/obj/species_organs/vox.dmi'
+ desc = "A brain with spikes on top of it. It has some odd metallic slot with wires on the side."
+ icon_state = "brain2"
+ mmi_icon = 'icons/obj/species_organs/vox.dmi'
+ mmi_icon_state = "mmi_full"
+
+/obj/item/organ/internal/kidneys/vox
+ name = "vox kidneys"
+ icon = 'icons/obj/species_organs/vox.dmi'
\ No newline at end of file
diff --git a/code/modules/surgery/organs/subtypes/vulpkanin.dm b/code/modules/surgery/organs/subtypes/vulpkanin.dm
index 959fbcc926c..2c583c8f84a 100644
--- a/code/modules/surgery/organs/subtypes/vulpkanin.dm
+++ b/code/modules/surgery/organs/subtypes/vulpkanin.dm
@@ -1,8 +1,11 @@
/obj/item/organ/internal/liver/vulpkanin
+ name = "vulpkanin liver"
+ icon = 'icons/obj/species_organs/vulpkanin.dmi'
alcohol_intensity = 1.4
/obj/item/organ/internal/eyes/vulpkanin
name = "vulpkanin eyeballs"
+ icon = 'icons/obj/species_organs/vulpkanin.dmi'
colourblind_matrix = MATRIX_VULP_CBLIND //The colour matrix and darksight parameters that the mob will recieve when they get the disability.
replace_colours = LIST_VULP_REPLACE
dark_view = 8
@@ -11,4 +14,22 @@
name = "wolpin eyeballs"
colourmatrix = MATRIX_VULP_CBLIND
dark_view = 8
- replace_colours = LIST_VULP_REPLACE
\ No newline at end of file
+ replace_colours = LIST_VULP_REPLACE
+
+/obj/item/organ/internal/heart/vulpkanin
+ name = "vulpkanin heart"
+ icon = 'icons/obj/species_organs/vulpkanin.dmi'
+
+/obj/item/organ/internal/brain/vulpkanin
+ icon = 'icons/obj/species_organs/vulpkanin.dmi'
+ icon_state = "brain2"
+ mmi_icon = 'icons/obj/species_organs/vulpkanin.dmi'
+ mmi_icon_state = "mmi_full"
+
+/obj/item/organ/internal/lungs/vulpkanin
+ name = "vulpkanin lungs"
+ icon = 'icons/obj/species_organs/vulpkanin.dmi'
+
+/obj/item/organ/internal/kidneys/vulpkanin
+ name = "vulpkanin kidneys"
+ icon = 'icons/obj/species_organs/vulpkanin.dmi'
\ No newline at end of file
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index 53691dd0264..46e4ee0c18b 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -57,10 +57,10 @@
origin_tech = "materials=1;biotech=1"
attack_verb = list("drilled")
- suicide_act(mob/user)
- to_chat(viewers(user), pick("[user] is pressing [src] to [user.p_their()] temple and activating it! It looks like [user.p_theyre()] trying to commit suicide.",
- "[user] is pressing [src] to [user.p_their()] chest and activating it! It looks like [user.p_theyre()] trying to commit suicide."))
- return (BRUTELOSS)
+/obj/item/surgicaldrill/suicide_act(mob/user)
+ to_chat(viewers(user), pick("[user] is pressing [src] to [user.p_their()] temple and activating it! It looks like [user.p_theyre()] trying to commit suicide.",
+ "[user] is pressing [src] to [user.p_their()] chest and activating it! It looks like [user.p_theyre()] trying to commit suicide."))
+ return BRUTELOSS
/obj/item/surgicaldrill/augment
desc = "Effectively a small power drill contained within your arm, edges dulled to prevent tissue damage. May or may not pierce the heavens."
@@ -87,11 +87,11 @@
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
hitsound = 'sound/weapons/bladeslice.ogg'
- suicide_act(mob/user)
- to_chat(viewers(user), pick("[user] is slitting [user.p_their()] wrists with [src]! It looks like [user.p_theyre()] trying to commit suicide.",
- "[user] is slitting [user.p_their()] throat with [src]! It looks like [user.p_theyre()] trying to commit suicide.",
- "[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku."))
- return (BRUTELOSS)
+/obj/item/scalpel/suicide_act(mob/user)
+ to_chat(viewers(user), pick("[user] is slitting [user.p_their()] wrists with [src]! It looks like [user.p_theyre()] trying to commit suicide.",
+ "[user] is slitting [user.p_their()] throat with [src]! It looks like [user.p_theyre()] trying to commit suicide.",
+ "[user] is slitting [user.p_their()] stomach open with [src]! It looks like [user.p_theyre()] trying to commit seppuku."))
+ return BRUTELOSS
/obj/item/scalpel/augment
diff --git a/config/example/config.txt b/config/example/config.txt
index ae6f9fefaa7..d93809c32cd 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -7,6 +7,9 @@ ADMIN_LEGACY_SYSTEM
## Add a # infront of this if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system.
BAN_LEGACY_SYSTEM
+## Add a # infront of this to unlimit the builds used to play. Advised is to keep it atleast 1421 due to the middle mouse button locking exploit
+MINIMUM_CLIENT_BUILD 1421
+
## Add a # here if you wish to use the setup where jobs have more access. This is intended for servers with low populations - where there are not enough players to fill all roles, so players need to do more than just one job. Also for servers where they don't want people to hide in their own departments.
JOBS_HAVE_MINIMAL_ACCESS
@@ -321,10 +324,10 @@ PLAYER_REROUTE_CAP 0
#DISABLE_SPACE_RUINS
## Minimum number of space ruins levels to generate
-EXTRA_SPACE_RUINS_LEVELS_MIN 2
+EXTRA_SPACE_RUIN_LEVELS_MIN 2
## Maximum number of space ruins levels to generate
-EXTRA_SPACE_RUINS_LEVELS_MAX 4
+EXTRA_SPACE_RUIN_LEVELS_MAX 4
## Uncomment to disable the OOC/LOOC channel by default.
#DISABLE_OOC
@@ -396,4 +399,7 @@ DISABLE_HIGH_POP_MC_MODE_AMOUNT 60
##DEVELOPER_EXPRESS_START
## Uncomment to disable automatic admin for localhost
-#DISABLE_LOCALHOST_ADMIN
\ No newline at end of file
+#DISABLE_LOCALHOST_ADMIN
+
+## Uncomment to give a confirmation before hitting start now
+#START_NOW_CONFIRMATION
\ No newline at end of file
diff --git a/config/example/game_options.txt b/config/example/game_options.txt
index 8a477dd6610..f934ba87b2b 100644
--- a/config/example/game_options.txt
+++ b/config/example/game_options.txt
@@ -1,10 +1,4 @@
### HEALTH ###
-## level of health at which a mob becomes unconscious (crit)
-HEALTH_THRESHOLD_CRIT -50
-
-## level of health at which a mob becomes dead
-HEALTH_THRESHOLD_DEAD -100
-
## Determines whether bones can be broken through excessive damage to the organ
## 0 means bones can't break, 1 means they can
BONES_CAN_BREAK 1
diff --git a/html/changelog.html b/html/changelog.html
index eeae1c1713d..d0fd0d59767 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -56,6 +56,457 @@
-->
+ 07 April 2019
+ Fox McCloud updated:
+
+ - Fixes Russian revolvers triggering no matter where you clicked
+
+ Kyep updated:
+
+ - Ghosting while alive, conscious, and a member of the crew will now result in your body being moved to cryo after 5 minutes, assuming your body isn't killed or restrained in any way in the meantime.
+ - An AI that ghosts while alive gets a dismissable hint that they might consider using OOC -> Wipe Core instead.
+ - Ghosting out of your body while you are alive, and an antag, will result in admins being informed, so that they may replace you as an antag if needed.
+
+
+ 06 April 2019
+ Fox McCloud updated:
+
+ - Fixes people popping out of cloning taking tons of damage
+ - Fixes Teslium recipe
+ - Fixes some reagents not causing status updates
+
+ Twinmold updated:
+
+ - No longer costs toner to send a fax to Central Command
+
+ dovydas12345 updated:
+
+ - Fixed diamond statue names and description.
+
+ farie82 updated:
+
+ - Sec huds work again. No longer does the perp need glasses to be set to arrest. Cool does not equal arrest now
+
+
+ 04 April 2019
+ Kyep updated:
+
+ - Improved the interface for Syndicate Uplinks. They now clearly mark which items are hijack-only and which are not. If you attempt to purchase a hijack-only item without hijack, they will explain why you can't.
+ - Atmos Gas Grenades (the uplink grenade kit) are now split into Knockout grenades (2 N2O grenades, 8 TC, available to all agents), and Plasma Fire grenades (2 plasma fire grenades, 12 TC, only available if you have hijack). This both makes knockout grenades more useful for normal traitors, and also prevents non-hijackers using a plasma fire grenade to cause massive casualties/damage.
+ - Plasma Grenades and the Syndicate Bomb can no longer show up in surplus crates, or be discounted. This means while you can buy one if you intend to, you're not randomly encouraged to bomb your target.
+
+
+ 03 April 2019
+ Fox McCloud updated:
+
+ - Dramatically improves human life performance (sorry, doesn't fix your actual crappy real life)
+ - Blobspores will additionally zomify all players who have 200 damage or more
+ - Holoparasites will additionally die once their host has 200 damage or more
+ - Fixes blob zombies who infect players who have no head being invisible
+
+ farie82 updated:
+
+ - Death nettle can be picked up again
+ - Auto cloning now doesn't clone a person more than once.
+ - A person in the cloning scanner won't be scanned if he's already being cloned
+
+
+ 02 April 2019
+ Alonefromhell & AffectedArc07 updated:
+
+ - Fixed an edgecase compile error for spacehotel.dmm
+
+ Arkatos updated:
+
+ - Added Medical Beamgun to a Syndicate Medical Cyborg
+ - Appropriate antagonist sound theme now plays when an antagonist is selected via Traitor Panel
+ - Cult sound theme now plays for a new cult converts
+ - Traitor/Malfunction sound theme now plays for newly autotraitored crew/AI
+
+ AzuleUtama updated:
+
+ - Cleaned up some outdated code left in uplinks.dm
+
+ Fox McCloud updated:
+
+ - Fixes some mobs not being able to hear sounds
+ - Fixes the Master Controller not actually shutting down on round end
+ - Adds space ants to the game; leave your food on tables or inside a container to avoid infestation!
+ - Fixes bees not properly generating if they have a reagent in them
+ - Can break bee boxes
+ - Fixes bees breaking things they shouldn't
+ - Fixes bees not properly injecting toxin if they lacked a reagent
+ - purchased bee boxes are no longer wrenched down by default
+ - Adds trick revolver to the syndicate uplink for the clown. Teach those pesky validhunters a lesson!
+ - Adds the ability for admins to start a revolver only summon gun version; there's also a suicidal version that makes half the guns summoned real and the other half trick revolvers
+ - stabilizing agent gets used up in reactions that utilize it
+ - flashbangs spark when they initially go off
+ - Fixes mech users being stunned by their own flashbangs
+ - Fixes necromantic stone not working properly and other edge cases where you had O2 damage and could become O2 damage immune
+
+ KasparoVy updated:
+
+ - Adds Vox-fitted Tajaran veil sprites.
+ - Removed stray pixel from Vox-fitted gasmask sprites.
+ - Adjusts the Vox-fitted blindfold sprite.
+
+ Kyep updated:
+
+ - Blob mobs can definitely no longer be spawned in xenobio.
+ - Changed playtime requirements for command jobs. HoS/RD/CE/CMO/AI now require 5h played in their department to be playable. HoP/Captain now require 5h played as a member of the command staff.
+
+ Markolie updated:
+
+ - Fixed some issues the compiler doesn't spot and some start up issues.
+
+ Ty-Omaha updated:
+
+ - Start now confirmation is now a config option
+ - Grid check event sound effect
+
+ farie82 updated:
+
+ - Antidrop give edge case fixed
+ - Can't give items to resting people now
+ - put_in_hands now checks if you actually have hands
+ - Wrapping lockers and crates now takes 1.5 seconds to do
+ - Welding lockers now takes 1.5 seconds to do
+
+
+ 01 April 2019
+ Arkatos updated:
+
+ - New Blob UI buttons for Storage Blob and Split consciousness abilities
+ - New custom icons for Storage Blob and Split consciousness abilities
+ - Added Node Requirement verb to the Blob. This verb, which is activated by default, enforces that resource and factory blob structures are built in a close proximity of the core/node in order to properly function. Players can disable it anytime in the Blob tab.
+ - Remove Blob verb now has a new feature - partial refund for special Blob structures. When Blob Overmind removes special blob structure (such as a factory or node), it will receive 30% of the structure cost back as a refund.
+ - Blob Overminds now show in Check Antagonists admin verb
+ - Blob Mobs now use complementary colors of the Blob Overmind reagent as their own color
+ - Removed Dark Matter from a list of possible Blob reagents
+
+ Fox McCloud updated:
+
+ - Fixes syndicate medborgs and regular medborgs not having handheld defibs
+ - Fixes multi-tile airlocks breaking and not leaving behind an assembly
+ - Updates the Timer SS
+ - Roundstart ChemMasters are now constructable/deconstructable
+ - Can upgrade ChemMasters. Larger beakers mean a larger reservoir
+ - Mobs that are gibbed with strange reagent and GBS have a bit more of a dramatic flare to them with violent convulsions before exploding into tiny bits
+
+ Ty-Omaha updated:
+
+ - Modified alert sounds for Code Gamma and Code Epsilon.
+
+ dovydas12345 updated:
+
+ - Fixes AI's toggle floor bolts ability
+
+ farie82 updated:
+
+ - Bluespace golems no longer can crash the server
+ - Spontaneous combustion now has a minimum stacksize of 1. No more getting wet from the fire virus
+
+
+ 30 March 2019
+ Fox McCloud updated:
+
+ - Fixes a runtime involving decapitation
+ - playing sounds performs better
+
+ Ty-Omaha updated:
+
+ - Removes SSD sleep bubbles from ghosts
+
+
+ 29 March 2019
+ Arkatos updated:
+
+ - Fixes #11087 - Swarmers are now locked to their default action intent
+ - Swarmers are now able to open airlocks and windoors (access restrictions still apply)
+ - Added new Wizard item - Bottle of Ooze! This powerful item awakens all-consuming Morph, ready to eat everyone and everything on the station! Be careful though, as Morph diet also includes Wizards.. Costs 1 point in the spellbook.
+ - Added custom icon for Bottle of Ooze
+ - Morph introduction is now properly formatted
+ - Added new Blob UI and icons, ported from /tg/station13
+ - Added new *Blob Help* verb, designated to help out new players playing as Blob
+ - Added descriptions for each Blob reagent
+ - Added complementary colors for each Blob reagent
+ - Blob marker now uses complementary color of Blob reagent as it's own color
+ - Blob shortcuts updated. Blob shortcuts are now: Click = Expand Blob | CTRL Click = Create Shield Blob | Middle Mouse Click = Rally Spores | Alt Click = Remove Blob
+
+ Fox McCloud updated:
+
+ - Crit has been dramatically overhauled. Treating patients now requires a broader range of medicine. Recommend checking out a guide for how to treat using the new system!
+ - Medical vendors now have styptic and silver sulfadiazine, saline, atropine, mannitol, mutadone, calomel, diphenhydramine, oculine, insulin, morphine, and potassium iodide for helping treat new patients. Amount of Gauze, Advanced Trauma, and Burn packs has also been increased.
+ - Adds new handheld defibs. Utilize these for treating patients with cardiac arrest. Note: these do not revive people from the dead!
+ - Doctors lockers now have a handheld defib in addition to a regular defib.
+ - Medical borgs now have a handheld defib
+ - CPR dramatically buffed. Heavily lowers O2 damage and resets losebreath to 0
+ - Cryoxadone tuned down a little
+ - Health analyzer UI altered ever so slightly for cardiac arerest, so it's easier to find
+ - Added bacon grease reagent to traitor poison bottles; induces immediate cardiac failure
+ - Upgraded Robotic Hearts now attempt to correct both cardiac failure and cardiac arrest tweak; Upgraded Robotic Hearts now do not punish you quite as severely for receiving a shock while having one (EMPs will still destroy you though)
+ - Corazone recipe removed
+ - hotspot sprites updated; fire will also now appear over top of things, rather than underneath it
+ - Roundstart chem dispensers are now construcable/deconstrucable and can be moved
+ - Energy ratio for chem dispensers increased by x10 (how many reagents you can dispense before running out and how quickly it recharges is all the same, however)
+ - Adds the ability to add a single unit of reagent in the chem dispenser
+ - Adds the ability to isolate reagents in the chem dispenser
+ - Portable chem dispenser removed (the circuit board for them now makes full dispensers)
+ - Fixes some suicides dealing damage and gibbing you at the same time
+ - Allows you to suicide with more object types. Currently the only new object type you can suicide with is the gibber
+
+ Kyep updated:
+
+ - Blob mobs can no longer be spawned in xenobio.
+ - Blob mobs spawned by blob cores can no longer have sentience potions used on them, which would allow whoever controls them to kill the blob with no countermeasure.
+
+ Mitchs98 updated:
+
+ - Adds in Shrimp & Fish Skewers as well as Cheeseburgers. Shrimp Skewer(Grill): 4 Shrimp(uncooked) + 1 Metal Rod, Fish Skewer(Grill): 2 Salmon Meat + Metal Rod + 10u Flour, Cheese Burger(Microwave): Burger + Cheese Wedge.
+
+ farie82 updated:
+
+ - Borgs can now only cuff people with two hands. Just like humanoids
+ - You can cuff people with at least one hand now
+
+ ingles98 updated:
+
+ - Plasma Golems will now report their suicide acts to the Admins.
+
+
+ 25 March 2019
+ Fox McCloud updated:
+
+ - Fixes some reagent performance edges cases
+ - Fixes chem smoke lagging under some circumstances
+ - Fixes smoke not wanting to garbage collect
+ - Fixes flares not returning a qdel hint
+ - Fixes hotspots being slow to ignite turfs around them
+ - Fixes LINDA not conducting temperature through things.
+
+ Mitchs98 updated:
+
+ - Chitinous Mass is no longer weaponized lag if examined.
+
+ farie82 updated:
+
+ - Diona nymphs are grabbable and punchable again
+
+
+ 24 March 2019
+ AffectedArc07 updated:
+
+ - Preferences are now in alphabetical order
+
+ AzuleUtama updated:
+
+ - Added Syndicate MMI for Roboticist Traitors, priced at 2TC. balance: Removed Syndicate MMI from the traitor surgery duffelbag. Price reduced to 2TC.
+
+ EmanTheAlmighty updated:
+
+ - Can no longer offer Gateway Terror Spiders sentience potions. ( They literally exploded if you did, and that could have been used to effortlessly clear out hordes of them. )
+ - Using the Shadowling ability "Hatch" as a monkey will change your HUD to be the human one.
+ - It is now possible to put a collar on any animal that has gained sentience.
+
+ Fox McCloud updated:
+
+ - Pills maximum size increased from 50 to 100
+ - Chem Master bottle size increased from 30 to 50
+ - Pill bottles can now hold 50 pills instead of 14
+ - Pill bottles can no longer hold patches
+ - Adds Patch Boxes, which can hold patches, but not pills
+ - Can now use a pill bottle or patch box on someone to apply a pill/patch from the bottle/box to a mob. Usual delays will still apply
+ - Can down an entire pill bottle at once!
+ - Cryostylane and pyrosium reactions now consume 2 of themselves when exposed to oxygen
+ - fires, temperature, and hotspots can heat anything that contains reagents
+ - Having hot/cold chemicals dumped on you or ingesting them will hurt you. Wear a mask or hat to protect from having someone dump the hot/cold things on you.
+ - Chem Heater temperature adjustment tweaked; can no longer set temperature on empty containers.
+ - Chem Heater generally heats faster, but cannot be upgraded
+ - Chem Heater automatically stops around target temperature
+ - Adjusts fire stacks and how they're applied with a few chems. Naplam, Phlogiston, fuel, thermite, and a few others have all received changes. Most direct fire damage removed.
+ - Adds phlogiston dust; a safer, cooler burning Phlogiston.
+ - Water and Firefighting foam will no longer automagically put out mob based fires; they'll reduce fire stacks (when fire stacks hit 0 they put the mob out)
+ - cryostylane puts out mobs instantly
+ - Heating fuel can set it off. Be careful when heating it now
+ - Increased welding fuel tank size from 1000 to 4000 (wall mounted are still 1000)
+ - Sorium and Dark matter now actually throw things
+ - Thermite now gets applied to turfs. You'll have to heat the turf up to ignite it. Anything that can heat can now ignite thermite on walls
+ - Adds fake hotspots. They don't do anything except set you on fire when you cross into them. Chemistry's pyrotechnics use these, for the most part; anything that causes a fireball that's chemistry related uses these
+ - Sorium and Liquid dark matter now have visual effects
+ - Fixes chem smoke being on the wrong layer.
+ - Adds in unidentified tank filled with an unknown experimental gas in deep space. Find it and experiment!
+
+ Tails2091 updated:
+
+ - New emotes to Cats and Corgis.
+ - Change directories for some creature sounds to be in the creature sound folder.
+ - Two bark sounds, a yelp, and a meow.
+
+ farie82 updated:
+
+ - Holo firedoors now update atmos correctly after being destroyed
+ - Inflatable walls/doors now update atmos correctly after being destroyed
+ - Alien resin walls now update atmos correctly after being destroyed
+ - Foamed metal walls now update atmos correctly after being destroyed
+ - Pod doors (shouldn't ever happen) now update atmos correctly after being destroyed
+ - Mining flaps now update atmos correctly after being destroyed
+
+
+ 23 March 2019
+ Arkatos updated:
+
+ - Players who enable AntagHUD are now unable to join the round as swarmers
+ - Adds a message explaining why Antag-banned players cannot join the round as cortical borer
+
+ Calecute updated:
+
+ - South Prison camera now belongs to Prison camera network, thus showind in Prison camera monitor
+
+ Kyep updated:
+
+ - Admins offering control of a mob with no real_name to ghosts will no longer cause a "Do you want to play as ?" popup. Instead, the ? will be replaced with a descriptive string, such as "the blobbernaut".
+
+ Tails2091 updated:
+
+ - Lockboxes actually close when locked now.
+
+ farie82 updated:
+
+ - When disarming a bomb from a guardian you now don't pickup an empty object.
+ - no more organ: spam sorry admins
+
+
+ 22 March 2019
+ Arkatos updated:
+
+ - Updated Tarot Deck description in Wizard's spellbook, credits to /tg/station13
+
+ Fox McCloud updated:
+
+ - Smoke now has much better sprites and has a new area of denial behavior
+
+ Mitchs98 updated:
+
+ - Fixed Dionae names so "Embrace of Starsong (as Embrace Of Starsong)" will no longer happen when renaming ID's at a ID Console.
+
+ Quantum-M updated:
+
+ - Vox Cargo Crate - Contains two vox tanks and two vox masks. Costs 50 cargo points.
+ - Plasmaman Cargo Crate - Contains a Orange plasmaman space suit and helmet, along with a breathing mask and a emergency plasmaman tank. Costs 75 cargo points and requires EVA access.
+
+
+ 20 March 2019
+ Dave-TH updated:
+
+ - Krav Maga gloves can no longer steal the unstealable.
+
+ farie82 updated:
+
+ - Fixed the middle mousebutton locking exploit
+
+
+ 17 March 2019
+ AffectedArc07 and Alonefromhell updated:
+
+ - Cell management consoles: See the status of all brig cells without having to leave your office
+ - New screen sprite for cell management console
+
+ Jazz23 updated:
+
+ - Xenobio hotkeys, slime potion thing, remote slime scanner, monkey recycler linking.
+
+ Kyep updated:
+
+ - It is no longer possible to crawl into a vent while you are simultaneously buckled to a chair or other solid object.
+
+ farie82 updated:
+
+ - Adds a confirmation to the start now verb. Make it ansari proof
+ - The invisible bumping into something should be fixed now
+ - Fixes the atmos bug
+
+
+ 16 March 2019
+ Ty-Omaha and Ionward updated:
+
+ - Carbon humans (people, not animals) who go SSD will now get ZZZ bubbles to indicate they are SSD
+
+
+ 15 March 2019
+ Arkatos updated:
+
+ - Fixes #10987 - Guardians can now see the action intent they are on
+ - Added custom action intent icons for Guardians
+
+ Couls updated:
+
+ - Added a new line to the defib examine text
+
+
+ 14 March 2019
+ Couls updated:
+
+ - tweaked shesi's fluff sprite
+
+ Quantum-M updated:
+
+ - Changes the stamp sprites.
+ - Add new sprites for the infernal and employment contracts.
+ - Different organ sprites for each species
+ - Different MMI sprites based on different species brains.
+
+
+ 13 March 2019
+ Couls updated:
+
+ - universal translate no longer makes emotes over comms impossible
+ - fixed a few typos with simple mobs
+
+
+ 12 March 2019
+ Arkatos updated:
+
+ - Fixes #10261 - Pure Vampires in Traitor+Vampire gamemode will now properly show in AntagHUD
+ - Fixes #9494 - Pure Changelings in Traitor+Changeling gamemode will now properly show in AntagHUD
+
+
+ 11 March 2019
+ Couls updated:
+
+ - Display if karma gains are enabled or not on round start(instead of just disabled)
+ - Fix wrong message when toggling karma
+
+ rb303 updated:
+
+ - Fluff scarf for Rb303
+
+
+ 10 March 2019
+ AffectedArc07 updated:
+
+ - You will now automatically be given admin rights if you connect to your local server
+ - Mapmerge has been replaced with mapmerge2
+ - Maps are now the TGM format. This means nothing for people who do not make map edits
+ - Discord-related verbs are now under "Special Verbs" instead of "OOC"
+
+ Couls updated:
+
+ - Toggle karma button in special verbs
+
+ Kyep updated:
+
+ - Admins can now flag characters as having an event role, which makes them show up when admins look at the antag list, in admin attack logs, on antaghuds, and on the end-round score screen.
+
+ Tails2091 updated:
+
+ - Added missing simple_animal emote help text.
+
+ TheMadTrickster updated:
+
+ - added new fixed nice sprites
+ - trashed old ugly buggy sprites
+
+
08 March 2019
AzuleUtama updated:
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 7c1992386ec..d6bd92e8040 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -9321,3 +9321,392 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Jazz23:
- tweak: Golems loose their shell when they switch species
- rscadd: Mousedrop applies slime speed/chill potions.
+2019-03-10:
+ AffectedArc07:
+ - rscadd: You will now automatically be given admin rights if you connect to your
+ local server
+ - tweak: Mapmerge has been replaced with mapmerge2
+ - tweak: Maps are now the TGM format. This means nothing for people who do not make
+ map edits
+ - tweak: Discord-related verbs are now under "Special Verbs" instead of "OOC"
+ Couls:
+ - rscadd: Toggle karma button in special verbs
+ Kyep:
+ - rscadd: Admins can now flag characters as having an event role, which makes them
+ show up when admins look at the antag list, in admin attack logs, on antaghuds,
+ and on the end-round score screen.
+ Tails2091:
+ - rscadd: Added missing simple_animal emote help text.
+ TheMadTrickster:
+ - rscadd: added new fixed nice sprites
+ - rscdel: trashed old ugly buggy sprites
+2019-03-11:
+ Couls:
+ - tweak: Display if karma gains are enabled or not on round start(instead of just
+ disabled)
+ - bugfix: Fix wrong message when toggling karma
+ rb303:
+ - rscadd: Fluff scarf for Rb303
+2019-03-12:
+ Arkatos:
+ - bugfix: 'Fixes #10261 - Pure Vampires in Traitor+Vampire gamemode will now properly
+ show in AntagHUD'
+ - bugfix: 'Fixes #9494 - Pure Changelings in Traitor+Changeling gamemode will now
+ properly show in AntagHUD'
+2019-03-13:
+ Couls:
+ - tweak: universal translate no longer makes emotes over comms impossible
+ - spellcheck: fixed a few typos with simple mobs
+2019-03-14:
+ Couls:
+ - tweak: tweaked shesi's fluff sprite
+ Quantum-M:
+ - tweak: Changes the stamp sprites.
+ - imageadd: Add new sprites for the infernal and employment contracts.
+ - imageadd: Different organ sprites for each species
+ - imageadd: Different MMI sprites based on different species brains.
+2019-03-15:
+ Arkatos:
+ - bugfix: 'Fixes #10987 - Guardians can now see the action intent they are on'
+ - rscadd: Added custom action intent icons for Guardians
+ Couls:
+ - rscadd: Added a new line to the defib examine text
+2019-03-16:
+ Ty-Omaha and Ionward:
+ - rscadd: Carbon humans (people, not animals) who go SSD will now get ZZZ bubbles
+ to indicate they are SSD
+2019-03-17:
+ AffectedArc07 and Alonefromhell:
+ - rscadd: 'Cell management consoles: See the status of all brig cells without having
+ to leave your office'
+ - imageadd: New screen sprite for cell management console
+ Jazz23:
+ - rscadd: Xenobio hotkeys, slime potion thing, remote slime scanner, monkey recycler
+ linking.
+ Kyep:
+ - bugfix: It is no longer possible to crawl into a vent while you are simultaneously
+ buckled to a chair or other solid object.
+ farie82:
+ - tweak: Adds a confirmation to the start now verb. Make it ansari proof
+ - bugfix: The invisible bumping into something should be fixed now
+ - bugfix: Fixes the atmos bug
+2019-03-20:
+ Dave-TH:
+ - bugfix: Krav Maga gloves can no longer steal the unstealable.
+ farie82:
+ - bugfix: Fixed the middle mousebutton locking exploit
+2019-03-22:
+ Arkatos:
+ - tweak: Updated Tarot Deck description in Wizard's spellbook, credits to /tg/station13
+ Fox McCloud:
+ - rscadd: Smoke now has much better sprites and has a new area of denial behavior
+ Mitchs98:
+ - bugfix: Fixed Dionae names so "Embrace of Starsong (as Embrace Of Starsong)" will
+ no longer happen when renaming ID's at a ID Console.
+ Quantum-M:
+ - rscadd: Vox Cargo Crate - Contains two vox tanks and two vox masks. Costs 50 cargo
+ points.
+ - rscadd: Plasmaman Cargo Crate - Contains a Orange plasmaman space suit and helmet,
+ along with a breathing mask and a emergency plasmaman tank. Costs 75 cargo points
+ and requires EVA access.
+2019-03-23:
+ Arkatos:
+ - bugfix: Players who enable AntagHUD are now unable to join the round as swarmers
+ - rscadd: Adds a message explaining why Antag-banned players cannot join the round
+ as cortical borer
+ Calecute:
+ - bugfix: South Prison camera now belongs to Prison camera network, thus showind
+ in Prison camera monitor
+ Kyep:
+ - bugfix: Admins offering control of a mob with no real_name to ghosts will no longer
+ cause a "Do you want to play as ?" popup. Instead, the ? will be replaced with
+ a descriptive string, such as "the blobbernaut".
+ Tails2091:
+ - bugfix: Lockboxes actually close when locked now.
+ farie82:
+ - bugfix: When disarming a bomb from a guardian you now don't pickup an empty object.
+ - bugfix: 'no more organ: spam sorry admins'
+2019-03-24:
+ AffectedArc07:
+ - tweak: Preferences are now in alphabetical order
+ AzuleUtama:
+ - rscadd: 'Added Syndicate MMI for Roboticist Traitors, priced at 2TC. balance:
+ Removed Syndicate MMI from the traitor surgery duffelbag. Price reduced to 2TC.'
+ EmanTheAlmighty:
+ - tweak: Can no longer offer Gateway Terror Spiders sentience potions. ( They literally
+ exploded if you did, and that could have been used to effortlessly clear out
+ hordes of them. )
+ - tweak: Using the Shadowling ability "Hatch" as a monkey will change your HUD to
+ be the human one.
+ - tweak: It is now possible to put a collar on any animal that has gained sentience.
+ Fox McCloud:
+ - tweak: Pills maximum size increased from 50 to 100
+ - tweak: Chem Master bottle size increased from 30 to 50
+ - tweak: Pill bottles can now hold 50 pills instead of 14
+ - rscdel: Pill bottles can no longer hold patches
+ - rscadd: Adds Patch Boxes, which can hold patches, but not pills
+ - rscadd: Can now use a pill bottle or patch box on someone to apply a pill/patch
+ from the bottle/box to a mob. Usual delays will still apply
+ - rscadd: Can down an entire pill bottle at once!
+ - tweak: Cryostylane and pyrosium reactions now consume 2 of themselves when exposed
+ to oxygen
+ - rscadd: fires, temperature, and hotspots can heat anything that contains reagents
+ - rscadd: Having hot/cold chemicals dumped on you or ingesting them will hurt you.
+ Wear a mask or hat to protect from having someone dump the hot/cold things on
+ you.
+ - tweak: Chem Heater temperature adjustment tweaked; can no longer set temperature
+ on empty containers.
+ - tweak: Chem Heater generally heats faster, but cannot be upgraded
+ - tweak: Chem Heater automatically stops around target temperature
+ - tweak: Adjusts fire stacks and how they're applied with a few chems. Naplam, Phlogiston,
+ fuel, thermite, and a few others have all received changes. Most direct fire
+ damage removed.
+ - rscadd: Adds phlogiston dust; a safer, cooler burning Phlogiston.
+ - tweak: Water and Firefighting foam will no longer automagically put out mob based
+ fires; they'll reduce fire stacks (when fire stacks hit 0 they put the mob out)
+ - tweak: cryostylane puts out mobs instantly
+ - tweak: Heating fuel can set it off. Be careful when heating it now
+ - tweak: Increased welding fuel tank size from 1000 to 4000 (wall mounted are still
+ 1000)
+ - tweak: Sorium and Dark matter now actually throw things
+ - tweak: Thermite now gets applied to turfs. You'll have to heat the turf up to
+ ignite it. Anything that can heat can now ignite thermite on walls
+ - rscadd: Adds fake hotspots. They don't do anything except set you on fire when
+ you cross into them. Chemistry's pyrotechnics use these, for the most part;
+ anything that causes a fireball that's chemistry related uses these
+ - rscadd: Sorium and Liquid dark matter now have visual effects
+ - bugfix: Fixes chem smoke being on the wrong layer.
+ - rscadd: Adds in unidentified tank filled with an unknown experimental gas in deep
+ space. Find it and experiment!
+ Tails2091:
+ - rscadd: New emotes to Cats and Corgis.
+ - tweak: Change directories for some creature sounds to be in the creature sound
+ folder.
+ - soundadd: Two bark sounds, a yelp, and a meow.
+ farie82:
+ - bugfix: Holo firedoors now update atmos correctly after being destroyed
+ - bugfix: Inflatable walls/doors now update atmos correctly after being destroyed
+ - bugfix: Alien resin walls now update atmos correctly after being destroyed
+ - bugfix: Foamed metal walls now update atmos correctly after being destroyed
+ - bugfix: Pod doors (shouldn't ever happen) now update atmos correctly after being
+ destroyed
+ - bugfix: Mining flaps now update atmos correctly after being destroyed
+2019-03-25:
+ Fox McCloud:
+ - bugfix: Fixes some reagent performance edges cases
+ - bugfix: Fixes chem smoke lagging under some circumstances
+ - bugfix: Fixes smoke not wanting to garbage collect
+ - bugfix: Fixes flares not returning a qdel hint
+ - bugfix: Fixes hotspots being slow to ignite turfs around them
+ - bugfix: Fixes LINDA not conducting temperature through things.
+ Mitchs98:
+ - bugfix: Chitinous Mass is no longer weaponized lag if examined.
+ farie82:
+ - bugfix: Diona nymphs are grabbable and punchable again
+2019-03-29:
+ Arkatos:
+ - bugfix: 'Fixes #11087 - Swarmers are now locked to their default action intent'
+ - tweak: Swarmers are now able to open airlocks and windoors (access restrictions
+ still apply)
+ - rscadd: Added new Wizard item - Bottle of Ooze! This powerful item awakens all-consuming
+ Morph, ready to eat everyone and everything on the station! Be careful though,
+ as Morph diet also includes Wizards.. Costs 1 point in the spellbook.
+ - imageadd: Added custom icon for Bottle of Ooze
+ - tweak: Morph introduction is now properly formatted
+ - rscadd: Added new Blob UI and icons, ported from /tg/station13
+ - rscadd: Added new *Blob Help* verb, designated to help out new players playing
+ as Blob
+ - rscadd: Added descriptions for each Blob reagent
+ - rscadd: Added complementary colors for each Blob reagent
+ - tweak: Blob marker now uses complementary color of Blob reagent as it's own color
+ - tweak: 'Blob shortcuts updated. Blob shortcuts are now: Click = Expand Blob |
+ CTRL Click = Create Shield Blob | Middle Mouse Click = Rally Spores | Alt Click
+ = Remove Blob'
+ Fox McCloud:
+ - rscadd: Crit has been dramatically overhauled. Treating patients now requires
+ a broader range of medicine. Recommend checking out a guide for how to treat
+ using the new system!
+ - rscadd: Medical vendors now have styptic and silver sulfadiazine, saline, atropine,
+ mannitol, mutadone, calomel, diphenhydramine, oculine, insulin, morphine, and
+ potassium iodide for helping treat new patients. Amount of Gauze, Advanced Trauma,
+ and Burn packs has also been increased.
+ - rscadd: 'Adds new handheld defibs. Utilize these for treating patients with cardiac
+ arrest. Note: these do not revive people from the dead!'
+ - rscadd: Doctors lockers now have a handheld defib in addition to a regular defib.
+ - rscadd: Medical borgs now have a handheld defib
+ - tweak: CPR dramatically buffed. Heavily lowers O2 damage and resets losebreath
+ to 0
+ - tweak: Cryoxadone tuned down a little
+ - tweak: Health analyzer UI altered ever so slightly for cardiac arerest, so it's
+ easier to find
+ - rscadd: Added bacon grease reagent to traitor poison bottles; induces immediate
+ cardiac failure
+ - tweak: Upgraded Robotic Hearts now attempt to correct both cardiac failure and
+ cardiac arrest tweak; Upgraded Robotic Hearts now do not punish you quite as
+ severely for receiving a shock while having one (EMPs will still destroy you
+ though)
+ - rscdel: Corazone recipe removed
+ - tweak: hotspot sprites updated; fire will also now appear over top of things,
+ rather than underneath it
+ - rscadd: Roundstart chem dispensers are now construcable/deconstrucable and can
+ be moved
+ - tweak: Energy ratio for chem dispensers increased by x10 (how many reagents you
+ can dispense before running out and how quickly it recharges is all the same,
+ however)
+ - rscadd: Adds the ability to add a single unit of reagent in the chem dispenser
+ - rscadd: Adds the ability to isolate reagents in the chem dispenser
+ - rscdel: Portable chem dispenser removed (the circuit board for them now makes
+ full dispensers)
+ - bugfix: Fixes some suicides dealing damage and gibbing you at the same time
+ - rscadd: Allows you to suicide with more object types. Currently the only new object
+ type you can suicide with is the gibber
+ Kyep:
+ - tweak: Blob mobs can no longer be spawned in xenobio.
+ - tweak: Blob mobs spawned by blob cores can no longer have sentience potions used
+ on them, which would allow whoever controls them to kill the blob with no countermeasure.
+ Mitchs98:
+ - rscadd: 'Adds in Shrimp & Fish Skewers as well as Cheeseburgers. Shrimp Skewer(Grill):
+ 4 Shrimp(uncooked) + 1 Metal Rod, Fish Skewer(Grill): 2 Salmon Meat + Metal
+ Rod + 10u Flour, Cheese Burger(Microwave): Burger + Cheese Wedge.'
+ farie82:
+ - bugfix: Borgs can now only cuff people with two hands. Just like humanoids
+ - tweak: You can cuff people with at least one hand now
+ ingles98:
+ - bugfix: Plasma Golems will now report their suicide acts to the Admins.
+2019-03-30:
+ Fox McCloud:
+ - bugfix: Fixes a runtime involving decapitation
+ - tweak: playing sounds performs better
+ Ty-Omaha:
+ - tweak: Removes SSD sleep bubbles from ghosts
+2019-04-01:
+ Arkatos:
+ - rscadd: New Blob UI buttons for Storage Blob and Split consciousness abilities
+ - imageadd: New custom icons for Storage Blob and Split consciousness abilities
+ - rscadd: Added Node Requirement verb to the Blob. This verb, which is activated
+ by default, enforces that resource and factory blob structures are built in
+ a close proximity of the core/node in order to properly function. Players can
+ disable it anytime in the Blob tab.
+ - rscadd: Remove Blob verb now has a new feature - partial refund for special Blob
+ structures. When Blob Overmind removes special blob structure (such as a factory
+ or node), it will receive 30% of the structure cost back as a refund.
+ - tweak: Blob Overminds now show in Check Antagonists admin verb
+ - tweak: Blob Mobs now use complementary colors of the Blob Overmind reagent as
+ their own color
+ - rscdel: Removed Dark Matter from a list of possible Blob reagents
+ Fox McCloud:
+ - bugfix: Fixes syndicate medborgs and regular medborgs not having handheld defibs
+ - bugfix: Fixes multi-tile airlocks breaking and not leaving behind an assembly
+ - tweak: Updates the Timer SS
+ - rscadd: Roundstart ChemMasters are now constructable/deconstructable
+ - tweak: Can upgrade ChemMasters. Larger beakers mean a larger reservoir
+ - rscadd: Mobs that are gibbed with strange reagent and GBS have a bit more of a
+ dramatic flare to them with violent convulsions before exploding into tiny bits
+ Ty-Omaha:
+ - tweak: Modified alert sounds for Code Gamma and Code Epsilon.
+ dovydas12345:
+ - bugfix: Fixes AI's toggle floor bolts ability
+ farie82:
+ - bugfix: Bluespace golems no longer can crash the server
+ - tweak: Spontaneous combustion now has a minimum stacksize of 1. No more getting
+ wet from the fire virus
+2019-04-02:
+ Alonefromhell & AffectedArc07:
+ - bugfix: Fixed an edgecase compile error for spacehotel.dmm
+ Arkatos:
+ - rscadd: Added Medical Beamgun to a Syndicate Medical Cyborg
+ - tweak: Appropriate antagonist sound theme now plays when an antagonist is selected
+ via Traitor Panel
+ - tweak: Cult sound theme now plays for a new cult converts
+ - tweak: Traitor/Malfunction sound theme now plays for newly autotraitored crew/AI
+ AzuleUtama:
+ - tweak: Cleaned up some outdated code left in uplinks.dm
+ Fox McCloud:
+ - bugfix: Fixes some mobs not being able to hear sounds
+ - bugfix: Fixes the Master Controller not actually shutting down on round end
+ - rscadd: Adds space ants to the game; leave your food on tables or inside a container
+ to avoid infestation!
+ - bugfix: Fixes bees not properly generating if they have a reagent in them
+ - rscadd: Can break bee boxes
+ - bugfix: Fixes bees breaking things they shouldn't
+ - bugfix: Fixes bees not properly injecting toxin if they lacked a reagent
+ - tweak: purchased bee boxes are no longer wrenched down by default
+ - rscadd: Adds trick revolver to the syndicate uplink for the clown. Teach those
+ pesky validhunters a lesson!
+ - rscadd: Adds the ability for admins to start a revolver only summon gun version;
+ there's also a suicidal version that makes half the guns summoned real and the
+ other half trick revolvers
+ - tweak: stabilizing agent gets used up in reactions that utilize it
+ - tweak: flashbangs spark when they initially go off
+ - bugfix: Fixes mech users being stunned by their own flashbangs
+ - bugfix: Fixes necromantic stone not working properly and other edge cases where
+ you had O2 damage and could become O2 damage immune
+ KasparoVy:
+ - rscadd: Adds Vox-fitted Tajaran veil sprites.
+ - rscdel: Removed stray pixel from Vox-fitted gasmask sprites.
+ - tweak: Adjusts the Vox-fitted blindfold sprite.
+ Kyep:
+ - bugfix: Blob mobs can definitely no longer be spawned in xenobio.
+ - tweak: Changed playtime requirements for command jobs. HoS/RD/CE/CMO/AI now require
+ 5h played in their department to be playable. HoP/Captain now require 5h played
+ as a member of the command staff.
+ Markolie:
+ - bugfix: Fixed some issues the compiler doesn't spot and some start up issues.
+ Ty-Omaha:
+ - tweak: Start now confirmation is now a config option
+ - rscadd: Grid check event sound effect
+ farie82:
+ - bugfix: Antidrop give edge case fixed
+ - bugfix: Can't give items to resting people now
+ - bugfix: put_in_hands now checks if you actually have hands
+ - tweak: Wrapping lockers and crates now takes 1.5 seconds to do
+ - tweak: Welding lockers now takes 1.5 seconds to do
+2019-04-03:
+ Fox McCloud:
+ - bugfix: Dramatically improves human life performance (sorry, doesn't fix your
+ actual crappy real life)
+ - tweak: Blobspores will additionally zomify all players who have 200 damage or
+ more
+ - tweak: Holoparasites will additionally die once their host has 200 damage or more
+ - bugfix: Fixes blob zombies who infect players who have no head being invisible
+ farie82:
+ - bugfix: Death nettle can be picked up again
+ - bugfix: Auto cloning now doesn't clone a person more than once.
+ - tweak: A person in the cloning scanner won't be scanned if he's already being
+ cloned
+2019-04-04:
+ Kyep:
+ - tweak: Improved the interface for Syndicate Uplinks. They now clearly mark which
+ items are hijack-only and which are not. If you attempt to purchase a hijack-only
+ item without hijack, they will explain why you can't.
+ - tweak: Atmos Gas Grenades (the uplink grenade kit) are now split into Knockout
+ grenades (2 N2O grenades, 8 TC, available to all agents), and Plasma Fire grenades
+ (2 plasma fire grenades, 12 TC, only available if you have hijack). This both
+ makes knockout grenades more useful for normal traitors, and also prevents non-hijackers
+ using a plasma fire grenade to cause massive casualties/damage.
+ - tweak: Plasma Grenades and the Syndicate Bomb can no longer show up in surplus
+ crates, or be discounted. This means while you can buy one if you intend to,
+ you're not randomly encouraged to bomb your target.
+2019-04-06:
+ Fox McCloud:
+ - bugfix: Fixes people popping out of cloning taking tons of damage
+ - bugfix: Fixes Teslium recipe
+ - bugfix: Fixes some reagents not causing status updates
+ Twinmold:
+ - bugfix: No longer costs toner to send a fax to Central Command
+ dovydas12345:
+ - spellcheck: Fixed diamond statue names and description.
+ farie82:
+ - bugfix: Sec huds work again. No longer does the perp need glasses to be set to
+ arrest. Cool does not equal arrest now
+2019-04-07:
+ Fox McCloud:
+ - bugfix: Fixes Russian revolvers triggering no matter where you clicked
+ Kyep:
+ - rscadd: Ghosting while alive, conscious, and a member of the crew will now result
+ in your body being moved to cryo after 5 minutes, assuming your body isn't killed
+ or restrained in any way in the meantime.
+ - rscadd: An AI that ghosts while alive gets a dismissable hint that they might
+ consider using OOC -> Wipe Core instead.
+ - rscadd: Ghosting out of your body while you are alive, and an antag, will result
+ in admins being informed, so that they may replace you as an antag if needed.
diff --git a/html/changelogs/AutoChangeLog-pr-10975.yml b/html/changelogs/AutoChangeLog-pr-10975.yml
deleted file mode 100644
index cf52ab8307d..00000000000
--- a/html/changelogs/AutoChangeLog-pr-10975.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "AffectedArc07"
-delete-after: True
-changes:
- - rscadd: "You will now automatically be given admin rights if you connect to your local server"
diff --git a/html/changelogs/AutoChangeLog-pr-10978.yml b/html/changelogs/AutoChangeLog-pr-10978.yml
deleted file mode 100644
index c7c72ef7a0a..00000000000
--- a/html/changelogs/AutoChangeLog-pr-10978.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "AffectedArc07"
-delete-after: True
-changes:
- - tweak: "Mapmerge has been replaced with mapmerge2"
- - tweak: "Maps are now the TGM format. This means nothing for people who do not make map edits"
diff --git a/html/changelogs/AutoChangeLog-pr-10989.yml b/html/changelogs/AutoChangeLog-pr-10989.yml
deleted file mode 100644
index 47ebfdbf015..00000000000
--- a/html/changelogs/AutoChangeLog-pr-10989.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "AffectedArc07"
-delete-after: True
-changes:
- - tweak: "Discord-related verbs are now under \"Special Verbs\" instead of \"OOC\""
diff --git a/html/changelogs/AutoChangeLog-pr-10996.yml b/html/changelogs/AutoChangeLog-pr-10996.yml
deleted file mode 100644
index 864311e9d1d..00000000000
--- a/html/changelogs/AutoChangeLog-pr-10996.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Couls"
-delete-after: True
-changes:
- - rscadd: "Toggle karma button in special verbs"
diff --git a/html/changelogs/AutoChangeLog-pr-11006.yml b/html/changelogs/AutoChangeLog-pr-11006.yml
deleted file mode 100644
index 16e49ace14f..00000000000
--- a/html/changelogs/AutoChangeLog-pr-11006.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Kyep"
-delete-after: True
-changes:
- - rscadd: "Admins can now flag characters as having an event role, which makes them show up when admins look at the antag list, in admin attack logs, on antaghuds, and on the end-round score screen."
diff --git a/html/changelogs/AutoChangeLog-pr-11026.yml b/html/changelogs/AutoChangeLog-pr-11026.yml
new file mode 100644
index 00000000000..aa1d9fa5b04
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11026.yml
@@ -0,0 +1,5 @@
+author: "farie82"
+delete-after: True
+changes:
+ - rscadd: "Gives you the option to disable text popup spam. Aka if enabled you won't get popups after you pressed T and had a lagspike and you typed a sentence containing a lot of T's. Default is off"
+ - tweak: "Now checks if OOC and LOOC are enabled before showing the popup"
diff --git a/html/changelogs/AutoChangeLog-pr-11096.yml b/html/changelogs/AutoChangeLog-pr-11096.yml
new file mode 100644
index 00000000000..d21076abf65
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11096.yml
@@ -0,0 +1,7 @@
+author: "Arkatos"
+delete-after: True
+changes:
+ - tweak: "Guardians can no longer change action intents on their own"
+ - bugfix: "Fixes #10900 - Guardians can no longer attack their host while inside them"
+ - rscadd: "Explosive and Support Guardians now get precise cooldown shown (instead of just static estimate) before their bomb and beacon abitilites are ready to be used again, respectively"
+ - tweak: "HARM action intent icon for Guardians updated"
diff --git a/html/changelogs/AutoChangeLog-pr-11161.yml b/html/changelogs/AutoChangeLog-pr-11161.yml
new file mode 100644
index 00000000000..50cb5f843ce
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11161.yml
@@ -0,0 +1,9 @@
+author: "Kyep"
+delete-after: True
+changes:
+ - bugfix: "Empress of terror (admin-only mob) is no longer incorrectly prevented from laying brown spider eggs."
+ - tweak: "Admins are now able to spawn a queen of terror in a room without a vent. Previously, queens would not allow this. Now, this just results in an alert to admins (since its probably a mistake) and deactivates the mob AI (but leaves it available for player control)."
+ - rscadd: "If there are player controlled terror spiders, admins using check antags panel will now be able to see eggs/spiderlings currently growing on the station. These counters only count eggs/spiderlings on station, and ignore fake spiderlings."
+ - bugfix: "Empress of terror's 'erase brood' ability no longer incorrectly causes mothers of terror to spawn spiderlings on death.
+sprite: Empress of terror now has its own sprite."
+ - tweak: "White spider infections have been nerfed a bit. They no longer provide passive healing or increase infection progress while their host/victim is in crit. Also, the first spiderling to emerge from an infection can no longer be a green. Finally, the eggs now self-delete after the third spiderling emerges, so even in the event they aren't treated with surgery, the host isn't left with confused movement forever."
diff --git a/html/changelogs/AutoChangeLog-pr-11182.yml b/html/changelogs/AutoChangeLog-pr-11182.yml
new file mode 100644
index 00000000000..a6b762c2d10
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11182.yml
@@ -0,0 +1,4 @@
+author: "Arkatos"
+delete-after: True
+changes:
+ - tweak: "Shadowling Glare ability reworked - The further Shadowling is from their glared target, the shorter stun their target gets. Stuns also have a delay before they kick in, based on the distance, however targets will be slowed and muted before stun takes effect. Targets on the tile just next to them are still stunned and muted for 10 seconds without any delay."
diff --git a/icons/atmos/tank.dmi b/icons/atmos/tank.dmi
index bf98899fb8e..3a6e2031cbc 100644
Binary files a/icons/atmos/tank.dmi and b/icons/atmos/tank.dmi differ
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 95099bb00f3..97256ff448a 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/goonstation/effects/64x64.dmi b/icons/goonstation/effects/64x64.dmi
new file mode 100644
index 00000000000..17910cfdfb1
Binary files /dev/null and b/icons/goonstation/effects/64x64.dmi differ
diff --git a/icons/goonstation/effects/effects.dmi b/icons/goonstation/effects/effects.dmi
new file mode 100644
index 00000000000..8f38e42718e
Binary files /dev/null and b/icons/goonstation/effects/effects.dmi differ
diff --git a/icons/goonstation/effects/fire.dmi b/icons/goonstation/effects/fire.dmi
index 48a1f9b90e6..03d0de0e38d 100644
Binary files a/icons/goonstation/effects/fire.dmi and b/icons/goonstation/effects/fire.dmi differ
diff --git a/icons/goonstation/mob/inhands/items_lefthand.dmi b/icons/goonstation/mob/inhands/items_lefthand.dmi
index 042c15f279b..cb8d5d66284 100644
Binary files a/icons/goonstation/mob/inhands/items_lefthand.dmi and b/icons/goonstation/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/goonstation/mob/inhands/items_righthand.dmi b/icons/goonstation/mob/inhands/items_righthand.dmi
index 051f205bac7..1698af9855e 100644
Binary files a/icons/goonstation/mob/inhands/items_righthand.dmi and b/icons/goonstation/mob/inhands/items_righthand.dmi differ
diff --git a/icons/goonstation/objects/objects.dmi b/icons/goonstation/objects/objects.dmi
index 8dadb400668..99ddeac3d10 100644
Binary files a/icons/goonstation/objects/objects.dmi and b/icons/goonstation/objects/objects.dmi differ
diff --git a/icons/mob/actions/actions.dmi b/icons/mob/actions/actions.dmi
index 08e645c5c9b..d21323c80b1 100644
Binary files a/icons/mob/actions/actions.dmi and b/icons/mob/actions/actions.dmi differ
diff --git a/icons/mob/blob.dmi b/icons/mob/blob.dmi
index 56c39b9a75d..4797c79496e 100644
Binary files a/icons/mob/blob.dmi and b/icons/mob/blob.dmi differ
diff --git a/icons/mob/guardian.dmi b/icons/mob/guardian.dmi
index b318bba573d..a10e1e0b0ec 100644
Binary files a/icons/mob/guardian.dmi and b/icons/mob/guardian.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 73df78f3f11..4cdf9b38920 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index f8f6ea63db1..68ebe9f6e91 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ
diff --git a/icons/mob/inhands/equipment/instruments_lefthand.dmi b/icons/mob/inhands/equipment/instruments_lefthand.dmi
index e88c8da2d1c..4ffaa7d8c05 100644
Binary files a/icons/mob/inhands/equipment/instruments_lefthand.dmi and b/icons/mob/inhands/equipment/instruments_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/instruments_righthand.dmi b/icons/mob/inhands/equipment/instruments_righthand.dmi
index 7b783c726e8..68899a4a7db 100644
Binary files a/icons/mob/inhands/equipment/instruments_righthand.dmi and b/icons/mob/inhands/equipment/instruments_righthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 3efddb08c4b..fe096499427 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/mob/species/vox/eyes.dmi b/icons/mob/species/vox/eyes.dmi
index 99ee47ac1fa..3d9a6c77bf8 100644
Binary files a/icons/mob/species/vox/eyes.dmi and b/icons/mob/species/vox/eyes.dmi differ
diff --git a/icons/mob/species/vox/mask.dmi b/icons/mob/species/vox/mask.dmi
index 7022c296574..971978ccff4 100644
Binary files a/icons/mob/species/vox/mask.dmi and b/icons/mob/species/vox/mask.dmi differ
diff --git a/icons/mob/sprite_accessories/human/human_hair.dmi b/icons/mob/sprite_accessories/human/human_hair.dmi
index 05a0b030052..4534c797cc3 100644
Binary files a/icons/mob/sprite_accessories/human/human_hair.dmi and b/icons/mob/sprite_accessories/human/human_hair.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 6463ef602b2..fdbea753a29 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/mob/terrorspider64.dmi b/icons/mob/terrorspider64.dmi
new file mode 100644
index 00000000000..392ad43b3a7
Binary files /dev/null and b/icons/mob/terrorspider64.dmi differ
diff --git a/icons/mob/ties.dmi b/icons/mob/ties.dmi
index db92d8c21a6..b7d3b243994 100644
Binary files a/icons/mob/ties.dmi and b/icons/mob/ties.dmi differ
diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi
index 56620c267b1..adf304513c7 100644
Binary files a/icons/obj/bureaucracy.dmi and b/icons/obj/bureaucracy.dmi differ
diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi
index f692814d18c..9c9f6d38e94 100644
Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index 3004a130246..418f221c78f 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 7a728d811c3..a3e93ba32af 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/computer.dmi b/icons/obj/computer.dmi
index c51b8d7050b..ac416274ebe 100644
Binary files a/icons/obj/computer.dmi and b/icons/obj/computer.dmi differ
diff --git a/icons/obj/custom_items.dmi b/icons/obj/custom_items.dmi
index 1dae65d3237..e1ca3d3380e 100644
Binary files a/icons/obj/custom_items.dmi and b/icons/obj/custom_items.dmi differ
diff --git a/icons/obj/species_organs/drask.dmi b/icons/obj/species_organs/drask.dmi
new file mode 100644
index 00000000000..95915450fcc
Binary files /dev/null and b/icons/obj/species_organs/drask.dmi differ
diff --git a/icons/obj/species_organs/grey.dmi b/icons/obj/species_organs/grey.dmi
new file mode 100644
index 00000000000..647febdc67b
Binary files /dev/null and b/icons/obj/species_organs/grey.dmi differ
diff --git a/icons/obj/species_organs/kidan.dmi b/icons/obj/species_organs/kidan.dmi
new file mode 100644
index 00000000000..8969d64c669
Binary files /dev/null and b/icons/obj/species_organs/kidan.dmi differ
diff --git a/icons/obj/species_organs/plasmaman.dmi b/icons/obj/species_organs/plasmaman.dmi
new file mode 100644
index 00000000000..e5b19f5d3a6
Binary files /dev/null and b/icons/obj/species_organs/plasmaman.dmi differ
diff --git a/icons/obj/species_organs/skrell.dmi b/icons/obj/species_organs/skrell.dmi
new file mode 100644
index 00000000000..998370f7344
Binary files /dev/null and b/icons/obj/species_organs/skrell.dmi differ
diff --git a/icons/obj/species_organs/tajaran.dmi b/icons/obj/species_organs/tajaran.dmi
new file mode 100644
index 00000000000..673e5d29a4e
Binary files /dev/null and b/icons/obj/species_organs/tajaran.dmi differ
diff --git a/icons/obj/species_organs/unathi.dmi b/icons/obj/species_organs/unathi.dmi
new file mode 100644
index 00000000000..018816c4068
Binary files /dev/null and b/icons/obj/species_organs/unathi.dmi differ
diff --git a/icons/obj/species_organs/vox.dmi b/icons/obj/species_organs/vox.dmi
new file mode 100644
index 00000000000..cb9626fa9ff
Binary files /dev/null and b/icons/obj/species_organs/vox.dmi differ
diff --git a/icons/obj/species_organs/vulpkanin.dmi b/icons/obj/species_organs/vulpkanin.dmi
new file mode 100644
index 00000000000..42d1338a8e1
Binary files /dev/null and b/icons/obj/species_organs/vulpkanin.dmi differ
diff --git a/icons/obj/surgery_drask.dmi b/icons/obj/surgery_drask.dmi
deleted file mode 100644
index 082d3e0f4f2..00000000000
Binary files a/icons/obj/surgery_drask.dmi and /dev/null differ
diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi
index 108e5603b25..07c8be38ed9 100644
Binary files a/icons/obj/wizard.dmi and b/icons/obj/wizard.dmi differ
diff --git a/nano/templates/brig_cells.tmpl b/nano/templates/brig_cells.tmpl
new file mode 100644
index 00000000000..652c8926378
--- /dev/null
+++ b/nano/templates/brig_cells.tmpl
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+ | Cell |
+ Occupant |
+ Crimes |
+ Brigged By |
+ Time Brigged For |
+ Time Left |
+ Release |
+
+
+
+ {{for data.cells}}
+
+ | {{:value.cell_id}} |
+ {{:value.occupant}} |
+ {{:value.crimes}} |
+ {{:value.brigged_by}} |
+ {{:value.time_set}} |
+ {{:value.time_left}} |
+ {{:helper.link('Release', null, {'release' : value.ref}, null, 'infoButton')}} |
+
+ {{/for}}
+
+
+
+
\ No newline at end of file
diff --git a/nano/templates/chem_dispenser.tmpl b/nano/templates/chem_dispenser.tmpl
index f8988e35e43..74d694530c9 100644
--- a/nano/templates/chem_dispenser.tmpl
+++ b/nano/templates/chem_dispenser.tmpl
@@ -16,6 +16,7 @@ Used In File(s): \code\modules\reagents\Chemistry-Machinery.dm
Dispense:
+ {{:helper.link('1', 'gear', {'amount' : 1}, (data.amount == 1) ? 'selected' : null)}}
{{:helper.link('5', 'gear', {'amount' : 5}, (data.amount == 5) ? 'selected' : null)}}
{{:helper.link('10', 'gear', {'amount' : 10}, (data.amount == 10) ? 'selected' : null)}}
{{:helper.link('20', 'gear', {'amount' : 20}, (data.amount == 20) ? 'selected' : null)}}
@@ -70,6 +71,7 @@ Used In File(s): \code\modules\reagents\Chemistry-Machinery.dm
+ {{:helper.link('Isolate', null, {'remove' : value.id, 'removeamount' : -1})}}
{{:helper.link('1', null, {'remove' : value.id, 'removeamount' : 1})}}
{{:helper.link('5', null, {'remove' : value.id, 'removeamount' : 5})}}
{{:helper.link('10', null, {'remove' : value.id, 'removeamount' : 10})}}
diff --git a/nano/templates/chem_master.tmpl b/nano/templates/chem_master.tmpl
index 1ccfcadfe70..385237727db 100644
--- a/nano/templates/chem_master.tmpl
+++ b/nano/templates/chem_master.tmpl
@@ -42,7 +42,7 @@
|
- {{:helper.link('Create pill (50u max)', 'arrow-right', {'createpill': 1})}}
+ {{:helper.link('Create pill (100u max)', 'arrow-right', {'createpill': 1})}}
|
{{:helper.link('Multiple', 'arrow-right', {'createpill_multiple': 1})}}
@@ -64,7 +64,7 @@
|
|
- {{:helper.link('Create bottle (30u max)', 'arrow-right', {'createbottle': 1})}}
+ {{:helper.link('Create bottle (50u max)', 'arrow-right', {'createbottle': 1})}}
|
{{:helper.link('Style', 'pencil', {'change_bottle': 1})}}
diff --git a/nano/templates/uplink.tmpl b/nano/templates/uplink.tmpl
index c67dbca9c61..3058bb10bbb 100644
--- a/nano/templates/uplink.tmpl
+++ b/nano/templates/uplink.tmpl
@@ -46,7 +46,7 @@ Used In File(s): \code\game\objects\items\devices\uplinks.dm
{{for value.items :itemValue:itemIndex}}
|
- {{:helper.link( itemValue.Name, 'gear', {'buy_item' : itemValue.obj_path, 'cost' : itemValue.Cost}, itemValue.Cost > data.crystals ? 'disabled' : null, null)}} - {{:itemValue.Cost}}
+ {{:helper.link( itemValue.Name, 'gear', {'buy_item' : itemValue.obj_path, 'cost' : itemValue.Cost}, itemValue.Cost > data.crystals ? 'disabled' : null, null)}} - {{:itemValue.Cost}} {{if itemValue.hijack_only}}(HIJACK AGENTS ONLY){{/if}}
|
{{/for}}
diff --git a/paradise.dme b/paradise.dme
index efa75177cce..b22da751ecc 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -131,6 +131,7 @@
#include "code\_onclick\hud\alert.dm"
#include "code\_onclick\hud\alien.dm"
#include "code\_onclick\hud\alien_larva.dm"
+#include "code\_onclick\hud\blob_overmind.dm"
#include "code\_onclick\hud\bot.dm"
#include "code\_onclick\hud\constructs.dm"
#include "code\_onclick\hud\devil.dm"
@@ -279,6 +280,7 @@
#include "code\datums\diseases\brainrot.dm"
#include "code\datums\diseases\cold.dm"
#include "code\datums\diseases\cold9.dm"
+#include "code\datums\diseases\critical.dm"
#include "code\datums\diseases\fake_gbs.dm"
#include "code\datums\diseases\flu.dm"
#include "code\datums\diseases\fluspanish.dm"
@@ -665,6 +667,7 @@
#include "code\game\machinery\computer\arcade.dm"
#include "code\game\machinery\computer\atmos_alert.dm"
#include "code\game\machinery\computer\atmos_control.dm"
+#include "code\game\machinery\computer\brigcells.dm"
#include "code\game\machinery\computer\buildandrepair.dm"
#include "code\game\machinery\computer\camera.dm"
#include "code\game\machinery\computer\camera_advanced.dm"
@@ -786,6 +789,7 @@
#include "code\game\objects\effects\decals\Cleanable\robots.dm"
#include "code\game\objects\effects\decals\Cleanable\tracks.dm"
#include "code\game\objects\effects\effect_system\effect_system.dm"
+#include "code\game\objects\effects\effect_system\effects_chem_smoke.dm"
#include "code\game\objects\effects\effect_system\effects_explosion.dm"
#include "code\game\objects\effects\effect_system\effects_foam.dm"
#include "code\game\objects\effects\effect_system\effects_other.dm"
@@ -829,6 +833,7 @@
#include "code\game\objects\items\devices\flash.dm"
#include "code\game\objects\items\devices\flashlight.dm"
#include "code\game\objects\items\devices\floor_painter.dm"
+#include "code\game\objects\items\devices\handheld_defib.dm"
#include "code\game\objects\items\devices\instruments.dm"
#include "code\game\objects\items\devices\laserpointer.dm"
#include "code\game\objects\items\devices\lightreplacer.dm"
@@ -1731,9 +1736,9 @@
#include "code\modules\mob\living\carbon\human\inventory.dm"
#include "code\modules\mob\living\carbon\human\life.dm"
#include "code\modules\mob\living\carbon\human\login.dm"
+#include "code\modules\mob\living\carbon\human\logout.dm"
#include "code\modules\mob\living\carbon\human\npcs.dm"
#include "code\modules\mob\living\carbon\human\say.dm"
-#include "code\modules\mob\living\carbon\human\shock.dm"
#include "code\modules\mob\living\carbon\human\status_procs.dm"
#include "code\modules\mob\living\carbon\human\update_icons.dm"
#include "code\modules\mob\living\carbon\human\update_stat.dm"
@@ -2351,6 +2356,7 @@
#include "code\modules\surgery\organs\subtypes\kidan.dm"
#include "code\modules\surgery\organs\subtypes\machine.dm"
#include "code\modules\surgery\organs\subtypes\nucleation.dm"
+#include "code\modules\surgery\organs\subtypes\plasmaman.dm"
#include "code\modules\surgery\organs\subtypes\shadow.dm"
#include "code\modules\surgery\organs\subtypes\skrell.dm"
#include "code\modules\surgery\organs\subtypes\standard.dm"
diff --git a/sound/Attributions.txt b/sound/Attributions.txt
index 262699e9c3f..729562855ba 100644
--- a/sound/Attributions.txt
+++ b/sound/Attributions.txt
@@ -1 +1,5 @@
-items/thermal_drill.ogg was sampled from Builders Drilling.wav under a Sampling Plus 1.0 license. It was uploaded by Koops on 2010-05-10. Source (http://soundbible.com/1420-Builders-Drilling.html)
\ No newline at end of file
+items/thermal_drill.ogg was sampled from Builders Drilling.wav under a Sampling Plus 1.0 license. It was uploaded by Koops on 2010-05-10. Source (http://soundbible.com/1420-Builders-Drilling.html)
+
+ambience/aurora_caelus.ogg is Music for Manatees by Kevin Macleod. It is under a CC-BY 3.0 license. It has been cropped and fades out.
+
+creatures/dog_yelp.ogg is DogYelp.wav. It is under a CC-BY 3.0 license. It has been cropped, EQ'd, and compressed to .ogg. Source (https://freesound.org/people/TobiasKosmos/sounds/163280/)
\ No newline at end of file
diff --git a/sound/ambience/license.txt b/sound/ambience/license.txt
deleted file mode 100644
index 5376422f21f..00000000000
--- a/sound/ambience/license.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-aurora_caelus.ogg is Music for Manatees, by Kevin Macleod. It has been licensed under CC-BY 3.0 license.
- It has been cropped for use ingame, and also fades out.
\ No newline at end of file
diff --git a/sound/creatures/cat_meow.ogg b/sound/creatures/cat_meow.ogg
new file mode 100644
index 00000000000..f52cbd2a172
Binary files /dev/null and b/sound/creatures/cat_meow.ogg differ
diff --git a/sound/misc/caw.ogg b/sound/creatures/caw.ogg
similarity index 100%
rename from sound/misc/caw.ogg
rename to sound/creatures/caw.ogg
diff --git a/sound/creatures/dog_bark1.ogg b/sound/creatures/dog_bark1.ogg
new file mode 100644
index 00000000000..809f3897c88
Binary files /dev/null and b/sound/creatures/dog_bark1.ogg differ
diff --git a/sound/creatures/dog_bark2.ogg b/sound/creatures/dog_bark2.ogg
new file mode 100644
index 00000000000..e4e27b0f862
Binary files /dev/null and b/sound/creatures/dog_bark2.ogg differ
diff --git a/sound/creatures/dog_yelp.ogg b/sound/creatures/dog_yelp.ogg
new file mode 100644
index 00000000000..22f1586014d
Binary files /dev/null and b/sound/creatures/dog_yelp.ogg differ
diff --git a/sound/misc/hoot.ogg b/sound/creatures/hoot.ogg
similarity index 100%
rename from sound/misc/hoot.ogg
rename to sound/creatures/hoot.ogg
diff --git a/sound/effects/mousesqueek.ogg b/sound/creatures/mousesqueak.ogg
similarity index 100%
rename from sound/effects/mousesqueek.ogg
rename to sound/creatures/mousesqueak.ogg
diff --git a/sound/misc/nymphchirp.ogg b/sound/creatures/nymphchirp.ogg
similarity index 100%
rename from sound/misc/nymphchirp.ogg
rename to sound/creatures/nymphchirp.ogg
diff --git a/sound/effects/new_siren.ogg b/sound/effects/new_siren.ogg
new file mode 100644
index 00000000000..24c4ecca9a1
Binary files /dev/null and b/sound/effects/new_siren.ogg differ
diff --git a/sound/effects/powerloss.ogg b/sound/effects/powerloss.ogg
new file mode 100644
index 00000000000..9a0835ecdb6
Binary files /dev/null and b/sound/effects/powerloss.ogg differ
diff --git a/strings/chemistry_tools.json b/strings/chemistry_tools.json
index 4a079102a69..5bf45fc6e58 100644
--- a/strings/chemistry_tools.json
+++ b/strings/chemistry_tools.json
@@ -468,6 +468,7 @@
"prions",
"spidereggs",
"concentrated_initro",
- "heartworms"
+ "heartworms",
+ "bacon_grease"
]
}
diff --git a/tools/mapmerge2/README.md b/tools/mapmerge2/README.md
index 1cd29510100..0ff4d21ac2e 100644
--- a/tools/mapmerge2/README.md
+++ b/tools/mapmerge2/README.md
@@ -13,17 +13,20 @@ version of the map while maintaining all the actual changes. It requires an old
version of the map to use as a reference and a new version of the map which
contains the desired changes.
-## Installation/Usage
+## Installation
-To install Python dependencies, run `Install Requirements.bat`
+To install Python dependencies, run `requirements-install.bat`, or run
+`python -m pip install -r requirements.txt` directly. See the [Git hooks]
+documentation to install the Git pre-commit hook which runs the map merger
+automatically, or use `tools/mapmerge/Prepare Maps.bat` to save backups before
+running `mapmerge.bat`.
-**BEFORE** making a map edit, run `Prepare Maps.bat` to create your backups. *These are required to run mapmerge successfully.*
-
-**AFTER** you have made your edit, run `Run Mapmerge.bat` to merge the maps.
+For up-to-date installation and detailed troubleshooting instructions, visit
+the [Map Merger] wiki article.
## Code Structure
-All the scripts are inside the `/src/` folder. Frontend scripts are meant to be run directly. They obey the environment
+Frontend scripts are meant to be run directly. They obey the environment
variables `TGM` to set whether files are saved in TGM (1) or DMM (0) format,
and `MAPROOT` to determine where maps are kept. By default, TGM is used and
the map root is autodetected. Each script may either prompt for the desired map
@@ -31,12 +34,19 @@ or be run with command-line parameters indicating which maps to act on. The
scripts include:
* `convert.py` for converting maps to and from the TGM format. Used by
- `Convert DMM to TGM.bat` and `Convert TGM to DMM.bat`.
+ `tgm2dmm.bat` and `dmm2tgm.bat`.
* `mapmerge.py` for running the map merge on map backups saved by
- `Prepare Maps.bat`. Used by `Run Mapmerge.bat`
+ `Prepare Maps.bat`. Used by `mapmerge.bat`
Implementation modules:
* `dmm.py` includes the map reader and writer.
* `mapmerge.py` includes the implementation of the map merge operation.
* `frontend.py` includes the common code for the frontend scripts.
+
+`precommit.py` is run by the [Git hooks] if installed, and merges the new
+version of any map saved in the index (`git add`ed) with the old version stored
+in Git when run.
+
+[Map Merger]: https://tgstation13.org/wiki/Map_Merger
+[Git hooks]: ../hooks/README.md
diff --git a/tools/mapmerge2/src/convert.py b/tools/mapmerge2/convert.py
similarity index 100%
rename from tools/mapmerge2/src/convert.py
rename to tools/mapmerge2/convert.py
diff --git a/tools/mapmerge2/dmi.py b/tools/mapmerge2/dmi.py
new file mode 100644
index 00000000000..f0a8182c9f0
--- /dev/null
+++ b/tools/mapmerge2/dmi.py
@@ -0,0 +1,253 @@
+# Tools for working with modern DreamMaker icon files (PNGs + metadata)
+
+import math
+from PIL import Image
+from PIL.PngImagePlugin import PngInfo
+
+DEFAULT_SIZE = 32, 32
+LOOP_UNLIMITED = 0
+LOOP_ONCE = 1
+
+NORTH = 1
+SOUTH = 2
+EAST = 4
+WEST = 8
+SOUTHEAST = SOUTH|EAST
+SOUTHWEST = SOUTH|WEST
+NORTHEAST = NORTH|EAST
+NORTHWEST = NORTH|WEST
+
+CARDINALS = [NORTH, SOUTH, EAST, WEST]
+DIR_ORDER = [SOUTH, NORTH, EAST, WEST, SOUTHEAST, SOUTHWEST, NORTHEAST, NORTHWEST]
+DIR_NAMES = {
+ 'SOUTH': SOUTH,
+ 'NORTH': NORTH,
+ 'EAST': EAST,
+ 'WEST': WEST,
+ 'SOUTHEAST': SOUTHEAST,
+ 'SOUTHWEST': SOUTHWEST,
+ 'NORTHEAST': NORTHEAST,
+ 'NORTHWEST': NORTHWEST,
+ **{str(x): x for x in DIR_ORDER},
+ **{x: x for x in DIR_ORDER},
+ '0': SOUTH,
+ None: SOUTH,
+}
+
+class Dmi:
+ version = "4.0"
+
+ def __init__(self, width, height):
+ self.width = width
+ self.height = height
+ self.states = []
+
+ @classmethod
+ def from_file(cls, fname):
+ image = Image.open(fname)
+
+ # no metadata = regular image file
+ if 'Description' not in image.info:
+ dmi = Dmi(*image.size)
+ state = dmi.state("")
+ state.frame(image)
+ return dmi
+
+ # read metadata
+ metadata = image.info['Description']
+ line_iter = iter(metadata.splitlines())
+ assert next(line_iter) == "# BEGIN DMI"
+ assert next(line_iter) == f"version = {cls.version}"
+
+ dmi = Dmi(*DEFAULT_SIZE)
+ state = None
+
+ for line in line_iter:
+ if line == "# END DMI":
+ break
+ key, value = line.lstrip().split(" = ")
+ if key == 'width':
+ dmi.width = int(value)
+ elif key == 'height':
+ dmi.height = int(value)
+ elif key == 'state':
+ state = dmi.state(unescape(value))
+ elif key == 'dirs':
+ state.dirs = int(value)
+ elif key == 'frames':
+ state._nframes = int(value)
+ elif key == 'delay':
+ state.delays = [parse_num(x) for x in value.split(',')]
+ elif key == 'loop':
+ state.loop = int(value)
+ elif key == 'rewind':
+ state.rewind = parse_bool(value)
+ elif key == 'hotspot':
+ x, y, frm = [int(x) for x in value.split(',')]
+ state.hotspot(frm - 1, x, y)
+ elif key == 'movement':
+ state.movement = parse_bool(value)
+ else:
+ raise NotImplementedError(key)
+
+ # cut image into frames
+ width, height = image.size
+ gridwidth = width // dmi.width
+ i = 0
+ for state in dmi.states:
+ for frame in range(state._nframes):
+ for dir in range(state.dirs):
+ px = dmi.width * (i % gridwidth)
+ py = dmi.height * (i // gridwidth)
+ im = image.crop((px, py, px + dmi.width, py + dmi.height))
+ assert im.size == (dmi.width, dmi.height)
+ state.frames.append(im)
+ i += 1
+ state._nframes = None
+
+ return dmi
+
+ def state(self, *args, **kwargs):
+ s = State(self, *args, **kwargs)
+ self.states.append(s)
+ return s
+
+ @property
+ def default_state(self):
+ return self.states[0]
+
+ def get_state(self, name):
+ for state in self.states:
+ if state.name == name:
+ return state
+ raise KeyError(name)
+ return self.default_state
+
+ def _assemble_comment(self):
+ comment = "# BEGIN DMI\n"
+ comment += f"version = {self.version}\n"
+ comment += f"\twidth = {self.width}\n"
+ comment += f"\theight = {self.height}\n"
+ for state in self.states:
+ comment += f"state = {escape(state.name)}\n"
+ comment += f"\tdirs = {state.dirs}\n"
+ comment += f"\tframes = {state.framecount}\n"
+ if state.framecount > 1 and len(state.delays): #any(x != 1 for x in state.delays):
+ comment += "\tdelay = " + ",".join(map(str, state.delays)) + "\n"
+ if state.loop != 0:
+ comment += f"\tloop = {state.loop}\n"
+ if state.rewind:
+ comment += "\trewind = 1\n"
+ if state.movement:
+ comment += "\tmovement = 1\n"
+ if state.hotspots and any(state.hotspots):
+ current = None
+ for i, value in enumerate(state.hotspots):
+ if value != current:
+ x, y = value
+ comment += f"\thotspot = {x},{y},{i + 1}\n"
+ current = value
+ comment += "# END DMI"
+ return comment
+
+ def to_file(self, filename, *, palette=False):
+ # assemble comment
+ comment = self._assemble_comment()
+
+ # assemble spritesheet
+ W, H = self.width, self.height
+ num_frames = sum(len(state.frames) for state in self.states)
+ sqrt = math.ceil(math.sqrt(num_frames))
+ output = Image.new('RGBA', (sqrt * W, math.ceil(num_frames / sqrt) * H))
+
+ i = 0
+ for state in self.states:
+ for frame in state.frames:
+ output.paste(frame, ((i % sqrt) * W, (i // sqrt) * H))
+ i += 1
+
+ # save
+ pnginfo = PngInfo()
+ pnginfo.add_text('Description', comment, zip=True)
+ if palette:
+ output = output.convert('P')
+ output.save(filename, 'png', optimize=True, pnginfo=pnginfo)
+
+class State:
+ def __init__(self, dmi, name, *, loop=LOOP_UNLIMITED, rewind=False, movement=False, dirs=1):
+ self.dmi = dmi
+ self.name = name
+ self.loop = loop
+ self.rewind = rewind
+ self.movement = movement
+ self.dirs = dirs
+
+ self._nframes = None # used during loading only
+ self.frames = []
+ self.delays = []
+ self.hotspots = None
+
+ @property
+ def framecount(self):
+ if self._nframes is not None:
+ return self._nframes
+ else:
+ return len(self.frames) // self.dirs
+
+ def frame(self, image, *, delay=1):
+ assert image.size == (self.dmi.width, self.dmi.height)
+ self.delays.append(delay)
+ self.frames.append(image)
+
+ def hotspot(self, first_frame, x, y):
+ if self.hotspots is None:
+ self.hotspots = [None] * self.framecount
+ for i in range(first_frame, self.framecount):
+ self.hotspots[i] = x, y
+
+ def _frame_index(self, frame=0, dir=None):
+ ofs = DIR_ORDER.index(DIR_NAMES[dir])
+ if ofs >= self.dirs:
+ ofs = 0
+ return frame * self.dirs + ofs
+
+ def get_frame(self, *args, **kwargs):
+ return self.frames[self._frame_index(*args, **kwargs)]
+
+def escape(text):
+ assert '\\' not in text and '"' not in text
+ return f'"{text}"'
+
+def unescape(text, quote='"'):
+ if text == 'null':
+ return None
+ if not (text.startswith(quote) and text.endswith(quote)):
+ raise ValueError(text)
+ text = text[1:-1]
+ assert '\\' not in text and quote not in text
+ return text
+
+def parse_num(value):
+ if '.' in value:
+ return float(value)
+ return int(value)
+
+def parse_bool(value):
+ if value not in ('0', '1'):
+ raise ValueError(value)
+ return value == '1'
+
+if __name__ == '__main__':
+ # test: can we load every DMI in the tree
+ import os
+
+ count = 0
+ for dirpath, dirnames, filenames in os.walk('.'):
+ if '.git' in dirnames:
+ dirnames.remove('.git')
+ for filename in filenames:
+ if filename.endswith('.dmi'):
+ Dmi.from_file(os.path.join(dirpath, filename))
+ count += 1
+
+ print(f"Successfully parsed {count} dmi files")
diff --git a/tools/mapmerge2/src/dmm.py b/tools/mapmerge2/dmm.py
similarity index 85%
rename from tools/mapmerge2/src/dmm.py
rename to tools/mapmerge2/dmm.py
index d76f07e32c6..8bb1dca3537 100644
--- a/tools/mapmerge2/src/dmm.py
+++ b/tools/mapmerge2/dmm.py
@@ -58,6 +58,23 @@ class DMM:
raise RuntimeError("ran out of keys, this shouldn't happen")
+ def overwrite_key(self, key, fixed, bad_keys):
+ try:
+ self.dictionary[key] = fixed
+ return None
+ except bidict.DuplicationError:
+ old_key = self.dictionary.inv[fixed]
+ bad_keys[key] = old_key
+ print(f"Merging '{num_to_key(key, self.key_length)}' into '{num_to_key(old_key, self.key_length)}'")
+ return old_key
+
+ def reassign_bad_keys(self, bad_keys):
+ if not bad_keys:
+ return
+ for k, v in self.grid.items():
+ # reassign the grid entries which used the old key
+ self.grid[k] = bad_keys.get(v, v)
+
def _presave_checks(self):
# last-second handling of bogus keys to help prevent and fix broken maps
self._ensure_free_keys(0)
@@ -70,9 +87,16 @@ class DMM:
new_key = bad_keys[k] = self.generate_new_key()
self.dictionary.forceput(new_key, self.dictionary[k])
print(f" {num_to_key(k, self.key_length, True)} -> {num_to_key(new_key, self.key_length)}")
- for k, v in self.grid.items():
- # reassign the grid entries which used the old key
- self.grid[k] = bad_keys.get(v, v)
+
+ # handle entries in the dictionary which have atoms in the wrong order
+ keys = list(self.dictionary.keys())
+ for key in keys:
+ value = self.dictionary[key]
+ if is_bad_atom_ordering(num_to_key(key, self.key_length, True), value):
+ fixed = tuple(fix_atom_ordering(value))
+ self.overwrite_key(key, fixed, bad_keys)
+
+ self.reassign_bad_keys(bad_keys)
def _ensure_free_keys(self, desired):
# ensure that free keys exist by increasing the key length if necessary
@@ -179,6 +203,45 @@ def parse_map_atom(atom):
return path, vars
+def is_bad_atom_ordering(key, atoms):
+ seen_turfs = 0
+ seen_areas = 0
+ can_fix = False
+ for each in atoms:
+ if each.startswith('/turf'):
+ if seen_turfs == 1:
+ print(f"Warning: key '{key}' has multiple turfs!")
+ if seen_areas:
+ print(f"Warning: key '{key}' has area before turf (autofixing...)")
+ can_fix = True
+ seen_turfs += 1
+ elif each.startswith('/area'):
+ if seen_areas == 1:
+ print(f"Warning: key '{key}' has multiple areas!!!")
+ seen_areas += 1
+ else:
+ if (seen_turfs or seen_areas) and not can_fix:
+ print(f"Warning: key '{key}' has movable after turf or area (autofixing...)")
+ can_fix = True
+ if not seen_areas or not seen_turfs:
+ print(f"Warning: key '{key}' is missing either a turf or area")
+ return can_fix
+
+def fix_atom_ordering(atoms):
+ movables = []
+ turfs = []
+ areas = []
+ for each in atoms:
+ if each.startswith('/turf'):
+ turfs.append(each)
+ elif each.startswith('/area'):
+ areas.append(each)
+ else:
+ movables.append(each)
+ movables.extend(turfs)
+ movables.extend(areas)
+ return movables
+
# ----------
# TGM writer
@@ -307,7 +370,7 @@ def _parse(map_raw_text):
continue
elif in_comment_line:
continue
- elif char == "\t":
+ elif char in "\r\t":
continue
if char == "/" and not in_quote_block:
@@ -415,6 +478,9 @@ def _parse(map_raw_text):
# grid block
for char in it:
+ if char == "\r":
+ continue
+
if in_coord_block:
if char == ",":
if reading_coord == "x":
diff --git a/tools/mapmerge2/Convert DMM to TGM.bat b/tools/mapmerge2/dmm2tgm.bat
similarity index 68%
rename from tools/mapmerge2/Convert DMM to TGM.bat
rename to tools/mapmerge2/dmm2tgm.bat
index c100d61fe71..bcf6150c2ea 100644
--- a/tools/mapmerge2/Convert DMM to TGM.bat
+++ b/tools/mapmerge2/dmm2tgm.bat
@@ -1,5 +1,5 @@
@echo off
set MAPROOT=../../_maps/
set TGM=1
-python ./src/convert.py
+python convert.py
pause
diff --git a/tools/mapmerge2/src/frontend.py b/tools/mapmerge2/frontend.py
similarity index 100%
rename from tools/mapmerge2/src/frontend.py
rename to tools/mapmerge2/frontend.py
diff --git a/tools/mapmerge2/map_scripts/cornersfix.txt b/tools/mapmerge2/map_scripts/cornersfix.txt
new file mode 100644
index 00000000000..d9ff8a20232
--- /dev/null
+++ b/tools/mapmerge2/map_scripts/cornersfix.txt
@@ -0,0 +1,30 @@
+/obj/effect/turf_decal/stripes/corner {dir=1} : /obj/item/bear_armor {@OLD;dir=8}
+/obj/effect/turf_decal/stripes/corner {dir=2} : /obj/effect/turf_decal/stripes/corner {@OLD;dir=@SKIP}
+/obj/effect/turf_decal/stripes/corner {dir=4} : /obj/effect/turf_decal/stripes/corner {@OLD;dir=1}
+/obj/effect/turf_decal/stripes/corner {dir=8} : /obj/effect/turf_decal/stripes/corner {@OLD;dir=4}
+/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/stripes/corner {@OLD}
+/obj/effect/turf_decal/stripes/red/corner {dir=1} : /obj/item/bear_armor {@OLD;dir=8}
+/obj/effect/turf_decal/stripes/red/corner {dir=2} : /obj/effect/turf_decal/stripes/red/corner {@OLD;dir=@SKIP}
+/obj/effect/turf_decal/stripes/red/corner {dir=4} : /obj/effect/turf_decal/stripes/red/corner {@OLD;dir=1}
+/obj/effect/turf_decal/stripes/red/corner {dir=8} : /obj/effect/turf_decal/stripes/red/corner {@OLD;dir=4}
+/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/stripes/red/corner {@OLD}
+/obj/effect/turf_decal/stripes/white/corner {dir=1} : /obj/item/bear_armor {@OLD;dir=8}
+/obj/effect/turf_decal/stripes/white/corner {dir=2} : /obj/effect/turf_decal/stripes/white/corner {@OLD;dir=@SKIP}
+/obj/effect/turf_decal/stripes/white/corner {dir=4} : /obj/effect/turf_decal/stripes/white/corner {@OLD;dir=1}
+/obj/effect/turf_decal/stripes/white/corner {dir=8} : /obj/effect/turf_decal/stripes/white/corner {@OLD;dir=4}
+/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/stripes/white/corner {@OLD}
+/obj/effect/turf_decal/box/corners {dir=1} : /obj/item/bear_armor {@OLD;dir=8}
+/obj/effect/turf_decal/box/corners {dir=2} : /obj/effect/turf_decal/box/corners {@OLD;dir=@SKIP}
+/obj/effect/turf_decal/box/corners {dir=4} : /obj/effect/turf_decal/box/corners {@OLD;dir=1}
+/obj/effect/turf_decal/box/corners {dir=8} : /obj/effect/turf_decal/box/corners {@OLD;dir=4}
+/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/box/corners {@OLD}
+/obj/effect/turf_decal/box/red/corners {dir=1} : /obj/item/bear_armor {@OLD;dir=8}
+/obj/effect/turf_decal/box/red/corners {dir=2} : /obj/effect/turf_decal/box/red/corners {@OLD;dir=@SKIP}
+/obj/effect/turf_decal/box/red/corners {dir=4} : /obj/effect/turf_decal/box/red/corners {@OLD;dir=1}
+/obj/effect/turf_decal/box/red/corners {dir=8} : /obj/effect/turf_decal/box/red/corners {@OLD;dir=4}
+/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/box/red/corners {@OLD}
+/obj/effect/turf_decal/box/white/corners {dir=1} : /obj/item/bear_armor {@OLD;dir=8}
+/obj/effect/turf_decal/box/white/corners {dir=2} : /obj/effect/turf_decal/box/white/corners {@OLD;dir=@SKIP}
+/obj/effect/turf_decal/box/white/corners {dir=4} : /obj/effect/turf_decal/box/white/corners {@OLD;dir=1}
+/obj/effect/turf_decal/box/white/corners {dir=8} : /obj/effect/turf_decal/box/white/corners {@OLD;dir=4}
+/obj/item/bear_armor {dir=8} : /obj/effect/turf_decal/box/white/corners {@OLD}
\ No newline at end of file
diff --git a/tools/mapmerge2/map_scripts/turfs2decals.txt b/tools/mapmerge2/map_scripts/turfs2decals.txt
new file mode 100644
index 00000000000..13ae02baf73
--- /dev/null
+++ b/tools/mapmerge2/map_scripts/turfs2decals.txt
@@ -0,0 +1,465 @@
+/turf/open/floor/circuit/killroom : /turf/open/floor/circuit/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/airless/asteroid : /obj/effect/turf_decal/sand , /turf/open/floor/plasteel/airless {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/airless/bar : /obj/effect/turf_decal/tile/bar , /obj/effect/turf_decal/tile/bar {dir=1} , /turf/open/floor/plasteel/airless {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/arrival {dir=1} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
+/turf/open/floor/plasteel/arrival {dir=@UNSET} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/arrival {dir=2} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/arrival {dir=4} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/arrival {dir=5} : /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/arrival {dir=6} : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/arrival {dir=8} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
+/turf/open/floor/plasteel/arrival {dir=9} : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
+/turf/open/floor/plasteel/arrival {dir=10} : /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/arrival/corner {dir=1} : /turf/open/floor/plasteel/white/corner {@OLD}
+/turf/open/floor/plasteel/arrival/corner {dir=@UNSET} : /turf/open/floor/plasteel/white/corner {@OLD}
+/turf/open/floor/plasteel/arrival/corner {dir=2} : /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/arrival/corner {dir=4} : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/arrival/corner {dir=8} : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/asteroid : /obj/effect/turf_decal/sand , /turf/open/floor/plasteel
+/turf/open/floor/plasteel/bar : /obj/effect/turf_decal/tile/bar , /obj/effect/turf_decal/tile/bar {dir=1} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/barber : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/blueyellow/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brown/telecomms/mainframe {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/brownold/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/caution {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1}
+/turf/open/floor/plasteel/caution {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/caution {dir=2} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/caution {dir=4} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/caution {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/checker {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/caution {dir=6} : /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/caution {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1}
+/turf/open/floor/plasteel/caution {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/corner {@OLD;dir=1}
+/turf/open/floor/plasteel/caution {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/checker {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/caution/corner {dir=1} : /turf/open/floor/plasteel/dark/corner {@OLD}
+/turf/open/floor/plasteel/caution/corner {dir=@UNSET} : /turf/open/floor/plasteel/dark/corner {@OLD}
+/turf/open/floor/plasteel/caution/corner {dir=2} : /turf/open/floor/plasteel/dark/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/caution/corner {dir=4} : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/caution/corner {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/cmo : /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/dark/telecomms/mainframe : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/dark/telecomms/server : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/dark/telecomms/server/walkway : /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkblue/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/side {dir=1} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/side {dir=@UNSET} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/side {dir=2} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/side {dir=4} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/side {dir=5} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/side {dir=6} : /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/side {dir=8} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/side {dir=9} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown {dir=4} , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/side {dir=10} : /obj/effect/turf_decal/tile/brown {dir=1} , /obj/effect/turf_decal/tile/brown , /obj/effect/turf_decal/tile/brown {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkbrown/corner : /obj/effect/turf_decal/tile/brown {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkgreen/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkpurple/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkred/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/darkyellow/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/escape {dir=1} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
+/turf/open/floor/plasteel/escape {dir=@UNSET} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/escape {dir=2} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/escape {dir=4} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/escape {dir=5} : /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/escape {dir=6} : /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/escape {dir=8} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
+/turf/open/floor/plasteel/escape {dir=9} : /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white/corner {@OLD;dir=1}
+/turf/open/floor/plasteel/escape {dir=10} : /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/cafeteria {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/escape/corner {dir=1} : /turf/open/floor/plasteel/white/corner {@OLD}
+/turf/open/floor/plasteel/escape/corner {dir=@UNSET} : /turf/open/floor/plasteel/white/corner {@OLD}
+/turf/open/floor/plasteel/escape/corner {dir=2} : /turf/open/floor/plasteel/white/corner {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/escape/corner {dir=4} : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/escape/corner {dir=8} : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/green/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/greenyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/hydrofloor : /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/corner : /obj/effect/turf_decal/tile/neutral {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/neutral/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/orange/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/purple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/red/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/redside {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/redside {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/redside {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/redside {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/redside {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/redside {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/redside {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/redside {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/redside {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/blueside {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/blueside {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/blueside {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/blueside {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/blueside {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/blueside {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/blueside {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/blueside {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redblue/blueside {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redgreen/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/redyellow/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/airless : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/airless {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/snowdin : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/snowdin {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/telecomms : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/telecomms/mainframe : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/killroom : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/side {dir=1} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/side {dir=@UNSET} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/side {dir=2} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/side {dir=4} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/side {dir=5} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/side {dir=6} : /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/side {dir=8} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/side {dir=9} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral {dir=4} , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/side {dir=10} : /obj/effect/turf_decal/tile/neutral {dir=1} , /obj/effect/turf_decal/tile/neutral , /obj/effect/turf_decal/tile/neutral {dir=8} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/vault/corner : /obj/effect/turf_decal/tile/neutral {dir=@OLD} , /turf/open/floor/plasteel/dark {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/corner : /obj/effect/turf_decal/tile/blue {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue {dir=4} , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteblue/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/blue {dir=1} , /obj/effect/turf_decal/tile/blue , /obj/effect/turf_decal/tile/blue {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/side {dir=1} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/side {dir=@UNSET} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/side {dir=2} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/side {dir=4} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/side {dir=5} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/side {dir=6} : /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/side {dir=8} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/side {dir=9} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green {dir=4} , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/side {dir=10} : /obj/effect/turf_decal/tile/green {dir=1} , /obj/effect/turf_decal/tile/green , /obj/effect/turf_decal/tile/green {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitegreen/corner : /obj/effect/turf_decal/tile/green {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/corner : /obj/effect/turf_decal/tile/purple {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=1} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=@UNSET} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=2} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=4} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=5} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=6} : /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=8} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=9} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple {dir=4} , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitepurple/side/telecomms {dir=10} : /obj/effect/turf_decal/tile/purple {dir=1} , /obj/effect/turf_decal/tile/purple , /obj/effect/turf_decal/tile/purple {dir=8} , /turf/open/floor/plasteel/white/telecomms {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/side {dir=1} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/side {dir=@UNSET} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/side {dir=2} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/side {dir=4} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/side {dir=5} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/side {dir=6} : /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/side {dir=8} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/side {dir=9} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red {dir=4} , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/side {dir=10} : /obj/effect/turf_decal/tile/red {dir=1} , /obj/effect/turf_decal/tile/red , /obj/effect/turf_decal/tile/red {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whitered/corner : /obj/effect/turf_decal/tile/red {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/whiteyellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel/white {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/side {dir=1} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/side {dir=@UNSET} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/side {dir=2} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/side {dir=4} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/side {dir=5} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/side {dir=6} : /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/side {dir=8} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/side {dir=9} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow {dir=4} , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/side {dir=10} : /obj/effect/turf_decal/tile/yellow {dir=1} , /obj/effect/turf_decal/tile/yellow , /obj/effect/turf_decal/tile/yellow {dir=8} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
+/turf/open/floor/plasteel/yellow/corner : /obj/effect/turf_decal/tile/yellow {dir=@OLD} , /turf/open/floor/plasteel {@OLD;dir=@SKIP}
\ No newline at end of file
diff --git a/tools/mapmerge2/Run Mapmerge.bat b/tools/mapmerge2/mapmerge.bat
similarity index 67%
rename from tools/mapmerge2/Run Mapmerge.bat
rename to tools/mapmerge2/mapmerge.bat
index 12d7896330e..5a066226b3c 100644
--- a/tools/mapmerge2/Run Mapmerge.bat
+++ b/tools/mapmerge2/mapmerge.bat
@@ -1,5 +1,5 @@
@echo off
set MAPROOT=../../_maps/
set TGM=1
-python ./src/mapmerge.py
+python mapmerge.py
pause
diff --git a/tools/mapmerge2/src/mapmerge.py b/tools/mapmerge2/mapmerge.py
similarity index 100%
rename from tools/mapmerge2/src/mapmerge.py
rename to tools/mapmerge2/mapmerge.py
diff --git a/tools/mapmerge2/merge_driver_dmi.py b/tools/mapmerge2/merge_driver_dmi.py
new file mode 100644
index 00000000000..37c0abd9543
--- /dev/null
+++ b/tools/mapmerge2/merge_driver_dmi.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python3
+import sys
+import dmi
+
+def images_equal(left, right):
+ if left.size != right.size:
+ return False
+ w, h = left.size
+ left_load, right_load = left.load(), right.load()
+ for y in range(0, h):
+ for x in range(0, w):
+ lpixel, rpixel = left_load[x, y], right_load[x, y]
+ # quietly ignore changes where both pixels are fully transparent
+ if lpixel != rpixel and (lpixel[3] != 0 or rpixel[3] != 0):
+ return False
+ return True
+
+def states_equal(left, right):
+ result = True
+
+ # basic properties
+ for attr in ('loop', 'rewind', 'movement', 'dirs', 'delays', 'hotspots', 'framecount'):
+ lval, rval = getattr(left, attr), getattr(right, attr)
+ if lval != rval:
+ result = False
+
+ # frames
+ for (left_frame, right_frame) in zip(left.frames, right.frames):
+ if not images_equal(left_frame, right_frame):
+ result = False
+
+ return result
+
+def key_of(state):
+ return (state.name, state.movement)
+
+def dictify(sheet):
+ result = {}
+ for state in sheet.states:
+ k = key_of(state)
+ if k in result:
+ print(f" duplicate {k!r}")
+ result[k] = state
+ return result
+
+def three_way_merge(base, left, right):
+ base_dims = base.width, base.height
+ if base_dims != (left.width, left.height) or base_dims != (right.width, right.height):
+ print("Dimensions have changed:")
+ print(f" Base: {base.width} x {base.height}")
+ print(f" Ours: {left.width} x {left.height}")
+ print(f" Theirs: {right.width} x {right.height}")
+ return True, None
+
+ base_states, left_states, right_states = dictify(base), dictify(left), dictify(right)
+
+ new_left = {k: v for k, v in left_states.items() if k not in base_states}
+ new_right = {k: v for k, v in right_states.items() if k not in base_states}
+ new_both = {}
+ conflicts = []
+ for key, state in list(new_left.items()):
+ in_right = new_right.get(key, None)
+ if in_right:
+ if states_equal(state, in_right):
+ # allow it
+ new_both[key] = state
+ else:
+ # generate conflict states
+ print(f" C: {state.name!r}: added differently in both!")
+ state.name = f"{state.name} !CONFLICT! left"
+ conflicts.append(state)
+ in_right.name = f"{state.name} !CONFLICT! right"
+ conflicts.append(in_right)
+ # don't add it a second time
+ del new_left[key]
+ del new_right[key]
+
+ final_states = []
+ # add states that are currently in the base
+ for state in base.states:
+ in_left = left_states.get(key_of(state), None)
+ in_right = right_states.get(key_of(state), None)
+ left_equals = in_left and states_equal(state, in_left)
+ right_equals = in_right and states_equal(state, in_right)
+
+ if not in_left and not in_right:
+ # deleted in both left and right, it's just deleted
+ print(f" {state.name!r}: deleted in both")
+ elif not in_left:
+ # left deletes
+ print(f" {state.name!r}: deleted in left")
+ if not right_equals:
+ print(f" ... but modified in right")
+ final_states.append(in_right)
+ elif not in_right:
+ # right deletes
+ print(f" {state.name!r}: deleted in right")
+ if not left_equals:
+ print(f" ... but modified in left")
+ final_states.append(in_left)
+ elif left_equals and right_equals:
+ # changed in neither
+ #print(f"Same in both: {state.name!r}")
+ final_states.append(state)
+ elif left_equals:
+ # changed only in right
+ print(f" {state.name!r}: changed in left")
+ final_states.append(in_right)
+ elif right_equals:
+ # changed only in left
+ print(f" {state.name!r}: changed in right")
+ final_states.append(in_left)
+ elif states_equal(in_left, in_right):
+ # changed in both, to the same thing
+ print(f" {state.name!r}: changed same in both")
+ final_states.append(in_left) # either or
+ else:
+ # changed in both
+ name = state.name
+ print(f" C: {name!r}: changed differently in both!")
+ state.name = f"{name} !CONFLICT! base"
+ conflicts.append(state)
+ in_left.name = f"{name} !CONFLICT! left"
+ conflicts.append(in_left)
+ in_right.name = f"{name} !CONFLICT! right"
+ conflicts.append(in_right)
+
+ # add states which both left and right added the same
+ for key, state in new_both.items():
+ print(f" {state.name!r}: added same in both")
+ final_states.append(state)
+
+ # add states that are brand-new in the left
+ for key, state in new_left.items():
+ print(f" {state.name!r}: added in left")
+ final_states.append(state)
+
+ # add states that are brand-new in the right
+ for key, state in new_right.items():
+ print(f" {state.name!r}: added in right")
+ final_states.append(state)
+
+ final_states.extend(conflicts)
+ merged = dmi.Dmi(base.width, base.height)
+ merged.states = final_states
+ return len(conflicts), merged
+
+def main(path, original, left, right):
+ print(f"Merging icon: {path}")
+
+ icon_orig = dmi.Dmi.from_file(original)
+ icon_left = dmi.Dmi.from_file(left)
+ icon_right = dmi.Dmi.from_file(right)
+
+ trouble, merged = three_way_merge(icon_orig, icon_left, icon_right)
+ if merged:
+ merged.to_file(left)
+ if trouble:
+ print("!!! Manual merge required!")
+ if merged:
+ print(" A best-effort merge was performed. You must edit the icon and remove all")
+ print(" icon states marked with !CONFLICT!, leaving only the desired icon.")
+ else:
+ print(" The icon was totally unable to be merged, you must start with one version")
+ print(" or the other and manually resolve the conflict.")
+ print(" Information about which states conflicted is listed above.")
+ return trouble
+
+if __name__ == '__main__':
+ if len(sys.argv) != 6:
+ print("DMI merge driver called with wrong number of arguments")
+ print(" usage: merge-driver-dmi %P %O %A %B %L")
+ exit(1)
+
+ # "left" is also the file that ought to be overwritten
+ _, path, original, left, right, conflict_size_marker = sys.argv
+ exit(main(path, original, left, right))
diff --git a/tools/mapmerge2/precommit.py b/tools/mapmerge2/precommit.py
new file mode 100644
index 00000000000..f5ea49a50ea
--- /dev/null
+++ b/tools/mapmerge2/precommit.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+import os
+import pygit2
+import dmm
+from mapmerge import merge_map
+
+def main(repo):
+ if repo.index.conflicts:
+ print("You need to resolve merge conflicts first.")
+ return 1
+
+ try:
+ repo.lookup_reference('MERGE_HEAD')
+ print("Not running mapmerge for merge commit.")
+ return 0
+ except KeyError:
+ pass
+
+ changed = 0
+ for path, status in repo.status().items():
+ if path.endswith(".dmm") and (status & (pygit2.GIT_STATUS_INDEX_MODIFIED | pygit2.GIT_STATUS_INDEX_NEW)):
+ # read the index
+ index_entry = repo.index[path]
+ index_map = dmm.DMM.from_bytes(repo[index_entry.id].read_raw())
+
+ try:
+ head_blob = repo[repo[repo.head.target].tree[path].id]
+ except KeyError:
+ # New map, no entry in HEAD
+ print(f"Converting new map: {path}", flush=True)
+ assert (status & pygit2.GIT_STATUS_INDEX_NEW)
+ merged_map = index_map
+ else:
+ # Entry in HEAD, merge the index over it
+ print(f"Merging map: {path}", flush=True)
+ assert not (status & pygit2.GIT_STATUS_INDEX_NEW)
+ head_map = dmm.DMM.from_bytes(head_blob.read_raw())
+ merged_map = merge_map(index_map, head_map)
+
+ # write to the index
+ blob_id = repo.create_blob(merged_map.to_bytes())
+ repo.index.add(pygit2.IndexEntry(path, blob_id, index_entry.mode))
+ changed += 1
+
+ # write to the working directory if that's clean
+ if status & (pygit2.GIT_STATUS_WT_DELETED | pygit2.GIT_STATUS_WT_MODIFIED):
+ print(f"Warning: {path} has unindexed changes, not overwriting them")
+ else:
+ merged_map.to_file(os.path.join(repo.workdir, path))
+
+ if changed:
+ repo.index.write()
+ print(f"Merged {changed} maps.")
+ return 0
+
+if __name__ == '__main__':
+ exit(main(pygit2.Repository(pygit2.discover_repository(os.getcwd()))))
diff --git a/tools/mapmerge2/Install Requirements.bat b/tools/mapmerge2/requirements-install.bat
similarity index 100%
rename from tools/mapmerge2/Install Requirements.bat
rename to tools/mapmerge2/requirements-install.bat
diff --git a/tools/mapmerge2/requirements.txt b/tools/mapmerge2/requirements.txt
index 095843b2d2a..adb42438e7e 100644
--- a/tools/mapmerge2/requirements.txt
+++ b/tools/mapmerge2/requirements.txt
@@ -1,3 +1,3 @@
-pygit2==0.26.0
+pygit2==0.27.2
bidict==0.13.1
Pillow==5.1.0
diff --git a/tools/mapmerge2/Convert TGM to DMM.bat b/tools/mapmerge2/tgm2dmm.bat
similarity index 68%
rename from tools/mapmerge2/Convert TGM to DMM.bat
rename to tools/mapmerge2/tgm2dmm.bat
index 9fb6d5419dd..2748533febf 100644
--- a/tools/mapmerge2/Convert TGM to DMM.bat
+++ b/tools/mapmerge2/tgm2dmm.bat
@@ -1,5 +1,5 @@
@echo off
set MAPROOT=../../_maps/
set TGM=0
-python ./src/convert.py
+python convert.py
pause
diff --git a/tools/mapmerge2/update_paths.py b/tools/mapmerge2/update_paths.py
new file mode 100644
index 00000000000..6359b6bb303
--- /dev/null
+++ b/tools/mapmerge2/update_paths.py
@@ -0,0 +1,163 @@
+# A script and syntax for applying path updates to maps.
+import re
+import os
+import argparse
+import frontend
+from dmm import *
+
+desc = """
+Update dmm files given update file/string.
+Replacement syntax example:
+ /turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {dir = @OLD ;tag = @SKIP;icon_state = @SKIP}
+ /turf/open/floor/plasteel/warningline : /obj/effect/turf_decal {@OLD} , /obj/thing {icon_state = @OLD:name; name = "meme"}
+ /turf/open/floor/plasteel/warningline{dir=2} : /obj/thing
+New paths properties:
+ @OLD - if used as property name copies all modified properties from original path to this one
+ property = @SKIP - will not copy this property through when global @OLD is used.
+ property = @OLD - will copy this modified property from original object even if global @OLD is not used
+ property = @OLD:name - will copy [name] property from original object even if global @OLD is not used
+ Anything else is copied as written.
+Old paths properties:
+ Will be used as a filter.
+ property = @UNSET - will apply the rule only if the property is not mapedited
+"""
+
+default_map_directory = "../../_maps"
+replacement_re = re.compile('\s*([^{]*)\s*(\{(.*)\})?')
+
+#urgent todo: replace with actual parser, this is slow as janitor in crit
+split_re = re.compile('((?:[A-Za-z0-9_\-$]+)\s*=\s*(?:"(?:.+?)"|[^";]*)|@OLD)')
+
+
+def props_to_string(props):
+ return "{{{0}}}".format(";".join([k+" = "+props[k] for k in props]))
+
+
+def string_to_props(propstring, verbose = False):
+ props = dict()
+ for raw_prop in re.split(split_re, propstring):
+ if not raw_prop or raw_prop.strip() == ';':
+ continue
+ prop = raw_prop.split('=', maxsplit=1)
+ props[prop[0].strip()] = prop[1].strip() if len(prop) > 1 else None
+ if verbose:
+ print("{0} to {1}".format(propstring, props))
+ return props
+
+
+def parse_rep_string(replacement_string, verbose = False):
+ # translates /blah/blah {meme = "test",} into path,prop dictionary tuple
+ match = re.match(replacement_re, replacement_string)
+ path = match.group(1)
+ props = match.group(3)
+ if props:
+ prop_dict = string_to_props(props, verbose)
+ else:
+ prop_dict = dict()
+ return path.strip(), prop_dict
+
+
+def update_path(dmm_data, replacement_string, verbose=False):
+ old_path_part, new_path_part = replacement_string.split(':', maxsplit=1)
+ old_path, old_path_props = parse_rep_string(old_path_part, verbose)
+ new_paths = list()
+ for replacement_def in new_path_part.split(','):
+ new_path, new_path_props = parse_rep_string(replacement_def, verbose)
+ new_paths.append((new_path, new_path_props))
+
+ def replace_def(match):
+ if match.group(2):
+ old_props = string_to_props(match.group(2), verbose)
+ else:
+ old_props = dict()
+ for filter_prop in old_path_props:
+ if filter_prop not in old_props:
+ if old_path_props[filter_prop] == "@UNSET":
+ continue
+ else:
+ return [match.group(0)]
+ else:
+ if old_props[filter_prop] != old_path_props[filter_prop] or old_path_props[filter_prop] == "@UNSET":
+ return [match.group(0)] #does not match current filter, skip the change.
+ if verbose:
+ print("Found match : {0}".format(match.group(0)))
+ out_paths = []
+ for new_path, new_props in new_paths:
+ out = new_path
+ out_props = dict()
+ for prop_name, prop_value in new_props.items():
+ if prop_name == "@OLD":
+ out_props = dict(old_props)
+ continue
+ if prop_value == "@SKIP":
+ out_props.pop(prop_name, None)
+ continue
+ if prop_value.startswith("@OLD"):
+ params = prop_value.split(":")
+ if prop_name in old_props:
+ out_props[prop_name] = old_props[params[1]] if len(params) > 1 else old_props[prop_name]
+ continue
+ out_props[prop_name] = prop_value
+ if out_props:
+ out += props_to_string(out_props)
+ out_paths.append(out)
+ if verbose:
+ print("Replacing with: {0}".format(out_paths))
+ return out_paths
+
+ def get_result(element):
+ p = re.compile("{0}\s*({{(.*)}})?$".format(re.escape(old_path)))
+ match = p.match(element)
+ if match:
+ return replace_def(match) # = re.sub(p,replace_def,element)
+ else:
+ return [element]
+
+ bad_keys = {}
+ keys = list(dmm_data.dictionary.keys())
+ for definition_key in keys:
+ def_value = dmm_data.dictionary[definition_key]
+ new_value = tuple(y for x in def_value for y in get_result(x))
+ if new_value != def_value:
+ dmm_data.overwrite_key(definition_key, new_value, bad_keys)
+ dmm_data.reassign_bad_keys(bad_keys)
+
+
+def update_map(map_filepath, updates, verbose=False):
+ print("Updating: {0}".format(map_filepath))
+ dmm_data = DMM.from_file(map_filepath)
+ for update_string in updates:
+ update_path(dmm_data, update_string, verbose)
+ dmm_data.to_file(map_filepath, True)
+
+
+def update_all_maps(map_directory, updates, verbose=False):
+ for root, _, files in os.walk(map_directory):
+ for filepath in files:
+ if filepath.endswith(".dmm"):
+ path = os.path.join(root, filepath)
+ update_map(path, updates, verbose)
+
+
+def main(args):
+ if args.inline:
+ updates = [args.update_source]
+ else:
+ with open(args.update_source) as f:
+ updates = [line for line in f if line and not line.startswith("#") and not line.isspace()]
+
+ if args.map:
+ update_map(args.map, updates, verbose=args.verbose)
+ else:
+ map_directory = args.directory or frontend.read_settings().map_folder
+ update_all_maps(map_directory, updates, verbose=args.verbose)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description=desc, formatter_class=argparse.RawTextHelpFormatter)
+ parser.add_argument("update_source", help="update file path / line of update notation")
+ parser.add_argument("--map", "-m", help="path to update, defaults to all maps in maps directory")
+ parser.add_argument("--directory", "-d", help="path to maps directory, defaults to _maps/")
+ parser.add_argument("--inline", "-i", help="treat update source as update string instead of path", action="store_true")
+ parser.add_argument("--verbose", "-v", help="toggle detailed update information", action="store_true")
+ main(parser.parse_args())
|