Merge remote-tracking branch 'refs/remotes/Citadel-Station-13/master' into syntheticbloods

This commit is contained in:
Poojawa
2019-08-10 23:48:47 -05:00
175 changed files with 9004 additions and 1473 deletions
@@ -131,9 +131,7 @@
if(!M || !M.current)
continue
if(isliving(M.current) && M.current.stat != DEAD)
var/turf/t_turf
if(isAI(M.current))
t_turf = isAI(M.current) ? get_step(get_step(src, NORTH),NORTH) : get_turf(src) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark.
var/turf/t_turf = isAI(M.current) ? get_step(get_step(src, NORTH),NORTH) : get_turf(src) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark.
do_teleport(M, t_turf, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
M.current.clear_fullscreen("flash", 5)
+5 -5
View File
@@ -655,15 +655,15 @@
if(H.stat == DEAD)
to_chat(user,"<span class='warning'>Only a revive rune can bring back the dead!</span>")
return
if(H.blood_volume < BLOOD_VOLUME_SAFE)
var/restore_blood = BLOOD_VOLUME_SAFE - H.blood_volume
if(H.blood_volume < (BLOOD_VOLUME_SAFE*H.blood_ratio))
var/restore_blood = (BLOOD_VOLUME_SAFE*H.blood_ratio) - H.blood_volume
if(uses*2 < restore_blood)
H.blood_volume += uses*2
to_chat(user,"<span class='danger'>You use the last of your blood rites to restore what blood you could!</span>")
uses = 0
return ..()
else
H.blood_volume = BLOOD_VOLUME_SAFE
H.blood_volume = (BLOOD_VOLUME_SAFE*H.blood_ratio)
uses -= round(restore_blood/2)
to_chat(user,"<span class='warning'>Your blood rites have restored [H == user ? "your" : "[H.p_their()]"] blood to safe levels!</span>")
var/overall_damage = H.getBruteLoss() + H.getFireLoss() + H.getToxLoss() + H.getOxyLoss()
@@ -698,7 +698,7 @@
if(H.cultslurring)
to_chat(user,"<span class='danger'>[H.p_their(TRUE)] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!</span>")
return
if(H.blood_volume > BLOOD_VOLUME_SAFE)
if(H.blood_volume > (BLOOD_VOLUME_SAFE*H.blood_ratio))
H.blood_volume -= 100
uses += 50
user.Beam(H,icon_state="drainbeam",time=10)
@@ -799,4 +799,4 @@
to_chat(user, "<span class='cultlarge'><b>Your hands glow with POWER OVERWHELMING!!!</b></span>")
else
to_chat(user, "<span class='cultitalic'>You need a free hand for this rite!</span>")
qdel(rite)
qdel(rite)
@@ -188,7 +188,7 @@
var/mob/living/simple_animal/M = L
if(M.health < M.maxHealth)
M.adjustHealth(-3)
if(ishuman(L) && L.blood_volume < BLOOD_VOLUME_NORMAL)
if(ishuman(L) && L.blood_volume < (BLOOD_VOLUME_NORMAL * L.blood_ratio))
L.blood_volume += 1.0
CHECK_TICK
if(last_corrupt <= world.time)
@@ -27,6 +27,7 @@
var/mob/living/L = owner
L.remove_status_effect(STATUS_EFFECT_INLOVE)
/datum/antagonist/valentine/greet()
to_chat(owner, "<span class='warning'><B>You're on a date with [date.name]! Protect [date.p_them()] at all costs. This takes priority over all other loyalties.</B></span>")
@@ -42,4 +43,21 @@
if(objectives_complete)
return "<span class='greentext big'>[owner.name] protected [owner.p_their()] date</span>"
else
return "<span class='redtext big'>[owner.name] date failed!</span>"
return "<span class='redtext big'>[owner.name] date failed!</span>"
//Just so it's distinct, basically.
/datum/antagonist/valentine/chem/greet()
to_chat(owner, "<span class='warning'><B>You're in love with [date.name]! Protect [date.p_them()] at all costs. This takes priority over all other loyalties.</B></span>")
/datum/antagonist/valentine/chem/roundend_report()
var/objectives_complete = TRUE
if(owner.objectives.len)
for(var/datum/objective/objective in owner.objectives)
if(!objective.check_completion())
objectives_complete = FALSE
break
if(objectives_complete)
return "<span class='greentext big'>[owner.name] protected [owner.p_their()] love: [date.name]! <i>What a cutie!</i></span>"
else
return "<span class='redtext big'>[owner.name] date failed!</span>"
+50 -2
View File
@@ -12,6 +12,7 @@
crit_fail = FALSE //Is the flash burnt out?
light_color = LIGHT_COLOR_WHITE
light_power = FLASH_LIGHT_POWER
var/flashing_overlay = "flash-f"
var/times_used = 0 //Number of times it's been used.
var/burnout_resistance = 0
var/last_used = 0 //last world.time it was used.
@@ -36,8 +37,8 @@
add_overlay("flashburnt")
attached_overlays += "flashburnt"
if(flash)
add_overlay("flash-f")
attached_overlays += "flash-f"
add_overlay(flashing_overlay)
attached_overlays += flashing_overlay
addtimer(CALLBACK(src, .proc/update_icon), 5)
if(holder)
holder.update_icon()
@@ -313,3 +314,50 @@
/obj/item/assembly/flash/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
activate()
return ..()
//ported from tg - check to make sure it can't appear where it's not supposed to.
/obj/item/assembly/flash/hypnotic
desc = "A modified flash device, programmed to emit a sequence of subliminal flashes that can send a vulnerable target into a hypnotic trance."
flashing_overlay = "flash-hypno" //I cannot find this icon no matter how hard I look in tg, so I might just make my own.
light_color = LIGHT_COLOR_PINK
cooldown = 20
/obj/item/assembly/flash/hypnotic/burn_out()
return
/obj/item/assembly/flash/hypnotic/flash_carbon(mob/living/carbon/M, mob/user, power = 15, targeted = TRUE, generic_message = FALSE)
if(!istype(M))
return
if(user)
log_combat(user, M, "[targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"]", src)
else //caused by emp/remote signal
M.log_message("was [targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"]",LOG_ATTACK)
if(generic_message && M != user)
to_chat(M, "<span class='disarm'>[src] emits a soothing light...</span>")
if(targeted)
if(M.flash_act(1, 1))
var/hypnosis = FALSE
if(M.hypnosis_vulnerable())
hypnosis = TRUE
if(user)
user.visible_message("<span class='disarm'>[user] blinds [M] with the flash!</span>", "<span class='danger'>You hypno-flash [M]!</span>")
if(!hypnosis)
to_chat(M, "<span class='notice'>The light makes you feel oddly relaxed...</span>")
M.confused += min(M.confused + 10, 20)
M.dizziness += min(M.dizziness + 10, 20)
M.drowsyness += min(M.drowsyness + 10, 20)
M.apply_status_effect(STATUS_EFFECT_PACIFY, 100)
else
M.apply_status_effect(/datum/status_effect/trance, 200, TRUE)
else if(user)
user.visible_message("<span class='disarm'>[user] fails to blind [M] with the flash!</span>", "<span class='warning'>You fail to hypno-flash [M]!</span>")
else
to_chat(M, "<span class='danger'>[src] fails to blind you!</span>")
else if(M.flash_act())
to_chat(M, "<span class='notice'>Such a pretty light...</span>")
M.confused += min(M.confused + 4, 20)
M.dizziness += min(M.dizziness + 4, 20)
M.drowsyness += min(M.drowsyness + 4, 20)
+9 -6
View File
@@ -72,11 +72,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/gender = MALE //gender of character (well duh)
var/age = 30 //age of character
var/underwear = "Nude" //underwear type
var/undie_color = "#FFFFFF"
var/undie_color = "FFF"
var/undershirt = "Nude" //undershirt type
var/shirt_color = "#FFFFFF"
var/shirt_color = "FFF"
var/socks = "Nude" //socks type
var/socks_color = "#FFFFFF"
var/socks_color = "FFF"
var/backbag = DBACKPACK //backpack type
var/jumpsuit_style = PREF_SUIT //suit/skirt
var/hair_style = "Bald" //Hair type
@@ -796,6 +796,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Voracious MediHound sleepers:</b> <a href='?_src_=prefs;preference=hound_sleeper'>[(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"]</a><br>"
dat += "<b>Hear Vore Sounds:</b> <a href='?_src_=prefs;preference=toggleeatingnoise'>[(cit_toggles & EATING_NOISES) ? "Yes" : "No"]</a><br>"
dat += "<b>Hear Vore Digestion Sounds:</b> <a href='?_src_=prefs;preference=toggledigestionnoise'>[(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"]</a><br>"
dat += "<b>Lewdchem:</b><a href='?_src_=prefs;preference=lewdchem'>[lewdchem == TRUE ? "Enabled" : "Disabled"]</a><BR>"
dat += "<b>Widescreen:</b> <a href='?_src_=prefs;preference=widescreenpref'>[widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"]</a><br>"
dat += "<b>Auto stand:</b> <a href='?_src_=prefs;preference=autostand'>[autostand ? "Enabled" : "Disabled"]</a><br>"
dat += "<b>Screen Shake:</b> <a href='?_src_=prefs;preference=screenshake'>[(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]</a><br>"
@@ -1533,7 +1534,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("undie_color")
var/n_undie_color = input(user, "Choose your underwear's color.", "Character Preference", undie_color) as color|null
if(n_undie_color)
undie_color = sanitize_hexcolor(n_undie_color, include_crunch= TRUE)
undie_color = sanitize_hexcolor(n_undie_color)
if("undershirt")
var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_list
@@ -1543,7 +1544,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("shirt_color")
var/n_shirt_color = input(user, "Choose your undershirt's color.", "Character Preference", shirt_color) as color|null
if(n_shirt_color)
shirt_color = sanitize_hexcolor(n_shirt_color, include_crunch= TRUE)
shirt_color = sanitize_hexcolor(n_shirt_color)
if("socks")
var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list
@@ -1553,7 +1554,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("socks_color")
var/n_socks_color = input(user, "Choose your socks' color.", "Character Preference", socks_color) as color|null
if(n_socks_color)
socks_color = sanitize_hexcolor(n_socks_color, include_crunch= TRUE)
socks_color = sanitize_hexcolor(n_socks_color)
if("eyes")
var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) as color|null
@@ -2037,6 +2038,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["genitals_use_skintone"] = !features["genitals_use_skintone"]
if("arousable")
arousable = !arousable
if("lewdchem")
lewdchem = !lewdchem
if("has_cock")
features["has_cock"] = !features["has_cock"]
if(features["has_cock"] == FALSE)
@@ -117,6 +117,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["widescreenpref"] >> widescreenpref
S["autostand"] >> autostand
S["cit_toggles"] >> cit_toggles
S["lewdchem"] >> lewdchem
//try to fix any outdated data if necessary
if(needs_update >= 0)
@@ -211,6 +212,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["widescreenpref"], widescreenpref)
WRITE_FILE(S["autostand"], autostand)
WRITE_FILE(S["cit_toggles"], cit_toggles)
WRITE_FILE(S["lewdchem"], lewdchem)
return 1
@@ -72,9 +72,30 @@
M.adjustStaminaLoss(-2) //Restore 2/3 of the stamina used assuming empty stam buffer. With proper stamina buffer management, this results in a net gain of +.5 stamina per click.
if(warcry)
M.say("[warcry]", ignore_spam = TRUE, forced = "north star warcry")
.= FALSE
/obj/item/clothing/gloves/rapid/attack_self(mob/user)
var/input = stripped_input(user,"What do you want your battlecry to be? Max length of 6 characters.", ,"", 7)
if(input)
warcry = input
/obj/item/clothing/gloves/rapid/hug
name = "Hugs of the North Star"
desc = "Just looking at these fills you with an urge to hug the shit out of people"
warcry = "owo" //Shouldn't ever come into play
/obj/item/clothing/gloves/rapid/hug/Touch(mob/living/target,proximity = TRUE)
var/mob/living/M = loc
if(M.a_intent == INTENT_HELP)
if(target.health >= 0 && !HAS_TRAIT(target, TRAIT_FAKEDEATH)) //Can't hug people who are dying/dead
if(target.on_fire || target.lying ) //No spamming extinguishing, helping them up, or other non-hugging/patting help interactions
return
else
M.changeNext_move(CLICK_CD_RAPID)
. = FALSE
/obj/item/clothing/gloves/rapid/hug/attack_self(mob/user)
return FALSE
+9 -4
View File
@@ -41,11 +41,16 @@
else
L.mind.add_antag_datum(/datum/antagonist/heartbreaker)
/proc/forge_valentines_objective(mob/living/lover,mob/living/date)
/proc/forge_valentines_objective(mob/living/lover,mob/living/date,var/chemLove = FALSE)
lover.mind.special_role = "valentine"
var/datum/antagonist/valentine/V = new
V.date = date.mind
lover.mind.add_antag_datum(V) //These really should be teams but i can't be assed to incorporate third wheels right now
if (chemLove == TRUE)
var/datum/antagonist/valentine/chem/V = new //Changes text and EOG check basically.
V.date = date.mind
lover.mind.add_antag_datum(V)
else
var/datum/antagonist/valentine/V = new
V.date = date.mind
lover.mind.add_antag_datum(V) //These really should be teams but i can't be assed to incorporate third wheels right now
/datum/round_event/valentines/announce(fake)
priority_announce("It's Valentine's Day! Give a valentine to that special someone!")
+7 -1
View File
@@ -15,6 +15,12 @@
var/list/wave_type
var/wave_name = "normal"
/datum/round_event/meteor_wave/setup()
announceWhen = 1
startWhen = rand(300, 600) //Yeah for SOME REASON this is measured in seconds and not deciseconds???
endWhen = startWhen + 60
/datum/round_event/meteor_wave/New()
..()
if(!wave_type)
@@ -46,7 +52,7 @@
kill()
/datum/round_event/meteor_wave/announce(fake)
priority_announce("Meteors have been detected on collision course with the station.", "Meteor Alert", 'sound/ai/meteors.ogg')
priority_announce("Meteors have been detected on collision course with the station. Estimated time until impact: [round(startWhen/60)] minutes.", "Meteor Alert", 'sound/ai/meteors.ogg')
/datum/round_event/meteor_wave/tick()
if(ISMULTIPLE(activeFor, 3))
@@ -573,4 +573,14 @@
name = "Maintenance Peaches"
desc = "I have a mouth and I must eat."
icon_state = "peachcanmaint"
tastes = list("peaches" = 1, "tin" = 7)
tastes = list("peaches" = 1, "tin" = 7)
/obj/item/reagent_containers/food/snacks/chocolatestrawberry
name = "Chocolate dipped strawberries"
desc = "A strawberry dipped in a bit of chocolate."
icon_state = "chocolatestrawberry"
list_reagents = list("sugar" = 5, "nutriment" = 2)
filling_color = "#ffdf26"
w_class = WEIGHT_CLASS_NORMAL
tastes = list("strawberries" = 5, "chocolate" = 3)
foodtype = FRUIT | SUGAR
@@ -308,7 +308,6 @@
tastes = list("bread" = 1, "egg" = 1, "cheese" = 1)
foodtype = GRAIN | MEAT | DAIRY
/obj/item/reagent_containers/food/snacks/sugarcookie
name = "sugar cookie"
desc = "Just like your little sister used to make."
@@ -369,6 +368,16 @@
tastes = list("cake" = 3, "blue cherry" = 1)
foodtype = GRAIN | FRUIT | SUGAR
/obj/item/reagent_containers/food/snacks/strawberrycupcake
name = "Strawberry cupcake"
desc = "Strawberry inside a delicious cupcake."
icon_state = "strawberrycupcake"
bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
list_reagents = list("nutriment" = 5, "vitamin" = 1)
filling_color = "#F0E68C"
tastes = list("cake" = 2, "strawberry" = 1)
foodtype = GRAIN | FRUIT | SUGAR
/obj/item/reagent_containers/food/snacks/honeybun
name = "honey bun"
desc = "A sticky pastry bun glazed with honey."
@@ -315,4 +315,12 @@
filling_color = "#1E90FF"
list_reagents = list("nutriment" = 2, "vitamin" = 4)
tastes = list("nuts" = 1, "pie" = 1)
foodtype = GRAIN
foodtype = GRAIN
/obj/item/reagent_containers/food/snacks/pie/strawberrypie
name = "strawberry pie"
desc = "A strawberry.pie."
icon_state = "strawberrypie"
bonus_reagents = list("nutriment" = 6, "vitamin" = 6)
tastes = list("strawberry" = 1, "pie" = 1)
foodtype = GRAIN | FRUIT | SUGAR
@@ -7,7 +7,7 @@
desc = "Nougat love it or hate it."
icon_state = "candy"
trash = /obj/item/trash/candy
list_reagents = list("nutriment" = 1, "sugar" = 3)
list_reagents = list("nutriment" = 1, "sugar" = 3, "cocoa" = 3)
junkiness = 25
filling_color = "#D2691E"
tastes = list("candy" = 1)
@@ -332,3 +332,12 @@
)
result = /obj/item/reagent_containers/food/snacks/riceball
subcategory = CAT_MISCFOOD
/datum/crafting_recipe/food/chocolatestrawberry
name = "Chocolate Strawberry"
reqs = list(
/obj/item/reagent_containers/food/snacks/chocolatebar = 1,
/obj/item/reagent_containers/food/snacks/grown/strawberries = 1
)
result = /obj/item/reagent_containers/food/snacks/chocolatestrawberry
subcategory = CAT_MISCFOOD
@@ -325,6 +325,15 @@ datum/crafting_recipe/food/donut/meat
result = /obj/item/reagent_containers/food/snacks/bluecherrycupcake
subcategory = CAT_PASTRY
/datum/crafting_recipe/food/strawberrycupcake
name = "Strawberry cherry cupcake"
reqs = list(
/obj/item/reagent_containers/food/snacks/pastrybase = 1,
/obj/item/reagent_containers/food/snacks/grown/strawberries = 1
)
result = /obj/item/reagent_containers/food/snacks/strawberrycupcake
subcategory = CAT_PASTRY
/datum/crafting_recipe/food/honeybun
name = "Honey bun"
reqs = list(
@@ -160,6 +160,15 @@
result = /obj/item/reagent_containers/food/snacks/pie/frostypie
subcategory = CAT_PIE
/datum/crafting_recipe/food/strawberrypie
name = "Strawberry pie"
reqs = list(
/obj/item/reagent_containers/food/snacks/pie/plain = 1,
/obj/item/reagent_containers/food/snacks/grown/strawberries = 1
)
result = /obj/item/reagent_containers/food/snacks/pie/strawberrypie
subcategory = CAT_PIE
/datum/crafting_recipe/food/baklava
name = "Baklava pie"
reqs = list(
@@ -404,6 +404,31 @@ h1.alert, h2.alert {color: #99aab5;}
.redtext {color: #c51e1e; font-size: 24px;}
.clown {color: #ff70c1; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;}
@keyframes velvet {
0% { color: #400020; }
40% { color: #FF0000; }
50% { color: #FF8888; }
60% { color: #FF0000; }
100% { color: #400020; }
}
.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;}
@keyframes hypnocolor {
0% { color: #202020; }
25% { color: #4b02ac; }
50% { color: #9f41f1; }
75% { color: #541c9c; }
100% { color: #7adbf3; }
}
.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;}
@keyframes phobia {
0% { color: #f75a5a; }
50% { color: #dd0000; }
100% { color: #f75a5a; }
}
.icon {height: 1em; width: auto;}
+19
View File
@@ -215,3 +215,22 @@
filling_color = "#7FFF00"
tastes = list("green grape" = 1)
distill_reagent = "cognac"
// Strawberry
/obj/item/seeds/strawberries
name = "pack of green grape seeds"
desc = "These seeds grow into strawberries vines."
icon_state = "seed-strawberry"
species = "strawberry"
plantname = "Strawberry Vine"
product = /obj/item/reagent_containers/food/snacks/grown/strawberries
reagents_add = list("vitamin" = 0.07, "nutriment" = 0.1, "sugar" = 0.1)
mutatelist = list()
/obj/item/reagent_containers/food/snacks/grown/strawberries
seed = /obj/item/seeds/strawberries
name = "strawberry"
icon_state = "strawberries"
filling_color = "#7FFF00"
tastes = list("strawberries" = 1)
wine_power = 20
+1
View File
@@ -127,6 +127,7 @@ Chemist
backpack = /obj/item/storage/backpack/chemistry
satchel = /obj/item/storage/backpack/satchel/chem
duffelbag = /obj/item/storage/backpack/duffelbag/med
l_hand = /obj/item/fermichem/pHbooklet
chameleon_extras = /obj/item/gun/syringe
+33 -10
View File
@@ -18,10 +18,10 @@
/mob/living/carbon/monkey/handle_blood()
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL)
if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio))
blood_volume += 0.1 // regenerate blood VERY slowly
if(blood_volume < BLOOD_VOLUME_OKAY)
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
if(blood_volume < (BLOOD_VOLUME_OKAY * blood_ratio))
adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.02, 1))
// Takes care blood loss and regeneration
/mob/living/carbon/human/handle_blood()
@@ -33,7 +33,7 @@
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER))
if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio) && !HAS_TRAIT(src, TRAIT_NOHUNGER))
var/nutrition_ratio = 0
switch(nutrition)
if(0 to NUTRITION_LEVEL_STARVING)
@@ -46,20 +46,22 @@
nutrition_ratio = 0.8
else
nutrition_ratio = 1
if(HAS_TRAIT(src, TRAIT_HIGH_BLOOD))
nutrition_ratio *= 1.2
if(satiety > 80)
nutrition_ratio *= 1.25
nutrition = max(0, nutrition - nutrition_ratio * HUNGER_FACTOR)
blood_volume = min(BLOOD_VOLUME_NORMAL, blood_volume + 0.5 * nutrition_ratio)
blood_volume = min((BLOOD_VOLUME_NORMAL * blood_ratio), blood_volume + 0.5 * nutrition_ratio)
//Effects of bloodloss
var/word = pick("dizzy","woozy","faint")
switch(blood_volume)
switch(blood_volume * INVERSE(blood_ratio))
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
if(prob(5))
to_chat(src, "<span class='warning'>You feel [word].</span>")
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1))
adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.01, 1))
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.02, 1))
if(prob(5))
blur_eyes(6)
to_chat(src, "<span class='warning'>You feel very [word].</span>")
@@ -111,7 +113,7 @@
blood_volume = initial(blood_volume)
/mob/living/carbon/human/restore_blood()
blood_volume = BLOOD_VOLUME_NORMAL
blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
bleed_rate = 0
/****************************************************
@@ -122,7 +124,7 @@
/mob/living/proc/transfer_blood_to(atom/movable/AM, amount, forced)
if(!blood_volume || !AM.reagents)
return 0
if(blood_volume < BLOOD_VOLUME_BAD && !forced)
if(blood_volume < (BLOOD_VOLUME_BAD * blood_ratio) && !forced)
return 0
if(blood_volume < amount)
@@ -322,3 +324,24 @@
var/obj/effect/decal/cleanable/oil/B = locate() in T.contents
if(!B)
B = new(T)
//This is a terrible way of handling it.
/mob/living/proc/ResetBloodVol()
if(ishuman(src))
var/mob/living/carbon/human/H = src
if (HAS_TRAIT(src, TRAIT_HIGH_BLOOD))
blood_ratio = 1.2
H.handle_blood()
return
blood_ratio = 1
H.handle_blood()
return
blood_ratio = 1
/mob/living/proc/AdjustBloodVol(var/value)
if(blood_ratio == value)
return
blood_ratio = value
if(ishuman(src))
var/mob/living/carbon/human/H = src
H.handle_blood()
+18 -1
View File
@@ -6,6 +6,7 @@
create_reagents(1000)
update_body_parts() //to update the carbon's new bodyparts appearance
GLOB.carbon_list += src
blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
/mob/living/carbon/Destroy()
//This must be done first, so the mob ghosts correctly before DNA etc is nulled
@@ -477,11 +478,13 @@
if(message)
visible_message("<span class='danger'>[src] throws up all over [p_them()]self!</span>", \
"<span class='userdanger'>You throw up all over yourself!</span>")
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomitself)
distance = 0
else
if(message)
visible_message("<span class='danger'>[src] throws up!</span>", "<span class='userdanger'>You throw up!</span>")
if(!isflyperson(src))
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomit)
if(stun)
Stun(80)
@@ -929,3 +932,17 @@
/mob/living/carbon/can_resist()
return bodyparts.len > 2 && ..()
/mob/living/carbon/proc/hypnosis_vulnerable()//unused atm, but added in case
if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
return FALSE
if(hallucinating())
return TRUE
if(IsSleeping())
return TRUE
if(HAS_TRAIT(src, TRAIT_DUMB))
return TRUE
GET_COMPONENT_FROM(mood, /datum/component/mood, src)
if(mood)
if(mood.sanity < SANITY_UNSTABLE)
return TRUE
@@ -278,7 +278,7 @@
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
msg += "[t_He] look[p_s()] extremely disgusted.\n"
if(blood_volume < BLOOD_VOLUME_SAFE)
if(blood_volume < (BLOOD_VOLUME_SAFE*blood_ratio))
msg += "[t_He] [t_has] pale skin.\n"
if(bleedsuppress)
@@ -312,6 +312,13 @@
if(91.01 to INFINITY)
msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
if(reagents.has_reagent("astral"))
msg += "[t_He] have wild, spacey eyes"
if(mind)
msg += " and have a strange, abnormal look to them.\n"
else
msg += " and don't look like they're all there.\n"
if(isliving(user))
var/mob/living/L = user
if(src != user && HAS_TRAIT(L, TRAIT_EMPATH) && !appears_dead)
@@ -335,6 +342,13 @@
msg += "</span>"
var/obj/item/organ/vocal_cords/Vc = user.getorganslot(ORGAN_SLOT_VOICE)
if(Vc)
if(istype(Vc, /obj/item/organ/vocal_cords/velvet))
if(client?.prefs.lewdchem)
msg += "<span class='velvet'><i>You feel your chords resonate looking at them.</i></span>\n"
if(!appears_dead)
if(stat == UNCONSCIOUS)
msg += "[t_He] [t_is]n't responding to anything around [t_him] and seem[p_s()] to be asleep.\n"
@@ -815,6 +815,8 @@
for(var/datum/mutation/human/HM in dna.mutations)
if(HM.quality != POSITIVE)
dna.remove_mutation(HM.name)
if(blood_volume < (BLOOD_VOLUME_NORMAL*blood_ratio))
blood_volume = (BLOOD_VOLUME_NORMAL*blood_ratio)
..()
/mob/living/carbon/human/check_weakness(obj/item/weapon, mob/living/attacker)
@@ -51,6 +51,7 @@
var/list/blood_smear = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0)
var/name_override //For temporary visible name changes
var/genital_override = FALSE //Force genitals on things incase of chems
var/nameless = FALSE //For drones of both the insectoid and robotic kind. And other types of nameless critters.
@@ -517,7 +517,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(B)
var/mutable_appearance/MA = mutable_appearance(B.icon, B.icon_state, -BODY_LAYER)
if(UNDIE_COLORABLE(B))
MA.color = H.undie_color
MA.color = "#[H.undie_color]"
standing += MA
if(H.undershirt)
@@ -533,7 +533,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else
MA = mutable_appearance(T.icon, T.icon_state, -BODY_LAYER)
if(UNDIE_COLORABLE(T))
MA.color = H.shirt_color
MA.color = "#[H.shirt_color]"
standing += MA
if(H.socks && H.get_num_legs(FALSE) >= 2)
@@ -546,7 +546,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/digilegs = (DIGITIGRADE in species_traits) ? "_d" : ""
var/mutable_appearance/MA = mutable_appearance(S.icon, "[S.icon_state][digilegs]", -BODY_LAYER)
if(UNDIE_COLORABLE(S))
MA.color = H.socks_color
MA.color = "[H.socks_color]"
standing += MA
if(standing.len)
@@ -50,14 +50,14 @@
H.adjustBruteLoss(5)
to_chat(H, "<span class='danger'>You feel empty!</span>")
if(H.blood_volume < BLOOD_VOLUME_NORMAL)
if(H.blood_volume < (BLOOD_VOLUME_NORMAL * H.blood_ratio))
if(H.nutrition >= NUTRITION_LEVEL_STARVING)
H.blood_volume += 3
H.nutrition -= 2.5
if(H.blood_volume < BLOOD_VOLUME_OKAY)
if(H.blood_volume < (BLOOD_VOLUME_OKAY*H.blood_ratio))
if(prob(5))
to_chat(H, "<span class='danger'>You feel drained!</span>")
if(H.blood_volume < BLOOD_VOLUME_BAD)
if(H.blood_volume < (BLOOD_VOLUME_BAD*H.blood_ratio))
Cannibalize_Body(H)
if(regenerate_limbs)
regenerate_limbs.UpdateButtonIcon()
@@ -89,7 +89,7 @@
var/list/limbs_to_heal = H.get_missing_limbs()
if(limbs_to_heal.len < 1)
return 0
if(H.blood_volume >= BLOOD_VOLUME_OKAY+40)
if(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
return 1
return 0
@@ -100,13 +100,13 @@
to_chat(H, "<span class='notice'>You feel intact enough as it is.</span>")
return
to_chat(H, "<span class='notice'>You focus intently on your missing [limbs_to_heal.len >= 2 ? "limbs" : "limb"]...</span>")
if(H.blood_volume >= 40*limbs_to_heal.len+BLOOD_VOLUME_OKAY)
if(H.blood_volume >= 40*limbs_to_heal.len+(BLOOD_VOLUME_OKAY*H.blood_ratio))
H.regenerate_limbs()
H.blood_volume -= 40*limbs_to_heal.len
to_chat(H, "<span class='notice'>...and after a moment you finish reforming!</span>")
return
else if(H.blood_volume >= 40)//We can partially heal some limbs
while(H.blood_volume >= BLOOD_VOLUME_OKAY+40)
while(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
var/healed_limb = pick(limbs_to_heal)
H.regenerate_limb(healed_limb)
limbs_to_heal -= healed_limb
@@ -140,7 +140,7 @@
bodies -= C // This means that the other bodies maintain a link
// so if someone mindswapped into them, they'd still be shared.
bodies = null
C.blood_volume = min(C.blood_volume, BLOOD_VOLUME_NORMAL)
C.blood_volume = min(C.blood_volume, (BLOOD_VOLUME_NORMAL*C.blood_ratio))
..()
/datum/species/jelly/slime/on_species_gain(mob/living/carbon/C, datum/species/old_species)
@@ -731,4 +731,4 @@
to_chat(H, "<span class='notice'>You connect [target]'s mind to your slime link!</span>")
else
to_chat(H, "<span class='warning'>You can't seem to link [target]'s mind...</span>")
to_chat(target, "<span class='warning'>The foreign presence leaves your mind.</span>")
to_chat(target, "<span class='warning'>The foreign presence leaves your mind.</span>")
@@ -46,7 +46,7 @@
C.adjustCloneLoss(-4)
return
C.blood_volume -= 0.75
if(C.blood_volume <= BLOOD_VOLUME_SURVIVE)
if(C.blood_volume <= (BLOOD_VOLUME_SURVIVE*C.blood_ratio))
to_chat(C, "<span class='danger'>You ran out of blood!</span>")
C.dust()
var/area/A = get_area(C)
@@ -88,4 +88,4 @@
AM.Hear(rendered, src, language, message, , spans)
if(critical) //Dying words.
succumb(1)
succumb()
+8
View File
@@ -229,6 +229,9 @@
else if(SA_partialpressure > 0.01)
if(prob(20))
emote(pick("giggle","laugh"))
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria)
else
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria")
//BZ (Facepunch port of their Agent B)
if(breath_gases[/datum/gas/bz])
@@ -527,6 +530,9 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
if(jitteriness)
do_jitter_animation(jitteriness)
jitteriness = max(jitteriness - restingpwr, 0)
SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "jittery", /datum/mood_event/jittery)
else
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "jittery")
if(stuttering)
stuttering = max(stuttering-1, 0)
@@ -612,6 +618,8 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
if(drunkenness >= 101)
adjustToxLoss(4) //Let's be honest you shouldn't be alive by now
else
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "drunk")
//used in human and monkey handle_environment()
/mob/living/carbon/proc/natural_bodytemperature_stabilization()
@@ -191,7 +191,7 @@
clear_alert("legcuffed")
if(legcuffed)
var/mutable_appearance/legcuffs = mutable_appearance('icons/mob/restraints.dmi', legcuffed.item_state, -LEGCUFF_LAYER)
legcuffs.color = handcuffed.color
legcuffs.color = legcuffed.color
overlays_standing[HANDCUFF_LAYER] = legcuffs
apply_overlay(LEGCUFF_LAYER)
+15 -5
View File
@@ -318,17 +318,27 @@
visible_message("<b>[src]</b> points at [A].", "<span class='notice'>You point at [A].</span>")
return TRUE
/mob/living/verb/succumb(whispered as null)
/mob/living/verb/succumb()
set name = "Succumb"
set category = "IC"
if(src.has_status_effect(/datum/status_effect/chem/enthrall))
var/datum/status_effect/chem/enthrall/E = src.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase < 3)
if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
to_chat(src, "<span class='notice'>Your mindshield prevents your mind from giving in!</span>")
else if(src.mind.assigned_role in GLOB.command_positions)
to_chat(src, "<span class='notice'>Your dedication to your department prevents you from giving in!</span>")
else
E.enthrallTally += 20
to_chat(src, "<span class='notice'>You give into [E.master]'s influence.</span>")
if (InCritical())
log_message("Has [whispered ? "whispered his final words" : "succumbed to death"] while in [InFullCritical() ? "hard":"soft"] critical with [round(health, 0.1)] points of health!", LOG_ATTACK)
log_message("Has succumbed to death while in [InFullCritical() ? "hard":"soft"] critical with [round(health, 0.1)] points of health!", LOG_ATTACK)
adjustOxyLoss(health - HEALTH_THRESHOLD_DEAD)
updatehealth()
if(!whispered)
to_chat(src, "<span class='notice'>You have given up life and succumbed to death.</span>")
to_chat(src, "<span class='notice'>You have given up life and succumbed to death.</span>")
death()
/mob/living/incapacitated(ignore_restraints, ignore_grab)
if(stat || IsUnconscious() || IsStun() || IsKnockdown() || recoveringstam || (!ignore_restraints && restrained(ignore_grab))) // CIT CHANGE - adds recoveringstam check here
return TRUE
@@ -532,7 +542,7 @@
var/trail_type = getTrail()
if(trail_type)
var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
if(blood_volume && blood_volume > max(BLOOD_VOLUME_NORMAL*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
if(blood_volume && blood_volume > max((BLOOD_VOLUME_NORMAL*blood_ratio)*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage.
var/newdir = get_dir(target_turf, start)
if(newdir != direction)
@@ -77,6 +77,7 @@
var/stun_absorption = null //converted to a list of stun absorption sources this mob has when one is added
var/blood_volume = 0 //how much blood the mob has
var/blood_ratio = 1 //How much blood the mob needs, in terms of ratio (i.e 1.2 will require BLOOD_VOLUME_NORMAL of 672) DO NOT GO ABOVE 3.55 Well, actually you can but, then they can't get enough blood.
var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override
var/see_override = 0 //0 for no override, sets see_invisible = see_override in silicon & carbon life process via update_sight()
+2 -1
View File
@@ -211,7 +211,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
send_speech(message, message_range, src, bubble_type, spans, language, message_mode)
if(succumbed)
succumb(1)
succumb()
to_chat(src, compose_message(src, language, message, , spans, message_mode))
return 1
@@ -281,6 +281,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode)
else
AM.Hear(rendered, src, message_language, message, , spans, message_mode)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message)
//speech bubble
var/list/speech_bubble_recipients = list()
@@ -0,0 +1,59 @@
/mob/living/simple_animal/astral
name = "Astral projection"
desc = "A soul of someone projecting their mind."
icon = 'icons/mob/mob.dmi'
icon_state = "ghost"
icon_living = "ghost"
mob_biotypes = list(MOB_SPIRIT)
attacktext = "raises the hairs on the neck of"
response_harm = "disrupts the concentration of"
response_disarm = "wafts"
friendly = "communes with"
loot = null
maxHealth = 10
health = 10
melee_damage_lower = 0
melee_damage_upper = 0
obj_damage = 0
deathmessage = "disappears as if it was never really there to begin with"
incorporeal_move = 1
alpha = 50
attacktext = "touches the mind of"
speak_emote = list("echos")
movement_type = FLYING
var/pseudo_death = FALSE
var/posses_safe = FALSE
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)
unsuitable_atmos_damage = 0
minbodytemp = 0
maxbodytemp = 100000
/mob/living/simple_animal/astral/death()
icon_state = "shade_dead"
Stun(1000)
canmove = 0
friendly = "deads at"
pseudo_death = TRUE
incorporeal_move = 0
to_chat(src, "<span class='notice'>Your astral projection is interrupted and your mind is sent back to your body with a shock!</span>")
/mob/living/simple_animal/astral/ClickOn(var/atom/A, var/params)
..()
if(pseudo_death == FALSE)
if(isliving(A))
if(ishuman(A))
var/mob/living/carbon/human/H = A
if(H.reagents.has_reagent("astral") && !H.mind)
var/datum/reagent/fermi/astral/As = locate(/datum/reagent/fermi/astral) in H.reagents.reagent_list
if(As.originalmind == src.mind && As.current_cycle < 10 && H.stat != DEAD) //So you can return to your body.
to_chat(src, "<span class='warning'><b><i>The intensity of the astrogen in your body is too much allow you to return to yourself yet!</b></i></span>")
return
to_chat(src, "<b><i>You astrally possess [H]!</b></i>")
log_game("FERMICHEM: [src] has astrally possessed [A]!")
src.mind.transfer_to(H)
qdel(src)
var/message = html_decode(stripped_input(src, "Enter a message to send to [A]", MAX_MESSAGE_LEN))
if(!message)
return
to_chat(A, "[src] projects into your mind, <b><i> \"[message]\"</b></i>")
log_game("FERMICHEM: [src] has astrally transmitted [message] into [A]")
@@ -292,3 +292,31 @@
if(L.a_intent == INTENT_HARM && L.reagents && !stat)
L.reagents.add_reagent("nutriment", 0.4)
L.reagents.add_reagent("vitamin", 0.4)
//Cat made
/mob/living/simple_animal/pet/cat/custom_cat
name = "White cat" //Incase it somehow gets spawned without an ID
desc = "A cute white catto!"
icon_state = "custom_cat"
icon_living = "custom_cat"
icon_dead = "custom_cat_dead"
gender = FEMALE
gold_core_spawnable = NO_SPAWN
health = 50 //So people can't instakill it s
maxHealth = 50
speak = list("Meowrowr!", "Mew!", "Miauen!")
speak_emote = list("wigglepurrs", "mewls")
emote_hear = list("meows.", "mews.")
emote_see = list("looks at you eagerly for pets!", "wiggles enthusiastically.")
gold_core_spawnable = NO_SPAWN
var/pseudo_death = FALSE
/mob/living/simple_animal/pet/cat/custom_cat/death()
if (pseudo_death == TRUE) //secret cat chem
icon_state = "custom_cat_dead"
Stun(1000)
canmove = 0
friendly = "deads at"
return
else
..()
@@ -55,4 +55,28 @@
/mob/living/simple_animal/hostile/zombie/drop_loot()
. = ..()
corpse.forceMove(drop_location())
corpse.create()
corpse.create()
/mob/living/simple_animal/hostile/unemployedclone
name = "Failed clone"
desc = "Somebody failed chemistry."
icon = 'icons/mob/human.dmi'
icon_state = "husk"
icon_living = "husk"
icon_dead = "husk"
mob_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
speak_chance = 0
stat_attack = UNCONSCIOUS //braains
maxHealth = 100
health = 100
harm_intent_damage = 5
melee_damage_lower = 21
melee_damage_upper = 21
attacktext = "bites"
attack_sound = 'sound/hallucinations/growl1.ogg'
a_intent = INTENT_HARM
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
spacewalk = FALSE
status_flags = CANPUSH
del_on_death = 0
+29
View File
@@ -32,4 +32,33 @@
last_taste_time = world.time
last_taste_text = text_output
//FermiChem - How to check pH of a beaker without a meter/pH paper.
//Basically checks the pH of the holder and burns your poor tongue if it's too acidic!
//TRAIT_AGEUSIA players can't taste, unless it's burning them.
//taking sips of a strongly acidic/alkaline substance will burn your tongue.
/mob/living/carbon/taste(datum/reagents/from)
var/obj/item/organ/tongue/T = getorganslot("tongue")
if (!T)
return
.=..()
if ((from.pH > 12.5) || (from.pH < 1.5))
to_chat(src, "<span class='warning'>You taste chemical burns!</span>")
T.adjustTongueLoss(src, 4)
if(istype(T, /obj/item/organ/tongue/cybernetic))
to_chat(src, "<span class='notice'>Your tongue moves on it's own in response to the liquid.</span>")
say("The pH is appropriately [round(from.pH, 1)].")
return
if (!HAS_TRAIT(src, TRAIT_AGEUSIA)) //I'll let you get away with not having 1 damage.
switch(from.pH)
if(11.5 to INFINITY)
to_chat(src, "<span class='warning'>You taste a strong alkaline flavour!</span>")
T.adjustTongueLoss(src, 1)
if(8.5 to 11.5)
to_chat(src, "<span class='notice'>You taste a sort of soapy tone in the mixture.</span>")
if(2.5 to 5.5)
to_chat(src, "<span class='notice'>You taste a sort of acid tone in the mixture.</span>")
if(-INFINITY to 2.5)
to_chat(src, "<span class='warning'>You taste a strong acidic flavour!</span>")
T.adjustTongueLoss(src, 1)
#undef DEFAULT_TASTE_SENSITIVITY
+339 -46
View File
@@ -1,4 +1,3 @@
/proc/build_chemical_reagent_list()
//Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
@@ -53,10 +52,16 @@
var/maximum_volume = 100
var/atom/my_atom = null
var/chem_temp = 150
var/pH = REAGENT_NORMAL_PH//Potential of hydrogen. Edited on adding new reagents, deleting reagents, and during fermi reactions.
var/overallPurity = 1
var/last_tick = 1
var/addiction_tick = 1
var/list/datum/reagent/addiction_list = new/list()
var/reagents_holder_flags
var/targetVol = 0 //the target volume, i.e. the total amount that can be created during a fermichem reaction.
var/reactedVol = 0 //how much of the reagent is reacted during a fermireaction
var/fermiIsReacting = FALSE //that prevents multiple reactions from occurring (i.e. add_reagent calls to process_reactions(), this stops any extra reactions.)
var/fermiReactID = null //ID of the chem being made during a fermireaction, kept here so it's cache isn't lost between loops/procs.
/datum/reagents/New(maximum=100, new_flags)
maximum_volume = maximum
@@ -121,11 +126,13 @@
/datum/reagents/proc/remove_all(amount = 1)
var/list/cached_reagents = reagent_list
if((total_volume - amount) <= 0)//Because this can result in 0, I don't want it to crash.
pH = 7
if(total_volume > 0)
var/part = amount / total_volume
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
remove_reagent(R.id, R.volume * part)
remove_reagent(R.id, R.volume * part, ignore_pH = TRUE)
update_total()
handle_reactions()
@@ -189,8 +196,11 @@
var/transfer_amount = T.volume * part
if(preserve_data)
trans_data = copy_data(T)
R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, no_react = 1) //we only handle reaction after every reagent has been transfered.
remove_reagent(T.id, transfer_amount)
R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, T.purity, pH, no_react = TRUE, ignore_pH = TRUE) //we only handle reaction after every reagent has been transfered.
remove_reagent(T.id, transfer_amount, ignore_pH = TRUE)
update_total()
R.update_total()
@@ -249,7 +259,8 @@
if(current_reagent.id == reagent)
if(preserve_data)
trans_data = current_reagent.data
R.add_reagent(current_reagent.id, amount, trans_data, src.chem_temp)
R.add_reagent(current_reagent.id, amount, trans_data, chem_temp, current_reagent.purity, pH, no_react = TRUE)
remove_reagent(current_reagent.id, amount, 1)
break
@@ -350,14 +361,21 @@
R.on_update (A)
update_total()
/datum/reagents/proc/handle_reactions()
/datum/reagents/proc/handle_reactions()//HERE EDIT HERE THE MAIN REACTION
if(fermiIsReacting == TRUE)
return
if(reagents_holder_flags & NO_REACT)
return //Yup, no reactions here. No siree.
var/list/cached_reagents = reagent_list
var/list/cached_reactions = GLOB.chemical_reactions_list
var/datum/cached_my_atom = my_atom
var/reaction_occurred = 0
var/reaction_occurred = 0 // checks if reaction, binary variable
var/continue_reacting = FALSE //Helps keep track what kind of reaction is occuring; standard or fermi.
do
var/list/possible_reactions = list()
reaction_occurred = 0
@@ -382,6 +400,7 @@
var/has_special_react = C.special_react
var/can_special_react = 0
for(var/B in cached_required_reagents)
if(!has_reagent(B, cached_required_reagents[B]))
break
@@ -402,7 +421,7 @@
if(!C.required_other)
matching_other = 1
else if(istype(cached_my_atom, /obj/item/slime_extract))
else if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract.
var/obj/item/slime_extract/M = cached_my_atom
if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this
@@ -413,7 +432,7 @@
if(!C.required_other)
matching_other = 1
if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))
if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))//Temperature check!!
meets_temp_requirement = 1
if(!has_special_react || C.check_special_react(src))
@@ -427,53 +446,268 @@
//select the reaction with the most extreme temperature requirements
for(var/V in possible_reactions)
var/datum/chemical_reaction/competitor = V
if(selected_reaction.is_cold_recipe) //if there are no recipe conflicts, everything in possible_reactions will have this same value for is_cold_reaction. warranty void if assumption not met.
if(selected_reaction.is_cold_recipe)
if(competitor.required_temp <= selected_reaction.required_temp)
selected_reaction = competitor
else
if(competitor.required_temp >= selected_reaction.required_temp)
if(competitor.required_temp >= selected_reaction.required_temp) //will return with the hotter reacting first.
selected_reaction = competitor
var/list/cached_required_reagents = selected_reaction.required_reagents
var/list/cached_results = selected_reaction.results
var/list/cached_required_reagents = selected_reaction.required_reagents//update reagents list
var/list/cached_results = selected_reaction.results//resultant chemical list
var/special_react_result = selected_reaction.check_special_react(src)
var/list/multiplier = INFINITY
for(var/B in cached_required_reagents)
multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))
for(var/B in cached_required_reagents)
remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1)
//Splits reactions into two types; FermiChem is advanced reaction mechanics, Other is default reaction.
//FermiChem relies on two additional properties; pH and impurity
//Temperature plays into a larger role too.
var/datum/chemical_reaction/C = selected_reaction
for(var/P in selected_reaction.results)
multiplier = max(multiplier, 1) //this shouldnt happen ...
SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)
add_reagent(P, cached_results[P]*multiplier, null, chem_temp)
if (C.FermiChem == TRUE && !continue_reacting)
if (chem_temp > C.ExplodeTemp) //This is first to ensure explosions.
var/datum/chemical_reaction/fermi/Ferm = selected_reaction
fermiIsReacting = FALSE
SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[Ferm] explosion"))
Ferm.FermiExplode(src, my_atom, volume = total_volume, temp = chem_temp, pH = pH)
return 0
var/list/seen = viewers(4, get_turf(my_atom))
var/iconhtml = icon2html(cached_my_atom, seen)
if(cached_my_atom)
if(!ismob(cached_my_atom)) // No bubbling mobs
if(selected_reaction.mix_sound)
playsound(get_turf(cached_my_atom), selected_reaction.mix_sound, 80, 1)
for(var/B in cached_required_reagents)
multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.01))
for(var/P in selected_reaction.results)
targetVol = cached_results[P]*multiplier
for(var/mob/M in seen)
to_chat(M, "<span class='notice'>[iconhtml] [selected_reaction.mix_message]</span>")
if( (chem_temp <= C.ExplodeTemp) && (chem_temp >= C.OptimalTempMin))
if( (pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) )//To prevent pointless reactions
if (fermiIsReacting == TRUE)
return 0
else
START_PROCESSING(SSprocessing, src)
selected_reaction.on_reaction(src, my_atom, multiplier)
fermiIsReacting = TRUE
fermiReactID = selected_reaction
reaction_occurred = 1
else //It's a little bit of a confusing nest, but esstentially we check if it's a fermireaction, then temperature, then pH. If this is true, the remainer of this handler is run.
return 0 //If pH is out of range
else
return 0 //If not hot enough
//Standard reaction mechanics:
else
if (C.FermiChem == TRUE)//Just to make sure
return 0
for(var/B in cached_required_reagents) //
multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.01))
for(var/B in cached_required_reagents)
remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1, ignore_pH = TRUE)
for(var/P in selected_reaction.results)
multiplier = max(multiplier, 1) //this shouldnt happen ...
SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)//log
add_reagent(P, cached_results[P]*multiplier, null, chem_temp)
var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers
var/iconhtml = icon2html(cached_my_atom, seen)
if(cached_my_atom)
if(!ismob(cached_my_atom)) // No bubbling mobs
if(selected_reaction.mix_sound)
playsound(get_turf(cached_my_atom), selected_reaction.mix_sound, 80, 1)
if(istype(cached_my_atom, /obj/item/slime_extract))
var/obj/item/slime_extract/ME2 = my_atom
ME2.Uses--
if(ME2.Uses <= 0) // give the notification that the slime core is dead
for(var/mob/M in seen)
to_chat(M, "<span class='notice'>[iconhtml] \The [my_atom]'s power is consumed in the reaction.</span>")
ME2.name = "used slime extract"
ME2.desc = "This extract has been used up."
to_chat(M, "<span class='notice'>[iconhtml] [selected_reaction.mix_message]</span>")
selected_reaction.on_reaction(src, multiplier, special_react_result)
reaction_occurred = 1
if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up.
var/obj/item/slime_extract/ME2 = my_atom
ME2.Uses--
if(ME2.Uses <= 0) // give the notification that the slime core is dead
for(var/mob/M in seen)
to_chat(M, "<span class='notice'>[iconhtml] \The [my_atom]'s power is consumed in the reaction.</span>")
ME2.name = "used slime extract"
ME2.desc = "This extract has been used up."
selected_reaction.on_reaction(src, multiplier, special_react_result)
reaction_occurred = 1
continue_reacting = TRUE
while(reaction_occurred)
update_total()
return 0
/datum/reagents/process()
var/datum/chemical_reaction/fermi/C = fermiReactID
var/list/cached_required_reagents = C.required_reagents//update reagents list
var/list/cached_results = C.results//resultant chemical list
var/multiplier = INFINITY
for(var/B in cached_required_reagents) //
multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.001))
if (multiplier == 0)
fermiEnd()
return
for(var/P in cached_results)
targetVol = cached_results[P]*multiplier
if (fermiIsReacting == FALSE)
CRASH("Fermi has refused to stop reacting even though we asked her nicely.")
if (chem_temp > C.OptimalTempMin && fermiIsReacting == TRUE)//To prevent pointless reactions
if( (pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) )
if (reactedVol < targetVol)
reactedVol = fermiReact(fermiReactID, chem_temp, pH, reactedVol, targetVol, cached_required_reagents, cached_results, multiplier)
else//Volume is used up
fermiEnd()
return
else//pH is out of range
fermiEnd()
return
else//Temperature is too low, or reaction has stopped.
fermiEnd()
return
/datum/reagents/proc/fermiEnd()
var/datum/chemical_reaction/fermi/C = fermiReactID
STOP_PROCESSING(SSprocessing, src)
fermiIsReacting = FALSE
reactedVol = 0
targetVol = 0
//pH check, handled at the end to reduce calls.
if(istype(my_atom, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = my_atom
RC.pH_check()
C.FermiFinish(src, my_atom)
handle_reactions()
update_total()
//Reaction sounds and words
playsound(get_turf(my_atom), C.mix_sound, 80, 1)
var/list/seen = viewers(5, get_turf(my_atom))
var/iconhtml = icon2html(my_atom, seen)
for(var/mob/M in seen)
to_chat(M, "<span class='notice'>[iconhtml] [C.mix_message]</span>")
/datum/reagents/proc/fermiReact(selected_reaction, cached_temp, cached_pH, reactedVol, targetVol, cached_required_reagents, cached_results, multiplier)
var/datum/chemical_reaction/fermi/C = selected_reaction
var/deltaT = 0
var/deltapH = 0
var/stepChemAmmount = 0
//get purity from combined beaker reactant purities HERE.
var/purity = 1
//Begin checks
//For now, purity is handled elsewhere (on add)
//Calculate DeltapH (Deviation of pH from optimal)
//Lower range
if (cached_pH < C.OptimalpHMin)
if (cached_pH < (C.OptimalpHMin - C.ReactpHLim))
deltapH = 0
return//If outside pH range, no reaction
else
deltapH = (((cached_pH - (C.OptimalpHMin - C.ReactpHLim))**C.CurveSharppH)/((C.ReactpHLim**C.CurveSharppH)))
//Upper range
else if (cached_pH > C.OptimalpHMax)
if (cached_pH > (C.OptimalpHMax + C.ReactpHLim))
deltapH = 0
return //If outside pH range, no reaction
else
deltapH = (((- cached_pH + (C.OptimalpHMax + C.ReactpHLim))**C.CurveSharppH)/(C.ReactpHLim**C.CurveSharppH))//Reverse - to + to prevent math operation failures.
//Within mid range
else if (cached_pH >= C.OptimalpHMin && cached_pH <= C.OptimalpHMax)
deltapH = 1
//This should never proc:
else
WARNING("[my_atom] attempted to determine FermiChem pH for '[C.id]' which broke for some reason! ([usr])")
//Calculate DeltaT (Deviation of T from optimal)
if (cached_temp < C.OptimalTempMax && cached_temp >= C.OptimalTempMin)
deltaT = (((cached_temp - C.OptimalTempMin)**C.CurveSharpT)/((C.OptimalTempMax - C.OptimalTempMin)**C.CurveSharpT))
else if (cached_temp >= C.OptimalTempMax)
deltaT = 1
else
deltaT = 0
purity = (deltapH)//set purity equal to pH offset
//Then adjust purity of result with reagent purity.
purity *= reactant_purity(C)
var/removeChemAmmount //remove factor
var/addChemAmmount //add factor
//ONLY WORKS FOR ONE PRODUCT AT THE MOMENT
//Calculate how much product to make and how much reactant to remove factors..
for(var/P in cached_results)
//stepChemAmmount = CLAMP(((deltaT * multiplier), 0, ((targetVol - reactedVol)/cached_results[P])) //used to have multipler, now it does
stepChemAmmount = (multiplier*cached_results[P])
if (stepChemAmmount >= C.RateUpLim)
stepChemAmmount = (C.RateUpLim)
addChemAmmount = deltaT * stepChemAmmount
if (addChemAmmount >= (targetVol - reactedVol))
addChemAmmount = (targetVol - reactedVol)
if (addChemAmmount < 0.01)
addChemAmmount = 0.01
removeChemAmmount = (addChemAmmount/cached_results[P])
//This is kept for future bugtesters.
//message_admins("Reaction vars: PreReacted: [reactedVol] of [targetVol]. deltaT [deltaT], multiplier [multiplier], Step [stepChemAmmount], uncapped Step [deltaT*(multiplier*cached_results[P])], addChemAmmount [addChemAmmount], removeFactor [removeChemAmmount] Pfactor [cached_results[P]], adding [addChemAmmount]")
//remove reactants
for(var/B in cached_required_reagents)
remove_reagent(B, (removeChemAmmount * cached_required_reagents[B]), safety = 1, ignore_pH = TRUE)
//add product
var/TotalStep = 0
for(var/P in cached_results)
SSblackbox.record_feedback("tally", "chemical_reaction", addChemAmmount, P)//log
SSblackbox.record_feedback("tally", "fermi_chem", addChemAmmount, P)
add_reagent(P, (addChemAmmount), null, cached_temp, purity)//add reagent function!! I THINK I can do this:
TotalStep += addChemAmmount//for multiple products
//Above should reduce yeild based on holder purity.
//Purity Check
for(var/datum/reagent/R in my_atom.reagents.reagent_list)
if(P == R.id)
if (R.purity < C.PurityMin)//If purity is below the min, blow it up.
fermiIsReacting = FALSE
SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[P] explosion"))
C.FermiExplode(src, my_atom, (reactedVol+targetVol), cached_temp, pH)
STOP_PROCESSING(SSprocessing, src)
return 0
C.FermiCreate(src)//proc that calls when step is done
//Apply pH changes and thermal output of reaction to beaker
chem_temp = round(cached_temp + (C.ThermicConstant * addChemAmmount))
pH += (C.HIonRelease * addChemAmmount)
//keep track of the current reacted amount
reactedVol = reactedVol + addChemAmmount
//Check extremes
if (chem_temp > C.ExplodeTemp)
//go to explode proc
fermiIsReacting = FALSE
SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[C] explosions"))
C.FermiExplode(src, my_atom, (reactedVol+targetVol), chem_temp, pH)
STOP_PROCESSING(SSprocessing, src)
return
//Make sure things are limited.
pH = CLAMP(pH, 0, 14)
//return said amount to compare for next step.
return (reactedVol)
//Currently calculates it irrespective of required reagents at the start
/datum/reagents/proc/reactant_purity(var/datum/chemical_reaction/fermi/C, holder)
var/list/cached_reagents = reagent_list
var/i = 0
var/cachedPurity
for(var/datum/reagent/R in my_atom.reagents.reagent_list)
if (R in cached_reagents)
cachedPurity += R.purity
i++
return cachedPurity/i
/datum/reagents/proc/isolate_reagent(reagent)
var/list/cached_reagents = reagent_list
for(var/_reagent in cached_reagents)
@@ -517,6 +751,7 @@
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
del_reagent(R.id)
pH = REAGENT_NORMAL_PH
return 0
/datum/reagents/proc/reaction(atom/A, method = TOUCH, volume_modifier = 1, show_message = 1)
@@ -563,13 +798,17 @@
/datum/reagents/proc/adjust_thermal_energy(J, min_temp = 2.7, max_temp = 1000)
var/S = specific_heat()
chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), 2.7, 1000)
chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), min_temp, max_temp)
if(istype(my_atom, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = my_atom
RC.temp_check()
/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, other_purity = 1, other_pH, no_react = 0, ignore_pH = FALSE)
/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0)
if(!isnum(amount) || !amount)
return FALSE
if(amount <= 0)
if(amount <= 0.00)
return FALSE
var/datum/reagent/D = GLOB.chemical_reagents_list[reagent]
@@ -577,6 +816,23 @@
WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])")
return FALSE
if (D.id == "water" && no_react == FALSE && !istype(my_atom, /obj/item/reagent_containers/food)) //Do like an otter, add acid to water, but also don't blow up botany.
if (pH <= 2)
SSblackbox.record_feedback("tally", "fermi_chem", 1, "water-acid explosions")
var/datum/effect_system/smoke_spread/chem/s = new
var/turf/T = get_turf(my_atom)
var/datum/reagents/R = new/datum/reagents(3000)
R.add_reagent("fermiAcid", amount)
for (var/datum/reagent/reagentgas in reagent_list)
R.add_reagent(reagentgas, amount/5)
remove_reagent(reagentgas, amount/5)
s.set_up(R, CLAMP(amount/10, 0, 2), T)
s.start()
return FALSE
if(!pH)
other_pH = D.pH
update_total()
var/cached_total = total_volume
if(cached_total + amount > maximum_volume)
@@ -587,6 +843,10 @@
var/cached_temp = chem_temp
var/list/cached_reagents = reagent_list
var/cached_pH = pH
//Equalize temperature - Not using specific_heat() because the new chemical isn't in yet.
var/specific_heat = 0
var/thermal_energy = 0
@@ -597,32 +857,55 @@
specific_heat += D.specific_heat * (amount / new_total)
thermal_energy += D.specific_heat * amount * reagtemp
chem_temp = thermal_energy / (specific_heat * new_total)
////
//cacluate reagent based pH shift.
if(ignore_pH == TRUE)
pH = ((cached_pH * cached_total)+(other_pH * amount))/(cached_total + amount)//should be right
else
pH = ((cached_pH * cached_total)+(D.pH * amount))/(cached_total + amount)//should be right
if(istype(my_atom, /obj/item/reagent_containers/))
var/obj/item/reagent_containers/RC = my_atom
RC.pH_check()//checks beaker resilience
//add the reagent to the existing if it exists
for(var/A in cached_reagents)
var/datum/reagent/R = A
if (R.id == reagent)
if (R.id == reagent) //IF MERGING
//Add amount and equalize purity
R.volume += amount
R.purity = ((R.purity * R.volume) + (other_purity * amount)) /((R.volume + amount)) //This should add the purity to the product
update_total()
if(my_atom)
my_atom.on_reagent_change(ADD_REAGENT)
R.on_merge(data, amount)
if(isliving(my_atom))
if(R.OnMobMergeCheck == TRUE)//Forces on_mob_add proc when a chem is merged
R.on_mob_add(my_atom, amount)
//else
// R.on_merge(data, amount, my_atom, other_purity)
R.on_merge(data, amount, my_atom, other_purity)
if(!no_react)
handle_reactions()
return TRUE
//otherwise make a new one
var/datum/reagent/R = new D.type(data)
cached_reagents += R
R.holder = src
R.volume = amount
R.purity = other_purity
R.loc = get_turf(my_atom)
if(data)
R.data = data
R.on_new(data)
if(R.addProc == TRUE)//Allows on new without data overhead.
R.on_new(pH) //Add more as desired.
if(isliving(my_atom))
R.on_mob_add(my_atom) //Must occur befor it could posibly run on_mob_delete
R.on_mob_add(my_atom, amount)
update_total()
if(my_atom)
my_atom.on_reagent_change(ADD_REAGENT)
@@ -630,12 +913,13 @@
handle_reactions()
return TRUE
/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15)
for(var/r_id in list_reagents)
var/amt = list_reagents[r_id]
add_reagent(r_id, amt, data)
/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to
/datum/reagents/proc/remove_reagent(reagent, amount, safety, ignore_pH = FALSE)//Added a safety check for the trans_id_to
if(isnull(amount))
amount = 0
@@ -653,6 +937,15 @@
for(var/A in cached_reagents)
var/datum/reagent/R = A
if (R.id == reagent)
if((total_volume - amount) <= 0)//Because this can result in 0, I don't want it to crash.
pH = 7
//In practice this is really confusing and players feel like it randomly melts their beakers, but I'm not sure how else to handle it. We'll see how it goes and I can remove this if it confuses people.
else if (ignore_pH == FALSE)
//if (((pH > R.pH) && (pH <= 7)) || ((pH < R.pH) && (pH >= 7)))
pH = (((pH - R.pH) / total_volume) * amount) + pH
if(istype(my_atom, /obj/item/reagent_containers/))
var/obj/item/reagent_containers/RC = my_atom
RC.pH_check()//checks beaker resilience)
//clamp the removal amount to be between current reagent amount
//and zero, to prevent removing more than the holder has stored
amount = CLAMP(amount, 0, R.volume)
@@ -189,10 +189,16 @@
data["beakerCurrentVolume"] = beakerCurrentVolume
data["beakerMaxVolume"] = beaker.volume
data["beakerTransferAmounts"] = beaker.possible_transfer_amounts
data["beakerCurrentpH"] = beaker.reagents.pH
//pH accuracy
for(var/obj/item/stock_parts/capacitor/C in component_parts)
data["partRating"]= 10**(C.rating-1)
else
data["beakerCurrentVolume"] = null
data["beakerMaxVolume"] = null
data["beakerTransferAmounts"] = null
data["beakerCurrentpH"] = null
var/chemicals[0]
var/recipes[0]
@@ -97,13 +97,21 @@
data["isBeakerLoaded"] = beaker ? 1 : 0
data["currentTemp"] = beaker ? beaker.reagents.chem_temp : null
data["currentpH"] = beaker ? beaker.reagents.pH : null
data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null
data["beakerMaxVolume"] = beaker ? beaker.volume : null
//purity and pH accuracy
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
data["partRating"]= 10**(M.rating-1)
if(M.rating == 4)
data["showPurity"] = 1
else
data["showPurity"] = 0
var beakerContents[0]
if(beaker)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list...
beakerContents.Add(list(list("name" = R.name, "volume" = R.volume, "purity" = R.purity))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
return data
@@ -21,6 +21,7 @@
var/analyzeVars[0]
var/useramount = 30 // Last used amount
var/list/pillStyles
var/fermianalyze //Give more detail on fermireactions on analysis
/obj/machinery/chem_master/Initialize()
create_reagents(100)
@@ -170,6 +171,7 @@
data["condi"] = condi
data["screen"] = screen
data["analyzeVars"] = analyzeVars
data["fermianalyze"] = fermianalyze
data["chosenPillStyle"] = chosenPillStyle
data["isPillBottleLoaded"] = bottle ? 1 : 0
if(bottle)
@@ -211,11 +213,13 @@
var/id = params["id"]
var/amount = text2num(params["amount"])
if (amount > 0)
end_fermi_reaction()
beaker.reagents.trans_id_to(src, id, amount)
. = TRUE
else if (amount == -1) // -1 means custom amount
useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null
if (useramount > 0)
end_fermi_reaction()
beaker.reagents.trans_id_to(src, id, useramount)
. = TRUE
@@ -387,7 +391,14 @@
state = "Gas"
var/const/P = 3 //The number of seconds between life ticks
var/T = initial(R.metabolization_rate) * (60 / P)
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
if(istype(R, /datum/reagent/fermi))
fermianalyze = TRUE
var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.id)
var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = initial(R.purity), "inverseRatioF" = initial(R.InverseChemVal), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
else
fermianalyze = FALSE
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
screen = "analyze"
return
@@ -397,6 +408,9 @@
/obj/machinery/chem_master/proc/end_fermi_reaction()//Ends any reactions upon moving.
if(beaker.reagents.fermiIsReacting)
beaker.reagents.fermiEnd()
/obj/machinery/chem_master/proc/isgoodnumber(num)
if(isnum(num))
+12 -1
View File
@@ -33,6 +33,16 @@
var/addiction_stage4_end = 40
var/overdosed = 0 // You fucked up and this is now triggering its overdose effects, purge that shit quick.
var/self_consuming = FALSE
//Fermichem vars:
var/purity = 1 //How pure a chemical is from 0 - 1.
var/addProc = FALSE //If the chemical should force an on_new() call
var/turf/loc = null //Should be the creation location!
var/pH = 7 //pH of the specific reagent, used for calculating the sum pH of a holder.
var/ImpureChem = "fermiTox"// What chemical is metabolised with an inpure reaction
var/InverseChemVal = 0.25 // If the impurity is below 0.5, replace ALL of the chem with InverseChem upon metabolising
var/InverseChem = "fermiTox"// What chem is metabolised when purity is below InverseChemVal, this shouldn't be made, but if it does, well, I guess I'll know about it.
var/DoNotSplit = FALSE // If impurity is handled within the main chem itself
var/OnMobMergeCheck = FALSE //Call on_mob_life proc when reagents are merging.
var/metabolizing = FALSE
var/invisible = FALSE //Set to true if it doesn't appear on handheld health analyzers.
@@ -59,7 +69,8 @@
/datum/reagent/proc/on_mob_life(mob/living/carbon/M)
current_cycle++
holder.remove_reagent(src.id, metabolization_rate * M.metabolism_efficiency) //By default it slowly disappears.
if(holder)
holder.remove_reagent(src.id, metabolization_rate * M.metabolism_efficiency) //By default it slowly disappears.
return
// Called when this reagent is first added to a mob
@@ -14,6 +14,7 @@
nutriment_factor = 0
taste_description = "alcohol"
var/boozepwr = 65 //Higher numbers equal higher hardness, higher hardness equals more intense alcohol poisoning
pH = 7.33
/*
Boozepwr Chart
@@ -86,6 +87,8 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = "piss water"
glass_name = "glass of beer"
glass_desc = "A freezing pint of beer."
pH = 4
/datum/reagent/consumable/ethanol/beer/light
name = "Light Beer"
@@ -95,6 +98,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = "dish water"
glass_name = "glass of light beer"
glass_desc = "A freezing pint of watery light beer."
pH = 5
/datum/reagent/consumable/ethanol/beer/green
name = "Green Beer"
@@ -105,6 +109,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "greenbeerglass"
glass_name = "glass of green beer"
glass_desc = "A freezing pint of green beer. Festive."
pH = 6
/datum/reagent/consumable/ethanol/beer/green/on_mob_life(mob/living/carbon/M)
if(M.color != color)
@@ -124,6 +129,8 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of RR coffee liquor"
glass_desc = "DAMN, THIS THING LOOKS ROBUST!"
shot_glass_icon_state = "shotglasscream"
pH = 6
/datum/reagent/consumable/ethanol/kahlua/on_mob_life(mob/living/carbon/M)
M.dizziness = max(0,M.dizziness-5)
@@ -145,6 +152,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of whiskey"
glass_desc = "The silky, smokey whiskey goodness inside the glass makes the drink look very classy."
shot_glass_icon_state = "shotglassbrown"
pH = 4.5
/datum/reagent/consumable/ethanol/thirteenloko
name = "Thirteen Loko"
@@ -161,6 +169,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of Thirteen Loko"
glass_desc = "This is a glass of Thirteen Loko, it appears to be of the highest quality. The drink, not the glass."
/datum/reagent/consumable/ethanol/thirteenloko/on_mob_life(mob/living/carbon/M)
M.drowsyness = max(0,M.drowsyness-7)
M.AdjustSleeping(-40)
@@ -221,6 +230,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of vodka"
glass_desc = "The glass contain wodka. Xynta."
shot_glass_icon_state = "shotglassclear"
pH = 8.1
/datum/reagent/consumable/ethanol/vodka/on_mob_life(mob/living/carbon/M)
M.radiation = max(M.radiation-2,0)
@@ -255,6 +265,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "threemileislandglass"
glass_name = "Three Mile Island Ice Tea"
glass_desc = "A glass of this is sure to prevent a meltdown."
pH = 3.5
/datum/reagent/consumable/ethanol/threemileisland/on_mob_life(mob/living/carbon/M)
M.set_drugginess(50)
@@ -270,6 +281,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "ginvodkaglass"
glass_name = "glass of gin"
glass_desc = "A crystal clear glass of Griffeater gin."
pH = 6.9
/datum/reagent/consumable/ethanol/rum
name = "Rum"
@@ -282,6 +294,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of rum"
glass_desc = "Now you want to Pray for a pirate suit, don't you?"
shot_glass_icon_state = "shotglassbrown"
pH = 6.5
/datum/reagent/consumable/ethanol/tequila
name = "Tequila"
@@ -294,6 +307,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of tequila"
glass_desc = "Now all that's missing is the weird colored shades!"
shot_glass_icon_state = "shotglassgold"
pH = 4
/datum/reagent/consumable/ethanol/vermouth
name = "Vermouth"
@@ -306,6 +320,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of vermouth"
glass_desc = "You wonder why you're even drinking this straight."
shot_glass_icon_state = "shotglassclear"
pH = 3.25
/datum/reagent/consumable/ethanol/wine
name = "Wine"
@@ -318,6 +333,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of wine"
glass_desc = "A very classy looking drink."
shot_glass_icon_state = "shotglassred"
pH = 3.45
/datum/reagent/consumable/ethanol/lizardwine
name = "Lizard wine"
@@ -327,6 +343,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
boozepwr = 45
quality = DRINK_FANTASTIC
taste_description = "scaley sweetness"
pH = 3
/datum/reagent/consumable/ethanol/grappa
name = "Grappa"
@@ -338,6 +355,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "grappa"
glass_name = "glass of grappa"
glass_desc = "A fine drink originally made to prevent waste by using the leftovers from winemaking."
pH = 3.5
/datum/reagent/consumable/ethanol/cognac
name = "Cognac"
@@ -350,6 +368,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of cognac"
glass_desc = "Damn, you feel like some kind of French aristocrat just by holding this."
shot_glass_icon_state = "shotglassbrown"
pH = 3.5
/datum/reagent/consumable/ethanol/absinthe
name = "Absinthe"
@@ -395,6 +414,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "aleglass"
glass_name = "glass of ale"
glass_desc = "A freezing pint of delicious Ale."
pH = 4.5
/datum/reagent/consumable/ethanol/goldschlager
name = "Goldschlager"
@@ -421,6 +441,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of patron"
glass_desc = "Drinking patron in the bar, with all the subpar ladies."
shot_glass_icon_state = "shotglassclear"
pH = 4.5
/datum/reagent/consumable/ethanol/gintonic
name = "Gin and Tonic"
@@ -433,6 +454,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "gintonicglass"
glass_name = "Gin and Tonic"
glass_desc = "A mild but still great cocktail. Drink up, like a true Englishman."
pH = 3
/datum/reagent/consumable/ethanol/rum_coke
name = "Rum and Coke"
@@ -445,6 +467,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "whiskeycolaglass"
glass_name = "Rum and Coke"
glass_desc = "The classic go-to of space-fratboys."
pH = 4
/datum/reagent/consumable/ethanol/cuba_libre
name = "Cuba Libre"
@@ -458,6 +481,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "Cuba Libre"
glass_desc = "A classic mix of rum, cola, and lime. A favorite of revolutionaries everywhere!"
/datum/reagent/consumable/ethanol/cuba_libre/on_mob_life(mob/living/carbon/M)
if(M.mind && M.mind.has_antag_datum(/datum/antagonist/rev)) //Cuba Libre, the traditional drink of revolutions! Heals revolutionaries.
M.adjustBruteLoss(-1, 0)
@@ -504,6 +528,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "Vodka martini"
glass_desc ="A bastardisation of the classic martini. Still great."
/datum/reagent/consumable/ethanol/white_russian
name = "White Russian"
id = "whiterussian"
@@ -557,8 +582,8 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_desc = "Tomato juice, mixed with Vodka and a lil' bit of lime. Tastes like liquid murder."
/datum/reagent/consumable/ethanol/bloody_mary/on_mob_life(mob/living/carbon/C)
if(C.blood_volume < BLOOD_VOLUME_NORMAL)
C.blood_volume = min(BLOOD_VOLUME_NORMAL, C.blood_volume + 3) //Bloody Mary quickly restores blood loss.
if(C.blood_volume < (BLOOD_VOLUME_NORMAL*C.blood_ratio))
C.blood_volume = min((BLOOD_VOLUME_NORMAL*C.blood_ratio), C.blood_volume + 3) //Bloody Mary quickly restores blood loss.
..()
/datum/reagent/consumable/ethanol/brave_bull
@@ -643,6 +668,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "beepskysmashglass"
glass_name = "Beepsky Smash"
glass_desc = "Heavy, hot and strong. Just like the Iron fist of the LAW."
pH = 2
overdose_threshold = 40
var/datum/brain_trauma/special/beepsky/B
@@ -1578,6 +1604,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "Bastion Bourbon"
glass_desc = "If you're feeling low, count on the buttery flavor of our own bastion bourbon."
shot_glass_icon_state = "shotglassgreen"
pH = 4
/datum/reagent/consumable/ethanol/bastion_bourbon/on_mob_metabolize(mob/living/L)
var/heal_points = 10
@@ -2106,6 +2133,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
can_synth = FALSE
var/list/names = list("null fruit" = 1) //Names of the fruits used. Associative list where name is key, value is the percentage of that fruit.
var/list/tastes = list("bad coding" = 1) //List of tastes. See above.
pH = 4
/datum/reagent/consumable/ethanol/fruit_wine/on_new(list/data)
names = data["names"]
@@ -168,6 +168,7 @@
/datum/reagent/consumable/laughter/on_mob_life(mob/living/carbon/M)
M.emote("laugh")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "chemical_laughter", /datum/mood_event/chemical_laughter)
..()
/datum/reagent/consumable/superlaughter
@@ -182,6 +183,7 @@
if(prob(30))
M.visible_message("<span class='danger'>[M] bursts out into a fit of uncontrollable laughter!</span>", "<span class='userdanger'>You burst out in a fit of uncontrollable laughter!</span>")
M.Stun(5)
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "chemical_laughter", /datum/mood_event/chemical_superlaughter)
..()
/datum/reagent/consumable/potato_juice
@@ -15,6 +15,7 @@
description = "An illegal chemical compound used as drug."
color = "#60A584" // rgb: 96, 165, 132
overdose_threshold = 30
pH = 9
/datum/reagent/drug/space_drugs/on_mob_life(mob/living/carbon/M)
M.set_drugginess(15)
@@ -44,6 +45,7 @@
addiction_threshold = 30
taste_description = "smoke"
trippy = FALSE
pH = 8
/datum/reagent/drug/nicotine/on_mob_life(mob/living/carbon/M)
if(prob(1))
@@ -65,6 +67,7 @@
color = "#FA00C8"
overdose_threshold = 20
addiction_threshold = 10
pH = 10
/datum/reagent/drug/crank/on_mob_life(mob/living/carbon/M)
if(prob(5))
@@ -112,6 +115,7 @@
color = "#0064B4"
overdose_threshold = 20
addiction_threshold = 15
pH = 9
/datum/reagent/drug/krokodil/on_mob_life(mob/living/carbon/M)
@@ -167,6 +171,7 @@
var/brain_damage = TRUE
var/jitter = TRUE
var/confusion = TRUE
pH = 5
/datum/reagent/drug/methamphetamine/on_mob_metabolize(mob/living/L)
..()
@@ -261,6 +266,7 @@
addiction_threshold = 10
taste_description = "salt" // because they're bathsalts?
var/datum/brain_trauma/special/psychotic_brawling/bath_salts/rage
pH = 8.2
/datum/reagent/drug/bath_salts/on_mob_metabolize(mob/living/L)
..()
@@ -357,6 +363,7 @@
description = "Amps you up and gets you going, fixes all stamina damage you might have but can cause toxin and oxygen damage."
reagent_state = LIQUID
color = "#78FFF0"
pH = 9.2
/datum/reagent/drug/aranesp/on_mob_life(mob/living/carbon/M)
var/high_message = pick("You feel amped up.", "You feel ready.", "You feel like you can push it to the limit.")
@@ -370,6 +377,84 @@
..()
. = 1
/datum/reagent/drug/happiness
name = "Happiness"
id = "happiness"
description = "Fills you with ecstasic numbness and causes minor brain damage. Highly addictive. If overdosed causes sudden mood swings."
reagent_state = LIQUID
color = "#FFF378"
addiction_threshold = 10
overdose_threshold = 20
pH = 10.5
/datum/reagent/drug/happiness/on_mob_add(mob/living/L)
..()
ADD_TRAIT(L, TRAIT_FEARLESS, id)
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug)
/datum/reagent/drug/happiness/on_mob_delete(mob/living/L)
REMOVE_TRAIT(L, TRAIT_FEARLESS, id)
SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "happiness_drug")
..()
/datum/reagent/drug/happiness/on_mob_life(mob/living/carbon/M)
M.jitteriness = 0
M.confused = 0
M.disgust = 0
M.adjustBrainLoss(0.2)
..()
. = 1
/datum/reagent/drug/happiness/overdose_process(mob/living/M)
if(prob(30))
var/reaction = rand(1,3)
switch(reaction)
if(1)
M.emote("laugh")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug_good_od)
if(2)
M.emote("sway")
M.Dizzy(25)
if(3)
M.emote("frown")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug_bad_od)
M.adjustBrainLoss(0.5)
..()
. = 1
/datum/reagent/drug/happiness/addiction_act_stage1(mob/living/M)// all work and no play makes jack a dull boy
GET_COMPONENT_FROM(mood, /datum/component/mood, M)
mood.setSanity(min(mood.sanity, SANITY_DISTURBED))
M.Jitter(5)
if(prob(20))
M.emote(pick("twitch","laugh","frown"))
..()
/datum/reagent/drug/happiness/addiction_act_stage2(mob/living/M)
GET_COMPONENT_FROM(mood, /datum/component/mood, M)
mood.setSanity(min(mood.sanity, SANITY_UNSTABLE))
M.Jitter(10)
if(prob(30))
M.emote(pick("twitch","laugh","frown"))
..()
/datum/reagent/drug/happiness/addiction_act_stage3(mob/living/M)
GET_COMPONENT_FROM(mood, /datum/component/mood, M)
mood.setSanity(min(mood.sanity, SANITY_CRAZY))
M.Jitter(15)
if(prob(40))
M.emote(pick("twitch","laugh","frown"))
..()
/datum/reagent/drug/happiness/addiction_act_stage4(mob/living/carbon/human/M)
GET_COMPONENT_FROM(mood, /datum/component/mood, M)
mood.setSanity(SANITY_INSANE)
M.Jitter(20)
if(prob(50))
M.emote(pick("twitch","laugh","frown"))
..()
. = 1
/datum/reagent/drug/skooma
name = "Skooma"
id = "skooma"
@@ -380,6 +465,7 @@
addiction_threshold = 1
addiction_stage3_end = 40
addiction_stage4_end = 240
pH = 12.5
/datum/reagent/drug/skooma/on_mob_metabolize(mob/living/L)
. = ..()
@@ -440,4 +526,3 @@
if(prob(40))
M.emote(pick("twitch","drool","moan"))
..()
@@ -230,6 +230,7 @@
description = "A special oil that noticably chills the body. Extracted from Icepeppers and slimes."
color = "#8BA6E9" // rgb: 139, 166, 233
taste_description = "mint"
pH = 13 //HMM! I wonder
/datum/reagent/consumable/frostoil/on_mob_life(mob/living/carbon/M)
var/cooling = 0
@@ -275,6 +276,7 @@
description = "A chemical agent used for self-defense and in police work."
color = "#B31008" // rgb: 179, 16, 8
taste_description = "scorching agony"
pH = 7.4
/datum/reagent/consumable/condensedcapsaicin/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(!ishuman(M) && !ismonkey(M))
@@ -402,6 +404,7 @@
color = "#E700E7" // rgb: 231, 0, 231
metabolization_rate = 0.2 * REAGENTS_METABOLISM
taste_description = "mushroom"
pH = 11
/datum/reagent/drug/mushroomhallucinogen/on_mob_life(mob/living/carbon/M)
M.slurring = max(M.slurring,50)
@@ -618,6 +621,7 @@
description = "A blinding substance extracted from certain onions."
color = "#c0c9a0"
taste_description = "bitterness"
pH = 5
/datum/reagent/consumable/tearjuice/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(!istype(M))
@@ -672,6 +676,7 @@
description = "An ichor, derived from a certain mushroom, makes for a bad time."
color = "#1d043d"
taste_description = "bitter mushroom"
pH = 12
/datum/reagent/consumable/entpoly/on_mob_life(mob/living/carbon/M)
if(current_cycle >= 10)
@@ -692,6 +697,7 @@
description = "A stimulating ichor which causes luminescent fungi to grow on the skin. "
color = "#b5a213"
taste_description = "tingling mushroom"
pH = 11.2
/datum/reagent/consumable/tinlux/reaction_mob(mob/living/M)
M.set_light(2)
@@ -706,6 +712,7 @@
color = "#d3a308"
nutriment_factor = 3 * REAGENTS_METABOLISM
taste_description = "fruity mushroom"
pH = 10.4
/datum/reagent/consumable/vitfro/on_mob_life(mob/living/carbon/M)
if(prob(80))
@@ -721,6 +728,7 @@
nutriment_factor = 5 * REAGENTS_METABOLISM
color = "#eef442" // rgb: 238, 244, 66
taste_description = "mournful honking"
pH = 9.2
/datum/reagent/consumable/astrotame
name = "Astrotame"
@@ -750,3 +758,4 @@
quality = FOOD_AMAZING
taste_mult = 100
can_synth = FALSE
pH = 6.1
@@ -18,6 +18,7 @@
name = "Leporazine"
id = "leporazine"
description = "Leporazine will effectively regulate a patient's body temperature, ensuring it never leaves safe levels."
pH = 8.4
color = "#82b8aa"
/datum/reagent/medicine/leporazine/on_mob_life(mob/living/carbon/M)
@@ -60,6 +61,9 @@
M.SetSleeping(0, 0)
M.jitteriness = 0
M.cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
if(M.blood_volume < (BLOOD_VOLUME_NORMAL*M.blood_ratio))
M.blood_volume = (BLOOD_VOLUME_NORMAL*M.blood_ratio)
for(var/thing in M.diseases)
var/datum/disease/D = thing
if(D.severity == DISEASE_SEVERITY_POSITIVE)
@@ -79,6 +83,7 @@
id = "synaptizine"
description = "Increases resistance to stuns as well as reducing drowsiness and hallucinations."
color = "#FF00FF"
pH = 4
/datum/reagent/medicine/synaptizine/on_mob_life(mob/living/carbon/M)
M.drowsyness = max(M.drowsyness-5, 0)
@@ -98,6 +103,7 @@
id = "synaphydramine"
description = "Reduces drowsiness, hallucinations, and Histamine from body."
color = "#EC536D" // rgb: 236, 83, 109
pH = 5.2
/datum/reagent/medicine/synaphydramine/on_mob_life(mob/living/carbon/M)
M.drowsyness = max(M.drowsyness-5, 0)
@@ -116,6 +122,7 @@
id = "inacusiate"
description = "Instantly restores all hearing to the patient, but does not cure deafness."
color = "#6600FF" // rgb: 100, 165, 255
pH = 2
/datum/reagent/medicine/inacusiate/on_mob_life(mob/living/carbon/M)
M.restoreEars()
@@ -127,6 +134,7 @@
description = "A chemical mixture with almost magical healing powers. Its main limitation is that the patient's body temperature must be under 270K for it to metabolise correctly."
color = "#0000C8"
taste_description = "sludge"
pH = 11
/datum/reagent/medicine/cryoxadone/on_mob_life(mob/living/carbon/M)
var/power = -0.00003 * (M.bodytemperature ** 2) + 3
@@ -148,6 +156,7 @@
color = "#0000C8"
taste_description = "muscle"
metabolization_rate = 1.5 * REAGENTS_METABOLISM
pH = 13
/datum/reagent/medicine/clonexadone/on_mob_life(mob/living/carbon/M)
if(M.bodytemperature < T0C)
@@ -163,6 +172,7 @@
description = "A mixture of cryoxadone and slime jelly, that apparently inverses the requirement for its activation."
color = "#f7832a"
taste_description = "spicy jelly"
pH = 12
/datum/reagent/medicine/pyroxadone/on_mob_life(mob/living/carbon/M)
if(M.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT)
@@ -194,6 +204,7 @@
color = "#669900" // rgb: 102, 153, 0
overdose_threshold = 30
taste_description = "fish"
pH = 12.2
/datum/reagent/medicine/rezadone/on_mob_life(mob/living/carbon/M)
M.setCloneLoss(0) //Rezadone is almost never used in favor of cryoxadone. Hopefully this will change that.
@@ -215,6 +226,7 @@
description = "Spaceacillin will prevent a patient from conventionally spreading any diseases they are currently infected with."
color = "#f2f2f2"
metabolization_rate = 0.1 * REAGENTS_METABOLISM
pH = 8.1
//Goon Chems. Ported mainly from Goonstation. Easily mixable (or not so easily) and provide a variety of effects.
/datum/reagent/medicine/silver_sulfadiazine
@@ -222,6 +234,7 @@
id = "silver_sulfadiazine"
description = "If used in touch-based applications, immediately restores burn wounds as well as restoring more over time. If ingested through other means, deals minor toxin damage."
reagent_state = LIQUID
pH = 7.2
color = "#ffeac9"
/datum/reagent/medicine/silver_sulfadiazine/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
@@ -235,6 +248,7 @@
if(show_message)
to_chat(M, "<span class='danger'>You feel your burns healing! It stings like hell!</span>")
M.emote("scream")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
..()
/datum/reagent/medicine/silver_sulfadiazine/on_mob_life(mob/living/carbon/M)
@@ -250,6 +264,7 @@
color = "#f7ffa5"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 25
pH = 10.7
/datum/reagent/medicine/oxandrolone/on_mob_life(mob/living/carbon/M)
if(M.getFireLoss() > 50)
@@ -271,6 +286,7 @@
description = "If used in touch-based applications, immediately restores bruising as well as restoring more over time. If ingested through other means, deals minor toxin damage."
reagent_state = LIQUID
color = "#FF9696"
pH = 6.7
/datum/reagent/medicine/styptic_powder/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(iscarbon(M) && M.stat != DEAD)
@@ -283,6 +299,7 @@
if(show_message)
to_chat(M, "<span class='danger'>You feel your bruises healing! It stings like hell!</span>")
M.emote("scream")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
..()
@@ -302,6 +319,7 @@
taste_description = "sweetness and salt"
var/last_added = 0
var/maximum_reachable = BLOOD_VOLUME_NORMAL - 10 //So that normal blood regeneration can continue with salglu active
pH = 5.5
/datum/reagent/medicine/salglu_solution/on_mob_life(mob/living/carbon/M)
if(last_added)
@@ -340,6 +358,7 @@
reagent_state = LIQUID
color = "#6D6374"
metabolization_rate = 0.4 * REAGENTS_METABOLISM
pH = 2.6
/datum/reagent/medicine/mine_salve/on_mob_life(mob/living/carbon/C)
C.hal_screwyhud = SCREWYHUD_HEALTHY
@@ -378,6 +397,7 @@
description = "Has a 100% chance of instantly healing brute and burn damage. One unit of the chemical will heal one point of damage. Touch application only."
reagent_state = LIQUID
color = "#FFEBEB"
pH = 11.5
/datum/reagent/medicine/synthflesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume,show_message = 1)
if(iscarbon(M))
@@ -388,6 +408,7 @@
M.adjustFireLoss(-1.25 * reac_volume)
if(show_message)
to_chat(M, "<span class='danger'>You feel your burns and bruises healing! It stings like hell!</span>")
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
..()
/datum/reagent/medicine/charcoal
@@ -398,6 +419,7 @@
color = "#000000"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "ash"
pH = 5
/datum/reagent/medicine/charcoal/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(-2*REM, 0)
@@ -415,6 +437,7 @@
color = "#DCDCDC"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
overdose_threshold = 30
pH = 2
/datum/reagent/medicine/omnizine/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(-0.5*REM, 0)
@@ -440,6 +463,7 @@
color = "#19C832"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "acid"
pH = 1.5
/datum/reagent/medicine/calomel/on_mob_life(mob/living/carbon/M)
for(var/datum/reagent/R in M.reagents.reagent_list)
@@ -457,6 +481,7 @@
reagent_state = LIQUID
color = "#14FF3C"
metabolization_rate = 2 * REAGENTS_METABOLISM
pH = 12 //It's a reducing agent
/datum/reagent/medicine/potass_iodide/on_mob_life(mob/living/carbon/M)
if(M.radiation > 0)
@@ -470,6 +495,7 @@
reagent_state = LIQUID
color = "#003153" // RGB 0, 49, 83
metabolization_rate = 0.5 * REAGENTS_METABOLISM
pH = 8.9
/datum/reagent/medicine/prussian_blue/on_mob_life(mob/living/carbon/M)
if(M.radiation > 0)
@@ -483,6 +509,7 @@
reagent_state = LIQUID
color = "#E6FFF0"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
pH = 1 //One of the best buffers, NEVERMIND!
var/healtoxinlover = FALSE
/datum/reagent/medicine/pen_acid/on_mob_life(mob/living/carbon/M)
@@ -500,6 +527,7 @@
description = "Reduces massive amounts of radiation and toxin damage while purging other chemicals from the body. Slimepeople friendly!"
color = "#91D865"
healtoxinlover = TRUE
pH = 12//invert
/datum/reagent/medicine/sal_acid
name = "Salicyclic Acid"
@@ -509,6 +537,7 @@
color = "#D2D2D2"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 25
pH = 2.1
/datum/reagent/medicine/sal_acid/on_mob_life(mob/living/carbon/M)
@@ -532,6 +561,7 @@
reagent_state = LIQUID
color = "#00FFFF"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
pH = 2
/datum/reagent/medicine/salbutamol/on_mob_life(mob/living/carbon/M)
M.adjustOxyLoss(-3*REM, 0)
@@ -547,6 +577,7 @@
reagent_state = LIQUID
color = "#FF6464"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
pH = 11
/datum/reagent/medicine/perfluorodecalin/on_mob_life(mob/living/carbon/human/M)
M.adjustOxyLoss(-12*REM, 0)
@@ -566,6 +597,7 @@
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 45
addiction_threshold = 30
pH = 12
/datum/reagent/medicine/ephedrine/on_mob_life(mob/living/carbon/M)
M.AdjustStun(-20, 0)
@@ -620,6 +652,7 @@
reagent_state = LIQUID
color = "#64FFE6"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
pH = 11.5
/datum/reagent/medicine/diphenhydramine/on_mob_life(mob/living/carbon/M)
if(prob(10))
@@ -637,6 +670,7 @@
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 30
addiction_threshold = 25
pH = 8.96
/datum/reagent/medicine/morphine/on_mob_metabolize(mob/living/L)
..()
@@ -705,6 +739,7 @@
color = "#FFFFFF"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
taste_description = "dull toxin"
pH = 10
/datum/reagent/medicine/oculine/on_mob_life(mob/living/carbon/M)
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
@@ -736,6 +771,7 @@
color = "#000000"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
overdose_threshold = 35
pH = 12
/datum/reagent/medicine/atropine/on_mob_life(mob/living/carbon/M)
if(M.health < 0)
@@ -765,6 +801,7 @@
color = "#D2FFFA"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
overdose_threshold = 30
pH = 10.2
/datum/reagent/medicine/epinephrine/on_mob_life(mob/living/carbon/M)
if(M.health < 0)
@@ -801,6 +838,7 @@
color = "#A0E85E"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "magnets"
pH = 0
/datum/reagent/medicine/strange_reagent/reaction_mob(mob/living/carbon/human/M, method=TOUCH, reac_volume)
if(M.stat == DEAD)
@@ -834,6 +872,7 @@
id = "mannitol"
description = "Efficiently restores brain damage."
color = "#DCDCFF"
pH = 10.4
/datum/reagent/medicine/mannitol/on_mob_life(mob/living/carbon/C)
C.adjustBrainLoss(-2*REM)
@@ -841,12 +880,26 @@
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
..()
/datum/reagent/medicine/neurine
name = "Neurine"
id = "neurine"
description = "Reacts with neural tissue, helping reform damaged connections. Can cure minor traumas."
color = "#EEFF8F"
/datum/reagent/medicine/neurine/on_mob_life(mob/living/carbon/C)
if(holder.has_reagent("neurotoxin"))
holder.remove_reagent("neurotoxin", 5)
if(prob(15))
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
..()
/datum/reagent/medicine/mutadone
name = "Mutadone"
id = "mutadone"
description = "Removes jitteriness and restores genetic defects."
color = "#5096C8"
taste_description = "acid"
pH = 2
/datum/reagent/medicine/mutadone/on_mob_life(mob/living/carbon/M)
M.jitteriness = 0
@@ -861,6 +914,7 @@
description = "Purges alcoholic substance from the patient's body and eliminates its side effects."
color = "#00B4C8"
taste_description = "raw egg"
pH = 4
/datum/reagent/medicine/antihol/on_mob_life(mob/living/carbon/M)
M.dizziness = 0
@@ -882,6 +936,7 @@
color = "#78008C"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 60
pH = 8.7
/datum/reagent/medicine/stimulants/on_mob_metabolize(mob/living/L)
..()
@@ -919,6 +974,7 @@
reagent_state = LIQUID
color = "#FFFFF0"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
pH = 6.7
/datum/reagent/medicine/insulin/on_mob_life(mob/living/carbon/M)
if(M.AdjustSleeping(-20, FALSE))
@@ -934,6 +990,7 @@
reagent_state = LIQUID
color = "#fc2626"
overdose_threshold = 30
pH = 5
/datum/reagent/medicine/bicaridine/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(-2*REM, 0)
@@ -952,6 +1009,7 @@
reagent_state = LIQUID
color = "#13d2f0"
overdose_threshold = 30
pH = 9.7
/datum/reagent/medicine/dexalin/on_mob_life(mob/living/carbon/M)
M.adjustOxyLoss(-2*REM, 0)
@@ -970,6 +1028,7 @@
reagent_state = LIQUID
color = "#ffc400"
overdose_threshold = 30
pH = 9
/datum/reagent/medicine/kelotane/on_mob_life(mob/living/carbon/M)
M.adjustFireLoss(-2*REM, 0)
@@ -989,6 +1048,7 @@
color = "#6aff00"
overdose_threshold = 30
taste_description = "a roll of gauze"
pH = 10
/datum/reagent/medicine/antitoxin/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(-2*REM, 0)
@@ -1007,6 +1067,7 @@
id = "inaprovaline"
description = "Stabilizes the breathing of patients. Good for those in critical condition."
reagent_state = LIQUID
pH = 8.5
color = "#5dc1f0"
/datum/reagent/medicine/inaprovaline/on_mob_life(mob/living/carbon/M)
@@ -1062,6 +1123,7 @@
description = "Miniature medical robots that swiftly restore bodily damage."
reagent_state = SOLID
color = "#555555"
pH = 11
/datum/reagent/medicine/syndicate_nanites/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(-5*REM, 0) //A ton of healing - this is a 50 telecrystal investment.
@@ -1075,14 +1137,15 @@
. = 1
/datum/reagent/medicine/neo_jelly
name = "Neo Jelly"
id = "neo_jelly"
description = "Gradually regenerates all types of damage, without harming slime anatomy.Can OD"
reagent_state = LIQUID
metabolization_rate = 1 * REAGENTS_METABOLISM
color = "#91D865"
overdose_threshold = 30
taste_description = "jelly"
name = "Neo Jelly"
id = "neo_jelly"
description = "Gradually regenerates all types of damage, without harming slime anatomy.Can OD"
reagent_state = LIQUID
metabolization_rate = 1 * REAGENTS_METABOLISM
color = "#91D865"
overdose_threshold = 30
taste_description = "jelly"
pH = 11.8
/datum/reagent/medicine/neo_jelly/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(-1.5*REM, 0)
@@ -1105,6 +1168,7 @@
description = "Ichor from an extremely powerful plant. Great for restoring wounds, but it's a little heavy on the brain."
color = rgb(255, 175, 0)
overdose_threshold = 25
pH = 11
/datum/reagent/medicine/earthsblood/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(-3 * REM, 0)
@@ -1132,6 +1196,7 @@
reagent_state = LIQUID
color = "#27870a"
metabolization_rate = 0.4 * REAGENTS_METABOLISM
pH = 4.3
/datum/reagent/medicine/haloperidol/on_mob_life(mob/living/carbon/M)
for(var/datum/reagent/drug/R in M.reagents.reagent_list)
@@ -1154,6 +1219,7 @@
color = "#a1a1a1"
overdose_threshold = 3 //To prevent people stacking massive amounts of a very strong healing reagent
can_synth = FALSE
pH = 14
/datum/reagent/medicine/lavaland_extract/on_mob_life(mob/living/carbon/M)
M.heal_bodypart_damage(5,5)
@@ -1217,6 +1283,7 @@
description = "A medication used to treat pain, fever, and inflammation, along with heart attacks."
color = "#F5F5F5"
self_consuming = TRUE
pH = 12.5
/datum/reagent/medicine/corazone/on_mob_metabolize(mob/living/M)
..()
@@ -1249,6 +1316,7 @@
overdose_threshold = 20 // with the random effects this might be awesome or might kill you at less than 10u (extensively tested)
taste_description = "salt" // it actually does taste salty
var/overdose_progress = 0 // to track overdose progress
pH = 7.89
/datum/reagent/medicine/modafinil/on_mob_metabolize(mob/living/M)
ADD_TRAIT(M, TRAIT_SLEEPIMMUNE, id)
@@ -1305,3 +1373,38 @@
M.adjustStaminaLoss(1.5*REM, 0)
..()
return TRUE
/datum/reagent/medicine/psicodine
name = "Psicodine"
id = "psicodine"
description = "Suppresses anxiety and other various forms of mental distress. Overdose causes hallucinations and minor toxin damage."
reagent_state = LIQUID
color = "#07E79E"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
overdose_threshold = 30
pH = 9.12
/datum/reagent/medicine/psicodine/on_mob_add(mob/living/L)
..()
ADD_TRAIT(L, TRAIT_FEARLESS, id)
/datum/reagent/medicine/psicodine/on_mob_delete(mob/living/L)
REMOVE_TRAIT(L, TRAIT_FEARLESS, id)
..()
/datum/reagent/medicine/psicodine/on_mob_life(mob/living/carbon/M)
M.jitteriness = max(0, M.jitteriness-6)
M.dizziness = max(0, M.dizziness-6)
M.confused = max(0, M.confused-6)
M.disgust = max(0, M.disgust-6)
GET_COMPONENT_FROM(mood, /datum/component/mood, M)
if(mood.sanity <= SANITY_NEUTRAL) // only take effect if in negative sanity and then...
mood.setSanity(min(mood.sanity+5, SANITY_NEUTRAL)) // set minimum to prevent unwanted spiking over neutral
..()
. = 1
/datum/reagent/medicine/psicodine/overdose_process(mob/living/M)
M.hallucination = min(max(0, M.hallucination + 5), 60)
M.adjustToxLoss(1, 0)
..()
. = 1
@@ -10,6 +10,7 @@
glass_name = "glass of tomato juice"
glass_desc = "Are you sure this is tomato juice?"
shot_glass_icon_state = "shotglassred"
pH = 7.4
/datum/reagent/blood/reaction_mob(mob/living/L, method=TOUCH, reac_volume)
if(data && data["viruses"])
@@ -183,6 +184,7 @@
taste_description = "gross iron"
shot_glass_icon_state = "shotglassred"
data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_HUMAN, "blood_type"= "O+","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
pH = 7.45
/datum/reagent/liquidgibs/xeno
name = "Liquid xeno gibs"
@@ -191,6 +193,7 @@
taste_description = "blended heresy"
shot_glass_icon_state = "shotglassgreen"
data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_XENO, "blood_type"="X*","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
pH = 2.5
/datum/reagent/liquidgibs/slime
name = "Slime sludge"
@@ -213,7 +216,7 @@
color = BLOOD_COLOR_OIL
taste_description = "chunky burnt oil"
data = list("donor"=null,"viruses"=null,"blood_DNA"=null, "bloodcolor" = BLOOD_COLOR_OIL, "blood_type"="HF","resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null,"cloneable"=null,"factions"=null)
pH = 9.75
/datum/reagent/vaccine
//data must contain virus type
@@ -314,6 +317,7 @@
glass_icon_state = "glass_clear"
glass_name = "glass of holy water"
glass_desc = "A glass of holy water."
pH = 7.5 //God is alkaline
/datum/reagent/water/holywater/on_mob_metabolize(mob/living/L)
..()
@@ -390,6 +394,7 @@
id = "unholywater"
description = "Something that shouldn't exist on this plane of existence."
taste_description = "suffering"
pH = 6.5
/datum/reagent/fuel/unholywater/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(method == TOUCH || method == VAPOR)
@@ -408,7 +413,7 @@
M.adjustOxyLoss(-2, 0)
M.adjustBruteLoss(-2, 0)
M.adjustFireLoss(-2, 0)
if(ishuman(M) && M.blood_volume < BLOOD_VOLUME_NORMAL)
if(ishuman(M) && M.blood_volume < (BLOOD_VOLUME_NORMAL*M.blood_ratio))
M.blood_volume += 3
else // Will deal about 90 damage when 50 units are thrown
M.adjustBrainLoss(3, 150)
@@ -432,6 +437,7 @@
M.adjustFireLoss(1, 0) //Hence the other damages... ain't I a bastard?
M.adjustBrainLoss(5, 150)
holder.remove_reagent(id, 1)
pH = 0.1
/datum/reagent/fuel/holyoil //Its oil
name = "Zelus Oil"
@@ -499,6 +505,7 @@
metabolization_rate = 10 * REAGENTS_METABOLISM // very fast, so it can be applied rapidly. But this changes on an overdose
overdose_threshold = 11 //Slightly more than one un-nozzled spraybottle.
taste_description = "sour oranges"
pH = 5
/datum/reagent/spraytan/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(ishuman(M))
@@ -697,6 +704,46 @@
race = /datum/species/android
mutationtext = "<span class='danger'>The pain subsides. You feel... artificial.</span>"
//Citadel Races
/datum/reagent/mutationtoxin/mammal
name = "Mammal Mutation Toxin"
id = "mammalmutationtoxin"
description = "A glowing toxin."
color = "#5EFF3B" //RGB: 94, 255, 59
race = /datum/species/mammal
mutationtext = "<span class='danger'>The pain subsides. You feel... fluffier.</span>"
/datum/reagent/mutationtoxin/aquatic
name = "Aquatic Mutation Toxin"
id = "aquaticmutationtoxin"
description = "A glowing toxin."
color = "#5EFF3B" //RGB: 94, 255, 59
race = /datum/species/aquatic
mutationtext = "<span class='danger'>The pain subsides. You feel... attracted to sea.</span>"
/datum/reagent/mutationtoxin/avian
name = "Avian Mutation Toxin"
id = "avianmutationtoxin"
description = "A glowing toxin."
color = "#5EFF3B" //RGB: 94, 255, 59
race = /datum/species/avian
mutationtext = "<span class='danger'>The pain subsides. You feel... feathery.</span>"
/datum/reagent/mutationtoxin/insect
name = "Insect Mutation Toxin"
id = "insectmutationtoxin"
description = "A glowing toxin."
color = "#5EFF3B" //RGB: 94, 255, 59
race = /datum/species/insect
mutationtext = "<span class='danger'>The pain subsides. You feel... attracted to dark, moist areas.</span>"
/datum/reagent/mutationtoxin/xenoperson
name = "Xeno Mutation Toxin"
id = "xenopersonmutationtoxin"
description = "A glowing toxin."
color = "#5EFF3B" //RGB: 94, 255, 59
race = /datum/species/xenoperson
mutationtext = "<span class='danger'>The pain subsides. You feel... oddly longing for the Queen.</span>" //sadly, not the British one.
//BLACKLISTED RACES
/datum/reagent/mutationtoxin/skeleton
@@ -823,6 +870,7 @@
color = "#202040" // rgb: 20, 20, 40
metabolization_rate = 0.25 * REAGENTS_METABOLISM
taste_description = "bitterness"
pH = 10
/datum/reagent/serotrotium/on_mob_life(mob/living/carbon/M)
if(ishuman(M))
@@ -837,6 +885,7 @@
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
taste_mult = 0 // oderless and tasteless
pH = 9.2//It's acutally a huge range and very dependant on the chemistry but pH is basically a made up var in it's implementation anyways
/datum/reagent/oxygen/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
@@ -857,6 +906,7 @@
reagent_state = SOLID
color = "#6E3B08" // rgb: 110, 59, 8
taste_description = "metal"
pH = 5.5
/datum/reagent/copper/reaction_obj(obj/O, reac_volume)
if(istype(O, /obj/item/stack/sheet/metal))
@@ -873,6 +923,7 @@
color = "#808080" // rgb: 128, 128, 128
taste_mult = 0
/datum/reagent/nitrogen/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
return 0
@@ -892,6 +943,7 @@
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
taste_mult = 0
pH = 0.1//Now I'm stuck in a trap of my own design. Maybe I should make -ve pHes? (not 0 so I don't get div/0 errors)
/datum/reagent/potassium
name = "Potassium"
@@ -923,6 +975,7 @@
reagent_state = SOLID
color = "#BF8C00" // rgb: 191, 140, 0
taste_description = "rotten eggs"
pH = 4.5
/datum/reagent/carbon
name = "Carbon"
@@ -931,6 +984,7 @@
reagent_state = SOLID
color = "#1C1300" // rgb: 30, 20, 0
taste_description = "sour chalk"
pH = 5
/datum/reagent/carbon/reaction_turf(turf/T, reac_volume)
if(!isspaceturf(T))
@@ -945,6 +999,7 @@
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
taste_description = "chlorine"
pH = 7.4
/datum/reagent/chlorine/on_mob_life(mob/living/carbon/M)
M.take_bodypart_damage(1*REM, 0, 0, 0)
@@ -958,6 +1013,7 @@
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
taste_description = "acid"
pH = 2
/datum/reagent/fluorine/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(1*REM, 0)
@@ -971,6 +1027,7 @@
reagent_state = SOLID
color = "#808080" // rgb: 128, 128, 128
taste_description = "salty metal"
pH = 11.6
/datum/reagent/phosphorus
name = "Phosphorus"
@@ -979,6 +1036,7 @@
reagent_state = SOLID
color = "#832828" // rgb: 131, 40, 40
taste_description = "vinegar"
pH = 6.5
/datum/reagent/lithium
name = "Lithium"
@@ -987,6 +1045,7 @@
reagent_state = SOLID
color = "#808080" // rgb: 128, 128, 128
taste_description = "metal"
pH = 11.3
/datum/reagent/lithium/on_mob_life(mob/living/carbon/M)
if(M.canmove && !isspaceturf(M.loc))
@@ -1001,6 +1060,7 @@
description = "Glycerol is a simple polyol compound. Glycerol is sweet-tasting and of low toxicity."
color = "#808080" // rgb: 128, 128, 128
taste_description = "sweetness"
pH = 9
/datum/reagent/radium
name = "Radium"
@@ -1009,6 +1069,7 @@
reagent_state = SOLID
color = "#C7C7C7" // rgb: 199,199,199
taste_description = "the colour blue and regret"
pH = 10
/datum/reagent/radium/on_mob_life(mob/living/carbon/M)
M.apply_effect(2*REM/M.metabolism_efficiency,EFFECT_IRRADIATE,0)
@@ -1028,6 +1089,7 @@
description = "Sterilizes wounds in preparation for surgery."
color = "#e6f1f5" // rgb: 200, 165, 220
taste_description = "bitterness"
pH = 10.5
/datum/reagent/space_cleaner/sterilizine/reaction_mob(mob/living/carbon/C, method=TOUCH, reac_volume)
if(method in list(TOUCH, VAPOR, PATCH))
@@ -1043,11 +1105,12 @@
description = "Pure iron is a metal."
reagent_state = SOLID
taste_description = "iron"
pH = 6
color = "#c2391d"
/datum/reagent/iron/on_mob_life(mob/living/carbon/C)
if(C.blood_volume < BLOOD_VOLUME_NORMAL)
if(C.blood_volume < (BLOOD_VOLUME_NORMAL*C.blood_ratio))
C.blood_volume += 0.01 //we'll have synthetics from medbay.
..()
@@ -1085,6 +1148,7 @@
reagent_state = SOLID
color = "#B8B8C0" // rgb: 184, 184, 192
taste_description = "the inside of a reactor"
pH = 4
/datum/reagent/uranium/on_mob_life(mob/living/carbon/M)
M.apply_effect(1/M.metabolism_efficiency,EFFECT_IRRADIATE,0)
@@ -1105,6 +1169,7 @@
reagent_state = SOLID
color = "#0000CC"
taste_description = "fizzling blue"
pH = 12
/datum/reagent/bluespace/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(method == TOUCH || method == VAPOR)
@@ -1137,6 +1202,7 @@
reagent_state = SOLID
color = "#A8A8A8" // rgb: 168, 168, 168
taste_mult = 0
pH = 10
/datum/reagent/fuel
name = "Welding fuel"
@@ -1147,6 +1213,8 @@
glass_icon_state = "dr_gibb_glass"
glass_name = "glass of welder fuel"
glass_desc = "Unless you're an industrial tool, this is probably not safe for consumption."
pH = 4
/datum/reagent/fuel/reaction_mob(mob/living/M, method=TOUCH, reac_volume)//Splashing people with welding fuel to make them easy to ignite!
if(method == TOUCH || method == VAPOR)
@@ -1165,6 +1233,7 @@
description = "A compound used to clean things. Now with 50% more sodium hypochlorite!"
color = "#A5F0EE" // rgb: 165, 240, 238
taste_description = "sourness"
pH = 5.5
/datum/reagent/space_cleaner/reaction_obj(obj/O, reac_volume)
if(istype(O, /obj/effect/decal/cleanable))
@@ -1222,6 +1291,7 @@
description = "A powerful, acidic cleaner sold by Waffle Co. Affects organic matter while leaving other objects unaffected."
metabolization_rate = 1.5 * REAGENTS_METABOLISM
taste_description = "acid"
pH = 2
/datum/reagent/space_cleaner/ez_clean/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(3.33)
@@ -1242,6 +1312,7 @@
color = "#7529b3" // rgb: 200, 165, 220
metabolization_rate = 1.5 * REAGENTS_METABOLISM
taste_description = "sourness"
pH = 11.9
/datum/reagent/cryptobiolin/on_mob_life(mob/living/carbon/M)
M.Dizzy(1)
@@ -1256,6 +1327,7 @@
description = "Impedrezene is a narcotic that impedes one's ability by slowing down the higher brain cell functions."
color = "#587a31" // rgb: 200, 165, 220A
taste_description = "numbness"
pH = 9.1
/datum/reagent/impedrezene/on_mob_life(mob/living/carbon/M)
M.jitteriness = max(M.jitteriness-5,0)
@@ -1298,6 +1370,7 @@
color = "#92D17D" // rgb: 146, 209, 125
can_synth = FALSE
taste_description = "slime"
pH = 11
/datum/reagent/fungalspores/reaction_mob(mob/living/L, method=TOUCH, reac_volume, show_message = 1, touch_protection = 0)
if(method==PATCH || method==INGEST || method==INJECT || (method == VAPOR && prob(min(reac_volume,100)*(1 - touch_protection))))
@@ -1309,6 +1382,7 @@
description = "A perfluoronated sulfonic acid that forms a foam when mixed with water."
color = "#9E6B38" // rgb: 158, 107, 56
taste_description = "metal"
pH = 13
/datum/reagent/foaming_agent// Metal foaming agent. This is lithium hydride. Add other recipes (e.g. LiH + H2O -> LiOH + H2) eventually.
name = "Foaming agent"
@@ -1317,6 +1391,7 @@
reagent_state = SOLID
color = "#664B63" // rgb: 102, 75, 99
taste_description = "metal"
pH = 12.5
/datum/reagent/smart_foaming_agent //Smart foaming agent. Functions similarly to metal foam, but conforms to walls.
name = "Smart foaming agent"
@@ -1325,6 +1400,7 @@
reagent_state = SOLID
color = "#664B63" // rgb: 102, 75, 99
taste_description = "metal"
pH = 11.8
/datum/reagent/ammonia
name = "Ammonia"
@@ -1333,6 +1409,7 @@
reagent_state = GAS
color = "#404030" // rgb: 64, 64, 48
taste_description = "mordant"
pH = 11.6
/datum/reagent/diethylamine
name = "Diethylamine"
@@ -1340,6 +1417,7 @@
description = "A secondary amine, mildly corrosive."
color = "#604030" // rgb: 96, 64, 48
taste_description = "iron"
pH = 12
/datum/reagent/carbondioxide
name = "Carbon Dioxide"
@@ -1348,6 +1426,7 @@
description = "A gas commonly produced by burning carbon fuels. You're constantly producing this in your lungs."
color = "#B0B0B0" // rgb : 192, 192, 192
taste_description = "something unknowable"
pH = 6
/datum/reagent/carbondioxide/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
@@ -1369,6 +1448,7 @@
metabolization_rate = 1.5 * REAGENTS_METABOLISM
color = "#808080"
taste_description = "sweetness"
pH = 5.8
/datum/reagent/nitrous_oxide/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
@@ -1428,6 +1508,7 @@
metabolization_rate = REAGENTS_METABOLISM
color = "90560B"
taste_description = "burning"
pH = 2
/datum/reagent/nitryl/on_mob_metabolize(mob/living/L)
..()
@@ -1461,6 +1542,7 @@
colorname = "red"
color = "#DA0000" // red
random_color_list = list("#DA0000")
pH = 0.5
/datum/reagent/colorful_reagent/crayonpowder/orange
name = "Orange Crayon Powder"
@@ -1468,6 +1550,7 @@
colorname = "orange"
color = "#FF9300" // orange
random_color_list = list("#FF9300")
pH = 2
/datum/reagent/colorful_reagent/crayonpowder/yellow
name = "Yellow Crayon Powder"
@@ -1475,6 +1558,7 @@
colorname = "yellow"
color = "#FFF200" // yellow
random_color_list = list("#FFF200")
pH = 5
/datum/reagent/colorful_reagent/crayonpowder/green
name = "Green Crayon Powder"
@@ -1483,12 +1567,14 @@
color = "#A8E61D" // green
random_color_list = list("#A8E61D")
/datum/reagent/colorful_reagent/crayonpowder/blue
name = "Blue Crayon Powder"
id = "bluecrayonpowder"
colorname = "blue"
color = "#00B7EF" // blue
random_color_list = list("#00B7EF")
pH = 10
/datum/reagent/colorful_reagent/crayonpowder/purple
name = "Purple Crayon Powder"
@@ -1496,6 +1582,7 @@
colorname = "purple"
color = "#DA00FF" // purple
random_color_list = list("#DA00FF")
pH = 13
/datum/reagent/colorful_reagent/crayonpowder/invisible
name = "Invisible Crayon Powder"
@@ -1530,6 +1617,7 @@
color = "#000000" // RBG: 0, 0, 0
var/tox_prob = 0
taste_description = "plant food"
pH = 3
/datum/reagent/plantnutriment/on_mob_life(mob/living/carbon/M)
if(prob(tox_prob))
@@ -1543,6 +1631,7 @@
description = "Cheap and extremely common type of plant nutriment."
color = "#376400" // RBG: 50, 100, 0
tox_prob = 10
pH = 2
/datum/reagent/plantnutriment/left4zednutriment
name = "Left 4 Zed"
@@ -1550,6 +1639,7 @@
description = "Unstable nutriment that makes plants mutate more often than usual."
color = "#1A1E4D" // RBG: 26, 30, 77
tox_prob = 25
pH = 1.5
/datum/reagent/plantnutriment/robustharvestnutriment
name = "Robust Harvest"
@@ -1557,6 +1647,7 @@
description = "Very potent nutriment that prevents plants from mutating."
color = "#9D9D00" // RBG: 157, 157, 0
tox_prob = 15
pH = 1
@@ -1584,6 +1675,7 @@
color = "#6b008f"
taste_description = "bitterness"
taste_mult = 1.5
pH = 1.5
/datum/reagent/stable_plasma/on_mob_life(mob/living/carbon/C)
C.adjustPlasma(10)
@@ -1596,6 +1688,7 @@
reagent_state = LIQUID
color = "#694600"
taste_description = "metal"
pH = 4.5
/datum/reagent/carpet
name = "Carpet"
@@ -1618,14 +1711,16 @@
reagent_state = LIQUID
color = "#b37740"
taste_description = "chemicals"
pH = 7.8
/datum/reagent/phenol
name = "Phenol"
id = "phenol"
description = "An aromatic ring of carbon with a hydroxyl group. A useful precursor to some medicines, but has no healing properties on its own."
reagent_state = LIQUID
taste_description = "sweet and tarry" //Again, not a strong acid.
pH = 5.5
color = "#e6e8ff"
taste_description = "acid"
/datum/reagent/ash
name = "Ash"
@@ -1634,14 +1729,15 @@
reagent_state = LIQUID
color = "#665c56"
taste_description = "ash"
pH = 6.5
/datum/reagent/acetone
name = "Acetone"
id = "acetone"
description = "A slick, slightly carcinogenic liquid. Has a multitude of mundane uses in everyday life."
reagent_state = LIQUID
taste_description = "solvent"//It's neutral though..?
color = "#e6e6e6"
taste_description = "acid"
/datum/reagent/colorful_reagent
name = "Colorful Reagent"
@@ -1731,6 +1827,7 @@
reagent_state = LIQUID
color = "#60A584" // rgb: 96, 165, 132
taste_description = "cool salt"
pH = 11.2
/datum/reagent/lye
name = "Lye"
@@ -1738,7 +1835,8 @@
description = "Also known as sodium hydroxide. As a profession making this is somewhat underwhelming."
reagent_state = LIQUID
color = "#FFFFD6" // very very light yellow
taste_description = "acid"
taste_description = "alkali" //who put ACID for NaOH ????
pH = 13
/datum/reagent/drying_agent
name = "Drying agent"
@@ -1747,6 +1845,7 @@
reagent_state = LIQUID
color = "#A70FFF"
taste_description = "dryness"
pH = 10.7
/datum/reagent/drying_agent/reaction_turf(turf/open/T, reac_volume)
if(istype(T))
@@ -1818,6 +1917,7 @@
description = "Royal Bee Jelly, if injected into a Queen Space Bee said bee will split into two bees."
color = "#00ff80"
taste_description = "strange honey"
pH = 3
/datum/reagent/royal_bee_jelly/on_mob_life(mob/living/carbon/M)
if(prob(2))
@@ -1839,6 +1939,7 @@
metabolization_rate = INFINITY
can_synth = FALSE
taste_description = "brains"
pH = 0.5
/datum/reagent/romerol/reaction_mob(mob/living/carbon/human/H, method=TOUCH, reac_volume)
// Silently add the zombie infection organ to be activated upon death
@@ -1897,6 +1998,7 @@
description = "the petroleum based components of plastic."
color = "#f7eded"
taste_description = "plastic"
pH = 6
/datum/reagent/glitter
name = "generic glitter"
@@ -1939,6 +2041,7 @@
color = "#AAAAAA55"
taste_description = "water"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
pH = 15
/datum/reagent/pax/on_mob_metabolize(mob/living/L)
..()
@@ -2027,6 +2130,13 @@
color = "#FAEAFF"
taste_description = "synthetic catnip"
/datum/reagent/moonsugar/on_mob_life(mob/living/carbon/M)
if(prob(20))
to_chat(M, "You find yourself unable to supress the desire to meow!")
M.emote("nya")
..()
//Kept for legacy, I think it will break everything if you enable it.
/datum/reagent/penis_enlargement
name = "Penis Enlargement"
id = "penis_enlargement"
@@ -23,6 +23,7 @@
color = "#792300" // rgb: 121, 35, 0
toxpwr = 2.5
taste_description = "mushroom"
pH = 13
/datum/reagent/toxin/mutagen
name = "Unstable mutagen"
@@ -32,6 +33,7 @@
toxpwr = 0
taste_description = "slime"
taste_mult = 0.9
pH = 2
/datum/reagent/toxin/mutagen/reaction_mob(mob/living/carbon/M, method=TOUCH, reac_volume)
if(!..())
@@ -61,6 +63,7 @@
taste_mult = 1.5
color = "#8228A0"
toxpwr = 3
pH = 4
/datum/reagent/toxin/plasma/on_mob_life(mob/living/carbon/C)
if(holder.has_reagent("epinephrine"))
@@ -93,6 +96,7 @@
color = "#7DC3A0"
toxpwr = 0
taste_description = "acid"
pH = 1.2
/datum/reagent/toxin/lexorin/on_mob_life(mob/living/carbon/C)
. = TRUE
@@ -115,6 +119,7 @@
toxpwr = 0
taste_description = "slime"
taste_mult = 1.3
pH = 10
/datum/reagent/toxin/slimejelly/on_mob_life(mob/living/carbon/M)
if(prob(10))
@@ -133,6 +138,7 @@
color = "#CF3600" // rgb: 207, 54, 0
toxpwr = 0
taste_description = "mint"
pH = 8
/datum/reagent/toxin/minttoxin/on_mob_life(mob/living/carbon/M)
if(HAS_TRAIT(M, TRAIT_FAT))
@@ -146,6 +152,7 @@
color = "#003333" // rgb: 0, 51, 51
toxpwr = 2
taste_description = "fish"
pH = 12
/datum/reagent/toxin/zombiepowder
name = "Zombie Powder"
@@ -155,6 +162,7 @@
color = "#669900" // rgb: 102, 153, 0
toxpwr = 0.5
taste_description = "death"
pH = 13
/datum/reagent/toxin/zombiepowder/on_mob_metabolize(mob/living/L)
..()
@@ -177,6 +185,7 @@
color = "#664700" // rgb: 102, 71, 0
toxpwr = 0.8
taste_description = "death"
pH = 14.5
/datum/reagent/toxin/ghoulpowder/on_mob_metabolize(mob/living/L)
..()
@@ -198,6 +207,7 @@
color = "#B31008" // rgb: 139, 166, 233
toxpwr = 0
taste_description = "sourness"
pH = 11
/datum/reagent/toxin/mindbreaker/on_mob_life(mob/living/carbon/M)
M.hallucination += 5
@@ -210,6 +220,7 @@
color = "#49002E" // rgb: 73, 0, 46
toxpwr = 1
taste_mult = 1
pH = 2
/datum/reagent/toxin/plantbgone/reaction_obj(obj/O, reac_volume)
if(istype(O, /obj/structure/alien/weeds))
@@ -234,6 +245,7 @@
id = "weedkiller"
description = "A harmful toxic mixture to kill weeds. Do not ingest!"
color = "#4B004B" // rgb: 75, 0, 75
pH = 3
/datum/reagent/toxin/pestkiller
name = "Pest Killer"
@@ -241,6 +253,7 @@
description = "A harmful toxic mixture to kill pests. Do not ingest!"
color = "#4B004B" // rgb: 75, 0, 75
toxpwr = 1
pH = 3.2
/datum/reagent/toxin/pestkiller/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
..()
@@ -254,6 +267,7 @@
description = "A natural toxin produced by blob spores that inhibits vision when ingested."
color = "#9ACD32"
toxpwr = 1
pH = 11
/datum/reagent/toxin/spore/on_mob_life(mob/living/carbon/C)
C.damageoverlaytemp = 60
@@ -268,6 +282,7 @@
color = "#9ACD32"
toxpwr = 0.5
taste_description = "burning"
pH = 13
/datum/reagent/toxin/spore_burning/on_mob_life(mob/living/carbon/M)
M.adjust_fire_stacks(2)
@@ -282,6 +297,7 @@
color = "#000067" // rgb: 0, 0, 103
toxpwr = 0
metabolization_rate = 1.5 * REAGENTS_METABOLISM
pH = 11
/datum/reagent/toxin/chloralhydrate/on_mob_life(mob/living/carbon/M)
switch(current_cycle)
@@ -326,6 +342,7 @@
glass_icon_state = "beerglass"
glass_name = "glass of beer"
glass_desc = "A freezing pint of beer."
pH = 2
/datum/reagent/toxin/fakebeer/on_mob_life(mob/living/carbon/M)
switch(current_cycle)
@@ -343,6 +360,7 @@
reagent_state = SOLID
color = "#5B2E0D" // rgb: 91, 46, 13
toxpwr = 0.5
pH = 4.2
/datum/reagent/toxin/teapowder
name = "Ground Tea Leaves"
@@ -351,6 +369,7 @@
reagent_state = SOLID
color = "#7F8400" // rgb: 127, 132, 0
toxpwr = 0.5
pH = 4.9
/datum/reagent/toxin/mutetoxin //the new zombie powder.
name = "Mute Toxin"
@@ -359,6 +378,7 @@
color = "#F0F8FF" // rgb: 240, 248, 255
toxpwr = 0
taste_description = "silence"
pH = 12.2
/datum/reagent/toxin/mutetoxin/on_mob_life(mob/living/carbon/M)
M.silent = max(M.silent, 3)
@@ -816,6 +836,7 @@
var/acidpwr = 10 //the amount of protection removed from the armour
taste_description = "acid"
self_consuming = TRUE
pH = 2.75
/datum/reagent/toxin/acid/reaction_mob(mob/living/carbon/C, method=TOUCH, reac_volume)
if(!istype(C))
@@ -17,6 +17,24 @@
var/mix_message = "The solution begins to bubble." //The message shown to nearby people upon mixing, if applicable
var/mix_sound = 'sound/effects/bubbles.ogg' //The sound played upon mixing, if applicable
//FermiChem!
var/OptimalTempMin = 200 // Lower area of bell curve for determining heat based rate reactions
var/OptimalTempMax = 800 // Upper end for above
var/ExplodeTemp = 900 // Temperature at which reaction explodes - If any reaction is this hot, it explodes!
var/OptimalpHMin = 5 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
var/OptimalpHMax = 10 // Higest value for above
var/ReactpHLim = 3 // How far out pH wil react, giving impurity place (Exponential phase)
var/CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)//Not implemented yet
var/CurveSharpT = 2 // How sharp the temperature exponential curve is (to the power of value)
var/CurveSharppH = 2 // How sharp the pH exponential curve is (to the power of value)
var/ThermicConstant = 1 // Temperature change per 1u produced
var/HIonRelease = 0.1 // pH change per 1u reaction
var/RateUpLim = 10 // Optimal/max rate possible if all conditions are perfect
var/FermiChem = FALSE // If the chemical uses the Fermichem reaction mechanics//If the chemical uses the Fermichem reaction mechanics
var/FermiExplode = FALSE // If the chemical explodes in a special way
var/PurityMin = 0.15 //If purity is below 0.15, it explodes too. Set to 0 to disable this.
/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume, specialreact)
return
//I recommend you set the result amount to the total volume of all components.
@@ -41,6 +41,13 @@
results = list("aranesp" = 3)
required_reagents = list("epinephrine" = 1, "atropine" = 1, "morphine" = 1)
/datum/chemical_reaction/happiness
name = "Happiness"
id = "happiness"
results = list("happiness" = 4)
required_reagents = list("nitrous_oxide" = 2, "epinephrine" = 1, "ethanol" = 1)
required_catalysts = list("plasma" = 5)
/datum/chemical_reaction/skooma
name = "skooma"
id = "skooma"
@@ -178,6 +178,12 @@
results = list("mutadone" = 3)
required_reagents = list("mutagen" = 1, "acetone" = 1, "bromine" = 1)
/datum/chemical_reaction/neurine
name = "Neurine"
id = "neurine"
results = list("neurine" = 3)
required_reagents = list("mannitol" = 1, "acetone" = 1, "oxygen" = 1)
/datum/chemical_reaction/antihol
name = "antihol"
id = "antihol"
@@ -264,3 +270,9 @@
results = list("modafinil" = 5)
required_reagents = list("diethylamine" = 1, "ammonia" = 1, "phenol" = 1, "acetone" = 1, "sacid" = 1)
required_catalysts = list("bromine" = 1) // as close to the real world synthesis as possible
/datum/chemical_reaction/psicodine
name = "Psicodine"
id = "psicodine"
results = list("psicodine" = 5)
required_reagents = list( "mannitol" = 2, "water" = 2, "impedrezene" = 1)
@@ -528,6 +528,16 @@
/datum/chemical_reaction/life/on_reaction(datum/reagents/holder, created_volume)
chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life") // Lol.
//This is missing, I'm adding it back (see tgwiki). Not sure why we don't have it.
/datum/chemical_reaction/life_friendly
name = "Life (Friendly)"
id = "life_friendly"
required_reagents = list("strange_reagent" = 1, "synthflesh" = 1, "sugar" = 1)
required_temp = 374
/datum/chemical_reaction/life_friendly/on_reaction(datum/reagents/holder, created_volume)
chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life (friendly)", FRIENDLY_SPAWN) //Pray for cute cats
/datum/chemical_reaction/corgium
name = "corgium"
id = "corgium"
+47 -1
View File
@@ -1,3 +1,6 @@
#define PH_WEAK (1 << 0)
#define TEMP_WEAK (1 << 1)
/obj/item/reagent_containers
name = "Container"
desc = "..."
@@ -12,6 +15,8 @@
var/spawned_disease = null
var/disease_amount = 20
var/spillable = FALSE
var/beaker_weakness_bitflag = NONE//Bitflag!
var/container_HP = 2
/obj/item/reagent_containers/Initialize(mapload, vol)
. = ..()
@@ -123,9 +128,50 @@
reagents.clear_reagents()
//melts plastic beakers
/obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M)
reagents.expose_temperature(1000)
if(beaker_weakness_bitflag & TEMP_WEAK)
var/list/seen = viewers(5, get_turf(src))
var/iconhtml = icon2html(src, seen)
for(var/mob/H in seen)
to_chat(H, "<span class='notice'>[iconhtml] \The [src]'s melts from the temperature!</span>")
playsound(get_turf(src), 'sound/FermiChem/heatmelt.ogg', 80, 1)
qdel(src)
..()
//melts plastic beakers
/obj/item/reagent_containers/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
reagents.expose_temperature(exposed_temperature)
reagents.expose_temperature(exposed_temperature)
temp_check()
/obj/item/reagent_containers/proc/temp_check()
if(beaker_weakness_bitflag & TEMP_WEAK)
if(reagents.chem_temp >= 444)//assuming polypropylene
var/list/seen = viewers(5, get_turf(src))
var/iconhtml = icon2html(src, seen)
for(var/mob/M in seen)
to_chat(M, "<span class='notice'>[iconhtml] \The [src]'s melts from the temperature!</span>")
playsound(get_turf(src), 'sound/FermiChem/heatmelt.ogg', 80, 1)
to_chat(M, "<span class='warning'><i>[iconhtml] Have you tried using glass or meta beakers for high temperature reactions? These are immune to temperature effects.</i></span>")
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times beakers have melted from temperature")
qdel(src)
//melts glass beakers
/obj/item/reagent_containers/proc/pH_check()
if(beaker_weakness_bitflag & PH_WEAK)
if((reagents.pH < 0.5) || (reagents.pH > 13.5))
var/list/seen = viewers(5, get_turf(src))
var/iconhtml = icon2html(src, seen)
container_HP--
if(container_HP <= 0)
for(var/mob/M in seen)
to_chat(M, "<span class='notice'>[iconhtml] \The [src]'s melts from the extreme pH!</span>")
playsound(get_turf(src), 'sound/FermiChem/acidmelt.ogg', 80, 1)
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times beakers have melted from pH")
qdel(src)
else
for(var/mob/M in seen)
to_chat(M, "<span class='notice'>[iconhtml] \The [src]'s is damaged by the extreme pH and begins to deform!</span>")
playsound(get_turf(src), 'sound/FermiChem/bufferadd.ogg', 50, 1)
to_chat(M, "<span class='warning'><i>[iconhtml] Have you tried using plastic beakers (XL) or metabeakers for high pH reactions? These beakers are immune to pH effects.</i></span>")
@@ -240,7 +240,7 @@
name = "Rhinovirus culture bottle"
desc = "A small bottle. Contains XY-rhinovirus culture in synthblood medium."
spawned_disease = /datum/disease/advance/cold
/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."
@@ -6,6 +6,7 @@
reagent_flags = OPENCONTAINER
spillable = TRUE
resistance_flags = ACID_PROOF
container_HP = 3
/obj/item/reagent_containers/glass/attack(mob/M, mob/user, obj/target)
@@ -108,11 +109,13 @@
/obj/item/reagent_containers/glass/beaker
name = "beaker"
desc = "A beaker. It can hold up to 50 units."
desc = "A beaker. It can hold up to 50 units. Unable to withstand extreme pHes"
icon = 'icons/obj/chemical.dmi'
icon_state = "beaker"
item_state = "beaker"
materials = list(MAT_GLASS=500)
beaker_weakness_bitflag = PH_WEAK
container_HP = 5
/obj/item/reagent_containers/glass/beaker/Initialize()
. = ..()
@@ -152,27 +155,33 @@
/obj/item/reagent_containers/glass/beaker/jar
name = "honey jar"
desc = "A jar for honey. It can hold up to 50 units of sweet delight."
desc = "A jar for honey. It can hold up to 50 units of sweet delight. Unable to withstand reagents of an extreme pH."
icon = 'icons/obj/chemical.dmi'
icon_state = "vapour"
/obj/item/reagent_containers/glass/beaker/large
name = "large beaker"
desc = "A large beaker. Can hold up to 100 units."
desc = "A large beaker. Can hold up to 100 units. Unable to withstand reagents of an extreme pH."
icon_state = "beakerlarge"
materials = list(MAT_GLASS=2500)
volume = 100
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
container_HP = 6
/obj/item/reagent_containers/glass/beaker/plastic
name = "x-large beaker"
desc = "An extra-large beaker. Can hold up to 120 units."
desc = "An extra-large beaker. Can hold up to 150 units. Is able to resist acid and alkaline solutions, but melts at 444K"
icon_state = "beakerwhite"
materials = list(MAT_GLASS=2500, MAT_PLASTIC=3000)
volume = 120
volume = 150
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,60,120)
possible_transfer_amounts = list(5,10,15,20,25,30,50,100,150)
/obj/item/reagent_containers/glass/beaker/plastic/Initialize()
beaker_weakness_bitflag &= ~PH_WEAK
beaker_weakness_bitflag |= TEMP_WEAK
. = ..()
/obj/item/reagent_containers/glass/beaker/plastic/update_icon()
icon_state = "beakerlarge" // hack to lets us reuse the large beaker reagent fill states
@@ -181,12 +190,16 @@
/obj/item/reagent_containers/glass/beaker/meta
name = "metamaterial beaker"
desc = "A large beaker. Can hold up to 180 units."
desc = "A large beaker. Can hold up to 200 units. Is able to withstand all chemical situations."
icon_state = "beakergold"
materials = list(MAT_GLASS=2500, MAT_PLASTIC=3000, MAT_GOLD=1000, MAT_TITANIUM=1000)
volume = 180
volume = 200
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,60,120,180)
possible_transfer_amounts = list(5,10,15,20,25,30,50,100,200)
/obj/item/reagent_containers/glass/beaker/meta/Initialize()
beaker_weakness_bitflag &= ~PH_WEAK
. = ..()
/obj/item/reagent_containers/glass/beaker/noreact
name = "cryostasis beaker"
@@ -197,17 +210,24 @@
reagent_flags = OPENCONTAINER | NO_REACT
volume = 50
amount_per_transfer_from_this = 10
container_HP = 10//shouldn't be needed
/obj/item/reagent_containers/glass/beaker/noreact/Initialize()
beaker_weakness_bitflag &= ~PH_WEAK
. = ..()
//reagents.set_reacting(FALSE) was this removed in a recent pr?
/obj/item/reagent_containers/glass/beaker/bluespace
name = "bluespace beaker"
desc = "A bluespace beaker, powered by experimental bluespace technology \
and Element Cuban combined with the Compound Pete. Can hold up to \
300 units."
300 units. Unable to withstand reagents of an extreme pH."
icon_state = "beakerbluespace"
materials = list(MAT_GLASS=3000)
volume = 300
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100,300)
container_HP = 8
/obj/item/reagent_containers/glass/beaker/cryoxadone
list_reagents = list("cryoxadone" = 30)
@@ -264,6 +284,11 @@
SLOT_L_STORE, SLOT_R_STORE,\
SLOT_GENERC_DEXTROUS_STORAGE
)
container_HP = 2
/obj/item/reagent_containers/glass/bucket/Initialize()
beaker_weakness_bitflag |= TEMP_WEAK
. = ..()
/obj/item/reagent_containers/glass/bucket/attackby(obj/O, mob/user, params)
if(istype(O, /obj/item/mop))
@@ -313,6 +338,11 @@
materials = list(MAT_GLASS=0)
volume = 50
amount_per_transfer_from_this = 10
container_HP = 2
/obj/item/reagent_containers/glass/beaker/waterbottle/Initialize()
beaker_weakness_bitflag |= TEMP_WEAK
. = ..()
/obj/item/reagent_containers/glass/beaker/waterbottle/empty
list_reagents = list()
@@ -324,6 +354,7 @@
list_reagents = list("water" = 100)
volume = 100
amount_per_transfer_from_this = 20
container_HP = 2
/obj/item/reagent_containers/glass/beaker/waterbottle/large/empty
list_reagents = list()
+259 -242
View File
@@ -1,242 +1,259 @@
/obj/item/reagent_containers/pill
name = "pill"
desc = "A tablet or capsule."
icon = 'icons/obj/chemical.dmi'
icon_state = "pill"
item_state = "pill"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
possible_transfer_amounts = list()
volume = 50
grind_results = list()
var/apply_type = INGEST
var/apply_method = "swallow"
var/roundstart = 0
var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills
var/dissolvable = TRUE
/obj/item/reagent_containers/pill/Initialize()
. = ..()
if(!icon_state)
icon_state = "pill[rand(1,20)]"
if(reagents.total_volume && roundstart)
name += " ([reagents.total_volume]u)"
/obj/item/reagent_containers/pill/attack_self(mob/user)
return
/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone)
if(!canconsume(M, user))
return 0
if(M == user)
M.visible_message("<span class='notice'>[user] attempts to [apply_method] [src].</span>")
if(self_delay)
if(!do_mob(user, M, self_delay))
return 0
to_chat(M, "<span class='notice'>You [apply_method] [src].</span>")
else
M.visible_message("<span class='danger'>[user] attempts to force [M] to [apply_method] [src].</span>", \
"<span class='userdanger'>[user] attempts to force [M] to [apply_method] [src].</span>")
if(!do_mob(user, M))
return 0
M.visible_message("<span class='danger'>[user] forces [M] to [apply_method] [src].</span>", \
"<span class='userdanger'>[user] forces [M] to [apply_method] [src].</span>")
var/makes_me_think = pick(strings("redpill.json", "redpill_questions"))
if(icon_state == "pill4" && prob(5)) //you take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes
addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, M, "<span class='notice'>[makes_me_think]</span>"), 50)
log_combat(user, M, "fed", reagents.log_list())
if(reagents.total_volume)
reagents.reaction(M, apply_type)
reagents.trans_to(M, reagents.total_volume)
qdel(src)
return 1
/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity)
. = ..()
if(!proximity)
return
if(!dissolvable || !target.is_refillable())
return
if(target.is_drainable() && !target.reagents.total_volume)
to_chat(user, "<span class='warning'>[target] is empty! There's nothing to dissolve [src] in.</span>")
return
if(target.reagents.holder_full())
to_chat(user, "<span class='warning'>[target] is full.</span>")
return
to_chat(user, "<span class='notice'>You dissolve [src] in [target].</span>")
for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius
to_chat(O, "<span class='warning'>[user] slips something into [target]!</span>")
reagents.trans_to(target, reagents.total_volume)
qdel(src)
/obj/item/reagent_containers/pill/tox
name = "toxins pill"
desc = "Highly toxic."
icon_state = "pill5"
list_reagents = list("toxin" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/cyanide
name = "cyanide pill"
desc = "Don't swallow this."
icon_state = "pill5"
list_reagents = list("cyanide" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/adminordrazine
name = "adminordrazine pill"
desc = "It's magic. We don't have to explain it."
icon_state = "pill16"
list_reagents = list("adminordrazine" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/morphine
name = "morphine pill"
desc = "Commonly used to treat insomnia."
icon_state = "pill8"
list_reagents = list("morphine" = 30)
roundstart = 1
/obj/item/reagent_containers/pill/stimulant
name = "stimulant pill"
desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!"
icon_state = "pill19"
list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30)
roundstart = 1
/obj/item/reagent_containers/pill/salbutamol
name = "salbutamol pill"
desc = "Used to treat oxygen deprivation."
icon_state = "pill16"
list_reagents = list("salbutamol" = 30)
roundstart = 1
/obj/item/reagent_containers/pill/charcoal
name = "charcoal pill"
desc = "Neutralizes many common toxins."
icon_state = "pill17"
list_reagents = list("charcoal" = 10)
roundstart = 1
/obj/item/reagent_containers/pill/epinephrine
name = "epinephrine pill"
desc = "Used to stabilize patients."
icon_state = "pill5"
list_reagents = list("epinephrine" = 15)
roundstart = 1
/obj/item/reagent_containers/pill/mannitol
name = "mannitol pill"
desc = "Used to treat brain damage."
icon_state = "pill17"
list_reagents = list("mannitol" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/mutadone
name = "mutadone pill"
desc = "Used to treat genetic damage."
icon_state = "pill20"
list_reagents = list("mutadone" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/salicyclic
name = "salicylic acid pill"
desc = "Used to dull pain."
icon_state = "pill9"
list_reagents = list("sal_acid" = 24)
roundstart = 1
/obj/item/reagent_containers/pill/oxandrolone
name = "oxandrolone pill"
desc = "Used to stimulate burn healing."
icon_state = "pill11"
list_reagents = list("oxandrolone" = 24)
roundstart = 1
/obj/item/reagent_containers/pill/insulin
name = "insulin pill"
desc = "Handles hyperglycaemic coma."
icon_state = "pill18"
list_reagents = list("insulin" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/antirad
name = "potassium iodide pill"
desc = "Used to treat radition used to counter radiation poisoning."
icon_state = "pill18"
list_reagents = list("potass_iodide" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/antirad_plus
name = "prussian blue pill"
desc = "Used to treat heavy radition poisoning."
icon = 'modular_citadel/icons/obj/modularpills.dmi'
icon_state = "prussian_blue"
list_reagents = list("prussian_blue" = 25, "water" = 10)
roundstart = 1
/obj/item/reagent_containers/pill/mutarad
name = "radiation treatment deluxe pill"
desc = "Used to treat heavy radition poisoning and genetic defects."
icon = 'modular_citadel/icons/obj/modularpills.dmi'
icon_state = "anit_rad_fixgene"
list_reagents = list("prussian_blue" = 15, "potass_iodide" = 15, "mutadone" = 15, "water" = 5)
roundstart = 1
///////////////////////////////////////// this pill is used only in a legion mob drop
/obj/item/reagent_containers/pill/shadowtoxin
name = "black pill"
desc = "I wouldn't eat this if I were you."
icon_state = "pill9"
color = "#454545"
list_reagents = list("shadowmutationtoxin" = 1)
//////////////////////////////////////// drugs
/obj/item/reagent_containers/pill/zoom
name = "zoom pill"
list_reagents = list("synaptizine" = 10, "nicotine" = 10, "methamphetamine" = 1)
/obj/item/reagent_containers/pill/happy
name = "happy pill"
list_reagents = list("sugar" = 10, "space_drugs" = 10)
/obj/item/reagent_containers/pill/lsd
name = "hallucinogen pill"
list_reagents = list("mushroomhallucinogen" = 15, "mindbreaker" = 15)
/obj/item/reagent_containers/pill/aranesp
name = "speedy pill"
list_reagents = list("aranesp" = 10)
/obj/item/reagent_containers/pill/floorpill
name = "floorpill"
desc = "A strange pill found in the depths of maintenance"
icon_state = "pill21"
var/static/list/names = list("maintenance pill","floorpill","mystery pill","suspicious pill","strange pill")
var/static/list/descs = list("Your feeling is telling you no, but...","Drugs are expensive, you can't afford not to eat any pills that you find."\
, "Surely, there's no way this could go bad.")
/obj/item/reagent_containers/pill/floorpill/Initialize()
list_reagents = list(get_random_reagent_id() = rand(10,50))
. = ..()
name = pick(names)
if(prob(20))
desc = pick(descs)
/obj/item/reagent_containers/pill/get_belt_overlay()
return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch")
/obj/item/reagent_containers/pill/penis_enlargement
name = "penis enlargement pill"
list_reagents = list("penis_enlargement" = 30)
/obj/item/reagent_containers/pill
name = "pill"
desc = "A tablet or capsule."
icon = 'icons/obj/chemical.dmi'
icon_state = "pill"
item_state = "pill"
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
possible_transfer_amounts = list()
volume = 50
grind_results = list()
var/apply_type = INGEST
var/apply_method = "swallow"
var/roundstart = 0
var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills
var/dissolvable = TRUE
/obj/item/reagent_containers/pill/Initialize()
. = ..()
if(!icon_state)
icon_state = "pill[rand(1,20)]"
if(reagents.total_volume && roundstart)
name += " ([reagents.total_volume]u)"
/obj/item/reagent_containers/pill/attack_self(mob/user)
return
/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone)
if(!canconsume(M, user))
return 0
if(M == user)
M.visible_message("<span class='notice'>[user] attempts to [apply_method] [src].</span>")
if(self_delay)
if(!do_mob(user, M, self_delay))
return 0
to_chat(M, "<span class='notice'>You [apply_method] [src].</span>")
else
M.visible_message("<span class='danger'>[user] attempts to force [M] to [apply_method] [src].</span>", \
"<span class='userdanger'>[user] attempts to force [M] to [apply_method] [src].</span>")
if(!do_mob(user, M))
return 0
M.visible_message("<span class='danger'>[user] forces [M] to [apply_method] [src].</span>", \
"<span class='userdanger'>[user] forces [M] to [apply_method] [src].</span>")
var/makes_me_think = pick(strings("redpill.json", "redpill_questions"))
if(icon_state == "pill4" && prob(5)) //you take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes
addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, M, "<span class='notice'>[makes_me_think]</span>"), 50)
log_combat(user, M, "fed", reagents.log_list())
if(reagents.total_volume)
reagents.reaction(M, apply_type)
reagents.trans_to(M, reagents.total_volume)
qdel(src)
return 1
/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity)
. = ..()
if(!proximity)
return
if(!dissolvable || !target.is_refillable())
return
if(target.is_drainable() && !target.reagents.total_volume)
to_chat(user, "<span class='warning'>[target] is empty! There's nothing to dissolve [src] in.</span>")
return
if(target.reagents.holder_full())
to_chat(user, "<span class='warning'>[target] is full.</span>")
return
to_chat(user, "<span class='notice'>You dissolve [src] in [target].</span>")
for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius
to_chat(O, "<span class='warning'>[user] slips something into [target]!</span>")
reagents.trans_to(target, reagents.total_volume)
qdel(src)
/obj/item/reagent_containers/pill/tox
name = "toxins pill"
desc = "Highly toxic."
icon_state = "pill5"
list_reagents = list("toxin" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/cyanide
name = "cyanide pill"
desc = "Don't swallow this."
icon_state = "pill5"
list_reagents = list("cyanide" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/adminordrazine
name = "adminordrazine pill"
desc = "It's magic. We don't have to explain it."
icon_state = "pill16"
list_reagents = list("adminordrazine" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/morphine
name = "morphine pill"
desc = "Commonly used to treat insomnia."
icon_state = "pill8"
list_reagents = list("morphine" = 30)
roundstart = 1
/obj/item/reagent_containers/pill/stimulant
name = "stimulant pill"
desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!"
icon_state = "pill19"
list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30)
roundstart = 1
/obj/item/reagent_containers/pill/salbutamol
name = "salbutamol pill"
desc = "Used to treat oxygen deprivation."
icon_state = "pill16"
list_reagents = list("salbutamol" = 30)
roundstart = 1
/obj/item/reagent_containers/pill/charcoal
name = "charcoal pill"
desc = "Neutralizes many common toxins."
icon_state = "pill17"
list_reagents = list("charcoal" = 10)
roundstart = 1
/obj/item/reagent_containers/pill/epinephrine
name = "epinephrine pill"
desc = "Used to stabilize patients."
icon_state = "pill5"
list_reagents = list("epinephrine" = 15)
roundstart = 1
/obj/item/reagent_containers/pill/mannitol
name = "mannitol pill"
desc = "Used to treat brain damage."
icon_state = "pill17"
list_reagents = list("mannitol" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/mutadone
name = "mutadone pill"
desc = "Used to treat genetic damage."
icon_state = "pill20"
list_reagents = list("mutadone" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/salicyclic
name = "salicylic acid pill"
desc = "Used to dull pain."
icon_state = "pill9"
list_reagents = list("sal_acid" = 24)
roundstart = 1
/obj/item/reagent_containers/pill/oxandrolone
name = "oxandrolone pill"
desc = "Used to stimulate burn healing."
icon_state = "pill11"
list_reagents = list("oxandrolone" = 24)
roundstart = 1
/obj/item/reagent_containers/pill/insulin
name = "insulin pill"
desc = "Handles hyperglycaemic coma."
icon_state = "pill18"
list_reagents = list("insulin" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/psicodine
name = "psicodine pill"
desc = "Used to treat mental instability and traumas."
list_reagents = list("psicodine" = 10)
icon_state = "pill22"
roundstart = 1
/obj/item/reagent_containers/pill/antirad
name = "potassium iodide pill"
desc = "Used to treat radition used to counter radiation poisoning."
icon_state = "pill18"
list_reagents = list("potass_iodide" = 50)
roundstart = 1
/obj/item/reagent_containers/pill/antirad_plus
name = "prussian blue pill"
desc = "Used to treat heavy radition poisoning."
icon = 'modular_citadel/icons/obj/modularpills.dmi'
icon_state = "prussian_blue"
list_reagents = list("prussian_blue" = 25, "water" = 10)
roundstart = 1
/obj/item/reagent_containers/pill/mutarad
name = "radiation treatment deluxe pill"
desc = "Used to treat heavy radition poisoning and genetic defects."
icon = 'modular_citadel/icons/obj/modularpills.dmi'
icon_state = "anit_rad_fixgene"
list_reagents = list("prussian_blue" = 15, "potass_iodide" = 15, "mutadone" = 15, "water" = 5)
roundstart = 1
///////////////////////////////////////// this pill is used only in a legion mob drop
/obj/item/reagent_containers/pill/shadowtoxin
name = "black pill"
desc = "I wouldn't eat this if I were you."
icon_state = "pill9"
color = "#454545"
list_reagents = list("shadowmutationtoxin" = 1)
//////////////////////////////////////// drugs
/obj/item/reagent_containers/pill/zoom
name = "zoom pill"
list_reagents = list("synaptizine" = 10, "nicotine" = 10, "methamphetamine" = 1)
/obj/item/reagent_containers/pill/happy
name = "happy pill"
list_reagents = list("sugar" = 10, "space_drugs" = 10)
/obj/item/reagent_containers/pill/lsd
name = "hallucinogen pill"
list_reagents = list("mushroomhallucinogen" = 15, "mindbreaker" = 15)
/obj/item/reagent_containers/pill/aranesp
name = "speedy pill"
list_reagents = list("aranesp" = 10)
/obj/item/reagent_containers/pill/happiness
name = "happiness pill"
desc = "It has a creepy smiling face on it."
icon_state = "pill_happy"
list_reagents = list("happiness" = 10)
/obj/item/reagent_containers/pill/floorpill
name = "floorpill"
desc = "A strange pill found in the depths of maintenance"
icon_state = "pill21"
var/static/list/names = list("maintenance pill","floorpill","mystery pill","suspicious pill","strange pill")
var/static/list/descs = list("Your feeling is telling you no, but...","Drugs are expensive, you can't afford not to eat any pills that you find."\
, "Surely, there's no way this could go bad.")
/obj/item/reagent_containers/pill/floorpill/Initialize()
list_reagents = list(get_random_reagent_id() = rand(10,50))
. = ..()
name = pick(names)
if(prob(20))
desc = pick(descs)
/obj/item/reagent_containers/pill/get_belt_overlay()
return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch")
/obj/item/reagent_containers/pill/penis_enlargement
name = "penis enlargement pill"
list_reagents = list("penis_enlarger" = 10)
/obj/item/reagent_containers/pill/breast_enlargement
name = "breast enlargement pill"
list_reagents = list("breast_enlarger" = 10)
@@ -554,6 +554,16 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/datum/design/cybernetic_tongue
name = "Cybernetic tongue"
desc = "A fancy cybernetic tongue."
id = "cybernetic_tongue"
build_type = PROTOLATHE
materials = list(MAT_METAL = 500, MAT_GLASS = 500)
build_path = /obj/item/organ/tongue/cybernetic
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
/////////////////////
//Adv Surgery Tools//
/////////////////////
+10 -1
View File
@@ -1,4 +1,3 @@
/////////////////////////////////////////
/////////////////HUDs////////////////////
/////////////////////////////////////////
@@ -480,6 +479,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
/datum/design/pHmeter
name = "Chemical Analyser"
desc = "A a electrode attached to a small circuit box that will tell you the pH of a solution."
id = "pHmeter"
build_type = PROTOLATHE
materials = list(MAT_METAL = 1000, MAT_SILVER = 100, MAT_DIAMOND = 100)
build_path = /obj/item/fermichem/pHmeter
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
/////////////////////////////////////////
////////////Armour///////////////////////
/////////////////////////////////////////
@@ -93,7 +93,7 @@
/datum/nanite_program/blood_restoring/check_conditions()
if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob
if(C.blood_volume >= BLOOD_VOLUME_SAFE)
if(C.blood_volume >= (BLOOD_VOLUME_SAFE*C.blood_ratio))
return FALSE
else
return FALSE
@@ -256,4 +256,3 @@
log_game("[C] has been successfully defibrillated by nanites.")
else
playsound(C, 'sound/machines/defib_failed.ogg', 50, 0)
+2 -2
View File
@@ -69,7 +69,7 @@
display_name = "Advanced Biotechnology"
description = "Advanced Biotechnology"
prereq_ids = list("biotech")
design_ids = list("piercesyringe", "crewpinpointer", "smoke_machine", "plasmarefiller", "limbgrower", "defibrillator", "meta_beaker", "healthanalyzer_advanced","harvester","holobarrier_med","smartdartgun","medicinalsmartdart")
design_ids = list("piercesyringe", "crewpinpointer", "smoke_machine", "plasmarefiller", "limbgrower", "defibrillator", "meta_beaker", "healthanalyzer_advanced","harvester","holobarrier_med","smartdartgun","medicinalsmartdart", "pHmeter")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -526,7 +526,7 @@
display_name = "Cybernetic Organs"
description = "We have the technology to rebuild him."
prereq_ids = list("adv_biotech")
design_ids = list("cybernetic_heart", "cybernetic_liver", "cybernetic_liver_u", "cybernetic_lungs", "cybernetic_lungs_u")
design_ids = list("cybernetic_heart", "cybernetic_liver", "cybernetic_liver_u", "cybernetic_lungs", "cybernetic_lungs_u", "cybernetic_tongue")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
+4
View File
@@ -60,6 +60,10 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
for(var/a in T.GetAllContents())
if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types))
return FALSE
if(istype(a, /obj/structure/closet))//Prevents eigenlockers from ending up at CC
var/obj/structure/closet/c = a
if(c.eigen_teleport == TRUE)
return FALSE
return TRUE
/obj/docking_port/mobile/supply/request(obj/docking_port/stationary/S)
@@ -15,7 +15,6 @@
var/die_with_shapeshifted_form = TRUE
var/convert_damage = FALSE //If you want to convert the caster's health to the shift, and vice versa.
var/convert_damage_type = BRUTE //Since simplemobs don't have advanced damagetypes, what to convert damage back into.
var/shapeshift_type
var/list/possible_shapes = list(/mob/living/simple_animal/mouse,\
/mob/living/simple_animal/pet/dog/corgi,\
@@ -167,4 +166,4 @@
/datum/soullink/shapeshift/sharerDies(gibbed, mob/living/sharer)
if(source)
source.shapeDeath(gibbed)
source.shapeDeath(gibbed)
+32
View File
@@ -1,6 +1,7 @@
#define LIVER_DEFAULT_HEALTH 100 //amount of damage required for liver failure
#define LIVER_DEFAULT_TOX_TOLERANCE 3 //amount of toxins the liver can filter out
#define LIVER_DEFAULT_TOX_LETHALITY 0.01 //lower values lower how harmful toxins are to the liver
#define LIVER_SWELLING_MOVE_MODIFY "pharma"
/obj/item/organ/liver
name = "liver"
@@ -16,6 +17,8 @@
var/toxTolerance = LIVER_DEFAULT_TOX_TOLERANCE//maximum amount of toxins the liver can just shrug off
var/toxLethality = LIVER_DEFAULT_TOX_LETHALITY//affects how much damage toxins do to the liver
var/filterToxins = TRUE //whether to filter toxins
var/swelling = 0
var/cachedmoveCalc = 1
/obj/item/organ/liver/on_life()
var/mob/living/carbon/C = owner
@@ -45,11 +48,40 @@
if(damage > maxHealth)//cap liver damage
damage = maxHealth
if(swelling >= 10)
pharmacokinesis()
/obj/item/organ/liver/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent("iron", 5)
return S
//Just in case
/obj/item/organ/liver/Remove(mob/living/carbon/M, special = 0)
..()
M.remove_movespeed_modifier(LIVER_SWELLING_MOVE_MODIFY)
M.ResetBloodVol() //At the moment, this shouldn't allow application twice. You either have this OR a thirsty ferret.
sizeMoveMod(1, M)
//Applies some of the effects to the patient.
/obj/item/organ/liver/proc/pharmacokinesis()
var/moveCalc = 1+((round(swelling) - 9)/3)
if(moveCalc == cachedmoveCalc)//reduce calculations
return
if(prob(5))
to_chat(owner, "<span class='notice'>You feel a stange ache in your side, almost like a sitch. This pain is affecting your movements and making you feel lightheaded.</span>")
var/mob/living/carbon/human/H = owner
H.add_movespeed_modifier(LIVER_SWELLING_MOVE_MODIFY, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc)
H.AdjustBloodVol(moveCalc/3)
sizeMoveMod(moveCalc, H)
/obj/item/organ/liver/proc/sizeMoveMod(var/value, mob/living/carbon/human/H)
if(cachedmoveCalc == value)
return
H.next_move_modifier /= cachedmoveCalc
H.next_move_modifier *= value
cachedmoveCalc = value
/obj/item/organ/liver/fly
name = "insectoid liver"
icon_state = "liver-x" //xenomorph liver? It's just a black liver so it fits.
+50 -4
View File
@@ -1,3 +1,5 @@
#define LUNGS_MAX_HEALTH 300
/obj/item/organ/lungs
name = "lungs"
icon_state = "lungs"
@@ -54,8 +56,40 @@
var/crit_stabilizing_reagent = "epinephrine"
//health
var/maxHealth = LUNGS_MAX_HEALTH
var/damage = 0
//TODO: lung health affects lung function
/obj/item/organ/lungs/proc/adjustLungLoss(damage_mod, mob/living/carbon/M) //damage might be too low atm.
if (maxHealth == INFINITY)
return
if(damage+damage_mod < 0)
damage = 0
return
damage += damage_mod
if ((damage / maxHealth) > 1)
to_chat(M, "<span class='userdanger'>You feel your lungs collapse within your chest as you gasp for air, unable to inflate them anymore!</span>")
M.emote("gasp")
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Lungs lost")
qdel(src)
else if ((damage / maxHealth) > 0.75)
to_chat(M, "<span class='warning'>It's getting really hard to breathe!!</span>")
M.emote("gasp")
M.Dizzy(3)
else if ((damage / maxHealth) > 0.5)
M.Dizzy(2)
to_chat(M, "<span class='notice'>Your chest is really starting to hurt.</span>")
M.emote("cough")
else if ((damage / maxHealth) > 0.2)
to_chat(M, "<span class='notice'>You feel an ache within your chest.</span>")
M.emote("cough")
M.Dizzy(1)
/obj/item/organ/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H)
//TODO: add lung damage = less oxygen gains
var/breathModifier = (5-(5*(damage/maxHealth)/2)) //range 2.5 - 5
if((H.status_flags & GODMODE))
return
if(HAS_TRAIT(H, TRAIT_NOBREATH))
@@ -124,7 +158,7 @@
else
H.failed_last_breath = FALSE
if(H.health >= H.crit_threshold)
H.adjustOxyLoss(-5)
H.adjustOxyLoss(-breathModifier) //More damaged lungs = slower oxy rate up to a factor of half
gas_breathed = breath_gases[/datum/gas/oxygen]
H.clear_alert("not_enough_oxy")
@@ -153,7 +187,7 @@
else
H.failed_last_breath = FALSE
if(H.health >= H.crit_threshold)
H.adjustOxyLoss(-5)
H.adjustOxyLoss(-breathModifier)
gas_breathed = breath_gases[/datum/gas/nitrogen]
H.clear_alert("nitro")
@@ -190,7 +224,7 @@
else
H.failed_last_breath = FALSE
if(H.health >= H.crit_threshold)
H.adjustOxyLoss(-5)
H.adjustOxyLoss(-breathModifier)
gas_breathed = breath_gases[/datum/gas/carbon_dioxide]
H.clear_alert("not_enough_co2")
@@ -220,7 +254,7 @@
else
H.failed_last_breath = FALSE
if(H.health >= H.crit_threshold)
H.adjustOxyLoss(-5)
H.adjustOxyLoss(-breathModifier)
gas_breathed = breath_gases[/datum/gas/plasma]
H.clear_alert("not_enough_tox")
@@ -244,6 +278,9 @@
else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning
if(prob(20))
H.emote(pick("giggle", "laugh"))
SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria)
else
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria")
// BZ
@@ -368,10 +405,13 @@
var/cold_modifier = H.dna.species.coldmod
if(breath_temperature < cold_level_3_threshold)
H.apply_damage_type(cold_level_3_damage*cold_modifier, cold_damage_type)
adjustLungLoss((cold_level_3_damage*cold_modifier*2), H)
if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold)
H.apply_damage_type(cold_level_2_damage*cold_modifier, cold_damage_type)
adjustLungLoss((cold_level_2_damage*cold_modifier*2), H)
if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold)
H.apply_damage_type(cold_level_1_damage*cold_modifier, cold_damage_type)
adjustLungLoss((cold_level_1_damage*cold_modifier*2), H)
if(breath_temperature < cold_level_1_threshold)
if(prob(20))
to_chat(H, "<span class='warning'>You feel [cold_message] in your [name]!</span>")
@@ -380,10 +420,13 @@
var/heat_modifier = H.dna.species.heatmod
if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold)
H.apply_damage_type(heat_level_1_damage*heat_modifier, heat_damage_type)
adjustLungLoss((heat_level_1_damage*heat_modifier*2), H)
if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold)
H.apply_damage_type(heat_level_2_damage*heat_modifier, heat_damage_type)
adjustLungLoss((heat_level_2_damage*heat_modifier*2), H)
if(breath_temperature > heat_level_3_threshold)
H.apply_damage_type(heat_level_3_damage*heat_modifier, heat_damage_type)
adjustLungLoss((heat_level_3_damage*heat_modifier*2), H)
if(breath_temperature > heat_level_1_threshold)
if(prob(20))
to_chat(H, "<span class='warning'>You feel [hot_message] in your [name]!</span>")
@@ -402,12 +445,14 @@
safe_oxygen_max = 0 // Like, at all.
safe_toxins_min = 16 //We breath THIS!
safe_toxins_max = 0
maxHealth = INFINITY//I don't understand how plamamen work, so I'm not going to try t give them special lungs atm
/obj/item/organ/lungs/cybernetic
name = "cybernetic lungs"
desc = "A cybernetic version of the lungs found in traditional humanoid entities. It functions the same as an organic lung and is merely meant as a replacement."
icon_state = "lungs-c"
synthetic = TRUE
maxHealth = 400
/obj/item/organ/lungs/cybernetic/emp_act()
. = ..()
@@ -427,6 +472,7 @@
cold_level_1_threshold = 200
cold_level_2_threshold = 140
cold_level_3_threshold = 100
maxHealth = 550
/obj/item/organ/lungs/ashwalker
name = "ash lungs"
@@ -153,6 +153,17 @@
// if they have no mutant tongues, give them a regular one
T.Insert(src)
else
var/obj/item/organ/tongue/oT = getorganslot(ORGAN_SLOT_TONGUE)
if(oT.name == "fluffy tongue")
var/obj/item/organ/tongue/T
if(dna && dna.species && dna.species.mutanttongue)
T = new dna.species.mutanttongue()
else
T = new()
oT.Remove(src)
qdel(oT)
T.Insert(src)
if(!getorganslot(ORGAN_SLOT_EYES))
var/obj/item/organ/eyes/E
+67 -1
View File
@@ -1,3 +1,5 @@
#define TONGUE_MAX_HEALTH 60
/obj/item/organ/tongue
name = "tongue"
desc = "A fleshy muscle mostly used for lying."
@@ -8,6 +10,8 @@
var/list/languages_possible
var/say_mod = null
var/taste_sensitivity = 15 // lower is more sensitive.
var/maxHealth = TONGUE_MAX_HEALTH
var/damage = 0
var/modifies_speech = FALSE
var/static/list/languages_possible_base = typecacheof(list(
/datum/language/common,
@@ -27,6 +31,29 @@
/obj/item/organ/tongue/proc/handle_speech(datum/source, list/speech_args)
/obj/item/organ/tongue/proc/adjustTongueLoss(mob/living/carbon/M, damage_mod)
if (maxHealth == "alien")
return
if (maxHealth == "bone")
var/target = M.get_bodypart(BODY_ZONE_HEAD)
M.apply_damage(damage_mod, BURN, target)
to_chat(M, "<span class='userdanger'>The drink burns your skull! Oof, your bones!</span>")
return
if(damage+damage_mod < 0)
damage = 0
return
damage += damage_mod
if ((damage / maxHealth) > 1)
to_chat(M, "<span class='userdanger'>Your tongue is singed beyond recognition, and disintegrates!</span>")
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Tongues lost to Fermi")
qdel(src)
else if ((damage / maxHealth) > 0.85)
to_chat(M, "<span class='warning'>Your tongue feels like it's about to fall out!.</span>")
else if ((damage / maxHealth) > 0.5)
to_chat(M, "<span class='notice'>Your tongue is really starting to hurt.</span>")
/obj/item/organ/tongue/Insert(mob/living/carbon/M, special = 0)
..()
if(say_mod && M.dna && M.dna.species)
@@ -51,6 +78,7 @@
icon_state = "tonguelizard"
say_mod = "hisses"
taste_sensitivity = 10 // combined nose + tongue, extra sensitive
maxHealth = 40 //extra sensitivity means tongue is more susceptible to damage
modifies_speech = TRUE
/obj/item/organ/tongue/lizard/handle_speech(datum/source, list/speech_args)
@@ -68,6 +96,7 @@
icon_state = "tonguefly"
say_mod = "buzzes"
taste_sensitivity = 25 // you eat vomit, this is a mercy
maxHealth = 80 //years of eatting trash has made your tongue strong
modifies_speech = TRUE
/obj/item/organ/tongue/fly/handle_speech(datum/source, list/speech_args)
@@ -85,6 +114,7 @@
icon_state = "tongueayylmao"
say_mod = "gibbers"
taste_sensitivity = 101 // ayys cannot taste anything.
maxHealth = 120 //Ayys probe a lot
modifies_speech = TRUE
/obj/item/organ/tongue/abductor/handle_speech(datum/source, list/speech_args)
@@ -113,6 +143,7 @@
icon_state = "tonguezombie"
say_mod = "moans"
taste_sensitivity = 32
maxHealth = 65 //Stop! It's already dead...!
modifies_speech = TRUE
/obj/item/organ/tongue/zombie/handle_speech(datum/source, list/speech_args)
@@ -137,6 +168,7 @@
icon_state = "tonguexeno"
say_mod = "hisses"
taste_sensitivity = 10 // LIZARDS ARE ALIENS CONFIRMED
maxHealth = "alien" //Their blood is acid, so, no, though a tongueless xeno might be funny
modifies_speech = TRUE // not really, they just hiss
var/static/list/languages_possible_alien = typecacheof(list(
/datum/language/xenocommon,
@@ -159,6 +191,7 @@
say_mod = "rattles"
attack_verb = list("bitten", "chattered", "chomped", "enamelled", "boned")
taste_sensitivity = 101 // skeletons cannot taste anything
maxHealth = "bone" //Take brute damage instead
modifies_speech = TRUE
var/chattering = FALSE
var/phomeme_type = "sans"
@@ -181,6 +214,7 @@
name = "plasma bone \"tongue\""
desc = "Like animated skeletons, Plasmamen vibrate their teeth in order to produce speech."
icon_state = "tongueplasma"
maxHealth = "alien"
modifies_speech = FALSE
/obj/item/organ/tongue/robot
@@ -192,6 +226,7 @@
attack_verb = list("beeped", "booped")
modifies_speech = TRUE
taste_sensitivity = 25 // not as good as an organic tongue
maxHealth = 100 //RoboTongue!
var/electronics_magic = TRUE
/obj/item/organ/tongue/robot/can_speak_in_language(datum/language/dt)
@@ -200,8 +235,39 @@
/obj/item/organ/tongue/robot/handle_speech(datum/source, list/speech_args)
speech_args[SPEECH_SPANS] |= SPAN_ROBOT
/obj/item/organ/tongue/fluffy
name = "fluffy tongue"
desc = "OwO what's this?"
icon_state = "tonguefluffy"
taste_sensitivity = 10 // extra sensitive and inquisitive uwu
maxHealth = 35 //Sensitive tongue!
modifies_speech = TRUE
/obj/item/organ/tongue/fluffy/handle_speech(datum/source, list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
if(copytext(message, 1, 2) != "*")
message = replacetext(message, "ne", "nye")
message = replacetext(message, "nu", "nyu")
message = replacetext(message, "na", "nya")
message = replacetext(message, "no", "nyo")
message = replacetext(message, "ove", "uv")
message = replacetext(message, "l", "w")
message = replacetext(message, "r", "w")
message = lowertext(message)
speech_args[SPEECH_MESSAGE] = message
/obj/item/organ/tongue/cybernetic
name = "cybernetic tongue"
desc = "A state of the art robotic tongue that can detect the pH of anything drank."
icon_state = "tonguecybernetic"
taste_sensitivity = 10
maxHealth = 60 //It's robotic!
/obj/item/organ/tongue/cybernetic/handle_speech(datum/source, list/speech_args)
speech_args[SPEECH_SPANS] |= SPAN_ROBOT
/obj/item/organ/tongue/robot/ipc
name = "positronic voicebox"
say_mod = "beeps"
desc = "A voice synthesizer used by IPCs to smoothly interface with organic lifeforms."
electronics_magic = FALSE
electronics_magic = FALSE
+862 -1
View File
@@ -575,7 +575,7 @@
cooldown = COOLDOWN_MEME
for(var/V in listeners)
var/mob/living/carbon/human/H = V
if(H.canbearoused && H.has_dna()) // probably a redundant check but for good measure
if(H.canbearoused && H.has_dna() && HAS_TRAIT(H, TRAIT_NYMPHO)) // probably a redundant check but for good measure
H.mob_climax(forced_climax=TRUE)
//DAB
@@ -608,6 +608,867 @@
return cooldown
//////////////////////////////////////
///////ENTHRAL VELVET CHORDS//////////
//////////////////////////////////////
//Heavily modified voice of god code
/obj/item/organ/vocal_cords/velvet
name = "Velvet chords"
desc = "The voice spoken from these just make you want to drift off, sleep and obey."
icon_state = "velvet_chords"
actions_types = list(/datum/action/item_action/organ_action/velvet)
spans = list("velvet")
/datum/action/item_action/organ_action/velvet
name = "Velvet chords"
var/obj/item/organ/vocal_cords/velvet/cords = null
//icon_icon = 'icons/mob/screen_alert.dmi'
//button_icon_state = "velvet_chords"
//icon = 'icons/mob/screen_alert.dmi'
//icon_state = "in_love"
/datum/action/item_action/organ_action/velvet/New()
..()
cords = target
/datum/action/item_action/organ_action/velvet/IsAvailable()
return TRUE
/datum/action/item_action/organ_action/velvet/Trigger()
. = ..()
var/command = input(owner, "Speak in a sultry tone", "Command")
if(QDELETED(src) || QDELETED(owner))
return
if(!command)
return
owner.say(".x[command]")
/obj/item/organ/vocal_cords/velvet/can_speak_with()
return TRUE
/obj/item/organ/vocal_cords/velvet/handle_speech(message) //actually say the message
owner.say(message, spans = spans, sanitize = FALSE)
velvetspeech(message, owner, 1)
//////////////////////////////////////
///////////FermiChem//////////////////
//////////////////////////////////////
//Removed span_list from input arguments.
/proc/velvetspeech(message, mob/living/user, base_multiplier = 1, message_admins = FALSE, debug = FALSE)
if(!user || !user.can_speak() || user.stat)
return 0 //no cooldown
var/log_message = message
//FIND THRALLS
message = lowertext(message)
var/mob/living/list/listeners = list()
for(var/mob/living/L in get_hearers_in_view(8, user))
if(L.can_hear() && !L.anti_magic_check(FALSE, TRUE) && L.stat != DEAD)
if(L.has_status_effect(/datum/status_effect/chem/enthrall))//Check to see if they have the status
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)//Check to see if pet is on cooldown from last command and if the master is right
if(E.master != user)
continue
if(ishuman(L))
var/mob/living/carbon/human/H = L
if(istype(H.ears, /obj/item/clothing/ears/earmuffs))
continue
if (E.cooldown > 0)//If they're on cooldown you can't give them more commands.
continue
listeners += L
if(!listeners.len)
return 0
//POWER CALCULATIONS
var/power_multiplier = base_multiplier
// Not sure I want to give extra power to anyone at the moment...? We'll see how it turns out
if(user.mind)
//Chaplains are very good at indoctrinating
if(user.mind.assigned_role == "Chaplain")
power_multiplier *= 1.2
//Command staff has authority
if(user.mind.assigned_role in GLOB.command_positions)
power_multiplier *= 1.1
//Why are you speaking
if(user.mind.assigned_role == "Mime")
power_multiplier *= 0.5
//Cultists are closer to their gods and are better at indoctrinating
if(iscultist(user))
power_multiplier *= 1.2
else if (is_servant_of_ratvar(user))
power_multiplier *= 1.2
else if (is_devil(user))//The devil is supposed to be seductive, right?
power_multiplier *= 1.2
//range = 0.5 - 1.4~
//most cases = 1
//Try to check if the speaker specified a name or a job to focus on
var/list/specific_listeners = list()
var/found_string = null
//Get the proper job titles
message = get_full_job_name(message)
for(var/V in listeners)
var/mob/living/L = V
if(dd_hasprefix(message, L.real_name))
specific_listeners += L //focus on those with the specified name
//Cut out the name so it doesn't trigger commands
found_string = L.real_name
power_multiplier += 0.5
else if(dd_hasprefix(message, L.first_name()))
specific_listeners += L //focus on those with the specified name
//Cut out the name so it doesn't trigger commands
found_string = L.first_name()
power_multiplier += 0.5
else if(L.mind && L.mind.assigned_role && dd_hasprefix(message, L.mind.assigned_role))
specific_listeners += L //focus on those with the specified job
//Cut out the job so it doesn't trigger commands
found_string = L.mind.assigned_role
power_multiplier += 0.25
if(specific_listeners.len)
listeners = specific_listeners
//power_multiplier *= (1 + (1/specific_listeners.len)) //Put this is if it becomes OP, power is judged internally on a thrall, so shouldn't be nessicary.
message = copytext(message, 0, 1)+copytext(message, 1 + length(found_string), length(message) + 1)//I have no idea what this does
var/obj/item/organ/tongue/T = user.getorganslot(ORGAN_SLOT_TONGUE)
if (T.name == "fluffy tongue") //If you sound hillarious, it's hard to take you seriously. This is a way for other players to combat/reduce their effectiveness.
power_multiplier *= 0.75
if(debug == TRUE)
to_chat(world, "[user]'s power is [power_multiplier].")
//Mixables
var/static/regex/enthral_words = regex("relax|obey|love|serve|docile|so easy|ara ara")
var/static/regex/reward_words = regex("good boy|good girl|good pet|good job")
var/static/regex/punish_words = regex("bad boy|bad girl|bad pet|bad job")
//phase 0
var/static/regex/saymyname_words = regex("say my name|who am i|whoami")
var/static/regex/wakeup_words = regex("revert|awaken|snap") //works
//phase1
var/static/regex/petstatus_words = regex("how are you|what is your status|are you okay")
var/static/regex/silence_words = regex("shut up|silence|be silent|ssh|quiet|hush")
var/static/regex/speak_words = regex("talk to me|speak")
var/static/regex/antiresist_words = regex("unable to resist|give in")//useful if you think your target is resisting a lot
var/static/regex/resist_words = regex("resist|snap out of it|fight")//useful if two enthrallers are fighting
var/static/regex/forget_words = regex("forget|muddled|awake and forget")
var/static/regex/attract_words = regex("come here|come to me|get over here|attract")
//phase 2
var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //wah, lewd
var/static/regex/awoo_words = regex("howl|awoo|bark")
var/static/regex/nya_words = regex("nya|meow|mewl")
var/static/regex/sleep_words = regex("sleep|slumber|rest")
var/static/regex/strip_words = regex("strip|derobe|nude")
var/static/regex/walk_words = regex("slow down|walk")
var/static/regex/run_words = regex("run|speed up")
var/static/regex/liedown_words = regex("lie down") //TO ADD
var/static/regex/knockdown_words = regex("drop|fall|trip|knockdown|kneel")
//phase 3
var/static/regex/statecustom_words = regex("state triggers|state your triggers")
var/static/regex/custom_words = regex("new trigger|listen to me")
var/static/regex/custom_words_words = regex("speak|echo|shock|cum|kneel|strip|trance")//What a descriptive name!
var/static/regex/custom_echo = regex("obsess|fills your mind|loop")
var/static/regex/instill_words = regex("feel|entice|overwhel")
var/static/regex/recognise_words = regex("recognise me|did you miss me?")
var/static/regex/objective_words = regex("new objective|obey this command|unable to resist|compulsed")
var/static/regex/heal_words = regex("live|heal|survive|mend|life|pets never die")
var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt")
var/static/regex/hallucinate_words = regex("get high|hallucinate")
var/static/regex/hot_words = regex("heat|hot|hell")
var/static/regex/cold_words = regex("cold|cool down|chill|freeze")
var/static/regex/getup_words = regex("get up")
var/static/regex/pacify_words = regex("more and more docile|complaisant|friendly|pacifist")
var/static/regex/charge_words = regex("charge|oorah|attack")
var/distancelist = list(2,2,1.5,1.3,1.15,1,0.8,0.6,0.5,0.25)
//CALLBACKS ARE USED FOR MESSAGES BECAUSE SAY IS HANDLED AFTER THE PROCESSING.
//Tier 1
//ENTHRAL mixable (works I think)
if(findtext(message, enthral_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
power_multiplier *= distancelist[get_dist(user, V)+1]
if(L == user)
continue
if(length(message))
E.enthrallTally += (power_multiplier*(((length(message))/200) + 1)) //encourage players to say more than one word.
else
E.enthrallTally += power_multiplier*1.25 //thinking about it, I don't know how this can proc
if(L.canbearoused)
if(L.client?.prefs.lewdchem)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='nicegreen'><i><b>[E.enthrallGender] is so nice to listen to.</b></i></span>"), 5)
E.cooldown += 1
//REWARD mixable works
if(findtext(message, reward_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
power_multiplier *= distancelist[get_dist(user, V)+1]
if(L == user)
continue
if (L.client?.prefs.lewdchem)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='love'>[E.enthrallGender] has praised me!!</span>"), 5)
if(HAS_TRAIT(L, TRAIT_NYMPHO))
L.adjustArousalLoss(2*power_multiplier)
if(HAS_TRAIT(L, TRAIT_MASO))
E.enthrallTally -= power_multiplier
E.resistanceTally += power_multiplier
E.cooldown += 1
else
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='nicegreen'><b><i>I've been praised for doing a good job!</b></i></span>"), 5)
E.resistanceTally -= power_multiplier
E.enthrallTally += power_multiplier
var/descmessage = "<span class='love'><i>[(L.client?.prefs.lewdchem?"I feel so happy! I'm a good pet who [E.enthrallGender] loves!":"I did a good job!")]</i></span>"
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "enthrallpraise", /datum/mood_event/enthrallpraise, descmessage)
E.cooldown += 1
//PUNISH mixable works
else if(findtext(message, punish_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
var/descmessage = "[(L.client?.prefs.lewdchem?"I've failed [E.enthrallGender]... What a bad, bad pet!":"I did a bad job...")]"
if(L == user)
continue
if (L.client?.prefs.lewdchem)
if(HAS_TRAIT(L, TRAIT_MASO))
L.adjustArousalLoss(3*power_multiplier)
descmessage += "And yet, it feels so good..!</span>" //I don't really understand masco, is this the right sort of thing they like?
E.enthrallTally += power_multiplier
E.resistanceTally -= power_multiplier
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='love'>I've let [E.enthrallGender] down...!</b></span>"), 5)
else
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='warning'>I've let [E.enthrallGender] down...</b></span>"), 5)
else
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='warning'>I've failed [E.master]...</b></span>"), 5)
E.resistanceTally += power_multiplier
E.enthrallTally += power_multiplier
E.cooldown += 1
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "enthrallscold", /datum/mood_event/enthrallscold, descmessage)
E.cooldown += 1
//teir 0
//SAY MY NAME works
if((findtext(message, saymyname_words)))
for(var/V in listeners)
var/mob/living/carbon/C = V
var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
REMOVE_TRAIT(C, TRAIT_MUTE, "enthrall")
C.silent = 0
if(C.client?.prefs.lewdchem)
addtimer(CALLBACK(C, /atom/movable/proc/say, "[E.enthrallGender]"), 5)
else
addtimer(CALLBACK(C, /atom/movable/proc/say, "[E.master]"), 5)
//WAKE UP
else if((findtext(message, wakeup_words)))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
L.SetSleeping(0)//Can you hear while asleep?
switch(E.phase)
if(0)
E.phase = 3
E.status = null
user.emote("snap")
if(L.client?.prefs.lewdchem)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='big warning'>The snapping of your [E.enthrallGender]'s fingers brings you back to your enthralled state, obedient and ready to serve.</b></span>"), 5)
else
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='big warning'>The snapping of [E.master]'s fingers brings you back to being under their influence.</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You wake up [L]!</i></span>")
//tier 1
//PETSTATUS i.e. how they are
else if((findtext(message, petstatus_words)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
REMOVE_TRAIT(H, TRAIT_MUTE, "enthrall")
var/speaktrigger = ""
//phase
switch(E.phase)
if(0)
continue
if(1)
addtimer(CALLBACK(H, /atom/movable/proc/say, "I feel happy being with you."), 5)
continue
if(2)
speaktrigger += "[(H.client?.prefs.lewdchem?"I think I'm in love with you... ":"I find you really inspirational, ")]" //'
if(3)
speaktrigger += "[(H.client?.prefs.lewdchem?"I'm devoted to being your pet":"I'm commited to following your cause!")]! "
if(4)
speaktrigger += "[(H.client?.prefs.lewdchem?"You are my whole world and all of my being belongs to you, ":"I cannot think of anything else but aiding your cause, ")] "//Redflags!!
//mood
GET_COMPONENT_FROM(mood, /datum/component/mood, H)
switch(mood.sanity)
if(SANITY_GREAT to INFINITY)
speaktrigger += "I'm beyond elated!! " //did you mean byond elated? hohoho
if(SANITY_NEUTRAL to SANITY_GREAT)
speaktrigger += "I'm really happy! "
if(SANITY_DISTURBED to SANITY_NEUTRAL)
speaktrigger += "I'm a little sad, "
if(SANITY_UNSTABLE to SANITY_DISTURBED)
speaktrigger += "I'm really upset, "
if(SANITY_CRAZY to SANITY_UNSTABLE)
speaktrigger += "I'm about to fall apart without you! "
if(SANITY_INSANE to SANITY_CRAZY)
speaktrigger += "Hold me, please.. "
//Withdrawal
switch(E.withdrawalTick)
if(10 to 36) //denial
speaktrigger += "I missed you, "
if(36 to 66) //barganing
speaktrigger += "I missed you, but I knew you'd come back for me! "
if(66 to 90) //anger
speaktrigger += "I couldn't take being away from you like that, "
if(90 to 140) //depression
speaktrigger += "I was so scared you'd never come back, "
if(140 to INFINITY) //acceptance
speaktrigger += "I'm hurt that you left me like that... I felt so alone... "
//hunger
switch(H.nutrition)
if(0 to NUTRITION_LEVEL_STARVING)
speaktrigger += "I'm famished, please feed me..! "
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
speaktrigger += "I'm so hungry... "
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
speaktrigger += "I'm hungry, "
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
speaktrigger += "I'm sated, "
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
speaktrigger += "I've a full belly! "
if(NUTRITION_LEVEL_FULL to INFINITY)
speaktrigger += "I'm fat... "
//health
switch(H.health)
if(100 to INFINITY)
speaktrigger += "I feel fit, "
if(80 to 99)
speaktrigger += "I ache a little bit, "
if(40 to 80)
speaktrigger += "I'm really hurt, "
if(0 to 40)
speaktrigger += "I'm in a lot of pain, help! "
if(-INFINITY to 0)
speaktrigger += "I'm barely concious and in so much pain, please help me! "
//toxin
switch(H.getToxLoss())
if(10 to 30)
speaktrigger += "I feel a bit queasy... "
if(30 to 60)
speaktrigger += "I feel nauseous... "
if(60 to INFINITY)
speaktrigger += "My head is pounding and I feel like I'm going to be sick... "
//oxygen
if (H.getOxyLoss() >= 25)
speaktrigger += "I can't breathe! "
//blind
if (HAS_TRAIT(H, TRAIT_BLIND))
speaktrigger += "I can't see! "
//deaf..?
if (HAS_TRAIT(H, TRAIT_DEAF))//How the heck you managed to get here I have no idea, but just in case!
speaktrigger += "I can barely hear you! "
//And the brain damage. And the brain damage. And the brain damage. And the brain damage. And the brain damage.
switch(H.getBrainLoss())
if(20 to 40)
speaktrigger += "I have a mild head ache, "
if(40 to 80)
speaktrigger += "I feel disorentated and confused, "
if(80 to 120)
speaktrigger += "My head feels like it's about to explode, "
if(120 to 160)
speaktrigger += "You are the only thing keeping my mind sane, "
if(160 to INFINITY)
speaktrigger += "I feel like I'm on the brink of losing my mind, "
//horny
if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && H.client?.prefs.lewdchem)
switch(H.getArousalLoss())
if(40 to 60)
speaktrigger += "I'm feeling a little horny, "
if(60 to 80)
speaktrigger += "I'm feeling horny, "
if(80 to INFINITY)
speaktrigger += "I'm really, really horny, "
//collar
if(istype(H.wear_neck, /obj/item/clothing/neck/petcollar))
speaktrigger += "I love the collar you gave me, "
//End
if(H.client?.prefs.lewdchem)
speaktrigger += "[E.enthrallGender]!"
else
speaktrigger += "[user.first_name()]!"
//say it!
addtimer(CALLBACK(H, /atom/movable/proc/say, "[speaktrigger]"), 5)
E.cooldown += 1
//SILENCE
else if((findtext(message, silence_words)))
for(var/mob/living/carbon/C in listeners)
var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
power_multiplier *= distancelist[get_dist(user, C)+1]
if (E.phase >= 3) //If target is fully enthralled,
ADD_TRAIT(C, TRAIT_MUTE, "enthrall")
else
C.silent += ((10 * power_multiplier) * E.phase)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "<span class='notice'>You are unable to speak!</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You silence [C].</i></span>")
E.cooldown += 3
//SPEAK
else if((findtext(message, speak_words)))//fix
for(var/mob/living/carbon/C in listeners)
var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
REMOVE_TRAIT(C, TRAIT_MUTE, "enthrall")
C.silent = 0
E.cooldown += 3
to_chat(user, "<span class='notice'><i>You [(C.client?.prefs.lewdchem?"allow [C] to speak again":"encourage [C] to speak again")].</i></span>")
//Antiresist
else if((findtext(message, antiresist_words)))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
E.status = "Antiresist"
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='big warning'>Your mind clouds over, as you find yourself unable to resist!</b></span>"), 5)
E.statusStrength = (1 * power_multiplier * E.phase)
E.cooldown += 15//Too short? yes, made 15
to_chat(user, "<span class='notice'><i>You frustrate [L]'s attempts at resisting.</i></span>")
//RESIST
else if((findtext(message, resist_words)))
for(var/mob/living/carbon/C in listeners)
var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
power_multiplier *= distancelist[get_dist(user, C)+1]
E.deltaResist += (power_multiplier)
E.owner_resist()
E.cooldown += 2
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "<span class='notice'>You are spurred into resisting from [user]'s words!'</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You spark resistance in [C].</i></span>")
//FORGET (A way to cancel the process)
else if((findtext(message, forget_words)))
for(var/mob/living/carbon/C in listeners)
var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase == 4)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "<span class='warning'>You're unable to forget about [(C.client?.prefs.lewdchem?"the dominating presence of [E.enthrallGender]":"[E.master]")]!</b></span>"), 5)
continue
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "<span class='warning'>You wake up, forgetting everything that just happened. You must've dozed off..? How embarassing!</b></span>"), 5)
C.Sleeping(50)
switch(E.phase)
if(1 to 2)
E.phase = -1
to_chat(C, "<span class='big warning'>You have no recollection of being enthralled by [E.master]!</b></span>")
to_chat(user, "<span class='notice'><i>You revert [C] back to their state before enthrallment.</i></span>")
if(3)
E.phase = 0
E.cooldown = 0
if(C.client?.prefs.lewdchem)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "<span class='big warning'>You revert to yourself before being enthralled by your [E.enthrallGender], with no memory of what happened.</b></span>"), 5)
else
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "<span class='big warning'>You revert to who you were before, with no memory of what happened with [E.master].</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You put [C] into a sleeper state, ready to turn them back at the snap of your fingers.</i></span>")
//ATTRACT
else if((findtext(message, attract_words)))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
L.throw_at(get_step_towards(user,L), 3 * power_multiplier, 1 * power_multiplier)
E.cooldown += 3
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>You are drawn towards [user]!</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You draw [L] towards you!</i></span>")
//teir 2
/* removed for now
//ORGASM
else if((findtext(message, orgasm_words)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase > 1)
if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && H.client?.prefs.lewdchem) // probably a redundant check but for good measure
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "<span class='love'>Your [E.enthrallGender] pushes you over the limit, overwhelming your body with pleasure.</b></span>"), 5)
H.mob_climax(forced_climax=TRUE)
H.SetStun(20)
H.setArousalLoss(H.min_arousal)
E.resistanceTally = 0 //makes resistance 0, but resets arousal, resistance buildup is faster unaroused (massively so).
E.enthrallTally += power_multiplier
E.cooldown += 6
else
H.throw_at(get_step_towards(user,H), 3 * power_multiplier, 1 * power_multiplier)
*/
//awoo
else if((findtext(message, awoo_words)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(2 to INFINITY)
H.say("*awoo")
E.cooldown += 1
//Nya
else if((findtext(message, nya_words)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(2 to INFINITY)
playsound(get_turf(H), pick('sound/effects/meow1.ogg', 'modular_citadel/sound/voice/nya.ogg'), 50, 1, -1) //I'm very tempted to write a Fermis clause that makes them merowr.ogg if it's me. But, I also don't think snowflakism is okay. I would've gotten away for it too, if it wern't for my morals.
H.emote("me", 1, "lets out a nya!")
E.cooldown += 1
//SLEEP
else if((findtext(message, sleep_words)))
for(var/mob/living/carbon/C in listeners)
var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(2 to INFINITY)
C.Sleeping(45 * power_multiplier)
E.cooldown += 10
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "<span class='notice'>Drowsiness suddenly overwhelms you as you fall asleep!</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You send [C] to sleep.</i></span>")
//STRIP
else if((findtext(message, strip_words)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(2 to INFINITY)
var/items = H.get_contents()
for(var/obj/item/W in items)
if(W == H.wear_suit)
H.dropItemToGround(W, TRUE)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "<span class='[(H.client?.prefs.lewdchem?"love":"warning")]'>Before you can even think about it, you quickly remove your clothes in response to [(H.client?.prefs.lewdchem?"your [E.enthrallGender]'s command'":"[E.master]'s directive'")].</b></span>"), 5)
E.cooldown += 10
//WALK
else if((findtext(message, walk_words)))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(2 to INFINITY)
if(L.m_intent != MOVE_INTENT_WALK)
L.toggle_move_intent()
E.cooldown += 1
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>You slow down to a walk.</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You encourage [L] to slow down.</i></span>")
//RUN
else if((findtext(message, run_words)))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(2 to INFINITY)
if(L.m_intent != MOVE_INTENT_RUN)
L.toggle_move_intent()
E.cooldown += 1
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>You speed up into a jog!</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You encourage [L] to pick up the pace!</i></span>")
//LIE DOWN
else if(findtext(message, liedown_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(2 to INFINITY)
L.lay_down()
E.cooldown += 10
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "[(L.client?.prefs.lewdchem?"<span class='love'>You eagerly lie down!":"<span class='notice'>You suddenly lie down!")]</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You encourage [L] to lie down.</i></span>")
//KNOCKDOWN
else if(findtext(message, knockdown_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(2 to INFINITY)
L.Knockdown(30 * power_multiplier * E.phase)
E.cooldown += 8
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>You suddenly drop to the ground!</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You encourage [L] to drop down to the ground.</i></span>")
//tier3
//STATE TRIGGERS
else if((findtext(message, statecustom_words)))//doesn't work
for(var/V in listeners)
var/mob/living/carbon/C = V
var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
if (E.phase == 3)
var/speaktrigger = ""
C.emote("me", 1, "whispers something quietly.")
if (get_dist(user, C) > 1)//Requires user to be next to their pet.
to_chat(user, "<span class='warning'>You need to be next to your pet to hear them!</b></span>")
continue
for (var/trigger in E.customTriggers)
speaktrigger += "[trigger], "
to_chat(user, "<b>[C]</b> whispers, \"<i>[speaktrigger] are my triggers.</i>\"")//So they don't trigger themselves!
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "<span class='notice'>You whisper your triggers to [(C.client?.prefs.lewdchem?"Your [E.enthrallGender]":"[E.master]")].</span>"), 5)
//CUSTOM TRIGGERS
else if((findtext(message, custom_words)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase == 3)
if (get_dist(user, H) > 1)//Requires user to be next to their pet.
to_chat(user, "<span class='warning'>You need to be next to your pet to give them a new trigger!</b></span>")
continue
else
user.emote("me", 1, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.")
user.SetStun(1000)//Hands are handy, so you have to stay still
H.SetStun(1000)
if (E.mental_capacity >= 5)
var/trigger = html_decode(stripped_input(user, "Enter the trigger phrase", MAX_MESSAGE_LEN))
var/custom_words_words_list = list("Speak", "Echo", "Shock", "Cum", "Kneel", "Strip", "Trance", "Cancel")
var/trigger2 = input(user, "Pick an effect", "Effects") in custom_words_words_list
trigger2 = lowertext(trigger2)
if ((findtext(trigger2, custom_words_words)))
if (trigger2 == "speak" || trigger2 == "echo")
var/trigger3 = html_decode(stripped_input(user, "Enter the phrase spoken. Abusing this to self antag is bannable.", MAX_MESSAGE_LEN))
E.customTriggers[trigger] = list(trigger2, trigger3)
log_game("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2], to send [trigger3].")
if(findtext(trigger3, "admin"))
message_admins("FERMICHEM: [user] maybe be trying to abuse MKUltra by implanting by [H] with [trigger], triggering [trigger2], to send [trigger3].")
else
E.customTriggers[trigger] = trigger2
log_game("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2].")
E.mental_capacity -= 5
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "<span class='notice'>[(H.client?.prefs.lewdchem?"your [E.enthrallGender]":"[E.master]")] whispers you a new trigger.</span>"), 5)
to_chat(user, "<span class='notice'><i>You sucessfully set the trigger word [trigger] in [H]</i></span>")
else
to_chat(user, "<span class='warning'>Your pet looks at you confused, it seems they don't understand that effect!</b></span>")
else
to_chat(user, "<span class='warning'>Your pet looks at you with a vacant blase expression, you don't think you can program anything else into them</b></span>")
user.SetStun(0)
H.SetStun(0)
//CUSTOM ECHO
else if((findtext(message, custom_echo)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase == 3)
if (get_dist(user, H) > 1)//Requires user to be next to their pet.
to_chat(user, "<span class='warning'>You need to be next to your pet to give them a new echophrase!</b></span>")
continue
else
user.emote("me", 1, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.")
user.SetStun(1000)//Hands are handy, so you have to stay still
H.SetStun(1000)
var/trigger = stripped_input(user, "Enter the loop phrase", MAX_MESSAGE_LEN)
var/customSpan = list("Notice", "Warning", "Hypnophrase", "Love", "Velvet")
var/trigger2 = input(user, "Pick the style", "Style") in customSpan
trigger2 = lowertext(trigger2)
E.customEcho = trigger
E.customSpan = trigger2
user.SetStun(0)
H.SetStun(0)
to_chat(user, "<span class='notice'><i>You sucessfully set an echoing phrase in [H]</i></span>")
//CUSTOM OBJECTIVE
else if((findtext(message, objective_words)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase == 3)
if (get_dist(user, H) > 1)//Requires user to be next to their pet.
to_chat(user, "<span class='warning'>You need to be next to your pet to give them a new objective!</b></span>")
continue
else
user.emote("me", 1, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.'")
user.SetStun(1000)//So you can't run away!
H.SetStun(1000)
if (E.mental_capacity >= 200)
var/datum/objective/brainwashing/objective = stripped_input(user, "Add an objective to give your pet.", MAX_MESSAGE_LEN)
if(!LAZYLEN(objective))
to_chat(user, "<span class='warning'>You can't give your pet an objective to do nothing!</b></span>")
continue
//Pets don't understand harm
objective = replacetext(lowertext(objective), "kill", "hug")
objective = replacetext(lowertext(objective), "murder", "cuddle")
objective = replacetext(lowertext(objective), "harm", "snuggle")
objective = replacetext(lowertext(objective), "decapitate", "headpat")
objective = replacetext(lowertext(objective), "strangle", "meow at")
objective = replacetext(lowertext(objective), "suicide", "self-love")
message_admins("[H] has been implanted by [user] with the objective [objective].")
log_game("FERMICHEM: [H] has been implanted by [user] with the objective [objective] via MKUltra.")
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "<span class='notice'>[(H.client?.prefs.lewdchem?"Your [E.enthrallGender]":"[E.master]")] whispers you a new objective.</span>"), 5)
brainwash(H, objective)
E.mental_capacity -= 200
to_chat(user, "<span class='notice'><i>You sucessfully give an objective to [H]</i></span>")
else
to_chat(user, "<span class='warning'>Your pet looks at you with a vacant blasé expression, you don't think you can program anything else into them</b></span>")
user.SetStun(0)
H.SetStun(0)
//INSTILL
else if((findtext(message, instill_words)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase == 3 && H.client?.prefs.lewdchem)
var/instill = stripped_input(user, "Instill an emotion in your [(user.client?.prefs.lewdchem?"Your pet":"listener")].", MAX_MESSAGE_LEN)
to_chat(H, "<i>[instill]</i>")
to_chat(user, "<span class='notice'><i>You sucessfully instill a feeling in [H]</i></span>")
log_game("FERMICHEM: [H] has been instilled by [user] with [instill] via MKUltra.")
E.cooldown += 1
//RECOGNISE
else if((findtext(message, recognise_words)))
for(var/V in listeners)
var/mob/living/carbon/human/H = V
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase > 1)
if(user.ckey == E.enthrallID && user.real_name == E.master.real_name)
E.master = user
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "<span class='nicegreen'>[(H.client?.prefs.lewdchem?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]</b></span>"), 5)
to_chat(user, "<span class='notice'><i>[H] looks at you with sparkling eyes, recognising you!</i></span>")
//I dunno how to do state objectives without them revealing they're an antag
//HEAL (maybe make this nap instead?)
else if(findtext(message, heal_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(3)//Tier 3 only
E.status = "heal"
E.statusStrength = (5 * power_multiplier)
E.cooldown += 5
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>You begin to lick your wounds.</b></span>"), 5)
L.Stun(15 * power_multiplier)
to_chat(user, "<span class='notice'><i>[L] begins to lick their wounds.</i></span>")
//STUN
else if(findtext(message, stun_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(3 to INFINITY)
L.Stun(40 * power_multiplier)
E.cooldown += 8
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>Your muscles freeze up!</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You cause [L] to freeze up!</i></span>")
//HALLUCINATE
else if(findtext(message, hallucinate_words))
for(var/V in listeners)
var/mob/living/carbon/C = V
var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(3 to INFINITY)
new /datum/hallucination/delusion(C, TRUE, null,150 * power_multiplier,0)
to_chat(user, "<span class='notice'><i>You send [C] on a trip.</i></span>")
//HOT
else if(findtext(message, hot_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(3 to INFINITY)
L.adjust_bodytemperature(50 * power_multiplier)//This seems nuts, reduced it, but then it didn't do anything, so I reverted it.
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>You feel your metabolism speed up!</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You speed [L]'s metabolism up!</i></span>")
//COLD
else if(findtext(message, cold_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(3 to INFINITY)
L.adjust_bodytemperature(-50 * power_multiplier)
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>You feel your metabolism slow down!</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You slow [L]'s metabolism down!</i></span>")
//GET UP
else if(findtext(message, getup_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(3 to INFINITY)//Tier 3 only
if(L.resting)
L.lay_down() //aka get up
L.SetStun(0)
L.SetKnockdown(0)
L.SetUnconscious(0) //i said get up i don't care if you're being tased
E.cooldown += 10 //This could be really strong
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>You jump to your feet from sheer willpower!</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You spur [L] to their feet!</i></span>")
//PACIFY
else if(findtext(message, pacify_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(3)//Tier 3 only
E.status = "pacify"
E.cooldown += 10
addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "<span class='notice'>You feel like never hurting anyone ever again.</b></span>"), 5)
to_chat(user, "<span class='notice'><i>You remove any intent to harm from [L]'s mind.</i></span>")
//CHARGE
else if(findtext(message, charge_words))
for(var/V in listeners)
var/mob/living/L = V
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
switch(E.phase)
if(3)//Tier 3 only
E.statusStrength = 2* power_multiplier
E.status = "charge"
E.cooldown += 10
to_chat(user, "<span class='notice'><i>You rally [L], leading them into a charge!</i></span>")
if(message_admins || debug)//Do you want this in?
message_admins("[ADMIN_LOOKUPFLW(user)] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
log_game("FERMICHEM: [key_name(user)] ckey: [user.key] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have spoken with a velvet voice")
//SSblackbox.record_feedback("tally", "Velvet_voice", 1, log_message) If this is on, it fills the thing up and OOFs the server
return
#undef COOLDOWN_STUN
#undef COOLDOWN_DAMAGE
+1 -1
View File
@@ -1325,7 +1325,7 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
desc = "A small device intended for recharging Cryptographic Sequencers. Using it will add five extra charges to the Cryptographic Sequencer."
item = /obj/item/emagrecharge
cost = 2
/datum/uplink_item/device_tools/cutouts
name = "Adaptive Cardboard Cutouts"
desc = "These cardboard cutouts are coated with a thin material that prevents discoloration and makes the images on them appear more lifelike. \
+3 -1
View File
@@ -28,7 +28,9 @@
contraband = list(/obj/item/reagent_containers/pill/tox = 3,
/obj/item/reagent_containers/pill/morphine = 4,
/obj/item/reagent_containers/pill/charcoal = 6)
premium = list(/obj/item/storage/box/hug/medical = 1,
premium = list(/obj/item/reagent_containers/medspray/synthflesh = 2,
/obj/item/storage/box/hug/medical = 1,
/obj/item/storage/pill_bottle/psicodine = 2,
/obj/item/reagent_containers/hypospray/medipen = 3,
/obj/item/storage/belt/medical = 3,
/obj/item/wrench/medical = 1,
+2 -1
View File
@@ -338,7 +338,8 @@
/obj/item/clothing/suit/toggle/labcoat/chemist = 3,
/obj/item/storage/backpack/chemistry = 3,
/obj/item/storage/backpack/satchel/chem = 3,
/obj/item/storage/bag/chemistry = 3)
/obj/item/storage/bag/chemistry = 3,
/obj/item/fermichem/pHbooklet = 3)//pH indicator)
refill_canister = /obj/item/vending_refill/wardrobe/chem_wardrobe
/obj/item/vending_refill/wardrobe/chem_wardrobe