diff --git a/code/modules/admin/sql_message_system.dm b/code/modules/admin/sql_message_system.dm
index 38316c904f..83b3d48380 100644
--- a/code/modules/admin/sql_message_system.dm
+++ b/code/modules/admin/sql_message_system.dm
@@ -335,7 +335,7 @@ proc/get_message_output(type, target_ckey)
if(!query_message_read.warn_execute())
return
if("watchlist entry")
- message_admins("Notice: [key_name_admin(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
+ message_admins("Notice: [key_name_admin(target_ckey)] has been on the watchlist since [timestamp] and has just connected - Reason: [text]")
send2irc_adminless_only("Watchlist", "[key_name(target_ckey)] is on the watchlist and has just connected - Reason: [text]")
if("memo")
output += "Memo by [admin_ckey] on [timestamp]"
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index e74f0c00d7..0bcb6f967e 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -558,7 +558,10 @@ Congratulations! You are now trained for invasive xenobiology research!"}
if(temp)
helptext = "Experimental gland detected!"
else
- helptext = "Subject suitable for experiments."
+ if (L.getorganslot(ORGAN_SLOT_HEART))
+ helptext = "Subject suitable for experiments."
+ else
+ helptext = "Subject unsuitable for experiments."
to_chat(user, "Probing result:[species]")
to_chat(user, "[helptext]")
diff --git a/code/modules/antagonists/abductor/equipment/abduction_surgery.dm b/code/modules/antagonists/abductor/equipment/abduction_surgery.dm
index 5b5bafdd21..ffce85e435 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_surgery.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_surgery.dm
@@ -53,3 +53,48 @@
var/obj/item/organ/heart/gland/gland = tool
gland.Insert(target, 2)
return 1
+
+/datum/surgery/pacify
+ name = "violence neutralization"
+ steps = list(/datum/surgery_step/incise,
+ /datum/surgery_step/retract_skin,
+ /datum/surgery_step/saw,
+ /datum/surgery_step/clamp_bleeders,
+ /datum/surgery_step/pacify,
+ /datum/surgery_step/close)
+
+ species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
+ possible_locs = list("head")
+ requires_bodypart_type = 0
+
+/datum/surgery/pacify/can_start(mob/user, mob/living/carbon/target)
+ if(!ishuman(user))
+ return FALSE
+ var/mob/living/carbon/human/H = user
+ . = FALSE
+ if(!(H.dna.species.id == "abductor"))
+ . = TRUE
+ for(var/obj/item/implant/abductor/A in H.implants)
+ . = TRUE
+ var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN)
+ if(!B)
+ to_chat(user, "It's hard to do surgery on someone's brain when they don't have one.")
+ return FALSE
+
+/datum/surgery_step/pacify
+ name = "rewire brain"
+ implements = list(/obj/item/hemostat = 100, /obj/item/screwdriver = 35, /obj/item/pen = 15)
+ time = 40
+
+/datum/surgery_step/pacify/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ user.visible_message("[user] begins to reshape [target]'s brain.", "You begin to reshape [target]'s brain...")
+
+/datum/surgery_step/pacify/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ user.visible_message("[user] successfully reshapes [target]'s brain!", "You succeed in reshaping [target]'s brain.")
+ target.gain_trauma(/datum/brain_trauma/severe/pacifism)
+ return TRUE
+
+/datum/surgery_step/pacify/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ user.visible_message("[user] successfully reshapes [target]'s brain!", "You screwed up, and rewired [target]'s brain the wrong way around...")
+ target.gain_trauma_type(BRAIN_TRAUMA_SEVERE)
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm
index 7e49415834..6eba723756 100644
--- a/code/modules/antagonists/abductor/equipment/gland.dm
+++ b/code/modules/antagonists/abductor/equipment/gland.dm
@@ -8,7 +8,7 @@
var/cooldown_low = 300
var/cooldown_high = 300
var/next_activation = 0
- var/uses // -1 For inifinite
+ var/uses // -1 For infinite
var/human_only = 0
var/active = 0
@@ -104,9 +104,9 @@
/obj/item/organ/heart/gland/heals/activate()
to_chat(owner, "You feel curiously revitalized.")
- owner.adjustBruteLoss(-20)
+ owner.adjustToxLoss(-20, FALSE, TRUE)
+ owner.heal_bodypart_damage(20, 20, TRUE)
owner.adjustOxyLoss(-20)
- owner.adjustFireLoss(-20)
/obj/item/organ/heart/gland/slime
cooldown_low = 600
@@ -116,18 +116,22 @@
mind_control_uses = 1
mind_control_duration = 2400
+/obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0)
+ ..()
+ owner.faction |= "slime"
+ owner.grant_language(/datum/language/slime)
+
/obj/item/organ/heart/gland/slime/activate()
to_chat(owner, "You feel nauseous!")
owner.vomit(20)
- var/mob/living/simple_animal/slime/Slime
- Slime = new(get_turf(owner), "grey")
+ var/mob/living/simple_animal/slime/Slime = new(get_turf(owner), "grey")
Slime.Friends = list(owner)
Slime.Leader = owner
/obj/item/organ/heart/gland/mindshock
- cooldown_low = 300
- cooldown_high = 300
+ cooldown_low = 400
+ cooldown_high = 700
uses = -1
icon_state = "mindshock"
mind_control_uses = 1
@@ -140,21 +144,30 @@
for(var/mob/living/carbon/H in orange(4,T))
if(H == owner)
continue
- to_chat(H, "You hear a buzz in your head.")
- H.confused += 20
+ switch(pick(1,3))
+ if(1)
+ to_chat(H, "You hear a loud buzz in your head, silencing your thoughts!")
+ H.Stun(50)
+ if(2)
+ to_chat(H, "You hear an annoying buzz in your head.")
+ H.confused += 15
+ H.adjustBrainLoss(10, 160)
+ if(3)
+ H.hallucination += 80
/obj/item/organ/heart/gland/pop
cooldown_low = 900
cooldown_high = 1800
uses = -1
- human_only = 1
+ human_only = TRUE
icon_state = "species"
mind_control_uses = 5
mind_control_duration = 300
/obj/item/organ/heart/gland/pop/activate()
to_chat(owner, "You feel unlike yourself.")
- var/species = pick(list(/datum/species/lizard, /datum/species/jelly/slime, /datum/species/pod, /datum/species/fly, /datum/species/jelly))
+ randomize_human(owner)
+ var/species = pick(list(/datum/species/human, /datum/species/lizard, /datum/species/moth, /datum/species/fly))
owner.set_species(species)
/obj/item/organ/heart/gland/ventcrawling
@@ -169,7 +182,6 @@
to_chat(owner, "You feel very stretchy.")
owner.ventcrawler = VENTCRAWLER_ALWAYS
-
/obj/item/organ/heart/gland/viral
cooldown_low = 1800
cooldown_high = 2400
@@ -180,30 +192,55 @@
/obj/item/organ/heart/gland/viral/activate()
to_chat(owner, "You feel sick.")
- var/virus_type = pick(/datum/disease/beesease, /datum/disease/brainrot, /datum/disease/magnitis)
- var/datum/disease/D = new virus_type()
- D.carrier = TRUE
- owner.viruses += D
- D.affected_mob = owner
+ var/datum/disease/advance/A = random_virus(pick(2,6),6)
+ A.carrier = TRUE
+ owner.viruses += A
+ A.affected_mob = owner
owner.med_hud_set_status()
+/obj/item/organ/heart/gland/viral/proc/random_virus(max_symptoms, max_level)
+ if(max_symptoms > SYMPTOM_LIMIT)
+ max_symptoms = SYMPTOM_LIMIT
+ var/datum/disease/advance/A = new(FALSE, null)
+ A.symptoms = list()
+ var/list/datum/symptom/possible_symptoms = list()
+ for(var/symptom in subtypesof(/datum/symptom))
+ var/datum/symptom/S = symptom
+ if(initial(S.level) > max_level)
+ continue
+ if(initial(S.level) <= 0) //unobtainable symptoms
+ continue
+ possible_symptoms += S
+ for(var/i in 1 to max_symptoms)
+ var/datum/symptom/chosen_symptom = pick_n_take(possible_symptoms)
+ if(chosen_symptom)
+ var/datum/symptom/S = new chosen_symptom
+ A.symptoms += S
+ A.Refresh() //just in case someone already made and named the same disease
+ return A
-/obj/item/organ/heart/gland/emp //TODO : Replace with something more interesting
- cooldown_low = 900
- cooldown_high = 1600
- uses = 10
+/obj/item/organ/heart/gland/trauma //TODO : Replace with something more interesting
+ cooldown_low = 800
+ cooldown_high = 1200
+ uses = 5
icon_state = "emp"
- mind_control_uses = 1
+ mind_control_uses = 3
mind_control_duration = 1800
-/obj/item/organ/heart/gland/emp/activate()
+/obj/item/organ/heart/gland/trauma/activate()
to_chat(owner, "You feel a spike of pain in your head.")
- empulse(get_turf(owner), 2, 5, 1)
+ if(prob(33))
+ owner.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, TRUE)
+ else
+ if(prob(20))
+ owner.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRUE)
+ else
+ owner.gain_trauma_type(BRAIN_TRAUMA_MILD, TRUE)
/obj/item/organ/heart/gland/spiderman
cooldown_low = 450
cooldown_high = 900
- uses = 10
+ uses = -1
icon_state = "spider"
mind_control_uses = 2
mind_control_duration = 2400
@@ -211,7 +248,8 @@
/obj/item/organ/heart/gland/spiderman/activate()
to_chat(owner, "You feel something crawling in your skin.")
owner.faction |= "spiders"
- new /obj/structure/spider/spiderling(owner.loc)
+ var/obj/structure/spider/spiderling/S = new(owner.drop_location())
+ S.directive = "Protect your nest inside [owner.real_name]."
/obj/item/organ/heart/gland/egg
cooldown_low = 300
@@ -225,71 +263,60 @@
/obj/item/organ/heart/gland/egg/activate()
to_chat(owner, "You lay an egg!")
- var/obj/item/reagent_containers/food/snacks/egg/egg = new(owner.loc)
+ var/obj/item/reagent_containers/food/snacks/egg/egg = new(owner.drop_location())
egg.reagents.add_reagent("sacid",20)
egg.desc += " It smells bad."
-/obj/item/organ/heart/gland/bloody
- cooldown_low = 200
- cooldown_high = 400
+/obj/item/organ/heart/gland/electric
+ cooldown_low = 800
+ cooldown_high = 1200
uses = -1
- mind_control_uses = 1
- mind_control_duration = 450
+ mind_control_uses = 2
+ mind_control_duration = 900
-/obj/item/organ/heart/gland/bloody/activate()
- owner.blood_volume -= 20
- owner.visible_message("[owner]'s skin erupts with blood!",\
- "Blood pours from your skin!")
+/obj/item/organ/heart/gland/electric/Insert(mob/living/carbon/M, special = 0)
+ ..()
+ owner.add_trait(TRAIT_SHOCKIMMUNE, "abductor_gland")
- for(var/turf/T in oview(3,owner)) //Make this respect walls and such
- owner.add_splatter_floor(T)
- for(var/mob/living/carbon/human/H in oview(3,owner)) //Blood decals for simple animals would be neat. aka Carp with blood on it.
- H.add_mob_blood(owner)
+/obj/item/organ/heart/gland/electric/Remove(mob/living/carbon/M, special = 0)
+ owner.remove_trait(TRAIT_SHOCKIMMUNE, "abductor_gland")
+ ..()
+/obj/item/organ/heart/gland/electric/activate()
+ owner.visible_message("[owner]'s skin starts emitting electric arcs!",\
+ "You feel electric energy building up inside you!")
+ playsound(get_turf(owner), "sparks", 100, 1, -1)
+ addtimer(CALLBACK(src, .proc/zap), rand(30, 100))
-/obj/item/organ/heart/gland/bodysnatch
- cooldown_low = 600
- cooldown_high = 600
- human_only = 1
- uses = 1
- mind_control_uses = 1
- mind_control_duration = 600
+/obj/item/organ/heart/gland/electric/proc/zap()
+ tesla_zap(owner, 4, 8000, FALSE, TRUE)
+ playsound(get_turf(owner), 'sound/magic/lightningshock.ogg', 50, 1)
-/obj/item/organ/heart/gland/bodysnatch/activate()
- to_chat(owner, "You feel something moving around inside you...")
- //spawn cocoon with clone greytide snpc inside
- if(ishuman(owner))
- var/obj/structure/spider/cocoon/abductor/C = new (get_turf(owner))
- C.Copy(owner)
- C.Start()
- owner.adjustBruteLoss(40)
- owner.add_splatter_floor()
+/obj/item/organ/heart/gland/chem
+ cooldown_low = 50
+ cooldown_high = 50
+ uses = -1
+ mind_control_uses = 3
+ mind_control_duration = 1200
+ var/list/possible_reagents = list()
-/obj/structure/spider/cocoon/abductor
- name = "slimy cocoon"
- desc = "Something is moving inside."
- icon = 'icons/effects/effects.dmi'
- icon_state = "cocoon_large3"
- color = rgb(10,120,10)
- density = TRUE
- var/hatch_time = 0
-
-/obj/structure/spider/cocoon/abductor/proc/Copy(mob/living/carbon/human/H)
- var/mob/living/carbon/human/interactive/greytide/clone = new(src)
- clone.hardset_dna(H.dna.uni_identity,H.dna.struc_enzymes,H.real_name, H.dna.blood_type, H.dna.species, H.dna.features)
-
-/obj/structure/spider/cocoon/abductor/proc/Start()
- hatch_time = world.time + 600
- START_PROCESSING(SSobj, src)
-
-/obj/structure/spider/cocoon/abductor/process()
- if(world.time > hatch_time)
- STOP_PROCESSING(SSobj, src)
- for(var/mob/M in contents)
- src.visible_message("[src] hatches!")
- M.forceMove(drop_location())
- qdel(src)
+/obj/item/organ/heart/gland/chem/Initialize()
+ ..()
+ for(var/X in subtypesof(/datum/reagent/drug))
+ var/datum/reagent/R = X
+ possible_reagents += initial(R.id)
+ for(var/X in subtypesof(/datum/reagent/medicine))
+ var/datum/reagent/R = X
+ possible_reagents += initial(R.id)
+ for(var/X in typesof(/datum/reagent/toxin))
+ var/datum/reagent/R = X
+ possible_reagents += initial(R.id)
+/obj/item/organ/heart/gland/chem/activate()
+ var/chem_to_add = pick(possible_reagents)
+ owner.reagents.add_reagent(chem_to_add, 2)
+ owner.adjustToxLoss(-2, TRUE, TRUE)
+ ..()
/obj/item/organ/heart/gland/plasma
cooldown_low = 1200
diff --git a/code/modules/antagonists/changeling/powers/hivemind.dm b/code/modules/antagonists/changeling/powers/hivemind.dm
index 0e9763d2a3..c84adc6e8f 100644
--- a/code/modules/antagonists/changeling/powers/hivemind.dm
+++ b/code/modules/antagonists/changeling/powers/hivemind.dm
@@ -27,7 +27,10 @@ GLOBAL_LIST_EMPTY(hivemind_bank)
chemical_cost = 10
dna_cost = -1
-/obj/effect/proc_holder/changeling/hivemind_upload/sting_action(var/mob/user)
+/obj/effect/proc_holder/changeling/hivemind_upload/sting_action(var/mob/living/user)
+ if (user.has_trait(CHANGELING_HIVEMIND_MUTE))
+ to_chat(user, "The poison in the air hinders our ability to interact with the hivemind.")
+ return
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/list/names = list()
for(var/datum/changelingprofile/prof in changeling.stored_profiles)
@@ -61,6 +64,9 @@ GLOBAL_LIST_EMPTY(hivemind_bank)
/obj/effect/proc_holder/changeling/hivemind_download/can_sting(mob/living/carbon/user)
if(!..())
return
+ if (user.has_trait(CHANGELING_HIVEMIND_MUTE))
+ to_chat(user, "The poison in the air hinders our ability to interact with the hivemind.")
+ return
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
var/datum/changelingprofile/first_prof = changeling.stored_profiles[1]
if(first_prof.name == user.real_name)//If our current DNA is the stalest, we gotta ditch it.
diff --git a/code/modules/antagonists/clockcult/clock_effect.dm b/code/modules/antagonists/clockcult/clock_effect.dm
index 10abf4e68b..b9de95b030 100644
--- a/code/modules/antagonists/clockcult/clock_effect.dm
+++ b/code/modules/antagonists/clockcult/clock_effect.dm
@@ -8,7 +8,7 @@
anchored = TRUE
density = FALSE
opacity = 0
- resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
/obj/effect/clockwork/Initialize()
. = ..()
diff --git a/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm b/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm
index ee49c0e2c1..86ca217dda 100644
--- a/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm
@@ -39,3 +39,6 @@
/obj/effect/clockwork/servant_blocker/singularity_pull()
return
+
+/obj/effect/clockwork/servant_blocker/ex_act(severity, target)
+ return
diff --git a/code/modules/antagonists/clockcult/clock_helpers/power_helpers.dm b/code/modules/antagonists/clockcult/clock_helpers/power_helpers.dm
index c2479460c7..37f09b405f 100644
--- a/code/modules/antagonists/clockcult/clock_helpers/power_helpers.dm
+++ b/code/modules/antagonists/clockcult/clock_helpers/power_helpers.dm
@@ -7,6 +7,7 @@
if(GLOB.ratvar_approaches)
amount *= 0.75 //The herald's beacon reduces power costs by 25% across the board!
GLOB.clockwork_power = GLOB.ratvar_awakens ? INFINITY : max(0, GLOB.clockwork_power + amount)
+ GLOB.clockwork_power = CLAMP(GLOB.clockwork_power, 0, MAX_CLOCKWORK_POWER)
for(var/obj/effect/clockwork/sigil/transmission/T in GLOB.all_clockwork_objects)
T.update_icon()
var/power_overwhelming = GLOB.clockwork_power
diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
index 0111567122..d0553e263b 100644
--- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
+++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
@@ -43,8 +43,7 @@
/obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and fabricator
clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture."
- quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \
- /datum/clockwork_scripture/create_object/stargazer)
+ quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard)
maximum_quickbound = 6 //we usually have one or two unique scriptures, so if ratvar is up let us bind one more
actions_types = list()
@@ -63,10 +62,10 @@
/obj/item/clockwork/slab/cyborg/janitor //five scriptures, plus a fabricator
quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/sigil_of_transgression, \
- /datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/mania_motor, /datum/clockwork_scripture/create_object/stargazer)
+ /datum/clockwork_scripture/create_object/ocular_warden, /datum/clockwork_scripture/create_object/mania_motor)
/obj/item/clockwork/slab/cyborg/service //five scriptures, plus xray vision
- quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, /datum/clockwork_scripture/create_object/stargazer, \
+ quickbound = list(/datum/clockwork_scripture/abscond, /datum/clockwork_scripture/create_object/replicant, \
/datum/clockwork_scripture/spatial_gateway, /datum/clockwork_scripture/create_object/clockwork_obelisk)
/obj/item/clockwork/slab/cyborg/miner //two scriptures, plus a spear and xray vision
@@ -425,7 +424,8 @@
data["scripturecolors"] = "Scriptures in yellow are related to construction and building.
\
Scriptures in red are related to attacking and offense.
\
Scriptures in blue are related to healing and defense.
\
- Scriptures in purple are niche but still important!"
+ Scriptures in purple are niche but still important!
\
+ Scriptures with italicized names are important to success."
generate_all_scripture()
data["scripture"] = list()
@@ -439,6 +439,8 @@
"required" = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])",
"type" = "[S.type]",
"quickbind" = S.quickbind)
+ if(S.important)
+ temp_info["name"] = "[temp_info["name"]]"
var/found = quickbound.Find(S.type)
if(found)
temp_info["bound"] = "[found]"
diff --git a/code/modules/antagonists/clockcult/clock_items/integration_cog.dm b/code/modules/antagonists/clockcult/clock_items/integration_cog.dm
index 866458b4f6..41473270d3 100644
--- a/code/modules/antagonists/clockcult/clock_items/integration_cog.dm
+++ b/code/modules/antagonists/clockcult/clock_items/integration_cog.dm
@@ -30,6 +30,6 @@
var/obj/item/stock_parts/cell/cell = apc.cell
if(cell && (cell.charge / cell.maxcharge > COG_MAX_SIPHON_THRESHOLD))
cell.use(1)
- adjust_clockwork_power(1) //Power is shared, so only do it once; this runs very quickly so it's about 1W/second
+ adjust_clockwork_power( ) //Power is shared, so only do it once; this runs very quickly so it's about 5 W/second
#undef COG_MAX_SIPHON_THRESHOLD
diff --git a/code/modules/antagonists/clockcult/clock_scripture.dm b/code/modules/antagonists/clockcult/clock_scripture.dm
index 046196f03a..67a8ba1ca3 100644
--- a/code/modules/antagonists/clockcult/clock_scripture.dm
+++ b/code/modules/antagonists/clockcult/clock_scripture.dm
@@ -28,6 +28,7 @@ Applications: 8 servants, 3 caches, and 100 CV
var/quickbind = FALSE //if this scripture can be quickbound to a clockwork slab
var/quickbind_desc = "This shouldn't be quickbindable. File a bug report!"
var/primary_component
+ var/important = FALSE //important scripture will be italicized in the slab's interface
var/sort_priority = 1 //what position the scripture should have in a list of scripture. Should be based off of component costs/reqs, but you can't initial() lists.
//messages for offstation scripture recital, courtesy ratvar's generals(and neovgre)
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm
index c06bb5395e..89b533f079 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_applications.dm
@@ -5,7 +5,7 @@
//Sigil of Transmission: Creates a sigil of transmission that can drain and store power for clockwork structures.
/datum/clockwork_scripture/create_object/sigil_of_transmission
- descname = "Powers Nearby Structures - Important!"
+ descname = "Powers Nearby Structures"
name = "Sigil of Transmission"
desc = "Places a sigil that can drain and will store energy to power clockwork structures."
invocations = list("Divinity...", "...power our creations!")
@@ -19,6 +19,7 @@
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 1
+ important = TRUE
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Transmission, which can drain and will store power for clockwork structures."
@@ -98,7 +99,7 @@
if(ishuman(L) && L.stat != DEAD)
human_servants++
construct_limit = human_servants / 4 //1 per 4 human servants, and a maximum of 3 marauders
- construct_limit = CLAMP(construct_limit - recent_marauders, 1, 3)
+ construct_limit = CLAMP(construct_limit - recent_marauders, 1, 3)
if(recent_marauders)
to_chat(invoker, "The Hierophant Network needs [MARAUDER_SCRIPTURE_SCALING_THRESHOLD / 10] seconds to recover from marauder summoning; recent summoning has limited the number of available marauders by [recent_marauders]!")
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
index 7e05e6a187..28ce2ccf60 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
@@ -3,36 +3,9 @@
/////////////
-//Stargazer: Creates a stargazer, a cheap power generator that utilizes starlight.
-/datum/clockwork_scripture/create_object/stargazer
- descname = "Generates Power From Starlight - Important!"
- name = "Stargazer"
- desc = "Forms a weak structure that generates power every second while within three tiles of starlight."
- invocations = list("Capture their inferior light for us!")
- channel_time = 50
- power_cost = 50
- object_path = /obj/structure/destructible/clockwork/stargazer
- creator_message = "You form a stargazer, which will generate power near starlight."
- observer_message = "A large lantern-shaped machine forms!"
- usage_tip = "For obvious reasons, make sure to place this near a window or somewhere else that can see space!"
- tier = SCRIPTURE_DRIVER
- one_per_tile = TRUE
- primary_component = HIEROPHANT_ANSIBLE
- sort_priority = 1
- quickbind = TRUE
- quickbind_desc = "Creates a stargazer, which generates power when near starlight."
-
-/datum/clockwork_scripture/create_object/stargazer/check_special_requirements()
- var/area/A = get_area(invoker)
- if(A.outdoors || A.map_name == "Space" || !A.blob_allowed)
- to_chat(invoker, "Stargazers can't be built off-station.")
- return
- return ..()
-
-
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
/datum/clockwork_scripture/create_object/integration_cog
- descname = "APC Power Siphoner"
+ descname = "Power Generation"
name = "Integration Cog"
desc = "Fabricates an integration cog, which can be used on an open APC to replace its innards and passively siphon its power."
invocations = list("Take that which sustains them!")
@@ -41,11 +14,12 @@
whispered = TRUE
object_path = /obj/item/clockwork/integration_cog
creator_message = "You form an integration cog, which can be inserted into an open APC to passively siphon power."
- usage_tip = "Tampering isn't visible unless the APC is opened."
+ usage_tip = "Tampering isn't visible unless the APC is opened. You can use the cog on a locked APC to unlock it."
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = HIEROPHANT_ANSIBLE
- sort_priority = 2
+ sort_priority = 1
+ important = TRUE
quickbind = TRUE
quickbind_desc = "Creates an integration cog, which can be used to siphon power from an open APC."
@@ -65,7 +39,7 @@
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
- sort_priority = 3
+ sort_priority = 2
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Transgression, which will briefly stun and slow the next non-Servant to cross it."
@@ -85,7 +59,7 @@
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
primary_component = HIEROPHANT_ANSIBLE
- sort_priority = 4
+ sort_priority = 3
quickbind = TRUE
quickbind_desc = "Creates a Sigil of Submission, which will convert non-Servants that remain on it."
@@ -102,13 +76,14 @@
usage_tip = "The light can be used from up to two tiles away. Damage taken will GREATLY REDUCE the stun's duration."
tier = SCRIPTURE_DRIVER
primary_component = BELLIGERENT_EYE
- sort_priority = 5
+ sort_priority = 4
slab_overlay = "volt"
ranged_type = /obj/effect/proc_holder/slab/kindle
ranged_message = "You charge the clockwork slab with divine energy.\n\
Left-click a target within melee range to stun!\n\
Click your slab to cancel."
timeout_time = 150
+ important = TRUE
quickbind = TRUE
quickbind_desc = "Stuns and mutes a target from a short range."
@@ -125,13 +100,14 @@
usage_tip = "The manacles are about as strong as zipties, and break when removed."
tier = SCRIPTURE_DRIVER
primary_component = BELLIGERENT_EYE
- sort_priority = 6
+ sort_priority = 5
ranged_type = /obj/effect/proc_holder/slab/hateful_manacles
slab_overlay = "hateful_manacles"
ranged_message = "You charge the clockwork slab with divine energy.\n\
Left-click a target within melee range to shackle!\n\
Click your slab to cancel."
timeout_time = 200
+ important = TRUE
quickbind = TRUE
quickbind_desc = "Applies handcuffs to a struck target."
@@ -148,7 +124,7 @@
usage_tip = "You cannot reactivate Vanguard while still shielded by it."
tier = SCRIPTURE_DRIVER
primary_component = VANGUARD_COGWHEEL
- sort_priority = 7
+ sort_priority = 6
quickbind = TRUE
quickbind_desc = "Allows you to temporarily absorb stuns. All stuns absorbed will affect you when disabled."
@@ -180,7 +156,7 @@
usage_tip = "The Compromise is very fast to invoke, and will remove holy water from the target Servant."
tier = SCRIPTURE_DRIVER
primary_component = VANGUARD_COGWHEEL
- sort_priority = 8
+ sort_priority = 7
quickbind = TRUE
quickbind_desc = "Allows you to convert a Servant's brute, burn, and oxygen damage to half toxin damage.
Click your slab to disable."
slab_overlay = "compromise"
@@ -192,7 +168,7 @@
//Abscond: Used to return to Reebe.
/datum/clockwork_scripture/abscond
- descname = "Return to Reebe - Important!"
+ descname = "Return to Reebe"
name = "Abscond"
desc = "Yanks you through space, returning you to home base."
invocations = list("As we bid farewell, and return to the stars...", "...we shall find our way home.")
@@ -204,7 +180,8 @@
usage_tip = "This can't be used while on Reebe, for obvious reasons."
tier = SCRIPTURE_DRIVER
primary_component = GEIS_CAPACITOR
- sort_priority = 9
+ sort_priority = 8
+ important = TRUE
quickbind = TRUE
quickbind_desc = "Returns you to Reebe."
@@ -246,7 +223,7 @@
//Replicant: Creates a new clockwork slab.
/datum/clockwork_scripture/create_object/replicant
- descname = "New Clockwork Slab - Important!"
+ descname = "New Clockwork Slab"
name = "Replicant"
desc = "Creates a new clockwork slab."
invocations = list("Metal, become greater!")
@@ -259,7 +236,8 @@
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = GEIS_CAPACITOR
- sort_priority = 10
+ sort_priority = 9
+ important = TRUE
quickbind = TRUE
quickbind_desc = "Creates a new Clockwork Slab."
@@ -279,6 +257,6 @@
tier = SCRIPTURE_DRIVER
space_allowed = TRUE
primary_component = GEIS_CAPACITOR
- sort_priority = 11
+ sort_priority = 10
quickbind = TRUE
quickbind_desc = "Creates a pair of Wraith Spectacles, which grant true sight but cause gradual vision loss."
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
index c86ff59b5f..9a78c64942 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
@@ -5,7 +5,7 @@
//Replica Fabricator: Creates a replica fabricator, used to convert objects and repair clockwork structures.
/datum/clockwork_scripture/create_object/replica_fabricator
- descname = "Creates Brass and Converts Objects - Important!"
+ descname = "Creates Brass and Converts Objects"
name = "Replica Fabricator"
desc = "Forms a device that, when used on certain objects, replaces them with their Ratvarian equivalents. It requires power to function."
invocations = list("With this device...", "...his presence shall be made known.")
@@ -19,6 +19,7 @@
space_allowed = TRUE
primary_component = HIEROPHANT_ANSIBLE
sort_priority = 1
+ important = TRUE
quickbind = TRUE
quickbind_desc = "Creates a Replica Fabricator, which can convert various objects to Ratvarian variants."
@@ -99,7 +100,7 @@
//Clockwork Armaments: Grants the invoker the ability to call forth a Ratvarian spear and clockwork armor.
/datum/clockwork_scripture/clockwork_armaments
- descname = "Summonable Armor and Weapons - Important!"
+ descname = "Summonable Armor and Weapons"
name = "Clockwork Armaments"
desc = "Allows the invoker to summon clockwork armor and a Ratvarian spear at will. The spear's attacks will generate Vitality, used for healing."
invocations = list("Grant me armaments...", "...from the forge of Armorer!")
@@ -110,6 +111,7 @@
tier = SCRIPTURE_SCRIPT
primary_component = VANGUARD_COGWHEEL
sort_priority = 5
+ important = TRUE
quickbind = TRUE
quickbind_desc = "Permanently binds clockwork armor and a Ratvarian spear to you."
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index 3b9fa7b8c4..1c90834cbd 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -6,6 +6,7 @@
antagpanel_category = "Cult"
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
+ var/datum/action/innate/cult/blood_magic/magic = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
var/give_equipment = FALSE
@@ -58,7 +59,7 @@
var/mob/living/current = owner.current
add_objectives()
if(give_equipment)
- equip_cultist()
+ equip_cultist(TRUE)
SSticker.mode.cult += owner // Only add after they've been given objectives
SSticker.mode.update_cult_icons_added(owner)
current.log_message("Has been converted to the cult of Nar'Sie!", INDIVIDUAL_ATTACK_LOG)
@@ -67,18 +68,16 @@
current.client.images += cult_team.blood_target_image
-/datum/antagonist/cult/proc/equip_cultist(tome=FALSE)
+/datum/antagonist/cult/proc/equip_cultist(metal=TRUE)
var/mob/living/carbon/H = owner.current
if(!istype(H))
return
if (owner.assigned_role == "Clown")
to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
-
- if(tome)
- . += cult_give_item(/obj/item/tome, H)
- else
- . += cult_give_item(/obj/item/paper/talisman/supply, H)
+ . += cult_give_item(/obj/item/melee/cultblade/dagger, H)
+ if(metal)
+ . += cult_give_item(/obj/item/stack/sheet/runed_metal/ten, H)
to_chat(owner, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.")
@@ -110,10 +109,11 @@
current = mob_override
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
- current.verbs += /mob/living/proc/cult_help
- if(!cult_team.cult_mastered)
+ if(!cult_team.cult_master)
vote.Grant(current)
communion.Grant(current)
+ if(ishuman(current))
+ magic.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
/datum/antagonist/cult/remove_innate_effects(mob/living/mob_override)
@@ -123,9 +123,9 @@
current = mob_override
current.faction -= "cult"
current.remove_language(/datum/language/narsie)
- current.verbs -= /mob/living/proc/cult_help
vote.Remove(current)
communion.Remove(current)
+ magic.Remove(current)
current.clear_alert("bloodsense")
/datum/antagonist/cult/on_removal()
@@ -153,16 +153,16 @@
/datum/antagonist/cult/get_admin_commands()
. = ..()
- .["Tome"] = CALLBACK(src,.proc/admin_give_tome)
- .["Amulet"] = CALLBACK(src,.proc/admin_give_amulet)
+ .["Dagger"] = CALLBACK(src,.proc/admin_give_dagger)
+ .["Dagger and Metal"] = CALLBACK(src,.proc/admin_give_metal)
-/datum/antagonist/cult/proc/admin_give_tome(mob/admin)
- if(equip_cultist(owner.current,1))
- to_chat(admin, "Spawning tome failed!")
+/datum/antagonist/cult/proc/admin_give_dagger(mob/admin)
+ if(!equip_cultist(FALSE))
+ to_chat(admin, "Spawning dagger failed!")
-/datum/antagonist/cult/proc/admin_give_amulet(mob/admin)
- if (equip_cultist(owner.current))
- to_chat(admin, "Spawning amulet failed!")
+/datum/antagonist/cult/proc/admin_give_metal(mob/admin)
+ if (!equip_cultist(TRUE))
+ to_chat(admin, "Spawning runed metal failed!")
/datum/antagonist/cult/master
ignore_implant = TRUE
@@ -218,7 +218,7 @@
var/blood_target_reset_timer
var/cult_vote_called = FALSE
- var/cult_mastered = FALSE
+ var/mob/living/cult_master
var/reckoning_complete = FALSE
@@ -326,4 +326,4 @@
return "
" + dat += "Are you absolutely sure you want to proceed? EldritchRelics Inc. takes no responsibilities for loss of sanity resulting from this action.
"
dat += "Yes.
"
dat += "No.
"
@@ -322,11 +322,11 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
var/spook = pick("blood", "brass")
var/turf/T = get_turf(src)
if(spook == "blood")
- new /obj/item/tome(T)
+ new /obj/item/melee/cultblade/dagger(T)
else
new /obj/item/clockwork/slab(T)
- to_chat(user, "Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a [spook == "blood" ? "dusty old tome" : "strange metal tablet"] sitting on the desk. You don't really remember printing it.[spook == "brass" ? " And how did it print something made of metal?" : ""]")
+ to_chat(user, "Your sanity barely endures the seconds spent in the vault's browsing window. The only thing to remind you of this when you stop browsing is a [spook == "blood" ? "sinister dagger" : "strange metal tablet"] sitting on the desk. You don't even remember where it came from...")
user.visible_message("[user] stares at the blank screen for a few moments, [user.p_their()] expression frozen in fear. When [user.p_they()] finally awaken[user.p_s()] from it, [user.p_they()] look[user.p_s()] a lot older.", 2)
/obj/machinery/computer/libraryconsole/bookmanagement/attackby(obj/item/W, mob/user, params)
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index 7178ab3314..842373dbad 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -4,8 +4,8 @@
/obj/effect/baseturf_helper //Set the baseturfs of every turf in the /area/ it is placed.
name = "baseturf editor"
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "syndballoon"
+ icon = 'icons/effects/mapping_helpers.dmi'
+ icon_state = ""
var/baseturf = null
layer = POINT_LAYER
@@ -72,7 +72,7 @@
return ..()
whitelist = typecacheof(whitelist)
return ..()
-
+
/obj/effect/baseturf_helper/picky/replace_baseturf(turf/thing)
if(!whitelist[thing.type])
return
@@ -86,18 +86,35 @@
name = "picky lavaland basalt baseturf helper"
baseturf = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
+
+/obj/effect/mapping_helpers
+ icon = 'icons/effects/mapping_helpers.dmi'
+ icon_state = ""
+
+/obj/effect/mapping_helpers/Initialize()
+ ..()
+ return INITIALIZE_HINT_QDEL
+
+//needs to do its thing before spawn_rivers() is called
+INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
+
+/obj/effect/mapping_helpers/no_lava
+ icon_state = "no_lava"
+
+/obj/effect/mapping_helpers/no_lava/Initialize()
+ . = ..()
+ var/turf/T = get_turf(src)
+ T.flags_1 |= NO_LAVA_GEN_1
+
//Contains the list of planetary z-levels defined by the planet_z helper.
GLOBAL_LIST_EMPTY(z_is_planet)
/obj/effect/mapping_helpers/planet_z //adds the map it is on to the z_is_planet list
name = "planet z helper"
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "syndballoon"
layer = POINT_LAYER
/obj/effect/mapping_helpers/planet_z/Initialize()
. = ..()
var/turf/T = get_turf(src)
GLOB.z_is_planet["[T.z]"] = TRUE
- return INITIALIZE_HINT_QDEL
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 0e20420e2a..2ef83c54b7 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -910,7 +910,18 @@
if(used)
return
used = TRUE
- var/choice = input(user,"Who do you want dead?","Choose Your Victim") as null|anything in GLOB.player_list
+
+ var/list/da_list = list()
+ for(var/I in GLOB.alive_mob_list & GLOB.player_list)
+ var/mob/living/L = I
+ da_list[L.real_name] = L
+
+ var/choice = input(user,"Who do you want dead?","Choose Your Victim") as null|anything in da_list
+
+ choice = da_list[choice]
+
+ if(!choice)
+ return
if(!(isliving(choice)))
to_chat(user, "[choice] is already dead!")
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index c872756872..71574104c6 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -55,7 +55,7 @@
new /datum/data/mining_equipment("Drone Melee Upgrade", /obj/item/device/mine_bot_ugprade, 400),
new /datum/data/mining_equipment("Drone Health Upgrade", /obj/item/device/mine_bot_ugprade/health, 400),
new /datum/data/mining_equipment("Drone Ranged Upgrade", /obj/item/device/mine_bot_ugprade/cooldown, 600),
- new /datum/data/mining_equipment("Drone AI Upgrade", /obj/item/slimepotion/sentience/mining, 1000),
+ new /datum/data/mining_equipment("Drone AI Upgrade", /obj/item/slimepotion/slime/sentience/mining, 1000),
new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 2500),
)
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 7caf57b0a6..3c33441561 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -255,7 +255,7 @@
//AI
-/obj/item/slimepotion/sentience/mining
+/obj/item/slimepotion/slime/sentience/mining
name = "minebot AI upgrade"
desc = "Can be used to grant sentience to minebots."
icon_state = "door_electronics"
diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm
index 5d51024adc..8f831d3f9d 100644
--- a/code/modules/mob/living/brain/MMI.dm
+++ b/code/modules/mob/living/brain/MMI.dm
@@ -2,7 +2,7 @@
name = "Man-Machine Interface"
desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity, that nevertheless has become standard-issue on Nanotrasen stations."
icon = 'icons/obj/assemblies.dmi'
- icon_state = "mmi_empty"
+ icon_state = "mmi_off"
w_class = WEIGHT_CLASS_NORMAL
var/braintype = "Cyborg"
var/obj/item/device/radio/radio = null //Let's give it a radio.
@@ -15,21 +15,19 @@
var/overrides_aicore_laws = FALSE // Whether the laws on the MMI, if any, override possible pre-existing laws loaded on the AI core.
/obj/item/device/mmi/update_icon()
- if(brain)
- if(istype(brain, /obj/item/organ/brain/alien))
- if(brainmob && brainmob.stat == DEAD)
- icon_state = "mmi_alien_dead"
- else
- icon_state = "mmi_alien"
- braintype = "Xenoborg" //HISS....Beep.
- else
- if(brainmob && brainmob.stat == DEAD)
- icon_state = "mmi_dead"
- else
- icon_state = "mmi_full"
- braintype = "Cyborg"
+ if(!brain)
+ icon_state = "mmi_off"
+ return
+ if(istype(brain, /obj/item/organ/brain/alien))
+ icon_state = "mmi_brain_alien"
+ braintype = "Xenoborg" //HISS....Beep.
else
- icon_state = "mmi_empty"
+ icon_state = "mmi_brain"
+ braintype = "Cyborg"
+ if(brainmob && brainmob.stat != DEAD)
+ add_overlay("mmi_alive")
+ else
+ add_overlay("mmi_dead")
/obj/item/device/mmi/Initialize()
. = ..()
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 277305343f..81f64d1d26 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -213,6 +213,8 @@
/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
if(tesla_shock && (flags_2 & TESLA_IGNORE_2))
return FALSE
+ if(has_trait(TRAIT_SHOCKIMMUNE))
+ return FALSE
shock_damage *= siemens_coeff
if(dna && dna.species)
shock_damage *= dna.species.siemens_coeff
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 3d76f28750..38f692bdb1 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -121,13 +121,13 @@
var/datum/action/innate/swap_body/swap_body
/datum/species/jelly/slime/on_species_loss(mob/living/carbon/C)
- if(slime_split)
+/* if(slime_split)
slime_split.Remove(C)
if(swap_body)
swap_body.Remove(C)
bodies -= C // This means that the other bodies maintain a link
// so if someone mindswapped into them, they'd still be shared.
- bodies = null
+ bodies = null */
C.blood_volume = min(C.blood_volume, BLOOD_VOLUME_NORMAL)
..()
@@ -146,26 +146,28 @@
/datum/species/jelly/slime/spec_death(gibbed, mob/living/carbon/human/H)
if(slime_split)
- var/datum/mind/M
- for(var/mob/living/L in bodies)
- if(L.mind && L.mind.active)
- M = L.mind
- if(!M || M != H.mind)
+ if(!H.mind || !H.mind.active)
return
+
var/list/available_bodies = (bodies - H)
+ for(var/mob/living/L in available_bodies)
+ if(!swap_body.can_swap(L))
+ available_bodies -= L
+
if(!LAZYLEN(available_bodies))
return
- swap_body.swap_to_dupe(M, pick(available_bodies))
+
+ swap_body.swap_to_dupe(H.mind, pick(available_bodies))
//If you're cloned you get your body pool back
/datum/species/jelly/slime/copy_properties_from(datum/species/jelly/slime/old_species)
bodies = old_species.bodies
/datum/species/jelly/slime/spec_life(mob/living/carbon/human/H)
-/* if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
+ if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
if(prob(5))
- to_chat(H, "You feel very bloated!")*/
- if(H.nutrition >= NUTRITION_LEVEL_WELL_FED)
+ to_chat(H, "You feel very bloated!")
+ else if(H.nutrition >= NUTRITION_LEVEL_WELL_FED)
H.blood_volume += 3
H.nutrition -= 2.5
@@ -222,7 +224,7 @@
spare.domutcheck()
spare.Move(get_step(H.loc, pick(NORTH,SOUTH,EAST,WEST)))
- H.blood_volume = BLOOD_VOLUME_SAFE
+ H.blood_volume *= 0.45
H.notransform = 0
var/datum/species/jelly/slime/origin_datum = H.dna.species
@@ -286,24 +288,31 @@
stat = "Unconscious"
if(DEAD)
stat = "Dead"
- var/current = body.mind
- var/is_conscious = (body.stat == CONSCIOUS)
+ var/occupied
+ if(body == H)
+ occupied = "owner"
+ else if(body.mind && body.mind.active)
+ occupied = "stranger"
+ else
+ occupied = "available"
L["status"] = stat
L["exoticblood"] = body.blood_volume
L["name"] = body.name
L["ref"] = "[REF(body)]"
- L["is_current"] = current
+ L["occupied"] = occupied
var/button
- if(current)
+ if(occupied == "owner")
button = "selected"
- else if(is_conscious)
+ else if(occupied == "stranger")
+ button = "danger"
+ else if(can_swap(body))
button = null
else
button = "disabled"
L["swap_button_state"] = button
- L["swappable"] = !current && is_conscious
+ L["swappable"] = (occupied == "available") && can_swap(body)
data["bodies"] += list(L)
@@ -315,32 +324,47 @@
var/mob/living/carbon/human/H = owner
if(!isslimeperson(owner))
return
- var/datum/species/jelly/slime/SS = H.dna.species
-
- var/datum/mind/M
- for(var/mob/living/L in SS.bodies)
- if(L.mind && L.mind.active)
- M = L.mind
- if(!M)
+ if(!H.mind || !H.mind.active)
return
- if(!isslimeperson(M.current))
- return
-
switch(action)
if("swap")
var/mob/living/carbon/human/selected = locate(params["ref"])
- if(!(selected in SS.bodies))
+ if(!can_swap(selected))
return
- if(!selected || QDELETED(selected) || !isslimeperson(selected))
- SS.bodies -= selected
- return
- if(M.current == selected)
- return
- if(selected.stat != CONSCIOUS)
- return
- swap_to_dupe(M, selected)
+ SStgui.close_uis(src)
+ swap_to_dupe(H.mind, selected)
+
+/datum/action/innate/swap_body/proc/can_swap(mob/living/carbon/human/dupe)
+ var/mob/living/carbon/human/H = owner
+ if(!isslimeperson(H))
+ return FALSE
+ var/datum/species/jelly/slime/SS = H.dna.species
+
+ if(QDELETED(dupe)) //Is there a body?
+ SS.bodies -= dupe
+ return FALSE
+
+ if(!isslimeperson(dupe)) //Is it a slimeperson?
+ SS.bodies -= dupe
+ return FALSE
+
+ if(dupe.stat == DEAD) //Is it alive?
+ return FALSE
+
+ if(dupe.stat != CONSCIOUS) //Is it awake?
+ return FALSE
+
+ if(dupe.mind && dupe.mind.active) //Is it unoccupied?
+ return FALSE
+
+ if(!(dupe in SS.bodies)) //Do we actually own it?
+ return FALSE
+
+ return TRUE
/datum/action/innate/swap_body/proc/swap_to_dupe(datum/mind/M, mob/living/carbon/human/dupe)
+ if(!can_swap(dupe)) //sanity check
+ return
if(M.current.stat == CONSCIOUS)
M.current.visible_message("[M.current] \
stops moving and starts staring vacantly into space.",
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index c4f85501d0..a5c6720db5 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -17,8 +17,8 @@
speedmod = 1
damage_overlay_type = ""//let's not show bloody wounds or burns over bones.
var/internal_fire = FALSE //If the bones themselves are burning clothes won't help you much
- disliked_food = NONE
- liked_food = NONE
+ disliked_food = FRUIT
+ liked_food = VEGETABLES
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H)
var/datum/gas_mixture/environment = H.loc.return_air()
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index 6bd77b908c..f3360e47fb 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -8,12 +8,10 @@
attack_sound = 'sound/weapons/slice.ogg'
miss_sound = 'sound/weapons/slashmiss.ogg'
burnmod = 1.25
- heatmod = 1.55
+ heatmod = 1.5
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/plant
- disliked_food = NONE
- liked_food = NONE
- toxic_food = NONE
-
+ disliked_food = MEAT | DAIRY
+ liked_food = VEGETABLES | FRUIT | GRAIN
/datum/species/pod/on_species_gain(mob/living/carbon/C, datum/species/old_species)
. = ..()
@@ -36,21 +34,18 @@
if(H.nutrition > NUTRITION_LEVEL_FULL)
H.nutrition = NUTRITION_LEVEL_FULL
if(light_amount > 0.2) //if there's enough light, heal
- H.heal_overall_damage(0.75,0)
- H.adjustOxyLoss(-0.5)
-
- if(H.nutrition < NUTRITION_LEVEL_STARVING + 55)
- H.adjustOxyLoss(5) //can eat to negate this unfortunately
- H.adjustToxLoss(3)
+ H.heal_overall_damage(1,1)
+ H.adjustToxLoss(-1)
+ H.adjustOxyLoss(-1)
+ if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
+ H.take_overall_damage(2,0)
/datum/species/pod/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
if(chem.id == "plantbgone")
- H.adjustToxLoss(5)
+ H.adjustToxLoss(3)
H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
- H.confused = max(H.confused, 1)
- return TRUE
-
+ return 1
/datum/species/pod/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
switch(P.type)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 2304502c40..6450c13bb7 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -303,6 +303,8 @@
/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
if(tesla_shock && (flags_2 & TESLA_IGNORE_2))
return FALSE
+ if(has_trait(TRAIT_SHOCKIMMUNE))
+ return FALSE
if(shock_damage > 0)
if(!illusion)
adjustFireLoss(shock_damage)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 650ac3e1a6..737069a44d 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -381,4 +381,4 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(.)
return .
- . = ..()
+ . = ..()
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 84f90a0c6d..1d48c56556 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -552,6 +552,16 @@
can_be_pushed = FALSE
hat_offset = 3
+/obj/item/robot_module/syndicate/rebuild_modules()
+ ..()
+ var/mob/living/silicon/robot/Syndi = loc
+ Syndi.faction -= "silicon" //ai turrets
+
+/obj/item/robot_module/syndicate/remove_module(obj/item/I, delete_after)
+ ..()
+ var/mob/living/silicon/robot/Syndi = loc
+ Syndi.faction += "silicon" //ai is your bff now!
+
/obj/item/robot_module/syndicate_medical
name = "Syndicate Medical"
basic_modules = list(
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index bc34c15e2b..5ed5bf5eb0 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -41,6 +41,7 @@
/mob/living/silicon/Initialize()
. = ..()
GLOB.silicon_mobs += src
+ faction += "silicon"
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.add_to_hud(src)
diag_hud_set_status()
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 0a3061cacc..6c6f39ffc1 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -37,12 +37,28 @@
var/seeking = FALSE
var/can_repair_constructs = FALSE
var/can_repair_self = FALSE
+ var/runetype
/mob/living/simple_animal/hostile/construct/Initialize()
. = ..()
update_health_hud()
+ var/spellnum = 1
for(var/spell in construct_spells)
- AddSpell(new spell(null))
+ var/the_spell = new spell(null)
+ AddSpell(the_spell)
+ var/obj/effect/proc_holder/spell/S = mob_spell_list[spellnum]
+ var/pos = 2+spellnum*31
+ if(construct_spells.len >= 4)
+ pos -= 31*(construct_spells.len - 4)
+ S.action.button.screen_loc = "6:[pos],4:-2"
+ S.action.button.moved = "6:[pos],4:-2"
+ spellnum++
+ if(runetype)
+ var/datum/action/innate/cult/create_rune/CR = new runetype(src)
+ CR.Grant(src)
+ var/pos = 2+spellnum*31
+ CR.button.screen_loc = "6:[pos],4:-2"
+ CR.button.moved = "6:[pos],4:-2"
/mob/living/simple_animal/hostile/construct/Login()
..()
@@ -104,22 +120,24 @@
desc = "A massive, armored construct built to spearhead attacks and soak up enemy fire."
icon_state = "behemoth"
icon_living = "behemoth"
- maxHealth = 250
- health = 250
+ maxHealth = 200
+ health = 200
response_harm = "harmlessly punches"
harm_intent_damage = 0
obj_damage = 90
melee_damage_lower = 30
melee_damage_upper = 30
attacktext = "smashes their armored gauntlet into"
- speed = 3
+ speed = 2.5
environment_smash = ENVIRONMENT_SMASH_WALLS
attack_sound = 'sound/weapons/punch3.ogg'
status_flags = 0
mob_size = MOB_SIZE_LARGE
force_threshold = 11
- construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall)
- playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \
+ construct_spells = list(/obj/effect/proc_holder/spell/targeted/forcewall/cult,
+ /obj/effect/proc_holder/spell/dumbfire/juggernaut)
+ runetype = /datum/action/innate/cult/create_rune/wall
+ playstyle_string = "You are a Juggernaut. Though slow, your shell can withstand extreme punishment, \
create shield walls, rip apart enemies and walls alike, and even deflect energy weapons."
/mob/living/simple_animal/hostile/construct/armored/hostile //actually hostile, will move around, hit things
@@ -164,15 +182,17 @@
desc = "A wicked, clawed shell constructed to assassinate enemies and sow chaos behind enemy lines."
icon_state = "floating"
icon_living = "floating"
- maxHealth = 75
- health = 75
+ maxHealth = 65
+ health = 65
melee_damage_lower = 25
melee_damage_upper = 25
retreat_distance = 2 //AI wraiths will move in and out of combat
attacktext = "slashes"
attack_sound = 'sound/weapons/bladeslice.ogg'
construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift)
- playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, can phase through walls, and your attacks will lower the cooldown on phasing."
+ runetype = /datum/action/innate/cult/create_rune/tele
+ playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, can phase through walls, and your attacks will lower the cooldown on phasing."
+
var/attack_refund = 10 //1 second per attack
var/crit_refund = 50 //5 seconds when putting a target into critical
var/kill_refund = 250 //full refund on kills
@@ -226,7 +246,9 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone,
/obj/effect/proc_holder/spell/aoe_turf/conjure/construct/lesser,
/obj/effect/proc_holder/spell/targeted/projectile/magic_missile/lesser)
- playstyle_string = "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \
+ runetype = /datum/action/innate/cult/create_rune/revive
+ playstyle_string = "You are an Artificer. You are incredibly weak and fragile, but you are able to construct fortifications, \
+
use magic missile, repair allied constructs, shades, and yourself (by clicking on them), \
and, most important of all, create new constructs by producing soulstones to capture souls, \
and shells to place those soulstones into."
@@ -299,9 +321,9 @@
attacktext = "butchers"
attack_sound = 'sound/weapons/bladeslice.ogg'
construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/area_conversion,
- /obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall)
- playstyle_string = "You are a Harvester. You are incapable of directly killing humans, but your attacks will remove their limbs: \
- Bring those who still cling to this world of illusion back to the Geometer so they may know Truth. Your form and any you are pulling can pass through runed walls effortlessly."
+ /obj/effect/proc_holder/spell/targeted/forcewall/cult)
+ playstyle_string = "You are a Harvester. You are incapable of directly killing humans, but your attacks will remove their limbs: \
+ Bring those who still cling to this world of illusion back to the Geometer so they may know Truth. Your form and any you are pulling can pass through runed walls effortlessly."
can_repair_constructs = TRUE
@@ -376,7 +398,7 @@
if(summon_objective.check_completion())
the_construct.master = C.cult_team.blood_target
-
+
if(!the_construct.master)
to_chat(the_construct, "You have no master to seek!")
the_construct.seeking = FALSE
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 4915ee8bec..ff9363ef64 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -43,12 +43,13 @@
/mob/living/simple_animal/mouse/death(gibbed, toast)
if(!ckey)
..(1)
- var/obj/item/reagent_containers/food/snacks/deadmouse/M = new(loc)
- M.icon_state = icon_dead
- M.name = name
- if(toast)
- M.add_atom_colour("#3A3A3A", FIXED_COLOUR_PRIORITY)
- M.desc = "It's toast."
+ if(!gibbed)
+ var/obj/item/reagent_containers/food/snacks/deadmouse/M = new(loc)
+ M.icon_state = icon_dead
+ M.name = name
+ if(toast)
+ M.add_atom_colour("#3A3A3A", FIXED_COLOUR_PRIORITY)
+ M.desc = "It's toast."
qdel(src)
else
..(gibbed)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index c6f0f6a91c..62b66464eb 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -14,7 +14,7 @@ If it fails to warp to a target, it may summon up to 6 slaughterlings from the b
If it does not summon all 6 slaughterlings, it will instead charge at its target, dealing massive damage to anything it hits and spraying a stream of blood.
At half health, it will either charge three times or warp, then charge, instead of doing a single charge.
-When Bubblegum dies, it leaves behind a chest that can contain three things:
+When Bubblegum dies, it leaves behind a H.E.C.K. mining suit as well as a chest that can contain three things:
1. A bottle that, when activated, drives everyone nearby into a frenzy
2. A contract that marks for death the chosen target
3. A spellblade that can slice off limbs at range
@@ -25,7 +25,7 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/bubblegum
name = "bubblegum"
- desc = "In what passes for a heirarchy among slaughter demons, this one is king."
+ desc = "In what passes for a hierarchy among slaughter demons, this one is king."
health = 2500
maxHealth = 2500
attacktext = "rends"
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
index d2980bbdaf..5cb5bbe165 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
@@ -366,7 +366,7 @@
r_pocket = /obj/item/restraints/legcuffs/bola/cult
l_pocket = /obj/item/melee/cultblade/dagger
glasses = /obj/item/clothing/glasses/night/cultblind
- backpack_contents = list(/obj/item/reagent_containers/food/drinks/bottle/unholywater = 1, /obj/item/device/cult_shift = 1, /obj/item/device/flashlight/flare/culttorch = 1, /obj/item/stack/sheet/runed_metal = 15)
+ backpack_contents = list(/obj/item/reagent_containers/glass/beaker/unholywater = 1, /obj/item/device/cult_shift = 1, /obj/item/device/flashlight/flare/culttorch = 1, /obj/item/stack/sheet/runed_metal = 15)
. = ..()
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index f9fee7369e..e7f6d3e49f 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -27,8 +27,6 @@
healable = 0
gender = NEUTER
- nutrition = 700
-
see_in_dark = 8
verb_say = "blorbles"
@@ -93,6 +91,7 @@
create_reagents(100)
set_colour(new_colour)
. = ..()
+ nutrition = 700
/mob/living/simple_animal/slime/Destroy()
for (var/A in actions)
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 53095045f6..87eddde125 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -68,32 +68,35 @@
return S.duration - world.time
return 0
-/mob/living/proc/Sleeping(amount, updating = TRUE) //Can't go below remaining duration
- var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
- if(S)
- S.duration = max(world.time + amount, S.duration)
- else if(amount > 0)
- S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
- return S
-
-/mob/living/proc/SetSleeping(amount, updating = TRUE) //Sets remaining duration
- var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
- if(amount <= 0)
+/mob/living/proc/Sleeping(amount, updating = TRUE, ignore_sleepimmune = FALSE) //Can't go below remaining duration
+ if((!has_trait(TRAIT_SLEEPIMMUNE)) || ignore_sleepimmune)
+ var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
if(S)
- qdel(S)
- else if(S)
- S.duration = world.time + amount
- else
- S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
- return S
+ S.duration = max(world.time + amount, S.duration)
+ else if(amount > 0)
+ S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
+ return S
-/mob/living/proc/AdjustSleeping(amount, updating = TRUE) //Adds to remaining duration
- var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
- if(S)
- S.duration += amount
- else if(amount > 0)
- S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
- return S
+/mob/living/proc/SetSleeping(amount, updating = TRUE, ignore_sleepimmune = FALSE) //Sets remaining duration
+ if((!has_trait(TRAIT_SLEEPIMMUNE)) || ignore_sleepimmune)
+ var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
+ if(amount <= 0)
+ if(S)
+ qdel(S)
+ else if(S)
+ S.duration = world.time + amount
+ else
+ S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
+ return S
+
+/mob/living/proc/AdjustSleeping(amount, updating = TRUE, ignore_sleepimmune = FALSE) //Adds to remaining duration
+ if((!has_trait(TRAIT_SLEEPIMMUNE)) || ignore_sleepimmune)
+ var/datum/status_effect/incapacitating/sleeping/S = IsSleeping()
+ if(S)
+ S.duration += amount
+ else if(amount > 0)
+ S = apply_status_effect(STATUS_EFFECT_SLEEPING, amount, updating)
+ return S
/////////////////////////////////// RESTING ////////////////////////////////////
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 35ec667027..312c789f07 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -69,10 +69,6 @@
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper)
assets.send(user)
- if(istype(src, /obj/item/paper/talisman)) //Talismans cannot be read
- if(!iscultist(user) && !user.stat)
- to_chat(user, "There are indecipherable images scrawled on the paper in what looks to be... blood?")
- return
if(in_range(user, src) || isobserver(user))
if(user.is_literate())
user << browse("
[stamps]", "window=[name]")
@@ -297,9 +293,6 @@
else
to_chat(user, "You don't know how to read or write.")
return
- if(istype(src, /obj/item/paper/talisman/))
- to_chat(user, "[P]'s ink fades away shortly after it is written.")
- return
else if(istype(P, /obj/item/stamp))
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index 0fa1439796..2293fb2fb2 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -77,7 +77,7 @@
set_security_level("delta")
SSshuttle.registerHostileEnvironment(src)
SSshuttle.lockdown = TRUE
- sleep(1150)
+ sleep(850)
if(resolved == FALSE)
resolved = TRUE
sound_to_playing_players('sound/machines/alarm.ogg')
diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm
index d4d09595af..96d0fd2e29 100644
--- a/code/modules/projectiles/ammunition/energy.dm
+++ b/code/modules/projectiles/ammunition/energy.dm
@@ -12,6 +12,7 @@
/obj/item/ammo_casing/energy/chameleon
projectile_type = /obj/item/projectile/energy/chameleon
e_cost = 0
+ var/hitscan_mode = FALSE
var/list/projectile_vars = list()
/obj/item/ammo_casing/energy/chameleon/ready_proj(atom/target, mob/living/user, quiet, zone_override = "")
@@ -19,8 +20,10 @@
if(!BB)
newshot()
for(var/V in projectile_vars)
- if(BB.vars[V])
+ if(BB.vars.Find(V))
BB.vars[V] = projectile_vars[V]
+ if(hitscan_mode)
+ BB.hitscan = TRUE
/obj/item/ammo_casing/energy/laser
projectile_type = /obj/item/projectile/beam/laser
@@ -69,10 +72,16 @@
projectile_type = /obj/item/projectile/beam/lasertag/bluetag
select_name = "bluetag"
+/obj/item/ammo_casing/energy/laser/bluetag/hitscan
+ projectile_type = /obj/item/projectile/beam/lasertag/bluetag/hitscan
+
/obj/item/ammo_casing/energy/laser/redtag
projectile_type = /obj/item/projectile/beam/lasertag/redtag
select_name = "redtag"
+/obj/item/ammo_casing/energy/laser/redtag/hitscan
+ projectile_type = /obj/item/projectile/beam/lasertag/redtag/hitscan
+
/obj/item/ammo_casing/energy/xray
projectile_type = /obj/item/projectile/beam/xray
e_cost = 50
diff --git a/code/modules/projectiles/guns/beam_rifle.dm b/code/modules/projectiles/guns/beam_rifle.dm
index fc00079d35..702079e72c 100644
--- a/code/modules/projectiles/guns/beam_rifle.dm
+++ b/code/modules/projectiles/guns/beam_rifle.dm
@@ -42,7 +42,7 @@
var/lastangle = 0
var/aiming_lastangle = 0
var/mob/current_user = null
- var/list/obj/effect/projectile_beam/current_tracers
+ var/list/obj/effect/projectile/tracer/current_tracers
var/structure_piercing = 2 //Amount * 2. For some reason structures aren't respecting this unless you have it doubled. Probably with the objects in question's Bump() code instead of this but I'll deal with this later.
var/structure_bleed_coeff = 0.7
@@ -546,93 +546,28 @@
/obj/item/projectile/beam/beam_rifle/hitscan
icon_state = ""
- var/tracer_type = /obj/effect/projectile_beam/tracer
- var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end.
+ hitscan = TRUE
+ tracer_type = /obj/effect/projectile/tracer/tracer/beam_rifle
var/constant_tracer = FALSE
- var/beam_index
-/obj/item/projectile/beam/beam_rifle/hitscan/Destroy()
- if(loc)
- var/datum/point/pcache = trajectory.copy_to()
- beam_segments[beam_index] = pcache
- generate_tracers(constant_tracer)
- return ..()
-
-/obj/item/projectile/beam/beam_rifle/hitscan/Collide(atom/target)
- var/datum/point/pcache = trajectory.copy_to()
- . = ..()
- if(. && !QDELETED(src)) //successful touch and not destroyed.
- beam_segments[beam_index] = pcache
- beam_index = pcache
- beam_segments[beam_index] = null
-
-/obj/item/projectile/beam/beam_rifle/hitscan/before_z_change(turf/oldloc, turf/newloc)
- var/datum/point/pcache = trajectory.copy_to()
- beam_segments[beam_index] = pcache
- beam_index = RETURN_PRECISE_POINT(newloc)
- beam_segments[beam_index] = null
- return ..()
-
-/obj/item/projectile/beam/beam_rifle/hitscan/proc/generate_tracers(highlander = FALSE, cleanup = TRUE)
+/obj/item/projectile/beam/beam_rifle/hitscan/generate_hitscan_tracers(cleanup = TRUE, duration = 5, highlander)
set waitfor = FALSE
+ if(isnull(highlander))
+ highlander = constant_tracer
if(highlander && istype(gun))
QDEL_LIST(gun.current_tracers)
for(var/datum/point/p in beam_segments)
- gun.current_tracers += generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 0)
+ gun.current_tracers += generate_tracer_between_points(p, beam_segments[p], tracer_type, color, 0)
else
for(var/datum/point/p in beam_segments)
- generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 5)
+ generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration)
if(cleanup)
QDEL_LIST(beam_segments)
beam_segments = null
QDEL_NULL(beam_index)
-/obj/item/projectile/beam/beam_rifle/hitscan/fire(setAngle, atom/direct_target) //oranges didn't let me make this a var the first time around so copypasta time
- set waitfor = FALSE
- var/turf/starting = get_turf(src)
- trajectory = new(starting.x, starting.y, starting.z, 0, 0, setAngle? setAngle : Angle, 33)
- if(!log_override && firer && original)
- add_logs(firer, original, "fired at", src, " [get_area(src)]")
- fired = TRUE
- if(setAngle)
- Angle = setAngle
- var/safety = 0 //The code works fine, but... just in case...
- var/turf/c2
- beam_segments = list() //initialize segment list with the list for the first segment
- beam_index = RETURN_PRECISE_POINT(src)
- beam_segments[beam_index] = null //record start.
- if(spread)
- Angle += (rand() - 0.5) * spread
- while(loc)
- if(paused || QDELETED(src))
- return
- if(++safety > (range * 3)) //If it's looping for way, way too long...
- qdel(src)
- stack_trace("WARNING: [type] projectile encountered infinite recursion in [__FILE__]/[__LINE__]!")
- return //Kill!
- var/matrix/M = new
- M.Turn(Angle)
- transform = M
- trajectory.increment()
- var/turf/T = trajectory.return_turf()
- if(T.z != loc.z)
- before_z_change(loc, T)
- trajectory_ignore_forcemove = TRUE
- forceMove(T)
- trajectory_ignore_forcemove = FALSE
- else
- step_towards(src, T)
- animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
-
- if(can_hit_target(original, permutated))
- Collide(original)
- Range()
- c2 = get_turf(src)
- if(istype(c2))
- cached = c2
-
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam
- tracer_type = /obj/effect/projectile_beam/tracer/aiming
+ tracer_type = /obj/effect/projectile/tracer/tracer/aiming
name = "aiming beam"
hitsound = null
hitsound_wall = null
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index cad3512766..29d0ee0958 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -116,19 +116,25 @@
icon_state = "bluetag"
desc = "A retro laser gun modified to fire harmless blue beams of light. Sound effects included!"
ammo_type = list(/obj/item/ammo_casing/energy/laser/bluetag)
- clumsy_check = 0
item_flags = NONE
+ clumsy_check = FALSE
pin = /obj/item/device/firing_pin/tag/blue
ammo_x_offset = 2
- selfcharge = 1
+ selfcharge = TRUE
+
+/obj/item/gun/energy/laser/bluetag/hitscan
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/bluetag/hitscan)
/obj/item/gun/energy/laser/redtag
name = "laser tag gun"
icon_state = "redtag"
desc = "A retro laser gun modified to fire harmless beams red of light. Sound effects included!"
ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag)
- clumsy_check = 0
item_flags = NONE
+ clumsy_check = FALSE
pin = /obj/item/device/firing_pin/tag/red
ammo_x_offset = 2
- selfcharge = 1
+ selfcharge = TRUE
+
+/obj/item/gun/energy/laser/redtag/hitscan
+ ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag/hitscan)
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index d3b6063824..3c8092307a 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -1,5 +1,6 @@
-#define MOVES_HITSCAN -1 //Not actually hitscan but close as we get.
+#define MOVES_HITSCAN -1 //Not actually hitscan but close as we get without actual hitscan.
+#define MUZZLE_EFFECT_PIXEL_INCREMENT 17 //How many pixels to move the muzzle flash up so your character doesn't look like they're shitting out lasers.
/obj/item/projectile
name = "projectile"
@@ -37,6 +38,7 @@
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
var/pixel_speed = 33 //pixels per move - DO NOT FUCK WITH THIS UNLESS YOU ABSOLUTELY KNOW WHAT YOU ARE DOING OR UNEXPECTED THINGS /WILL/ HAPPEN!
var/Angle = 0
+ var/original_angle = 0 //Angle at firing
var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle
var/spread = 0 //amount (in degrees) of projectile spread
animate_movement = 0 //Use SLIDE_STEPS in conjunction with legacy
@@ -46,6 +48,15 @@
var/colliding = FALSE //pause processing..
+ //Hitscan
+ var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored.
+ var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation.
+ var/datum/point/beam_index
+ var/turf/hitscan_last //last turf touched during hitscanning.
+ var/tracer_type
+ var/muzzle_type
+ var/impact_type
+
var/ignore_source_check = FALSE
var/damage = 10
@@ -53,7 +64,7 @@
var/nodamage = 0 //Determines if the projectile will skip any damage inflictions
var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb
var/projectile_type = /obj/item/projectile
- var/range = 50 //This will de-increment every step. When 0, it will delete the projectile.
+ var/range = 50 //This will de-increment every step. When 0, it will deletze the projectile.
var/is_reflectable = FALSE // Can it be reflected or not?
//Effects
var/stun = 0
@@ -111,7 +122,7 @@
if(!nodamage && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_loca) && prob(75))
var/turf/closed/wall/W = target_loca
- if(impact_effect_type)
+ if(impact_effect_type && !hitscan)
new impact_effect_type(target_loca, hitx, hity)
W.add_dent(WALL_DENT_SHOT, hitx, hity)
@@ -119,7 +130,7 @@
return 0
if(!isliving(target))
- if(impact_effect_type)
+ if(impact_effect_type && !hitscan)
new impact_effect_type(target_loca, hitx, hity)
return 0
@@ -136,7 +147,7 @@
new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_loca, splatter_dir)
if(prob(33))
L.add_splatter_floor(target_loca)
- else if(impact_effect_type)
+ else if(impact_effect_type && !hitscan)
new impact_effect_type(target_loca, hitx, hity)
var/organ_hit_text = ""
@@ -173,14 +184,22 @@
/obj/item/projectile/proc/on_ricochet(atom/A)
return
+/obj/item/projectile/proc/store_hitscan_collision(datum/point/pcache)
+ beam_segments[beam_index] = pcache
+ beam_index = pcache
+ beam_segments[beam_index] = null
+
/obj/item/projectile/Collide(atom/A)
colliding = TRUE
+ var/datum/point/pcache = trajectory.copy_to()
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
ricochets++
if(A.handle_ricochet(src))
on_ricochet(A)
ignore_source_check = TRUE
range = initial(range)
+ if(hitscan)
+ store_hitscan_collision(pcache)
return TRUE
if(firer && !ignore_source_check)
if(A == firer || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech
@@ -275,7 +294,9 @@
return getline(current, ending)
/obj/item/projectile/proc/before_z_change(turf/oldloc, turf/newloc)
- return
+ var/datum/point/pcache = trajectory.copy_to()
+ if(hitscan)
+ store_hitscan_collision(pcache)
/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
return TRUE //Bullets don't drift in space
@@ -324,13 +345,17 @@
return
var/turf/target = locate(CLAMP(starting + xo, 1, world.maxx), CLAMP(starting + yo, 1, world.maxy), starting.z)
setAngle(Get_Angle(src, target))
+ original_angle = Angle
if(!nondirectional_sprite)
var/matrix/M = new
M.Turn(Angle)
transform = M
+ forceMove(starting)
trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed)
last_projectile_move = world.time
fired = TRUE
+ if(hitscan)
+ process_hitscan()
if(!isprocessing)
START_PROCESSING(SSprojectiles, src)
pixel_move(1) //move it now!
@@ -350,11 +375,29 @@
if(trajectory && !trajectory_ignore_forcemove && isturf(target))
trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
-/obj/item/projectile/proc/pixel_move(moves, trajectory_multiplier = 1)
+/obj/item/projectile/proc/record_hitscan_start(datum/point/pcache)
+ beam_segments = list() //initialize segment list with the list for the first segment
+ beam_index = pcache
+ beam_segments[beam_index] = null //record start.
+
+/obj/item/projectile/proc/process_hitscan()
+ var/safety = range * 3
+ record_hitscan_start(RETURN_POINT_VECTOR_INCREMENT(src, Angle, MUZZLE_EFFECT_PIXEL_INCREMENT, 1))
+ while(loc && !QDELETED(src))
+ if(paused)
+ stoplag(1)
+ continue
+ if(safety-- <= 0)
+ qdel(src)
+ stack_trace("WARNING: [type] projectile encountered infinite recursion during hitscanning in [__FILE__]/[__LINE__]!")
+ return //Kill!
+ pixel_move(1, 1, TRUE)
+
+/obj/item/projectile/proc/pixel_move(moves, trajectory_multiplier = 1, hitscanning = FALSE)
if(!loc || !trajectory)
return
last_projectile_move = world.time
- if(!nondirectional_sprite)
+ if(!nondirectional_sprite && !hitscanning)
var/matrix/M = new
M.Turn(Angle)
transform = M
@@ -365,14 +408,18 @@
trajectory_ignore_forcemove = TRUE
forceMove(T)
trajectory_ignore_forcemove = FALSE
- pixel_x = trajectory.return_px()
- pixel_y = trajectory.return_py()
+ if(!hitscanning)
+ pixel_x = trajectory.return_px()
+ pixel_y = trajectory.return_py()
else
step_towards(src, T)
- pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier
- pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier
- animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
-
+ if(!hitscanning)
+ pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier
+ pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier
+ if(!hitscanning)
+ animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
+ if(isturf(loc))
+ hitscan_last = loc
if(can_hit_target(original, permutated))
Collide(original)
Range()
@@ -446,8 +493,40 @@
Collide(AM)
/obj/item/projectile/Destroy()
+ if(hitscan)
+ if(loc)
+ var/datum/point/pcache = trajectory.copy_to()
+ beam_segments[beam_index] = pcache
+ generate_hitscan_tracers()
STOP_PROCESSING(SSprojectiles, src)
return ..()
+/obj/item/projectile/proc/generate_hitscan_tracers(cleanup = TRUE, duration = 3)
+ if(!length(beam_segments))
+ return
+ if(tracer_type)
+ for(var/datum/point/p in beam_segments)
+ generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration)
+ if(muzzle_type && duration > 0)
+ var/datum/point/p = beam_segments[1]
+ var/atom/movable/thing = new muzzle_type
+ p.move_atom_to_src(thing)
+ var/matrix/M = new
+ M.Turn(original_angle)
+ thing.transform = M
+ QDEL_IN(thing, duration)
+ if(impact_type && duration > 0)
+ var/datum/point/p = beam_segments[beam_segments[beam_segments.len]]
+ var/atom/movable/thing = new impact_type
+ p.move_atom_to_src(thing)
+ var/matrix/M = new
+ M.Turn(Angle)
+ thing.transform = M
+ QDEL_IN(thing, duration)
+ if(cleanup)
+ QDEL_LIST(beam_segments)
+ beam_segments = null
+ QDEL_NULL(beam_index)
+
/obj/item/projectile/experience_pressure_difference()
return
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index ef00c35563..3ba0d092c5 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -16,11 +16,17 @@
is_reflectable = TRUE
/obj/item/projectile/beam/laser
+ tracer_type = /obj/effect/projectile/tracer/laser
+ muzzle_type = /obj/effect/projectile/muzzle/laser
+ impact_type = /obj/effect/projectile/impact/laser
/obj/item/projectile/beam/laser/heavylaser
name = "heavy laser"
icon_state = "heavylaser"
damage = 40
+ tracer_type = /obj/effect/projectile/tracer/heavy_laser
+ muzzle_type = /obj/effect/projectile/muzzle/heavy_laser
+ impact_type = /obj/effect/projectile/impact/heavy_laser
/obj/item/projectile/beam/laser/on_hit(atom/target, blocked = FALSE)
. = ..()
@@ -54,6 +60,9 @@
impact_effect_type = /obj/effect/temp_visual/impact_effect/green_laser
light_color = LIGHT_COLOR_GREEN
+ tracer_type = /obj/effect/projectile/tracer/xray
+ muzzle_type = /obj/effect/projectile/muzzle/xray
+ impact_type = /obj/effect/projectile/impact/xray
/obj/item/projectile/beam/disabler
name = "disabler beam"
@@ -65,6 +74,9 @@
eyeblur = 0
impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
light_color = LIGHT_COLOR_BLUE
+ tracer_type = /obj/effect/projectile/tracer/disabler
+ muzzle_type = /obj/effect/projectile/muzzle/disabler
+ impact_type = /obj/effect/projectile/impact/disabler
/obj/item/projectile/beam/pulse
name = "pulse"
@@ -72,6 +84,9 @@
damage = 50
impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser
light_color = LIGHT_COLOR_BLUE
+ tracer_type = /obj/effect/projectile/tracer/pulse
+ muzzle_type = /obj/effect/projectile/muzzle/pulse
+ impact_type = /obj/effect/projectile/impact/pulse
/obj/item/projectile/beam/pulse/on_hit(atom/target, blocked = FALSE)
. = ..()
@@ -126,10 +141,22 @@
suit_types = list(/obj/item/clothing/suit/bluetag)
impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser
light_color = LIGHT_COLOR_RED
+ tracer_type = /obj/effect/projectile/tracer/laser
+ muzzle_type = /obj/effect/projectile/muzzle/laser
+ impact_type = /obj/effect/projectile/impact/laser
+
+/obj/item/projectile/beam/lasertag/redtag/hitscan
+ hitscan = TRUE
/obj/item/projectile/beam/lasertag/bluetag
icon_state = "bluelaser"
suit_types = list(/obj/item/clothing/suit/redtag)
+ tracer_type = /obj/effect/projectile/tracer/laser/blue
+ muzzle_type = /obj/effect/projectile/muzzle/laser/blue
+ impact_type = /obj/effect/projectile/impact/laser/blue
+
+/obj/item/projectile/beam/lasertag/bluetag/hitscan
+ hitscan = TRUE
/obj/item/projectile/beam/instakill
name = "instagib laser"
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index b5c966f03f..2d7f8f5cce 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -19,6 +19,9 @@
jitter = 20
hitsound = 'sound/weapons/taserhit.ogg'
range = 7
+ tracer_type = /obj/effect/projectile/tracer/stun
+ muzzle_type = /obj/effect/projectile/muzzle/stun
+ impact_type = /obj/effect/projectile/impact/stun
/obj/item/projectile/energy/electrode/on_hit(atom/target, blocked = FALSE)
. = ..()
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index af21066dc4..e8f309309a 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -184,6 +184,9 @@
var/pressure_decrease_active = FALSE
var/pressure_decrease = 0.25
var/mine_range = 3 //mines this many additional tiles of rock
+ tracer_type = /obj/effect/projectile/tracer/plasma_cutter
+ muzzle_type = /obj/effect/projectile/muzzle/plasma_cutter
+ impact_type = /obj/effect/projectile/impact/plasma_cutter
/obj/item/projectile/plasma/Initialize()
. = ..()
diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
index 5e5493df18..0886aacb06 100644
--- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
@@ -245,21 +245,31 @@
/datum/reagent/drug/bath_salts
name = "Bath Salts"
id = "bath_salts"
- description = "Makes you nearly impervious to stuns and grants a stamina regeneration buff, but you will be a nearly uncontrollable tramp-bearded raving lunatic."
+ description = "Makes you impervious to stuns and grants a stamina regeneration buff, but you will be a nearly uncontrollable tramp-bearded raving lunatic."
reagent_state = LIQUID
color = "#FAFAFA"
overdose_threshold = 20
addiction_threshold = 10
taste_description = "salt" // because they're bathsalts?
+/datum/reagent/drug/bath_salts/on_mob_add(mob/M)
+ ..()
+ if(isliving(M))
+ var/mob/living/L = M
+ L.add_trait(TRAIT_STUNIMMUNE, id)
+ L.add_trait(TRAIT_SLEEPIMMUNE, id)
+
+/datum/reagent/drug/bath_salts/on_mob_delete(mob/M)
+ if(isliving(M))
+ var/mob/living/L = M
+ L.remove_trait(TRAIT_STUNIMMUNE, id)
+ L.remove_trait(TRAIT_SLEEPIMMUNE, id)
+ ..()
/datum/reagent/drug/bath_salts/on_mob_life(mob/living/M)
var/high_message = pick("You feel amped up.", "You feel ready.", "You feel like you can push it to the limit.")
if(prob(5))
to_chat(M, "[high_message]")
- M.AdjustStun(-60, 0)
- M.AdjustKnockdown(-60, 0)
- M.AdjustUnconscious(-60, 0)
M.adjustStaminaLoss(-5, 0)
M.adjustBrainLoss(0.5)
M.adjustToxLoss(0.1, 0)
@@ -333,7 +343,7 @@
/datum/reagent/drug/aranesp
name = "Aranesp"
id = "aranesp"
- description = "Amps you up and gets you going, fixes all stamina damage you might have but can cause toxin and oxygen damage.."
+ 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"
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index ae396f4ea4..8fc9134b4a 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -1205,6 +1205,22 @@
overdose_threshold = 20
addiction_threshold = 5
+/datum/reagent/medicine/ketrazine/on_mob_add(mob/M)
+ ..()
+ if(isliving(M))
+ var/mob/living/L = M
+ L.add_trait(TRAIT_SLEEPIMMUNE, id)
+ L.add_trait(TRAIT_IGNORESLOWDOWN, id)
+ L.add_trait(TRAIT_GOTTAGOFAST, id)
+
+/datum/reagent/medicine/ketrazine/on_mob_delete(mob/M)
+ if(isliving(M))
+ var/mob/living/L = M
+ L.remove_trait(TRAIT_SLEEPIMMUNE, id)
+ L.remove_trait(TRAIT_IGNORESLOWDOWN, id)
+ L.remove_trait(TRAIT_GOTTAGOFAST, id)
+ ..()
+
/datum/reagent/medicine/ketrazine/on_mob_life(mob/living/M)
M.adjustToxLoss(-3*REM, 0)
M.adjustBruteLoss(-5*REM, 0)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 309273900d..d80e43b8a4 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -200,6 +200,11 @@
data = 1
data++
M.jitteriness = min(M.jitteriness+4,10)
+ if(iscultist(M))
+ for(var/datum/action/innate/cult/blood_magic/BM in M.actions)
+ to_chat(M, "Your blood rites falter as holy water scours your body!")
+ for(var/datum/action/innate/cult/blood_spell/BS in BM.spells)
+ qdel(BS)
if(data >= 30) // 12 units, 54 seconds @ metabolism 0.4 units & tick rate 1.8 sec
if(!M.stuttering)
M.stuttering = 1
@@ -216,7 +221,7 @@
"You can't save him. Nothing can save him now", "It seems that Nar-Sie will triumph after all")].")
if("emote")
M.visible_message("[M] [pick("whimpers quietly", "shivers as though cold", "glances around in paranoia")].")
- if(data >= 75) // 30 units, 135 seconds
+ if(data >= 60) // 30 units, 135 seconds
if(iscultist(M) || is_servant_of_ratvar(M))
if(iscultist(M))
SSticker.mode.remove_cultist(M.mind, FALSE, TRUE)
@@ -245,7 +250,7 @@
/datum/reagent/fuel/unholywater/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(method == TOUCH || method == VAPOR)
- M.reagents.add_reagent("unholywater", (reac_volume/4))
+ M.reagents.add_reagent(id,reac_volume/4)
return
return ..()
@@ -255,17 +260,20 @@
M.AdjustUnconscious(-20, 0)
M.AdjustStun(-40, 0)
M.AdjustKnockdown(-40, 0)
+ M.adjustStaminaLoss(-10, 0)
M.adjustToxLoss(-2, 0)
M.adjustOxyLoss(-2, 0)
M.adjustBruteLoss(-2, 0)
M.adjustFireLoss(-2, 0)
- else
+ if(ishuman(M) && M.blood_volume < BLOOD_VOLUME_NORMAL)
+ M.blood_volume += 3
+ else // Will deal about 90 damage when 50 units are thrown
M.adjustBrainLoss(3, 150)
- M.adjustToxLoss(1, 0)
+ M.adjustToxLoss(2, 0)
M.adjustFireLoss(2, 0)
M.adjustOxyLoss(2, 0)
M.adjustBruteLoss(2, 0)
- holder.remove_reagent(src.id, 1)
+ holder.remove_reagent(id, 1)
. = 1
/datum/reagent/hellwater //if someone has this in their system they've really pissed off an eldrich god
@@ -1763,3 +1771,32 @@
var/mob/living/L = M
L.remove_trait(TRAIT_PACIFISM, id)
..()
+
+/datum/reagent/pax/borg
+ name = "synth-pax"
+ id = "synthpax"
+ description = "A colorless liquid that suppresses violence on the subjects. Cheaper to synthetize, but wears out faster than normal Pax."
+ metabolization_rate = 1.5 * REAGENTS_METABOLISM
+
+/datum/reagent/bz_metabolites
+ name = "BZ metabolites"
+ id = "bz_metabolites"
+ description = "A harmless metabolite of BZ gas"
+ color = "#FAFF00"
+ taste_description = "acrid cinnamon"
+ metabolization_rate = 0.2 * REAGENTS_METABOLISM
+
+/datum/reagent/bz_metabolites/on_mob_add(mob/living/L)
+ ..()
+ L.add_trait(CHANGELING_HIVEMIND_MUTE, id)
+
+/datum/reagent/bz_metabolites/on_mob_delete(mob/living/L)
+ ..()
+ L.remove_trait(CHANGELING_HIVEMIND_MUTE, id)
+
+/datum/reagent/bz_metabolites/on_mob_life(mob/living/L)
+ if(L.mind)
+ var/datum/antagonist/changeling/changeling = L.mind.has_antag_datum(/datum/antagonist/changeling)
+ if(changeling)
+ changeling.chem_charges = max(changeling.chem_charges-2, 0)
+ return ..()
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index 44f904b0a7..11d41ea20f 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -194,7 +194,7 @@
required_other = 1
/datum/chemical_reaction/slime/slimestabilizer/on_reaction(datum/reagents/holder)
- new /obj/item/slimepotion/stabilizer(get_turf(holder.my_atom))
+ new /obj/item/slimepotion/slime/stabilizer(get_turf(holder.my_atom))
..()
/datum/chemical_reaction/slime/slimefoam
@@ -326,7 +326,7 @@
required_other = 1
/datum/chemical_reaction/slime/slimepsteroid/on_reaction(datum/reagents/holder)
- new /obj/item/slimepotion/steroid(get_turf(holder.my_atom))
+ new /obj/item/slimepotion/slime/steroid(get_turf(holder.my_atom))
..()
/datum/chemical_reaction/slime/slimeregen
@@ -358,7 +358,7 @@
required_other = 1
/datum/chemical_reaction/slime/slimemutator/on_reaction(datum/reagents/holder)
- new /obj/item/slimepotion/mutator(get_turf(holder.my_atom))
+ new /obj/item/slimepotion/slime/mutator(get_turf(holder.my_atom))
..()
/datum/chemical_reaction/slime/slimebloodlust
@@ -394,7 +394,7 @@
required_other = 1
/datum/chemical_reaction/slime/docility/on_reaction(datum/reagents/holder)
- new /obj/item/slimepotion/docility(get_turf(holder.my_atom))
+ new /obj/item/slimepotion/slime/docility(get_turf(holder.my_atom))
..()
/datum/chemical_reaction/slime/gender
@@ -465,7 +465,7 @@
required_other = 1
/datum/chemical_reaction/slime/slimepotion2/on_reaction(datum/reagents/holder)
- new /obj/item/slimepotion/sentience(get_turf(holder.my_atom))
+ new /obj/item/slimepotion/slime/sentience(get_turf(holder.my_atom))
..()
//Adamantine
diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm
index bc92521b93..98bac76ab8 100644
--- a/code/modules/reagents/reagent_containers/blood_pack.dm
+++ b/code/modules/reagents/reagent_containers/blood_pack.dm
@@ -2,7 +2,7 @@
name = "blood pack"
desc = "Contains blood used for transfusion. Must be attached to an IV drip."
icon = 'icons/obj/bloodpack.dmi'
- icon_state = "empty"
+ icon_state = "bloodpack"
volume = 200
var/blood_type = null
var/labelled = 0
@@ -31,14 +31,14 @@
name = "blood pack"
/obj/item/reagent_containers/blood/update_icon()
- var/percent = round((reagents.total_volume / volume) * 100)
- switch(percent)
- if(0 to 9)
- icon_state = "empty"
- if(10 to 50)
- icon_state = "half"
- if(51 to INFINITY)
- icon_state = "full"
+ cut_overlays()
+
+ var/v = min(round(reagents.total_volume / volume * 10), 10)
+ if(v > 0)
+ var/mutable_appearance/filling = mutable_appearance('icons/obj/reagentfillings.dmi', "bloodpack1")
+ filling.icon_state = "bloodpack[v]"
+ filling.color = mix_color_from_reagents(reagents.reagent_list)
+ add_overlay(filling)
/obj/item/reagent_containers/blood/random
icon_state = "random_bloodpack"
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index faa56c4fba..0dec687f68 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -225,13 +225,13 @@ Borg Shaker
/obj/item/reagent_containers/borghypo/peace
name = "Peace Hypospray"
- reagent_ids = list("dizzysolution","tiresolution","pax")
+ reagent_ids = list("dizzysolution","tiresolution","synthpax")
accepts_reagent_upgrades = FALSE
/obj/item/reagent_containers/borghypo/peace/hacked
desc = "Everything's peaceful in death!"
icon_state = "borghypo_s"
- reagent_ids = list("dizzysolution","tiresolution","pax","tirizene","sulfonal","sodium_thiopental","cyanide","neurotoxin2")
+ reagent_ids = list("dizzysolution","tiresolution","synthpax","tirizene","sulfonal","sodium_thiopental","cyanide","neurotoxin2")
accepts_reagent_upgrades = FALSE
/obj/item/reagent_containers/borghypo/epi
diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm
index b3b0f8df99..1268b2be87 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -19,14 +19,14 @@ The currently supporting non-reagent materials. All material amounts are set as
Don't add new keyword/IDs if they are made from an existing one (such as rods which are made from metal). Only add raw materials.
-Design Guidlines
+Design Guidelines
- When adding new designs, check rdreadme.dm to see what kind of things have already been made and where new stuff is needed.
- A single sheet of anything is 2000 units of material. Materials besides metal/glass require help from other jobs (mining for
other types of metals and chemistry for reagents).
- Add the AUTOLATHE tag to
*/
-//DESIGNS ARE GLOBAL. DO NOT CREATE OR DESTROY THEM AT RUNTIME OUTSIDE OF INIT, JUST REFERENCE THEM TO WHATEVER YOU'RE DOING!
+//DESIGNS ARE GLOBAL. DO NOT CREATE OR DESTROY THEM AT RUNTIME OUTSIDE OF INIT, JUST REFERENCE THEM TO WHATEVER YOU'RE DOING! //why are you yelling?
/datum/design //Datum for object designs, used in construction
var/name = "Name" //Name of the created object.
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 02e4d89bad..57d0397819 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -104,6 +104,16 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_ALL
+/datum/design/defibrillator_mount
+ name = "Defibrillator Wall Mount"
+ desc = "An all-in-one mounted frame for holding defibrillators, complete with ID-locked clamps and recharging cables."
+ id = "defibmount"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 2000, MAT_GLASS = 1000)
+ build_path = /obj/item/wallframe/defib_mount
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
/datum/design/alienscalpel
name = "Alien Scalpel"
desc = "An advanced scalpel obtained through Abductor technology."
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index a5545f3e9a..3d48e814e9 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -17,7 +17,7 @@
display_name = "Biological Technology"
description = "What makes us tick." //the MC, silly!
prereq_ids = list("base")
- design_ids = list("chem_heater", "chem_master", "chem_dispenser", "sleeper", "pandemic")
+ design_ids = list("chem_heater", "chem_master", "chem_dispenser", "sleeper", "pandemic", "defibmount")
research_cost = 2500
export_price = 5000
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index ca929e5e9a..45460eccbd 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -26,8 +26,11 @@
var/datum/action/innate/slime_pick_up/slime_up_action = new
var/datum/action/innate/feed_slime/feed_slime_action = new
var/datum/action/innate/monkey_recycle/monkey_recycle_action = new
+ var/datum/action/innate/slime_scan/scan_action = new
+ var/datum/action/innate/feed_potion/potion_action = new
var/list/stored_slimes = list()
+ var/obj/item/slimepotion/slime/current_potion
var/max_slimes = 5
var/monkeys = 0
@@ -66,6 +69,16 @@
monkey_recycle_action.Grant(user)
actions += monkey_recycle_action
+ if(scan_action)
+ scan_action.target = src
+ scan_action.Grant(user)
+ actions += scan_action
+
+ if(potion_action)
+ potion_action.target = src
+ potion_action.Grant(user)
+ actions += potion_action
+
/obj/machinery/computer/camera_advanced/xenobio/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/reagent_containers/food/snacks/monkeycube))
monkeys++
@@ -83,6 +96,16 @@
if (loaded)
to_chat(user, "You fill [src] with the monkey cubes stored in [O]. [src] now has [monkeys] monkey cubes stored.")
return
+ else if(istype(O, /obj/item/slimepotion/slime))
+ var/replaced = FALSE
+ if(user && !user.transferItemToLoc(O, src))
+ return
+ if(!QDELETED(current_potion))
+ current_potion.forceMove(drop_location())
+ replaced = TRUE
+ current_potion = O
+ to_chat(user, "You load [O] in the console's potion slot[replaced ? ", replacing the one that was there before" : ""].")
+ return
..()
/datum/action/innate/slime_place
@@ -173,3 +196,44 @@
qdel(M)
else
to_chat(owner, "Target is not near a camera. Cannot proceed.")
+
+/datum/action/innate/slime_scan
+ name = "Scan Slime"
+ icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon_state = "slime_scan"
+
+/datum/action/innate/slime_scan/Activate()
+ if(!target || !isliving(owner))
+ return
+ var/mob/living/C = owner
+ var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
+
+ if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
+ for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
+ slime_scan(S, C)
+ else
+ to_chat(owner, "Target is not near a camera. Cannot proceed.")
+
+/datum/action/innate/feed_potion
+ name = "Apply Potion"
+ icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon_state = "slime_potion"
+
+/datum/action/innate/feed_potion/Activate()
+ if(!target || !isliving(owner))
+ return
+
+ var/mob/living/C = owner
+ var/mob/camera/aiEye/remote/xenobio/remote_eye = C.remote_control
+ var/obj/machinery/computer/camera_advanced/xenobio/X = target
+
+ if(QDELETED(X.current_potion))
+ to_chat(owner, "No potion loaded.")
+ return
+
+ if(GLOB.cameranet.checkTurfVis(remote_eye.loc))
+ for(var/mob/living/simple_animal/slime/S in remote_eye.loc)
+ X.current_potion.attack(S, C)
+ break
+ else
+ to_chat(owner, "Target is not near a camera. Cannot proceed.")
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index a072e16059..77f5a04c88 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -327,7 +327,7 @@
/obj/item/slime_extract/lightpink/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
if(SLIME_ACTIVATE_MINOR)
- var/obj/item/slimepotion/docility/O = new(null, 1)
+ var/obj/item/slimepotion/slime/docility/O = new(null, 1)
if(!user.put_in_active_hand(O))
O.forceMove(user.drop_location())
playsound(user, 'sound/effects/splat.ogg', 50, 1)
@@ -335,7 +335,7 @@
return 150
if(SLIME_ACTIVATE_MAJOR)
- var/obj/item/slimepotion/sentience/O = new(null, 1)
+ var/obj/item/slimepotion/slime/sentience/O = new(null, 1)
if(!user.put_in_active_hand(O))
O.forceMove(user.drop_location())
playsound(user, 'sound/effects/splat.ogg', 50, 1)
@@ -539,19 +539,19 @@
to_chat(user, "You cannot transfer [src] to [target]! It appears the potion must be given directly to a slime to absorb." )
return
-/obj/item/slimepotion/docility
+/obj/item/slimepotion/slime/docility
name = "docility potion"
desc = "A potent chemical mix that nullifies a slime's hunger, causing it to become docile and tame."
icon = 'icons/obj/chemical.dmi'
icon_state = "potsilver"
-/obj/item/slimepotion/docility/attack(mob/living/simple_animal/slime/M, mob/user)
+/obj/item/slimepotion/slime/docility/attack(mob/living/simple_animal/slime/M, mob/user)
if(!isslime(M))
to_chat(user, "The potion only works on slimes!")
return ..()
if(M.stat)
to_chat(user, "The slime is dead!")
- return ..()
+ return
M.docile = 1
M.nutrition = 700
@@ -565,33 +565,31 @@
M.real_name = newname
qdel(src)
-/obj/item/slimepotion/sentience
+/obj/item/slimepotion/slime/sentience
name = "intelligence potion"
desc = "A miraculous chemical mix that grants human like intelligence to living beings."
icon = 'icons/obj/chemical.dmi'
icon_state = "potpink"
var/list/not_interested = list()
- var/being_used = 0
+ var/being_used = FALSE
var/sentience_type = SENTIENCE_ORGANIC
-/obj/item/slimepotion/sentience/afterattack(mob/living/M, mob/user)
- if(being_used || !ismob(M) || !user.Adjacent(M))
+/obj/item/slimepotion/slime/sentience/attack(mob/living/M, mob/user)
+ if(being_used || !ismob(M))
return
if(!isanimal(M) || M.ckey) //only works on animals that aren't player controlled
to_chat(user, "[M] is already too intelligent for this to work!")
- return ..()
+ return
if(M.stat)
to_chat(user, "[M] is dead!")
- return ..()
+ return
var/mob/living/simple_animal/SM = M
if(SM.sentience_type != sentience_type)
to_chat(user, "[src] won't work on [SM].")
- return ..()
-
-
+ return
to_chat(user, "You offer [src] to [SM]...")
- being_used = 1
+ being_used = TRUE
var/list/candidates = pollCandidatesForMob("Do you want to play as [SM.name]?", ROLE_ALIEN, null, ROLE_ALIEN, 50, SM, POLL_IGNORE_SENTIENCE_POTION) // see poll_ignore.dm
var/mob/dead/observer/theghost = null
@@ -608,17 +606,17 @@
qdel(src)
else
to_chat(user, "[SM] looks interested for a moment, but then looks back down. Maybe you should try again later.")
- being_used = 0
+ being_used = FALSE
..()
-/obj/item/slimepotion/sentience/proc/after_success(mob/living/user, mob/living/simple_animal/SM)
+/obj/item/slimepotion/slime/sentience/proc/after_success(mob/living/user, mob/living/simple_animal/SM)
return
-/obj/item/slimepotion/sentience/nuclear
+/obj/item/slimepotion/slime/sentience/nuclear
name = "syndicate intelligence potion"
desc = "A miraculous chemical mix that grants human like intelligence to living beings. It has been modified with Syndicate technology to also grant an internal radio implant to the target and authenticate with identification systems."
-/obj/item/slimepotion/sentience/nuclear/after_success(mob/living/user, mob/living/simple_animal/SM)
+/obj/item/slimepotion/slime/sentience/nuclear/after_success(mob/living/user, mob/living/simple_animal/SM)
var/obj/item/implant/radio/imp = new(src)
imp.implant(SM, user)
@@ -667,25 +665,25 @@
SM.name = "[SM.name] as [user.real_name]"
qdel(src)
-/obj/item/slimepotion/steroid
+/obj/item/slimepotion/slime/steroid
name = "slime steroid"
desc = "A potent chemical mix that will cause a baby slime to generate more extract."
icon = 'icons/obj/chemical.dmi'
icon_state = "potred"
-/obj/item/slimepotion/steroid/attack(mob/living/simple_animal/slime/M, mob/user)
+/obj/item/slimepotion/slime/steroid/attack(mob/living/simple_animal/slime/M, mob/user)
if(!isslime(M))//If target is not a slime.
to_chat(user, "The steroid only works on baby slimes!")
return ..()
if(M.is_adult) //Can't steroidify adults
to_chat(user, "Only baby slimes can use the steroid!")
- return ..()
+ return
if(M.stat)
to_chat(user, "The slime is dead!")
- return ..()
+ return
if(M.cores >= 5)
to_chat(user, "The slime already has the maximum amount of extract!")
- return ..()
+ return
to_chat(user, "You feed the slime the steroid. It will now produce one more extract.")
M.cores++
@@ -697,46 +695,46 @@
icon = 'icons/obj/chemical.dmi'
icon_state = "potpurple"
-/obj/item/slimepotion/stabilizer
+/obj/item/slimepotion/slime/stabilizer
name = "slime stabilizer"
desc = "A potent chemical mix that will reduce the chance of a slime mutating."
icon = 'icons/obj/chemical.dmi'
icon_state = "potcyan"
-/obj/item/slimepotion/stabilizer/attack(mob/living/simple_animal/slime/M, mob/user)
+/obj/item/slimepotion/slime/stabilizer/attack(mob/living/simple_animal/slime/M, mob/user)
if(!isslime(M))
to_chat(user, "The stabilizer only works on slimes!")
return ..()
if(M.stat)
to_chat(user, "The slime is dead!")
- return ..()
+ return
if(M.mutation_chance == 0)
to_chat(user, "The slime already has no chance of mutating!")
- return ..()
+ return
to_chat(user, "You feed the slime the stabilizer. It is now less likely to mutate.")
M.mutation_chance = CLAMP(M.mutation_chance-15,0,100)
qdel(src)
-/obj/item/slimepotion/mutator
+/obj/item/slimepotion/slime/mutator
name = "slime mutator"
desc = "A potent chemical mix that will increase the chance of a slime mutating."
icon = 'icons/obj/chemical.dmi'
icon_state = "potgreen"
-/obj/item/slimepotion/mutator/attack(mob/living/simple_animal/slime/M, mob/user)
+/obj/item/slimepotion/slime/mutator/attack(mob/living/simple_animal/slime/M, mob/user)
if(!isslime(M))
to_chat(user, "The mutator only works on slimes!")
return ..()
if(M.stat)
to_chat(user, "The slime is dead!")
- return ..()
+ return
if(M.mutator_used)
to_chat(user, "This slime has already consumed a mutator, any more would be far too unstable!")
- return ..()
+ return
if(M.mutation_chance == 100)
to_chat(user, "The slime is already guaranteed to mutate!")
- return ..()
+ return
to_chat(user, "You feed the slime the mutator. It is now more likely to mutate.")
M.mutation_chance = CLAMP(M.mutation_chance+12,0,100)
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 2d6d1ed75f..19162d5259 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -104,7 +104,6 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
pass_flags = PASSTABLE
density = FALSE
opacity = 0
- base_action = /datum/action/spell_action/spell
var/school = "evocation" //not relevant at now, but may be important later if there are changes to how spells work. the ones I used for now will probably be changed... maybe spell presets? lacking flexibility but with some other benefit?
@@ -151,6 +150,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
action_icon = 'icons/mob/actions/actions_spells.dmi'
action_icon_state = "spell_default"
action_background_icon_state = "bg_spell"
+ base_action = /datum/action/spell_action/spell
/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm
index 69a8ab07b7..07e75002bc 100644
--- a/code/modules/spells/spell_types/construct_spells.dm
+++ b/code/modules/spells/spell_types/construct_spells.dm
@@ -82,7 +82,7 @@
desc = "This spell reaches into Nar-Sie's realm, summoning one of the legendary fragments across time and space."
school = "conjuration"
- charge_max = 3000
+ charge_max = 2400
clothes_req = 0
invocation = "none"
invocation_type = "none"
@@ -95,30 +95,26 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/cult
cult_req = 1
- charge_max = 4000
+ charge_max = 3600
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/noncult
summon_type = list(/obj/item/device/soulstone/anybody)
-
-
-/obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall
+/obj/effect/proc_holder/spell/targeted/forcewall/cult
name = "Shield"
desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire."
-
school = "transmutation"
- charge_max = 300
- clothes_req = 0
+ charge_max = 400
+ clothes_req = FALSE
invocation = "none"
invocation_type = "none"
- range = 0
- summon_type = list(/obj/effect/forcefield/cult)
- summon_lifespan = 200
+ wall_type = /obj/effect/forcefield/cult
action_icon = 'icons/mob/actions/actions_cult.dmi'
action_icon_state = "cultforcewall"
action_background_icon_state = "bg_demon"
+
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift
name = "Phase Shift"
desc = "This spell allows you to pass through walls."
@@ -279,4 +275,38 @@
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/golem
charge_max = 800
jaunt_in_type = /obj/effect/temp_visual/dir_setting/cult/phase
- jaunt_out_type = /obj/effect/temp_visual/dir_setting/cult/phase/out
\ No newline at end of file
+ jaunt_out_type = /obj/effect/temp_visual/dir_setting/cult/phase/out
+
+
+/obj/effect/proc_holder/spell/dumbfire/juggernaut
+ name = "Gauntlet Echo"
+ desc = "Channels energy into your gauntlet - firing its essence forward in a slow-moving but devastating blow."
+ proj_icon_state = "cursehand0"
+ proj_name = "Shadowfist"
+ proj_type = "/obj/effect/proc_holder/spell/targeted/inflict_handler/juggernaut" //IMPORTANT use only subtypes of this
+ proj_lifespan = 15
+ proj_step_delay = 7
+ charge_max = 350
+ clothes_req = FALSE
+ action_icon = 'icons/mob/actions/actions_cult.dmi'
+ action_icon_state = "cultfist"
+ action_background_icon_state = "bg_demon"
+ sound = 'sound/weapons/resonator_blast.ogg'
+ proj_trigger_range = 0
+ ignore_factions = list("cult")
+
+/obj/effect/proc_holder/spell/targeted/inflict_handler/juggernaut
+ name = "Gauntlet Echo"
+ amt_dam_brute = 30
+ amt_knockdown = 50
+ sound = 'sound/weapons/punch3.ogg'
+
+/obj/effect/proc_holder/spell/targeted/inflict_handler/juggernaut/cast(list/targets,mob/user = usr)
+ var/turf/T = get_turf(src)
+ playsound(T, 'sound/weapons/resonator_blast.ogg', 100, FALSE)
+ new /obj/effect/temp_visual/cult/sac(T)
+ for(var/obj/O in range(src,1))
+ if(O.density && !istype(O, /obj/structure/destructible/cult))
+ O.take_damage(90, BRUTE, "gauntlet echo", 0)
+ new /obj/effect/temp_visual/cult/turf/floor
+ ..()
diff --git a/code/modules/spells/spell_types/dumbfire.dm b/code/modules/spells/spell_types/dumbfire.dm
index f86c29fdc2..f4a56fc466 100644
--- a/code/modules/spells/spell_types/dumbfire.dm
+++ b/code/modules/spells/spell_types/dumbfire.dm
@@ -22,6 +22,7 @@
var/proj_lifespan = 100 //in deciseconds * proj_step_delay
var/proj_step_delay = 1 //lower = faster
+ var/list/ignore_factions = list() //Faction types that will be ignored
/obj/effect/proc_holder/spell/dumbfire/choose_targets(mob/user = usr)
@@ -74,8 +75,18 @@
var/mob/living/L = locate(/mob/living) in range(projectile, proj_trigger_range) - user
if(L && L.stat != DEAD)
- projectile.cast(L.loc,user=user)
- break
+ if(!ignore_factions.len)
+ projectile.cast(L.loc,user=user)
+ break
+ else
+ var/faction_check = FALSE
+ for(var/faction in L.faction)
+ if(ignore_factions.Find(faction))
+ faction_check = TRUE
+ break
+ if(!faction_check)
+ projectile.cast(L.loc,user=user)
+ break
if(proj_trail && projectile)
proj_trail(projectile)
diff --git a/code/modules/spells/spell_types/forcewall.dm b/code/modules/spells/spell_types/forcewall.dm
index a9d13728a3..9efbbdf875 100644
--- a/code/modules/spells/spell_types/forcewall.dm
+++ b/code/modules/spells/spell_types/forcewall.dm
@@ -29,7 +29,6 @@
/obj/effect/forcefield/wizard/Initialize(mapload, mob/summoner)
. = ..()
wizard = summoner
- QDEL_IN(src, 300)
/obj/effect/forcefield/wizard/CanPass(atom/movable/mover, turf/target)
if(mover == wizard)
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index 0afa4f225b..42f5adfeca 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -249,10 +249,13 @@
var/bz_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/bz][MOLES])
if(bz_pp > BZ_trip_balls_min)
H.hallucination += 20
+ H.reagents.add_reagent("bz_metabolites",5)
if(prob(33))
H.adjustBrainLoss(3, 150)
+
else if(bz_pp > 0.01)
H.hallucination += 5//Removed at 2 per tick so this will slowly build up
+ H.reagents.add_reagent("bz_metabolites",1)
// Tritium
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 4c4137d52c..3e7e026ef4 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -1061,7 +1061,7 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
/datum/uplink_item/device_tools/potion
name = "Syndicate Sentience Potion"
- item = /obj/item/slimepotion/sentience/nuclear
+ item = /obj/item/slimepotion/slime/sentience/nuclear
desc = "A potion recovered at great risk by undercover syndicate operatives and then subsequently modified with syndicate technology. Using it will make any animal sentient, and bound to serve you, as well as implanting an internal radio for communication and an internal ID card for opening doors."
cost = 4
include_modes = list(/datum/game_mode/nuclear)
@@ -1211,6 +1211,15 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
item = /obj/item/storage/box/hug/reverse_revolver
restricted_roles = list("Clown")
+/datum/uplink_item/role_restricted/reverse_bear_trap
+ name = "Reverse Bear Trap"
+ desc = "An ingenious execution device worn on (or forced onto) the head. Arming it starts a 1-minute kitchen timer mounted on the bear trap. When it goes off, the trap's jaws will \
+ violently open, instantly killing anyone wearing it by tearing their jaws in half. To arm, attack someone with it while they're not wearing headgear, and you will force it onto their \
+ head after three seconds uninterrupted."
+ cost = 5
+ item = /obj/item/device/reverse_bear_trap
+ restricted_roles = list("Clown")
+
/datum/uplink_item/role_restricted/mimery
name = "Guide to Advanced Mimery Series"
desc = "The classical two part series on how to further hone your mime skills. Upon studying the series, the user should be able to make 3x1 invisible walls, and shoot bullets out of their fingers. Obviously only works for Mimes."
@@ -1372,7 +1381,7 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
exclude_modes = list(/datum/game_mode/nuclear)
cant_discount = TRUE
var/starting_crate_value = 50
-
+
/datum/uplink_item/badass/surplus/super
name = "Super Surplus Crate"
desc = "A dusty SUPER-SIZED from the back of the Syndicate warehouse. Rumored to contain a valuable assortment of items, \