Merge remote-tracking branch 'upstream/master'

This commit is contained in:
DeltaFire
2021-08-03 03:31:38 +02:00
223 changed files with 138456 additions and 132405 deletions
@@ -13,5 +13,5 @@
//Recover from stuns.
/obj/effect/proc_holder/changeling/adrenaline/sting_action(mob/living/user)
user.do_adrenaline(0, FALSE, 70, 0, TRUE, list(/datum/reagent/medicine/epinephrine = 3, /datum/reagent/drug/methamphetamine/changeling = 10, /datum/reagent/medicine/changelingadrenaline = 5), "<span class='notice'>Energy rushes through us.</span>", 0, 0.75, 0)
user.do_adrenaline(0, FALSE, 70, 0, TRUE, list(/datum/reagent/medicine/epinephrine = 3, /datum/reagent/medicine/changelinghaste = 10, /datum/reagent/medicine/changelingadrenaline = 5), "<span class='notice'>Energy rushes through us.</span>", 0, 0.75, 0)
return TRUE
@@ -13,7 +13,7 @@
if(!air)
return
if (air.get_oxidation_power(exposed_temperature) < 0.5)
if (air.get_oxidation_power(exposed_temperature) < 0.5 || air.get_moles(GAS_HYPERNOB) > 5)
return
var/has_fuel = air.get_moles(GAS_PLASMA) > 0.5 || air.get_moles(GAS_TRITIUM) > 0.5 || air.get_fuel_amount(exposed_temperature) > 0.5
if(active_hotspot)
@@ -152,7 +152,7 @@
if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1))
qdel(src)
return
if(!location.air || location.air.get_oxidation_power() < 0.5 || (INSUFFICIENT(GAS_PLASMA) && INSUFFICIENT(GAS_TRITIUM) && location.air.get_fuel_amount() < 0.5))
if(!location.air || location.air.get_moles(GAS_HYPERNOB) > 5 || location.air.get_oxidation_power() < 0.5 || (INSUFFICIENT(GAS_PLASMA) && INSUFFICIENT(GAS_TRITIUM) && location.air.get_fuel_amount() < 0.5))
qdel(src)
return
@@ -1,6 +1,6 @@
/obj/machinery/atmospherics/pipe/heat_exchanging
level = 2
var/minimum_temperature_difference = 20
var/minimum_temperature_difference = 0.01
var/thermal_conductivity = WINDOW_HEAT_TRANSFER_COEFFICIENT
color = "#404040"
buckle_lying = 1
@@ -433,7 +433,7 @@
var/list/danger = list()
for(var/id in air_contents.get_gases())
var/gas = air_contents.get_moles(id)
if(!GLOB.gas_data.flags[id] & GAS_FLAG_DANGEROUS)
if(!(GLOB.gas_data.flags[id] & GAS_FLAG_DANGEROUS))
continue
if(gas > (GLOB.gas_data.visibility[id] || MOLES_GAS_VISIBLE)) //if moles_visible is undefined, default to default visibility
danger[GLOB.gas_data.names[id]] = gas //ex. "plasma" = 20
+5
View File
@@ -187,6 +187,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/vore_flags = 0
var/list/belly_prefs = list()
var/vore_taste = "nothing in particular"
var/vore_smell = null
var/toggleeatingnoise = TRUE
var/toggledigestionnoise = TRUE
var/hound_sleeper = TRUE
@@ -1068,6 +1069,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Voracious MediHound sleepers:</b> <a href='?_src_=prefs;preference=hound_sleeper'>[(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"]</a><br>"
dat += "<b>Hear Vore Sounds:</b> <a href='?_src_=prefs;preference=toggleeatingnoise'>[(cit_toggles & EATING_NOISES) ? "Yes" : "No"]</a><br>"
dat += "<b>Hear Vore Digestion Sounds:</b> <a href='?_src_=prefs;preference=toggledigestionnoise'>[(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"]</a><br>"
dat += "<b>Allow trash forcefeeding (requires Trashcan quirk)</b> <a href='?_src_=prefs;preference=toggleforcefeedtrash'>[(cit_toggles & TRASH_FORCEFEED) ? "Yes" : "No"]</a><br>"
dat += "<b>Forced Feminization:</b> <a href='?_src_=prefs;preference=feminization'>[(cit_toggles & FORCED_FEM) ? "Allowed" : "Disallowed"]</a><br>"
dat += "<b>Forced Masculinization:</b> <a href='?_src_=prefs;preference=masculinization'>[(cit_toggles & FORCED_MASC) ? "Allowed" : "Disallowed"]</a><br>"
dat += "<b>Lewd Hypno:</b> <a href='?_src_=prefs;preference=hypno'>[(cit_toggles & HYPNO) ? "Allowed" : "Disallowed"]</a><br>"
@@ -2800,6 +2802,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("toggledigestionnoise")
cit_toggles ^= DIGESTION_NOISES
if("toggleforcefeedtrash")
cit_toggles ^= TRASH_FORCEFEED
if("breast_enlargement")
cit_toggles ^= BREAST_ENLARGEMENT
@@ -821,6 +821,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["vore_flags"] >> vore_flags
S["vore_taste"] >> vore_taste
S["vore_smell"] >> vore_smell
var/char_vr_path = "[vr_path]/character_[default_slot]_v2.json"
if(fexists(char_vr_path))
var/list/json_from_file = json_decode(file2text(char_vr_path))
@@ -994,6 +995,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
vore_flags = sanitize_integer(vore_flags, 0, MAX_VORE_FLAG, 0)
vore_taste = copytext(vore_taste, 1, MAX_TASTE_LEN)
vore_smell = copytext(vore_smell, 1, MAX_TASTE_LEN)
belly_prefs = SANITIZE_LIST(belly_prefs)
cit_character_pref_load(S)
@@ -1147,6 +1149,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["vore_flags"] , vore_flags)
WRITE_FILE(S["vore_taste"] , vore_taste)
WRITE_FILE(S["vore_smell"] , vore_smell)
var/char_vr_path = "[vr_path]/character_[default_slot]_v2.json"
var/belly_prefs_json = safe_json_encode(list("belly_prefs" = belly_prefs))
if(fexists(char_vr_path))
+6
View File
@@ -482,3 +482,9 @@
icon_state = "kabuto"
item_state = "kabuto"
flags_inv = HIDEHAIR|HIDEEARS
/obj/item/clothing/head/human_leather
name = "human skin hat"
desc = "This will scare them. All will know my power."
icon_state = "human_leather"
item_state = "human_leather"
+2 -2
View File
@@ -103,14 +103,14 @@
. = ..()
AddElement(/datum/element/polychromic, poly_colors, 3)
/obj/item/clothing/neck/cancloak/polychromic
/obj/item/clothing/neck/cloak/cancloak/polychromic
name = "canvas cloak"
desc = "A rugged cloak made of canvas."
icon_state = "cancloak"
item_state = "cloak"
var/list/poly_colors = list("#585858", "#373737", "#BEBEBE")
/obj/item/clothing/neck/cancloak/polychromic/ComponentInitialize()
/obj/item/clothing/neck/cloak/cancloak/polychromic/ComponentInitialize()
. = ..()
AddElement(/datum/element/polychromic, poly_colors, 3)
+1 -1
View File
@@ -5,7 +5,7 @@
weight = 8
/datum/round_event/cat_surgeon/announce(fake)
priority_announce("One of our... ahem... 'special' cases has escaped. Our sensors now show their tracker implant on your station. On an unrelated note, has anyone seen our cats?",
priority_announce("One of our... ahem... 'special' cases has escaped. As it happens their last known location before their tracker went dead is your station so keep an eye out for them. On an unrelated note, has anyone seen our cats?",
sender_override = "Nanotrasen Psych Ward")
/datum/round_event/cat_surgeon/start()
+1 -1
View File
@@ -31,7 +31,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
if(!hallucination)
return
hallucination--
hallucination = max(hallucination-1, 0)
if(world.time < next_hallucination)
return
@@ -468,7 +468,7 @@
/obj/item/reagent_containers/medspray/sterilizine = 1)
/obj/machinery/smartfridge/organ/preloaded/Initialize()
..()
. = ..()
var/list = list(/obj/item/organ/tongue, /obj/item/organ/brain, /obj/item/organ/heart, /obj/item/organ/liver, /obj/item/organ/ears, /obj/item/organ/eyes, /obj/item/organ/tail, /obj/item/organ/stomach)
var/newtype = pick(list)
load(new newtype(src.loc))
@@ -73,3 +73,40 @@
icon_state = "barrel_open"
else
icon_state = "barrel"
/obj/structure/custom_keg
name = "Plasteel Keg"
desc = "A large plasteel keg. You can use it to hold liquids. You may wanna label this, too."
icon = 'icons/obj/objects.dmi'
icon_state = "keg"
density = TRUE
anchored = FALSE
pressure_resistance = 2 * ONE_ATMOSPHERE
max_integrity = 300
var/open = FALSE
/obj/structure/custom_keg/Initialize()
create_reagents(1000, DRAINABLE | AMOUNT_VISIBLE)
. = ..()
/obj/structure/custom_keg/examine(mob/user)
. = ..()
. += "<span class='notice'>It is currently [open?"open, letting you pour liquids in.":"closed, letting you draw liquids from the tap."]</span>"
/obj/structure/custom_keg/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
open = !open
if(open)
DISABLE_BITFIELD(reagents.reagents_holder_flags, DRAINABLE)
ENABLE_BITFIELD(reagents.reagents_holder_flags, REFILLABLE)
to_chat(user, "<span class='notice'>You open [src], letting you fill it.</span>")
else
DISABLE_BITFIELD(reagents.reagents_holder_flags, REFILLABLE)
ENABLE_BITFIELD(reagents.reagents_holder_flags, DRAINABLE)
to_chat(user, "<span class='notice'>You close [src], letting you draw from its tap.</span>")
update_icon()
/obj/structure/custom_keg/update_icon_state()
if(open)
icon_state = "keg_open"
else
icon_state = "keg"
@@ -19,7 +19,7 @@
/obj/item/integrated_circuit/atmospherics/Initialize()
air_contents = new(volume)
..()
return ..()
/obj/item/integrated_circuit/atmospherics/return_air()
return air_contents
@@ -679,7 +679,7 @@
icon_state = "crow"
matrixed_sections = MATRIX_RED
/datum/sprite_accessory/tails/mam_tail/cow
/datum/sprite_accessory/tails/mam_tails/cow
name = "Cow"
icon_state = "cow"
matrixed_sections = MATRIX_RED
+11 -3
View File
@@ -358,7 +358,7 @@
return
I.item_flags |= BEING_REMOVED
breakouttime = I.breakouttime
var/datum/cuffbreak_checker/cuffbreak_checker = new(get_turf(src))
var/datum/cuffbreak_checker/cuffbreak_checker = new(get_turf(src), istype(I, /obj/item/restraints)? I : null)
if(!cuff_break)
visible_message("<span class='warning'>[src] attempts to remove [I]!</span>")
to_chat(src, "<span class='notice'>You attempt to remove [I]... (This will take around [DisplayTimeText(breakouttime)] and you need to stand still.)</span>")
@@ -384,16 +384,22 @@
/datum/cuffbreak_checker
var/turf/last
var/obj/item/restraints/cuffs
/datum/cuffbreak_checker/New(turf/initial_turf)
/datum/cuffbreak_checker/New(turf/initial_turf, obj/item/restraints/R)
last = initial_turf
if(R)
cuffs = R
/datum/cuffbreak_checker/proc/check_movement(atom/user, delay, atom/target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, list/passed_in)
if(get_turf(user) != last)
last = get_turf(user)
passed_in[1] = 0.5
if(cuffs && !cuffs.allow_breakout_movement)
return DO_AFTER_STOP
else
passed_in[1] = 1
return DO_AFTER_CONTINUE
/mob/living/carbon/proc/uncuff()
if (handcuffed)
@@ -961,7 +967,9 @@
/mob/living/carbon/ExtinguishMob()
for(var/X in get_equipped_items())
var/obj/item/I = X
I.acid_level = 0 //washes off the acid on our clothes
var/datum/component/acid/acid = I.GetComponent(/datum/component/acid)
if(acid)
acid.level = 0
I.extinguish() //extinguishes our clothes
..()
@@ -1101,9 +1101,9 @@
if(HAS_TRAIT(src, TRAIT_TOXINLOVER))
return "<font color='#00ffff'>"
if(isplasmaman(src))
return "<font color='#800080'"
return "<font color='#800080'>"
if(isgolem(src))
return "<font color='#8b4513'"
return "<font color='#8b4513'>"
return "<font color='#18d855'>"
@@ -15,7 +15,6 @@
block_parry_data = /datum/block_parry_data/unarmed/human
default_block_parry_data = /datum/block_parry_data/unarmed/human
causes_dirt_buildup_on_floor = TRUE
//Hair colour and style
var/hair_color = "000"
@@ -52,6 +51,9 @@
var/obj/item/l_store = null
var/obj/item/s_store = null
/// When an braindead player has their equipment fiddled with, we log that info here for when they come back so they know who took their ID while they were DC'd for 30 seconds
var/list/afk_thefts
var/special_voice = "" // For changing our voice. Used by a symptom.
var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding
@@ -90,13 +90,31 @@
//End bloody footprints
S.step_action()
if(movement_type & GROUND)
dirt_buildup()
/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee.
if(dna.species.space_move(src))
return TRUE
return ..()
/mob/living/carbon/human/dirt_buildup(strength)
/mob/living/carbon/human/proc/dirt_buildup(strength = 1)
if(!shoes || !(shoes.body_parts_covered & FEET))
return // barefoot advantage
return ..()
var/turf/open/T = loc
if(!istype(T) || !T.dirt_buildup_allowed)
return
var/area/A = T.loc
if(!A.dirt_buildup_allowed)
return
var/multiplier = CONFIG_GET(number/turf_dirty_multiplier)
strength *= multiplier
var/obj/effect/decal/cleanable/dirt/D = locate() in T
if(D)
D.dirty(strength)
else
T.dirtyness += strength
if(T.dirtyness >= (isnull(T.dirt_spawn_threshold)? CONFIG_GET(number/turf_dirt_threshold) : T.dirt_spawn_threshold))
D = new /obj/effect/decal/cleanable/dirt(T)
D.dirty(T.dirt_spawn_threshold - T.dirtyness)
T.dirtyness = 0 // reset.
@@ -2,3 +2,33 @@
..()
if(dna?.species?.has_field_of_vision && CONFIG_GET(flag/use_field_of_vision))
LoadComponent(/datum/component/field_of_vision, field_of_vision_type)
if(!LAZYLEN(afk_thefts))
return
var/list/print_msg = list()
print_msg += "<span class='info'>*---------*</span>"
print_msg += "<span class='userdanger'>As you snap back to consciousness, you recall people messing with your stuff...</span>"
afk_thefts = reverseRange(afk_thefts)
for(var/list/iter_theft as anything in afk_thefts)
if(!islist(iter_theft) || LAZYLEN(iter_theft) != AFK_THEFT_TIME)
stack_trace("[src] ([ckey]) returned to their body and had a null/malformed afk_theft entry. Contents: [json_encode(iter_theft)]")
continue
var/thief_name = iter_theft[AFK_THEFT_NAME]
var/theft_message = iter_theft[AFK_THEFT_MESSAGE]
var/time_since = world.time - iter_theft[AFK_THEFT_TIME]
if(time_since > AFK_THEFT_FORGET_DETAILS_TIME)
print_msg += "\t<span class='danger'><b>Someone [theft_message], but it was at least [DisplayTimeText(AFK_THEFT_FORGET_DETAILS_TIME)] ago.</b></span>"
else
print_msg += "\t<span class='danger'><b>[thief_name] [theft_message] roughly [DisplayTimeText(time_since, 10)] ago.</b></span>"
if(LAZYLEN(afk_thefts) >= AFK_THEFT_MAX_MESSAGES)
print_msg += "<span class='warning'>There may have been more, but that's all you can remember...</span>"
print_msg += "<span class='info'>*---------*</span>"
to_chat(src, print_msg.Join("\n"))
LAZYNULL(afk_thefts)
@@ -439,6 +439,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
* * pref_load - Preferences to be loaded from character setup, loads in preferred mutant things like bodyparts, digilegs, skin color, etc.
*/
/datum/species/proc/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load)
set waitfor = FALSE
// Drop the items the new species can't wear
for(var/slot_id in no_equip)
var/obj/item/thing = C.get_item_by_slot(slot_id)
+11 -11
View File
@@ -1,6 +1,6 @@
/mob/living/carbon/BiologicalLife(seconds, times_fired)
//Reagent processing needs to come before breathing, to prevent edge cases.
handle_organs()
handle_organs(seconds, times_fired)
. = ..() // if . is false, we are dead.
if(stat == DEAD)
stop_sound_channel(CHANNEL_HEARTBEAT)
@@ -23,7 +23,7 @@
handle_brain_damage()
if(stat != DEAD)
handle_liver()
handle_liver(seconds, times_fired)
if(stat != DEAD)
handle_corruption()
@@ -378,25 +378,25 @@
/mob/living/carbon/proc/handle_blood()
return
/mob/living/carbon/proc/handle_bodyparts()
/mob/living/carbon/proc/handle_bodyparts(seconds, times_fired)
for(var/I in bodyparts)
var/obj/item/bodypart/BP = I
if(BP.needs_processing)
. |= BP.on_life()
. |= BP.on_life(seconds, times_fired)
/mob/living/carbon/proc/handle_organs()
/mob/living/carbon/proc/handle_organs(seconds, times_fired)
if(stat != DEAD)
for(var/V in internal_organs)
var/obj/item/organ/O = V
if(O)
O.on_life()
O.on_life(seconds, times_fired)
else
if(reagents.has_reagent(/datum/reagent/toxin/formaldehyde, 1) || reagents.has_reagent(/datum/reagent/preservahyde, 1)) // No organ decay if the body contains formaldehyde. Or preservahyde.
return
for(var/V in internal_organs)
var/obj/item/organ/O = V
if(O)
O.on_death() //Needed so organs decay while inside the body.
O.on_death(seconds, times_fired) //Needed so organs decay while inside the body.
/mob/living/carbon/handle_diseases()
for(var/thing in diseases)
@@ -687,16 +687,16 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
//LIVER//
/////////
/mob/living/carbon/proc/handle_liver()
/mob/living/carbon/proc/handle_liver(seconds, times_fired)
var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
if((!dna && !liver) || (NOLIVER in dna.species.species_traits))
return
if(!liver || liver.organ_flags & ORGAN_FAILING)
liver_failure()
liver_failure(seconds, times_fired)
/mob/living/carbon/proc/liver_failure()
/mob/living/carbon/proc/liver_failure(seconds, times_fired)
reagents.end_metabolization(src, keep_liverless = TRUE) //Stops trait-based effects on reagents, to prevent permanent buffs
reagents.metabolize(src, can_overdose=FALSE, liverless = TRUE)
reagents.metabolize(src, seconds, times_fired, can_overdose=FALSE, liverless = TRUE)
if(HAS_TRAIT(src, TRAIT_STABLELIVER))
return
adjustToxLoss(4, TRUE, TRUE)
@@ -173,4 +173,4 @@
if(prob(10))
var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src)
equip_to_slot_or_del(helmet,SLOT_HEAD)
helmet.attack_self(src) // todo encapsulate toggle
INVOKE_ASYNC(helmet, /obj/item.proc/attack_self, src) // todo encapsulate toggle
+13
View File
@@ -911,6 +911,12 @@
"<span class='userdanger'>[src] tries to remove your [what.name].</span>", target = src,
target_message = "<span class='danger'>You try to remove [who]'s [what.name].</span>")
what.add_fingerprint(src)
if(ishuman(who))
var/mob/living/carbon/human/victim_human = who
if(victim_human.key && !victim_human.client) // AKA braindead
if(victim_human.stat <= SOFT_CRIT && LAZYLEN(victim_human.afk_thefts) <= AFK_THEFT_MAX_MESSAGES)
var/list/new_entry = list(list(src.name, "tried unequipping your [what]", world.time))
LAZYADD(victim_human.afk_thefts, new_entry)
else
to_chat(src,"<span class='notice'>You try to remove [who]'s [what.name].</span>")
what.add_fingerprint(src)
@@ -957,6 +963,13 @@
to_chat(src, "<span class='warning'>\The [what.name] doesn't fit in that place!</span>")
return
if(ishuman(who))
var/mob/living/carbon/human/victim_human = who
if(victim_human.key && !victim_human.client) // AKA braindead
if(victim_human.stat <= SOFT_CRIT && LAZYLEN(victim_human.afk_thefts) <= AFK_THEFT_MAX_MESSAGES)
var/list/new_entry = list(list(src.name, "tried equipping you with [what]", world.time))
LAZYADD(victim_human.afk_thefts, new_entry)
who.visible_message("<span class='notice'>[src] tries to put [what] on [who].</span>",
"<span class='notice'>[src] tries to put [what] on you.</span>", target = src,
target_message = "<span class='notice'>You try to put [what] on [who].</span>")
@@ -67,8 +67,6 @@
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
var/incorporeal_move = FALSE //FALSE is off, INCORPOREAL_MOVE_BASIC is normal, INCORPOREAL_MOVE_SHADOW is for ninjas
//and INCORPOREAL_MOVE_JAUNT is blocked by holy water/salt
/// Do we make floors dirty as we move?
var/causes_dirt_buildup_on_floor = FALSE
var/list/roundstart_quirks = list()
@@ -102,31 +102,6 @@
if(lying && !buckled && prob(getBruteLoss()*200/maxHealth))
makeTrail(newloc, T, old_direction)
if(causes_dirt_buildup_on_floor && (movement_type & GROUND))
dirt_buildup()
/**
* Attempts to make the floor dirty.
*/
/mob/living/proc/dirt_buildup(strength = 1)
var/turf/open/T = loc
if(!istype(T) || !T.dirt_buildup_allowed)
return
var/area/A = T.loc
if(!A.dirt_buildup_allowed)
return
var/multiplier = CONFIG_GET(number/turf_dirty_multiplier)
strength *= multiplier
var/obj/effect/decal/cleanable/dirt/D = locate() in T
if(D)
D.dirty(strength)
else
T.dirtyness += strength
if(T.dirtyness >= (isnull(T.dirt_spawn_threshold)? CONFIG_GET(number/turf_dirt_threshold) : T.dirt_spawn_threshold))
D = new /obj/effect/decal/cleanable/dirt(T)
D.dirty(T.dirt_spawn_threshold - T.dirtyness)
T.dirtyness = 0 // reset.
/mob/living/Move_Pulled(atom/A)
. = ..()
if(!. || !isliving(A))
@@ -966,7 +966,8 @@
upgrades.Cut()
speed = 0
vtec = 0
vtec_disabled = FALSE
ionpulse = FALSE
revert_shell()
@@ -82,6 +82,18 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
if(!opened)
return ..()
/mob/living/silicon/robot/disarm_shove(mob/living/carbon/human/H)
visible_message(span_danger("[src]'s motors grind as they are shoved by [H]!"))
vtec_disable(10 SECONDS)
/mob/living/silicon/robot/proc/vtec_disable(time)
var/datum/status_effect/vtec_disabled/V = has_status_effect(/datum/status_effect/vtec_disabled)
if(V)
V.duration = max(V.duration, world.time + time)
else
apply_status_effect(/datum/status_effect/vtec_disabled, time)
update_movespeed()
/mob/living/silicon/robot/fire_act()
if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
IgniteMob()
@@ -61,7 +61,9 @@
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list())
var/speed = 0 // VTEC speed boost.
var/vtec = 0 // VTEC speed boost.
/// vtec shorted out
var/vtec_disabled = FALSE
var/magpulse = FALSE // Magboot-like effect.
var/ionpulse = FALSE // Jetpack-like effect.
var/ionpulse_on = FALSE // Jetpack-like effect.
@@ -23,4 +23,4 @@
. = ..()
if(!resting && !(combat_flags & COMBAT_FLAG_SPRINT_ACTIVE))
. += 1
. += speed
. += vtec_disabled? 0 : vtec
@@ -79,6 +79,8 @@
M.visible_message("[M] pets [src].", \
"<span class='notice'>You pet [src].</span>", target = src,
target_message = "[M] pets you.")
if(INTENT_DISARM)
disarm_shove(M)
if(INTENT_GRAB)
grabbedby(M)
else
@@ -88,6 +90,9 @@
"<span class='warning'>[M] punches you, but doesn't leave a dent.</span>", null, COMBAT_MESSAGE_RANGE, null, M,
"<span class='danger'>You punch [src], but don't leave a dent.</span>")
/mob/living/silicon/proc/disarm_shove(mob/living/carbon/human/H)
visible_message(span_danger("[H] shoves [src], but doesn't manage to make much of an effect."))
/mob/living/silicon/attack_drone(mob/living/simple_animal/drone/M)
if(M.a_intent == INTENT_HARM)
return
@@ -33,7 +33,7 @@
/mob/living/simple_animal/bot/secbot/grievous/Initialize()
. = ..()
weapon = new baton_type(src)
weapon.attack_self(src)
INVOKE_ASYNC(weapon, /obj/item.proc/attack_self, src)
/mob/living/simple_animal/bot/secbot/grievous/Destroy()
QDEL_NULL(weapon)
@@ -381,6 +381,7 @@
..()
/mob/living/simple_animal/pet/dog/corgi/Ian/proc/Read_Memory()
set waitfor = FALSE
if(fexists("data/npc_saves/Ian.sav")) //legacy compatability to convert old format to new
var/savefile/S = new /savefile("data/npc_saves/Ian.sav")
S["age"] >> age
@@ -364,11 +364,10 @@
/mob/living/simple_animal/hostile/proc/AttackingTarget()
SEND_SIGNAL(src, COMSIG_HOSTILE_ATTACKINGTARGET, target)
in_melee = TRUE
/* sorry for the simplemob vore fans
if(vore_active)
if(isliving(target))
var/mob/living/L = target
if(!client && L.Adjacent(src) && CHECK_BITFIELD(L.vore_flags,DEVOURABLE)) // aggressive check to ensure vore attacks can be made
if(!client && L.Adjacent(src) && CHECK_BITFIELD(L.vore_flags, DEVOURABLE) && CHECK_BITFIELD(L.vore_flags, MOBVORE)) // aggressive check to ensure vore attacks can be made
if(prob(voracious_chance))
vore_attack(src,L,src)
else
@@ -379,7 +378,6 @@
return target.attack_animal(src)
else
return target.attack_animal(src)
*/
return target.attack_animal(src)
/mob/living/simple_animal/hostile/proc/Aggro()
@@ -35,14 +35,16 @@
coffer.Grant(src)
riot = new /datum/action/cooldown/riot
riot.Grant(src)
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
INVOKE_ASYNC(src, .proc/poll_for_player)
/mob/living/simple_animal/hostile/regalrat/proc/poll_for_player()
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the Royal Rat, cheesey be his crown?", ROLE_SENTIENCE, null, FALSE, 100, POLL_IGNORE_SENTIENCE_POTION)
if(LAZYLEN(candidates) && !mind)
var/mob/dead/observer/C = pick(candidates)
key = C.key
notify_ghosts("All rise for the rat king, ascendant to the throne in \the [get_area(src)].", source = src, action = NOTIFY_ORBIT, flashwindow = FALSE)
AddElement(/datum/element/ventcrawling, given_tier = VENTCRAWLER_ALWAYS)
/mob/living/simple_animal/hostile/regalrat/handle_automated_action()
if(prob(20))
riot.Trigger()
@@ -30,6 +30,7 @@
setup_visuals()
/mob/living/simple_animal/hostile/zombie/proc/setup_visuals()
set waitfor = FALSE
var/datum/preferences/dummy_prefs = new
dummy_prefs.pref_species = new /datum/species/zombie
dummy_prefs.be_random_body = TRUE
+7 -26
View File
@@ -144,33 +144,14 @@
message = "<span class='emote'><b>[user]</b> <i>[user.say_emphasis(message)]</i></span>"
var/list/show_to = list()
var/list/processing = list()
var/safety = 25
var/list/processed = list()
for(var/obj/structure/table/T in range(user, 1))
processing |= T
for(var/i = 1; i <= processing.len; ++i)
var/obj/structure/table/T = processing[i]
if(safety-- <= 0)
to_chat(user, "Table scan aborted early, some people might have not received the message (max 25)")
break
if(get_dist(T, user) > 7)
continue // nah
processing |= T
for(var/mob/living/M in range(T, 1)) // no ghosts/cameramobs
show_to |= M
var/obj/structure/table/other
other = locate() in get_step(T, NORTH)
if(other)
processing |= other
other = locate() in get_step(T, SOUTH)
if(other)
processing |= other
other = locate() in get_step(T, WEST)
if(other)
processing |= other
other = locate() in get_step(T, EAST)
if(other)
processing |= other
if(processed[T])
continue
for(var/obj/structure/table/T2 in T.connected_floodfill(25))
processed[T2] = TRUE
for(var/mob/living/L in range(T2, 1))
show_to |= L
for(var/i in show_to)
var/mob/M = i
+45 -9
View File
@@ -2,17 +2,53 @@
blacklisted_movetypes = (FLYING|FLOATING)
/datum/movespeed_modifier/reagent/stimulants
multiplicative_slowdown = -0.5
multiplicative_slowdown = -0.55
/datum/movespeed_modifier/reagent/ephedrine
// strong painkiller effect that caps out at slightly above runspeed
multiplicative_slowdown = -1.5
priority = -100
complex_calculation = TRUE
absolute_max_tiles_per_second = 7
/datum/movespeed_modifier/reagent/pepperspray
multiplicative_slowdown = 0.25
/datum/movespeed_modifier/reagent/monkey_energy
multiplicative_slowdown = -0.35
/datum/movespeed_modifier/reagent/changelinghaste
multiplicative_slowdown = -2
// extremely strong painkiller effect: allows user to run at old sprint speeds but not over by cancelling out slowdowns.
// however, will not make user go faster than that
multiplicative_slowdown = -4
priority = -100
complex_calculation = TRUE
absolute_max_tiles_per_second = 8
/datum/movespeed_modifier/reagent/methamphetamine
// very strong painkiller effect that caps out at slightly above runspeed
multiplicative_slowdown = -2.5
priority = -100
complex_calculation = TRUE
absolute_max_tiles_per_second = 7.5
/datum/movespeed_modifier/reagent/nitryl
multiplicative_slowdown = -0.65
/datum/movespeed_modifier/reagent/freon
multiplicative_slowdown = 1.6
/datum/movespeed_modifier/reagent/halon
multiplicative_slowdown = 1.8
/datum/movespeed_modifier/reagent/lenturi
multiplicative_slowdown = 1.5
/datum/movespeed_modifier/reagent/nuka_cola
multiplicative_slowdown = -0.35
/datum/movespeed_modifier/reagent/nooartrium
multiplicative_slowdown = 2
/datum/movespeed_modifier/reagent/skooma
multiplicative_slowdown = -1
/datum/movespeed_modifier/reagent/nitryl
multiplicative_slowdown = -1
/datum/movespeed_modifier/reagent/meth
multiplicative_slowdown = -0.5
absolute_max_tiles_per_second = 11
@@ -51,3 +51,11 @@
/datum/movespeed_modifier/status_effect/off_balance
variable = TRUE
/datum/movespeed_modifier/status_effect/slime/light_pink
// decently good painkiller + speedup effect
blacklisted_movetypes = FLYING | FLOATING
priority = -150 // someday we really need to make these defines lmao
multiplicative_slowdown = -2
complex_calculation = TRUE
absolute_max_tiles_per_second = 7
+9 -6
View File
@@ -77,6 +77,11 @@ Contents:
cell.name = "black power cell"
cell.icon_state = "bscell"
/obj/item/clothing/suit/space/space_ninja/Destroy()
if(affecting)
unlock_suit()
return ..()
//Simply deletes all the attachments and self, killing all related procs.
/obj/item/clothing/suit/space/space_ninja/proc/terminate()
qdel(n_hood)
@@ -84,7 +89,6 @@ Contents:
qdel(n_shoes)
qdel(src)
//Randomizes suit parameters.
/obj/item/clothing/suit/space/space_ninja/proc/randomize_param()
s_cost = rand(1,20)
@@ -93,7 +97,6 @@ Contents:
s_bombs = rand(5,20)
a_boost = rand(1,7)
//This proc prevents the suit from being taken off.
/obj/item/clothing/suit/space/space_ninja/proc/lock_suit(mob/living/carbon/human/H)
if(!istype(H))
@@ -113,14 +116,14 @@ Contents:
return FALSE
affecting = H
ADD_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT) //colons make me go all |=
slowdown = 0
n_hood = H.head
ADD_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT)
n_shoes = H.shoes
ADD_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT)
n_shoes.slowdown -= 0.5
n_shoes.slowdown = -0.25
n_gloves = H.gloves
ADD_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT)
ADD_TRAIT(affecting, TRAIT_TASED_RESISTANCE, NINJA_SUIT_TRAIT)
return TRUE
/obj/item/clothing/suit/space/space_ninja/proc/lockIcons(mob/living/carbon/human/H)
@@ -133,19 +136,19 @@ Contents:
/obj/item/clothing/suit/space/space_ninja/proc/unlock_suit()
affecting = null
REMOVE_TRAIT(src, TRAIT_NODROP, NINJA_SUIT_TRAIT)
slowdown = 1
icon_state = "s-ninja"
if(n_hood)//Should be attached, might not be attached.
REMOVE_TRAIT(n_hood, TRAIT_NODROP, NINJA_SUIT_TRAIT)
if(n_shoes)
REMOVE_TRAIT(n_shoes, TRAIT_NODROP, NINJA_SUIT_TRAIT)
n_shoes.slowdown += 0.5
n_shoes.slowdown = 0.25
if(n_gloves)
n_gloves.icon_state = "s-ninja"
n_gloves.item_state = "s-ninja"
REMOVE_TRAIT(n_gloves, TRAIT_NODROP, NINJA_SUIT_TRAIT)
n_gloves.candrain=0
n_gloves.draining=0
REMOVE_TRAIT(affecting, TRAIT_TASED_RESISTANCE, NINJA_SUIT_TRAIT)
/obj/item/clothing/suit/space/space_ninja/examine(mob/user)
@@ -241,7 +241,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
///How much the bullets damage should be multiplied by when it is added to the internal variables
var/bullet_energy = 2
///How much hallucination should we produce per unit of power?
var/hallucination_power = 0.1
var/hallucination_power = 0.05 // 2 seconds per second at a distance of 7 with a typical nitrogen setup
///Our internal radio
var/obj/item/radio/radio
@@ -648,6 +648,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
for(var/mob/living/carbon/human/l in fov_viewers(src, HALLUCINATION_RANGE(power))) // If they can see it without mesons on. Bad on them.
if(!istype(l.glasses, /obj/item/clothing/glasses/meson))
var/D = sqrt(1 / max(1, get_dist(l, src)))
if(!l.hallucination)
to_chat(l, "<span class='warning'>Looking at the supermatter unprotected gives you a headache...</span>")
l.hallucination += power * hallucination_power * D
l.hallucination = clamp(l.hallucination, 0, 200)
for(var/mob/living/l in range(src, round((power / 100) ** 0.25)))
@@ -32,12 +32,13 @@
/obj/item/ammo_casing/energy/temp
projectile_type = /obj/item/projectile/temp
select_name = "freeze"
e_cost = 250
e_cost = 50 // twenty shots before emptying
fire_sound = 'sound/weapons/pulse3.ogg'
/obj/item/ammo_casing/energy/temp/hot
projectile_type = /obj/item/projectile/temp/hot
select_name = "bake"
fire_sound = 'sound/weapons/pulse2.ogg'
/obj/item/ammo_casing/energy/meteor
projectile_type = /obj/item/projectile/meteor
@@ -310,9 +310,10 @@
/obj/item/gun/energy/temperature
name = "temperature gun"
icon_state = "freezegun"
item_state = null
desc = "A gun that changes temperatures."
ammo_type = list(/obj/item/ammo_casing/energy/temp, /obj/item/ammo_casing/energy/temp/hot)
cell_type = "/obj/item/stock_parts/cell/high"
shaded_charge = TRUE
pin = null
/obj/item/gun/energy/temperature/security
@@ -114,7 +114,7 @@
can_unsuppress = FALSE
/obj/item/gun/syringe/dart/Initialize()
..()
. = ..()
chambered = new /obj/item/ammo_casing/syringegun/dart(src)
/obj/item/gun/syringe/dart/attackby(obj/item/A, mob/user, params, show_msg = TRUE)
@@ -31,6 +31,11 @@
else if(tase_duration && (C.status_flags & CANKNOCKDOWN) && !HAS_TRAIT(C, TRAIT_STUNIMMUNE) && !HAS_TRAIT(C, TRAIT_TASED_RESISTANCE))
C.apply_status_effect(strong_tase? STATUS_EFFECT_TASED : STATUS_EFFECT_TASED_WEAK, tase_duration)
addtimer(CALLBACK(C, /mob/living/carbon.proc/do_jitter_animation, jitter), 5)
else if(iscyborg(target))
target.visible_message(span_danger("A shower of sparks emit from [target] on impact from [src]!"))
do_sparks(1, TRUE, target)
var/mob/living/silicon/robot/R = target
R.vtec_disable(10 SECONDS)
/obj/item/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet
do_sparks(1, TRUE, src)
@@ -1,9 +1,17 @@
/obj/item/projectile/temp
name = "freeze beam"
icon_state = "ice_2"
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
damage = 0
light_range = 2
damage_type = BURN
nodamage = FALSE
hitsound = 'sound/weapons/frost.ogg'
hitsound_wall = 'sound/weapons/frost.ogg'
ricochets_max = 50 //Honk!
ricochet_chance = 80
is_reflectable = TRUE
light_color = LIGHT_COLOR_BLUE
flag = "energy"
var/temperature = 100
@@ -15,7 +23,12 @@
/obj/item/projectile/temp/hot
name = "heat beam"
icon_state = "lava"
damage = 10
hitsound = 'sound/weapons/sear.ogg'
hitsound_wall = 'sound/weapons/effects/searwall.ogg'
temperature = 400
light_color = LIGHT_COLOR_RED
/obj/item/projectile/temp/cryo
name = "cryo beam"
+92 -64
View File
@@ -280,71 +280,114 @@
R.handle_reactions()
return amount
/datum/reagents/proc/metabolize(mob/living/carbon/C, can_overdose = FALSE, liverless = FALSE)
/**
* Triggers metabolizing for all the reagents in this holder
*
* Arguments:
* * mob/living/carbon/carbon - The mob to metabolize in, if null it uses [/datum/reagents/var/my_atom]
* * delta_time - the time in server seconds between proc calls (when performing normally it will be 2)
* * times_fired - the number of times the owner's life() tick has been called aka The number of times SSmobs has fired
* * can_overdose - Allows overdosing
* * liverless - Stops reagents that aren't set as [/datum/reagent/var/self_consuming] from metabolizing
*/
/datum/reagents/proc/metabolize(mob/living/carbon/owner, delta_time, times_fired, can_overdose = FALSE, liverless = FALSE)
var/list/cached_reagents = reagent_list
var/list/cached_addictions = addiction_list
if(C)
expose_temperature(C.bodytemperature, 0.25)
var/need_mob_update = 0
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
if(QDELETED(R.holder))
continue
if(liverless && !R.self_consuming) //need to be metabolized
continue
if(!C)
C = R.holder.my_atom
if(!R.metabolizing)
R.metabolizing = TRUE
R.on_mob_metabolize(C)
if(C && R)
if(C.reagent_check(R) != 1)
if(can_overdose)
if(R.overdose_threshold)
if(R.volume > R.overdose_threshold && !R.overdosed)
R.overdosed = 1
var/turf/CT = get_turf(C)
log_reagent("OVERDOSE START: [key_name(C)] at [AREACOORD(CT)] started overdosing on [R.volume] units of [R].")
need_mob_update += R.overdose_start(C)
if(R.addiction_threshold)
if(R.volume > R.addiction_threshold && !is_type_in_list(R, cached_addictions))
var/datum/reagent/new_reagent = new R.type()
cached_addictions.Add(new_reagent)
if(R.overdosed)
need_mob_update += R.overdose_process(C)
if(is_type_in_list(R,cached_addictions))
for(var/addiction in cached_addictions)
var/datum/reagent/A = addiction
if(istype(R, A))
A.addiction_stage = -15 // you're satisfied for a good while.
need_mob_update += R.on_mob_life(C)
if(owner)
expose_temperature(owner.bodytemperature, 0.25)
var/need_mob_update = FALSE
for(var/datum/reagent/reagent as anything in cached_reagents)
need_mob_update += metabolize_reagent(owner, reagent, delta_time, times_fired, can_overdose, liverless)
if(can_overdose)
if(addiction_tick == 6)
addiction_tick = 1
for(var/addiction in cached_addictions)
for(var/addiction in addiction_list)
var/datum/reagent/R = addiction
if(C && R)
if(owner && R)
R.addiction_stage++
if(1 <= R.addiction_stage && R.addiction_stage <= R.addiction_stage1_end)
need_mob_update += R.addiction_act_stage1(C)
need_mob_update += R.addiction_act_stage1(owner)
else if(R.addiction_stage1_end < R.addiction_stage && R.addiction_stage <= R.addiction_stage2_end)
need_mob_update += R.addiction_act_stage2(C)
need_mob_update += R.addiction_act_stage2(owner)
else if(R.addiction_stage2_end < R.addiction_stage && R.addiction_stage <= R.addiction_stage3_end)
need_mob_update += R.addiction_act_stage3(C)
need_mob_update += R.addiction_act_stage3(owner)
else if(R.addiction_stage3_end < R.addiction_stage && R.addiction_stage <= R.addiction_stage4_end)
need_mob_update += R.addiction_act_stage4(C)
need_mob_update += R.addiction_act_stage4(owner)
else if(R.addiction_stage4_end < R.addiction_stage)
remove_addiction(R)
else
SEND_SIGNAL(C, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose")
SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose")
addiction_tick++
if(C && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates.
C.updatehealth()
C.update_mobility()
C.update_stamina()
if(owner && need_mob_update) //some of the metabolized reagents had effects on the mob that requires some updates.
owner.updatehealth()
owner.update_mobility()
owner.update_stamina()
update_total()
/*
* Metabolises a single reagent for a target owner carbon mob. See above.
*
* Arguments:
* * mob/living/carbon/owner - The mob to metabolize in, if null it uses [/datum/reagents/var/my_atom]
* * delta_time - the time in server seconds between proc calls (when performing normally it will be 2)
* * times_fired - the number of times the owner's life() tick has been called aka The number of times SSmobs has fired
* * can_overdose - Allows overdosing
* * liverless - Stops reagents that aren't set as [/datum/reagent/var/self_consuming] from metabolizing
*/
/datum/reagents/proc/metabolize_reagent(mob/living/carbon/owner, datum/reagent/reagent, delta_time, times_fired, can_overdose = FALSE, liverless = FALSE)
var/need_mob_update = FALSE
if(QDELETED(reagent.holder))
return FALSE
if(!owner)
owner = reagent.holder.my_atom
if(owner && reagent)
if(!owner.reagent_check(reagent, delta_time, times_fired) != TRUE)
return
if(liverless && !reagent.self_consuming) //need to be metabolized
return
if(!reagent.metabolizing)
reagent.metabolizing = TRUE
reagent.on_mob_metabolize(owner)
if(can_overdose)
if(reagent.overdose_threshold)
if(reagent.volume >= reagent.overdose_threshold && !reagent.overdosed)
reagent.overdosed = TRUE
need_mob_update += reagent.overdose_start(owner)
log_game("[key_name(owner)] has started overdosing on [reagent.name] at [reagent.volume] units.")
// for(var/addiction in reagent.addiction_types)
// owner.mind?.add_addiction_points(addiction, reagent.addiction_types[addiction] * REAGENTS_METABOLISM)
if(reagent.addiction_threshold)
if(reagent.volume > reagent.addiction_threshold && !is_type_in_list(reagent, addiction_list))
var/datum/reagent/new_reagent = new reagent.type()
addiction_list.Add(new_reagent)
if(is_type_in_list(reagent, addiction_list))
for(var/addiction in addiction_list)
var/datum/reagent/A = addiction
if(istype(reagent, A))
A.addiction_stage = -15 // you're satisfied for a good while.
if(reagent.overdosed)
need_mob_update += reagent.overdose_process(owner, delta_time, times_fired)
need_mob_update += reagent.on_mob_life(owner, delta_time, times_fired)
return need_mob_update
/// Signals that metabolization has stopped, triggering the end of trait-based effects
/datum/reagents/proc/end_metabolization(mob/living/carbon/C, keep_liverless = TRUE)
var/list/cached_reagents = reagent_list
for(var/datum/reagent/reagent as anything in cached_reagents)
if(QDELETED(reagent.holder))
continue
if(keep_liverless && reagent.self_consuming) //Will keep working without a liver
continue
if(!C)
C = reagent.holder.my_atom
if(reagent.metabolizing)
reagent.metabolizing = FALSE
reagent.on_mob_end_metabolize(C)
/datum/reagents/proc/remove_addiction(datum/reagent/R)
to_chat(my_atom, "<span class='notice'>You feel like you've gotten over your need for [R.name].</span>")
SEND_SIGNAL(my_atom, COMSIG_CLEAR_MOOD_EVENT, "[R.type]_overdose")
@@ -354,21 +397,6 @@
addiction_list.Remove(R)
qdel(R)
//Signals that metabolization has stopped, triggering the end of trait-based effects
/datum/reagents/proc/end_metabolization(mob/living/carbon/C, keep_liverless = TRUE)
var/list/cached_reagents = reagent_list
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
if(QDELETED(R.holder))
continue
if(keep_liverless && R.self_consuming) //Will keep working without a liver
continue
if(!C)
C = R.holder.my_atom
if(R.metabolizing)
R.metabolizing = FALSE
R.on_mob_end_metabolize(C)
/datum/reagents/proc/conditional_update_move(atom/A, Running = 0)
var/list/cached_reagents = reagent_list
for(var/reagent in cached_reagents)
@@ -505,11 +505,11 @@
value = REAGENT_VALUE_COMMON
/datum/reagent/consumable/nuka_cola/on_mob_metabolize(mob/living/carbon/M)
M.add_movespeed_modifier(/datum/movespeed_modifier/reagent/meth)
M.add_movespeed_modifier(/datum/movespeed_modifier/reagent/nuka_cola)
return ..()
/datum/reagent/consumable/nuka_cola/on_mob_end_metabolize(mob/living/carbon/M)
M.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/meth)
M.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/nuka_cola)
return ..()
/datum/reagent/consumable/nuka_cola/on_mob_life(mob/living/carbon/M)
@@ -164,62 +164,54 @@
/datum/reagent/drug/methamphetamine
name = "Methamphetamine"
description = "Reduces stun times by about 300%, and allows the user to quickly recover stamina while dealing a small amount of Brain damage. If overdosed the subject will move randomly, laugh randomly, drop items and suffer from Toxin and Brain damage. If addicted the subject will constantly jitter and drool, before becoming dizzy and losing motor control and eventually suffer heavy toxin damage."
description = "Reduces stun times by about 300%, speeds the user up, and allows the user to quickly recover stamina while dealing a small amount of Brain damage. If overdosed the subject will move randomly, laugh randomly, drop items and suffer from Toxin and Brain damage. If addicted the subject will constantly jitter and drool, before becoming dizzy and losing motor control and eventually suffer heavy toxin damage."
reagent_state = LIQUID
color = "#FAFAFA"
overdose_threshold = 20
addiction_threshold = 10
metabolization_rate = 0.75 * REAGENTS_METABOLISM
var/brain_damage = TRUE
var/jitter = TRUE
var/confusion = TRUE
pH = 5
addiction_threshold = 10
value = REAGENT_VALUE_UNCOMMON
/datum/reagent/drug/methamphetamine/on_mob_metabolize(mob/living/L)
..()
ADD_TRAIT(L, TRAIT_IGNOREDAMAGESLOWDOWN, type)
L.update_movespeed()
ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
L.add_movespeed_modifier(/datum/movespeed_modifier/reagent/meth)
L.add_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine)
/datum/reagent/drug/methamphetamine/on_mob_end_metabolize(mob/living/L)
REMOVE_TRAIT(L, TRAIT_IGNOREDAMAGESLOWDOWN, type)
L.update_movespeed()
REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
L.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/meth)
L.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine)
..()
/datum/reagent/drug/methamphetamine/on_mob_life(mob/living/carbon/M)
/datum/reagent/drug/methamphetamine/on_mob_life(mob/living/carbon/M, delta_time, times_fired)
var/high_message = pick("You feel hyper.", "You feel like you need to go faster.", "You feel like you can run the world.")
if(prob(5))
to_chat(M, "<span class='notice'>[high_message]</span>")
M.AdjustAllImmobility(-40, 0)
M.AdjustUnconscious(-40, 0)
M.adjustStaminaLoss(-7.5 * REM, 0)
if(jitter)
M.Jitter(2)
if(brain_damage)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, rand(1,4))
M.heal_overall_damage(2, 2)
if(prob(5))
if(DT_PROB(2.5, delta_time))
to_chat(M, span_notice("[high_message]"))
// SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "tweaking", /datum/mood_event/stimulant_medium, name)
M.AdjustStun(-40 * REM * delta_time)
M.AdjustKnockdown(-40 * REM * delta_time)
M.AdjustUnconscious(-40 * REM * delta_time)
M.AdjustParalyzed(-40 * REM * delta_time)
M.AdjustImmobilized(-40 * REM * delta_time)
M.adjustStaminaLoss(-2 * REM * delta_time, 0)
M.Jitter(2 * REM * delta_time)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, rand(1, 4) * REM * delta_time)
if(DT_PROB(2.5, delta_time))
M.emote(pick("twitch", "shiver"))
..()
. = 1
. = TRUE
/datum/reagent/drug/methamphetamine/overdose_process(mob/living/M)
/datum/reagent/drug/methamphetamine/overdose_process(mob/living/M, delta_time, times_fired)
if(CHECK_MOBILITY(M, MOBILITY_MOVE) && !ismovable(M.loc))
for(var/i in 1 to 4)
for(var/i in 1 to round(4 * REM * delta_time, 1))
step(M, pick(GLOB.cardinals))
if(prob(20))
if(DT_PROB(10, delta_time))
M.emote("laugh")
if(prob(33))
M.visible_message("<span class='danger'>[M]'s hands flip out and flail everywhere!</span>")
if(DT_PROB(18, delta_time))
M.visible_message(span_danger("[M]'s hands flip out and flail everywhere!"))
M.drop_all_held_items()
..()
M.adjustToxLoss(1, 0)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, pick(0.5, 0.6, 0.7, 0.8, 0.9, 1))
. = 1
M.adjustToxLoss(1 * REM * delta_time, 0)
M.adjustOrganLoss(ORGAN_SLOT_BRAIN, (rand(5, 10) / 10) * REM * delta_time)
. = TRUE
/datum/reagent/drug/methamphetamine/addiction_act_stage1(mob/living/M)
M.Jitter(5)
@@ -256,14 +248,6 @@
..()
. = 1
/datum/reagent/drug/methamphetamine/changeling
name = "Changeling Adrenaline"
addiction_threshold = 35
overdose_threshold = 35
jitter = FALSE
brain_damage = FALSE
value = REAGENT_VALUE_RARE
/datum/reagent/drug/bath_salts
name = "Bath Salts"
description = "Makes you impervious to stuns and grants a stamina regeneration buff, but you will be a nearly uncontrollable tramp-bearded raving lunatic."
@@ -345,6 +345,8 @@
victim.confused = max(M.confused, 3)
victim.damageoverlaytemp = 60
victim.DefaultCombatKnockdown(80, override_hardstun = 0.1, override_stamdmg = min(reac_volume * 3, 15))
victim.add_movespeed_modifier(/datum/movespeed_modifier/reagent/pepperspray)
addtimer(CALLBACK(victim, /mob.proc/remove_movespeed_modifier, /datum/movespeed_modifier/reagent/pepperspray), 10 SECONDS)
return
else if ( eyes_covered ) // Eye cover is better than mouth cover
victim.blur_eyes(3)
@@ -358,6 +360,8 @@
victim.confused = max(M.confused, 6)
victim.damageoverlaytemp = 75
victim.DefaultCombatKnockdown(80, override_hardstun = 0.1, override_stamdmg = min(reac_volume * 5, 25))
victim.add_movespeed_modifier(/datum/movespeed_modifier/reagent/pepperspray)
addtimer(CALLBACK(victim, /mob.proc/remove_movespeed_modifier, /datum/movespeed_modifier/reagent/pepperspray), 10 SECONDS)
victim.update_damage_hud()
/datum/reagent/consumable/condensedcapsaicin/on_mob_life(mob/living/carbon/M)
@@ -706,21 +706,42 @@
addiction_threshold = 30
pH = 12
/datum/reagent/medicine/ephedrine/on_mob_life(mob/living/carbon/M)
M.AdjustAllImmobility(-20, FALSE)
M.AdjustUnconscious(-20, FALSE)
M.adjustStaminaLoss(-4.5*REM, FALSE)
M.Jitter(10)
if(prob(50))
M.confused = max(M.confused, 1)
/datum/reagent/medicine/ephedrine/on_mob_metabolize(mob/living/L)
..()
L.add_movespeed_modifier(/datum/movespeed_modifier/reagent/ephedrine)
ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
/datum/reagent/medicine/ephedrine/on_mob_end_metabolize(mob/living/L)
L.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/ephedrine)
REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
..()
/datum/reagent/medicine/ephedrine/on_mob_life(mob/living/carbon/M, delta_time, times_fired)
// if(DT_PROB(10 * (1-creation_purity), delta_time) && iscarbon(M))
// var/obj/item/I = M.get_active_held_item()
// if(I && M.dropItemToGround(I))
// to_chat(M, span_notice("Your hands spaz out and you drop what you were holding!"))
// M.Jitter(10)
M.AdjustAllImmobility(-20 * REM * delta_time)
M.adjustStaminaLoss(-1 * REM * delta_time, FALSE)
..()
return TRUE
/datum/reagent/medicine/ephedrine/overdose_process(mob/living/M)
if(prob(33))
M.adjustToxLoss(0.5*REM, 0)
/datum/reagent/medicine/ephedrine/overdose_process(mob/living/M, delta_time, times_fired)
if(DT_PROB(1, delta_time) && iscarbon(M))
var/datum/disease/D = new /datum/disease/heart_failure
M.ForceContractDisease(D)
to_chat(M, span_userdanger("You're pretty sure you just felt your heart stop for a second there.."))
M.playsound_local(M, 'sound/effects/singlebeat.ogg', 100, 0)
if(DT_PROB(3.5, delta_time))
to_chat(M, span_notice("[pick("Your head pounds.", "You feel a tight pain in your chest.", "You find it hard to stay still.", "You feel your heart practically beating out of your chest.")]"))
if(DT_PROB(18, delta_time))
M.adjustToxLoss(1, 0)
M.losebreath++
. = 1
. = TRUE
return TRUE
/datum/reagent/medicine/ephedrine/addiction_act_stage1(mob/living/M)
@@ -981,7 +1002,7 @@
M.grab_ghost()
M.emote("gasp")
log_combat(M, M, "revived", src)
var/list/policies = CONFIG_GET(keyed_list/policyconfig)
var/list/policies = CONFIG_GET(keyed_list/policy)
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds
var/late = timelimit && (tplus > timelimit)
var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT]
@@ -1415,37 +1436,42 @@
/datum/reagent/medicine/changelingadrenaline
name = "Changeling Adrenaline"
description = "Reduces the duration of unconciousness, knockdown and stuns. Restores stamina, but deals toxin damage when overdosed."
color = "#918e53"
color = "#C1151D"
overdose_threshold = 30
value = REAGENT_VALUE_VERY_RARE
/datum/reagent/medicine/changelingadrenaline/on_mob_metabolize(mob/living/L)
..()
ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
/datum/reagent/medicine/changelingadrenaline/on_mob_end_metabolize(mob/living/L)
REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
..()
/datum/reagent/medicine/changelingadrenaline/on_mob_life(mob/living/carbon/M as mob)
M.AdjustUnconscious(-20, 0)
M.AdjustAllImmobility(-20, 0)
M.AdjustSleeping(-20, 0)
M.adjustStaminaLoss(-30, 0)
/datum/reagent/medicine/changelingadrenaline/on_mob_life(mob/living/carbon/metabolizer, delta_time, times_fired)
..()
metabolizer.AdjustAllImmobility(-20 * REM * delta_time)
metabolizer.adjustStaminaLoss(-10 * REM * delta_time, 0)
metabolizer.Jitter(10 * REM * delta_time)
metabolizer.Dizzy(10 * REM * delta_time)
return TRUE
/datum/reagent/medicine/changelingadrenaline/overdose_process(mob/living/M as mob)
M.adjustToxLoss(5, 0) //let's make this mildly more toxic because of the stamina buff
/datum/reagent/medicine/changelingadrenaline/on_mob_metabolize(mob/living/L)
..()
ADD_TRAIT(L, TRAIT_SLEEPIMMUNE, type)
ADD_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
L.add_movespeed_mod_immunities(type, /datum/movespeed_modifier/damage_slowdown)
/datum/reagent/medicine/changelingadrenaline/on_mob_end_metabolize(mob/living/L)
..()
REMOVE_TRAIT(L, TRAIT_SLEEPIMMUNE, type)
REMOVE_TRAIT(L, TRAIT_TASED_RESISTANCE, type)
L.remove_movespeed_mod_immunities(type, /datum/movespeed_modifier/damage_slowdown)
L.Dizzy(0)
L.Jitter(0)
/datum/reagent/medicine/changelingadrenaline/overdose_process(mob/living/metabolizer, delta_time, times_fired)
metabolizer.adjustToxLoss(1 * REM * delta_time, 0)
..()
return TRUE
/datum/reagent/medicine/changelinghaste
name = "Changeling Haste"
description = "Drastically increases movement speed, but deals toxin damage."
color = "#669153"
metabolization_rate = 1
value = REAGENT_VALUE_VERY_RARE
color = "#AE151D"
metabolization_rate = 2.5 * REAGENTS_METABOLISM
/datum/reagent/medicine/changelinghaste/on_mob_metabolize(mob/living/L)
..()
@@ -1455,11 +1481,12 @@
L.remove_movespeed_modifier(/datum/movespeed_modifier/reagent/changelinghaste)
..()
/datum/reagent/medicine/changelinghaste/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(2, 0)
/datum/reagent/medicine/changelinghaste/on_mob_life(mob/living/carbon/metabolizer, delta_time, times_fired)
metabolizer.adjustToxLoss(2 * REM * delta_time, 0)
..()
return TRUE
/datum/reagent/medicine/corazone
// Heart attack code will not do damage if corazone is present
// because it's SPACE MAGIC ASPIRIN
@@ -287,7 +287,9 @@
/datum/reagent/water/reaction_obj(obj/O, reac_volume)
O.extinguish()
O.acid_level = 0
var/datum/component/acid/acid = O.GetComponent(/datum/component/acid)
if(acid)
acid.level = 0
// cubes
if(istype(O, /obj/item/reagent_containers/food/snacks/cube))
var/obj/item/reagent_containers/food/snacks/cube/cube = O
@@ -42,6 +42,7 @@
return ..()
/obj/machinery/rnd/production/proc/update_research()
set waitfor = FALSE
host_research.copy_research_to(stored_research, TRUE)
update_designs()
@@ -55,7 +55,7 @@
display_name = "Nanite Replication Protocols"
description = "Advanced behaviours that allow nanites to exploit certain circumstances to replicate faster."
prereq_ids = list("nanite_smart")
design_ids = list("kickstart_nanites","factory_nanites","tinker_nanites","offline_nanites","synergy_nanites")
design_ids = list("kickstart_nanites","factory_nanites","offline_nanites","synergy_nanites")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
hidden = TRUE
experimental = TRUE
@@ -622,7 +622,9 @@
var/obj/O = owner.get_active_held_item()
if(O)
O.extinguish() //All shamelessly copied from water's reaction_obj, since I didn't seem to be able to get it here for some reason.
O.acid_level = 0
var/datum/component/acid/acid = O.GetComponent(/datum/component/acid)
if(acid)
acid.level = 0
// Monkey cube
if(istype(O, /obj/item/reagent_containers/food/snacks/cube))
to_chat(owner, "<span class='warning'>[linked_extract] kept your hands wet! It makes [O] expand!</span>")
@@ -702,16 +704,20 @@
/datum/status_effect/stabilized/sepia
id = "stabilizedsepia"
colour = "sepia"
var/mod = 0
var/list/possible = list(
-0.5,
-0.25,
0,
0.5,
1
)
/datum/status_effect/stabilized/sepia/New(list/arguments)
. = ..()
possible = typelist(NAMEOF(src, possible), possible)
/datum/status_effect/stabilized/sepia/tick()
if(prob(50) && mod > -1)
mod--
owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/sepia, multiplicative_slowdown = 1)
else if(mod < 1)
mod++
// yeah a value of 0 does nothing but replacing the trait in place is cheaper than removing and adding repeatedly
owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/sepia, multiplicative_slowdown = 0)
owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/status_effect/sepia, multiplicative_slowdown = safepick(possible))
return ..()
/datum/status_effect/stabilized/sepia/on_remove()
@@ -932,6 +938,7 @@
/datum/status_effect/stabilized/lightpink/on_apply()
ADD_TRAIT(owner, TRAIT_FREESPRINT, "stabilized_slime")
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/slime/light_pink)
return ..()
/datum/status_effect/stabilized/lightpink/tick()
@@ -943,6 +950,7 @@
/datum/status_effect/stabilized/lightpink/on_remove()
REMOVE_TRAIT(owner, TRAIT_FREESPRINT, "stabilized_slime")
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/slime/light_pink)
return ..()
/datum/status_effect/stabilized/adamantine
+1 -1
View File
@@ -69,7 +69,7 @@
for(var/obj/item/organ/O in target.internal_organs)//zap those buggers back to life!
if(O.organ_flags & ORGAN_FAILING)
O.applyOrganDamage(-5)
var/list/policies = CONFIG_GET(keyed_list/policyconfig)
var/list/policies = CONFIG_GET(keyed_list/policy)
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds
var/late = timelimit && (tplus > timelimit)
var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT]
+1 -1
View File
@@ -188,7 +188,7 @@
needs_processing = .
//Return TRUE to get whatever mob this is in to update health.
/obj/item/bodypart/proc/on_life()
/obj/item/bodypart/proc/on_life(seconds, times_fired)
if(stam_heal_tick && stamina_dam > DAMAGE_PRECISION) //DO NOT update health here, it'll be done in the carbon's life.
if(heal_damage(brute = 0, burn = 0, stamina = (stam_heal_tick * (disabled ? 2 : 1)), only_robotic = FALSE, only_organic = FALSE, updating_health = FALSE))
. |= BODYPART_LIFE_UPDATE_HEALTH
+1 -1
View File
@@ -42,7 +42,7 @@
if(target.revive())
target.visible_message("...[target]'s posibrain flickers to life once again!")
target.emote("ping")
var/list/policies = CONFIG_GET(keyed_list/policyconfig)
var/list/policies = CONFIG_GET(keyed_list/policy)
var/timelimit = CONFIG_GET(number/defib_cmd_time_limit) * 10 //the config is in seconds, not deciseconds
var/late = timelimit && (tplus > timelimit)
var/policy = late? policies[POLICYCONFIG_ON_DEFIB_LATE] : policies[POLICYCONFIG_ON_DEFIB_INTACT]
+2 -2
View File
@@ -25,7 +25,7 @@
var/cachedmoveCalc = 1
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/iron = 5)
/obj/item/organ/liver/on_life()
/obj/item/organ/liver/on_life(seconds, times_fired)
. = ..()
if(!. || !owner)//can't process reagents with a failing liver
return
@@ -40,7 +40,7 @@
damage += (thisamount*toxLethality)
//metabolize reagents
owner.reagents.metabolize(owner, can_overdose=TRUE)
owner.reagents.metabolize(owner, seconds, times_fired, can_overdose=TRUE)
if(damage > 10 && prob(damage/3))//the higher the damage the higher the probability
to_chat(owner, "<span class='warning'>You feel a dull pain in your abdomen.</span>")
@@ -92,18 +92,18 @@
on_death() //Kinda hate doing it like this, but I really don't want to call process directly.
//Sources; life.dm process_organs
/obj/item/organ/proc/on_death() //Runs when outside AND inside.
/obj/item/organ/proc/on_death(seconds, times_fired) //Runs when outside AND inside.
decay()
//Applys the slow damage over time decay
/obj/item/organ/proc/decay()
/obj/item/organ/proc/decay(seconds, times_fired)
if(!can_decay())
STOP_PROCESSING(SSobj, src)
return
is_cold()
if(organ_flags & ORGAN_FROZEN)
return
applyOrganDamage(maxHealth * decay_factor)
applyOrganDamage(maxHealth * decay_factor * (seconds * 0.5))
/obj/item/organ/proc/can_decay()
if(CHECK_BITFIELD(organ_flags, ORGAN_NO_SPOIL | ORGAN_SYNTHETIC | ORGAN_FAILING))
@@ -151,7 +151,7 @@
organ_flags &= ~ORGAN_FROZEN
return FALSE
/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing or synthetic
/obj/item/organ/proc/on_life(seconds, times_fired) //repair organ damage if the organ is not failing or synthetic
if(organ_flags & ORGAN_FAILING || !owner)
return FALSE
if(organ_flags & ORGAN_SYNTHETIC_EMP) //Synthetic organ has been emped, is now failing.
+64 -41
View File
@@ -1,8 +1,15 @@
#define COOLDOWN_STUN 1200
#define COOLDOWN_KNOCKDOWN 600
#define COOLDOWN_DAMAGE 600
#define COOLDOWN_MEME 300
#define COOLDOWN_NONE 100
#define COOLDOWN_STUN 300
#define COOLDOWN_KNOCKDOWN 300
#define COOLDOWN_DAMAGE 300
#define COOLDOWN_MEME 150
#define COOLDOWN_NONE 50
/// anything above this requires adminbus, to prevent a cultist from stacking chaplain + cult + specific listener = 8x, which is enough to instantly kill someone with damage.
#define VOG_MAX_STANDARD_POWER 3
/// max damage we can do in one "blast" to a listener
#define VOG_MAX_BURST_DAMAGE 40
/// max healing we can do in one "blast" to a listener
#define VOG_MAX_BURST_HEAL 40
/obj/item/organ/vocal_cords //organs that are activated through speech with the :x/MODE_KEY_VOCALCORDS channel
name = "vocal cords"
@@ -130,13 +137,11 @@
return 0 //no cooldown
var/log_message = uppertext(message)
if(!span_list || !span_list.len)
if(iscultist(user))
span_list = list("narsiesmall")
else if (is_servant_of_ratvar(user))
span_list = list("ratvar")
else
span_list = list()
if(iscultist(user))
span_list = list("narsiesmall")
else if (is_servant_of_ratvar(user))
span_list = list("ratvar")
LAZYINITLIST(span_list)
user.say(message, spans = span_list, sanitize = FALSE)
@@ -156,39 +161,24 @@
cooldown = COOLDOWN_NONE
return cooldown
var/power_multiplier = base_multiplier
if(user.mind)
//Chaplains are very good at speaking with the voice of god
if(user.mind.assigned_role == "Chaplain")
power_multiplier *= 2
//Command staff has authority
if(user.mind.assigned_role in GLOB.command_positions)
power_multiplier *= 1.4
//Why are you speaking
if(user.mind.assigned_role == "Mime")
power_multiplier *= 0.5
//Cultists are closer to their gods and are more powerful, but they'll give themselves away
if(iscultist(user))
power_multiplier *= 2
else if (is_servant_of_ratvar(user))
power_multiplier *= 2
//Try to check if the speaker specified a name or a job to focus on
var/list/specific_listeners = list()
var/found_string = null
var/devil_target = FALSE
//Get the proper job titles
message = get_full_job_name(message)
// limitation: this only checks at the start of the message.
// if we wanted to check anywhere we'd have to make the user use delimiters to specify who they're talking to,
// as otherwise it'd be far too computationally and logically expensive to find out who we want.
for(var/V in listeners)
var/mob/living/L = V
var/datum/antagonist/devil/devilinfo = is_devil(L)
if(devilinfo && findtext(message, devilinfo.truename))
var/start = findtext(message, devilinfo.truename)
listeners = list(L) //Devil names are unique.
power_multiplier *= 5 //if you're a devil and god himself addressed you, you fucked up
devil_target = TRUE //if you're a devil and god himself addressed you, you fucked up
//Cut out the name so it doesn't trigger commands
message = copytext(message, 1, start) + copytext(message, start + length(devilinfo.truename))
break
@@ -207,10 +197,14 @@
//Cut out the job so it doesn't trigger commands
found_string = L.mind.assigned_role
var/power_multiplier = get_vog_multiplier(user, base_multiplier, specific_listeners)
var/adminbus = power_multiplier > VOG_MAX_STANDARD_POWER // an admin is being a dunce, bypass hard scaling limits on this message
if(devil_target)
power_multiplier = max(power_multiplier, 5)
if(specific_listeners.len)
listeners = specific_listeners
power_multiplier *= (1 + (1/specific_listeners.len)) //2x on a single guy, 1.5x on two and so on
message = copytext(message, length(found_string) + 1)
listeners = specific_listeners.Copy()
var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt")
var/static/regex/knockdown_words = regex("drop|fall|trip|knockdown")
@@ -264,7 +258,7 @@
cooldown = COOLDOWN_STUN
for(var/V in listeners)
var/mob/living/L = V
L.Stagger(60 * power_multiplier)
L.Stagger(40 * power_multiplier)
//KNOCKDOWN
else if(findtext(message, knockdown_words))
@@ -272,6 +266,7 @@
for(var/V in listeners)
var/mob/living/L = V
L.DefaultCombatKnockdown()
L.Stagger(10 * power_multiplier)
//VOMIT
else if((findtext(message, vomit_words)))
@@ -285,13 +280,13 @@
for(var/mob/living/carbon/C in listeners)
if(user.mind && (user.mind.assigned_role == "Curator" || user.mind.assigned_role == "Mime"))
power_multiplier *= 3
C.silent += (10 * power_multiplier)
C.silent += (5 * power_multiplier)
//HALLUCINATE
else if((findtext(message, hallucinate_words)))
cooldown = COOLDOWN_MEME
for(var/mob/living/carbon/C in listeners)
new /datum/hallucination/delusion(C, TRUE, null,150 * power_multiplier,0)
new /datum/hallucination/delusion(C, TRUE, null, 150 * power_multiplier, 0)
//WAKE UP
else if((findtext(message, wakeup_words)))
@@ -305,14 +300,14 @@
cooldown = COOLDOWN_DAMAGE
for(var/V in listeners)
var/mob/living/L = V
L.heal_overall_damage(10 * power_multiplier, 10 * power_multiplier, 0, FALSE, FALSE)
L.heal_overall_damage(min(17.5 * power_multiplier, adminbus? INFINITY : VOG_MAX_BURST_HEAL), min(17.5 * power_multiplier, VOG_MAX_BURST_HEAL), 0, FALSE, FALSE)
//BRUTE DAMAGE
else if((findtext(message, hurt_words)))
cooldown = COOLDOWN_DAMAGE
for(var/V in listeners)
var/mob/living/L = V
L.apply_damage(15 * power_multiplier, def_zone = BODY_ZONE_CHEST, wound_bonus=CANT_WOUND)
L.apply_damage(min(20 * power_multiplier, adminbus? INFINITY : VOG_MAX_BURST_DAMAGE), def_zone = BODY_ZONE_CHEST, wound_bonus = CANT_WOUND)
//BLEED
else if((findtext(message, bleed_words)))
@@ -334,14 +329,14 @@
cooldown = COOLDOWN_DAMAGE
for(var/V in listeners)
var/mob/living/L = V
L.adjust_bodytemperature(50 * power_multiplier)
L.adjust_bodytemperature(75 * power_multiplier)
//COLD
else if((findtext(message, cold_words)))
cooldown = COOLDOWN_DAMAGE
for(var/V in listeners)
var/mob/living/L = V
L.adjust_bodytemperature(-50 * power_multiplier)
L.adjust_bodytemperature(-75 * power_multiplier)
//REPULSE
else if((findtext(message, repulse_words)))
@@ -596,6 +591,34 @@
return cooldown
/proc/get_vog_multiplier(mob/living/carbon/user, base_multiplier = 1, list/specific_listeners = list())
if(base_multiplier >= VOG_MAX_STANDARD_POWER)
return base_multiplier // an admin bussed you and they probably didn't realize you were a chaplain/cultist.
var/special_check = get_vog_special(user)
if(!special_check)
return 0
. = min(base_multiplier * special_check, VOG_MAX_STANDARD_POWER) // anything above should require conscious admin fuckery, as things are balanced around 3 multiplier tops (see: damage being 15*3)
if(!specific_listeners.len)
return
. = min(. * (1 + (1 / specific_listeners.len)), VOG_MAX_STANDARD_POWER)
/// get special role multiplier for voice of god. No double dipping.
/proc/get_vog_special(mob/living/carbon/user)
if(iscultist(user) || is_servant_of_ratvar(user))
return 2 // servant of god
if(user.mind)
// servant of god
if(user.mind.assigned_role == "Chaplain")
return 2
// shut up you broke your vow
if(user.mind.assigned_role == "Mime")
return 0.5
if(user.mind.assigned_role in GLOB.command_positions)
return 1.4 // heads are great at speaking with authority
return 1
//////////////////////////////////////
///////ENTHRAL VELVET CHORDS//////////
//////////////////////////////////////
+18
View File
@@ -0,0 +1,18 @@
/**
* tgui state: vorepanel_state
*
* Only checks that the user and src_object are the same.
**/
GLOBAL_DATUM_INIT(ui_vorepanel_state, /datum/ui_state/vorepanel_state, new)
/datum/ui_state/vorepanel_state/can_use_topic(src_object, mob/user)
if(src_object != user)
// Note, in order to allow others to look at others vore panels, change this to
// UI_UPDATE
return UI_CLOSE
if(!user.client)
return UI_CLOSE
if(user.stat == DEAD)
return UI_DISABLED
return UI_INTERACTIVE
+12 -15
View File
@@ -9,7 +9,7 @@
* * buttons - The options that can be chosen by the user, each string is assigned a button on the UI.
* * timeout - The timeout of the alert, after which the modal will close and qdel itself. Set to zero for no timeout.
*/
/proc/tgui_alert(mob/user, message, title, list/buttons, timeout = 60 SECONDS)
/proc/tgui_alert(mob/user, message = null, title = null, list/buttons = list("Ok"), timeout = 0)
if (!user)
user = usr
if (!istype(user))
@@ -35,9 +35,9 @@
* * title - The of the alert modal, shown on the top of the TGUI window.
* * buttons - The options that can be chosen by the user, each string is assigned a button on the UI.
* * callback - The callback to be invoked when a choice is made.
* * timeout - The timeout of the alert, after which the modal will close and qdel itself. Set to zero for no timeout.
* * timeout - The timeout of the alert, after which the modal will close and qdel itself. Disabled by default, can be set to seconds otherwise.
*/
/proc/tgui_alert_async(mob/user, message, title, list/buttons, datum/callback/callback, timeout = 60 SECONDS)
/proc/tgui_alert_async(mob/user, message = null, title = null, list/buttons = list("Ok"), datum/callback/callback, timeout = 0)
if (!user)
user = usr
if (!istype(user))
@@ -90,7 +90,7 @@
* the window was closed by the user.
*/
/datum/tgui_modal/proc/wait()
while (!choice && !closed)
while (!choice && !closed && !QDELETED(src))
stoplag(1)
/datum/tgui_modal/ui_interact(mob/user, datum/tgui/ui)
@@ -124,10 +124,13 @@
if("choose")
if (!(params["choice"] in buttons))
return
choice = params["choice"]
set_choice(params["choice"])
SStgui.close_uis(src)
return TRUE
/datum/tgui_modal/proc/set_choice(choice)
src.choice = choice
/**
* # async tgui_modal
*
@@ -138,23 +141,17 @@
var/datum/callback/callback
/datum/tgui_modal/async/New(mob/user, message, title, list/buttons, callback, timeout)
..(user, title, message, buttons, timeout)
..(user, message, title, buttons, timeout)
src.callback = callback
/datum/tgui_modal/async/Destroy(force, ...)
QDEL_NULL(callback)
. = ..()
/datum/tgui_modal/async/ui_close(mob/user)
/datum/tgui_modal/async/set_choice(choice)
. = ..()
qdel(src)
/datum/tgui_modal/async/ui_act(action, list/params)
. = ..()
if (!. || choice == null)
return
callback.InvokeAsync(choice)
qdel(src)
if(!isnull(src.choice))
callback?.InvokeAsync(src.choice)
/datum/tgui_modal/async/wait()
return
+4 -6
View File
@@ -138,12 +138,10 @@ Notes:
. = ..()
if(tooltips)
if(!QDELETED(src))
var/list/examine_list = examine(src)
var/get_tooltip_data = get_tooltip_data()
if(length(get_tooltip_data))
examine_list = get_tooltip_data
var/examine_data = examine_list.Join("<br />")
openToolTip(usr, src, params, title = name, content = examine_data)
var/list/tooltip_data = get_tooltip_data()
if(length(tooltip_data))
var/examine_data = tooltip_data.Join("<br />")
openToolTip(usr, src, params, title = name, content = examine_data)
/atom/movable/MouseExited(location, control, params)
. = ..()
+1 -1
View File
@@ -44,7 +44,7 @@
// #include "heretic_knowledge.dm"
// #include "holidays.dm"
#include "initialize_sanity.dm"
#include "keybinding_init.dm"
// #include "keybinding_init.dm"
#include "machine_disassembly.dm"
#include "medical_wounds.dm"
#include "merge_type.dm"
+1 -1
View File
@@ -3,4 +3,4 @@
var/datum/keybinding/KB = i
if(initial(KB.keybind_signal) || !initial(KB.name))
continue
Fail("[KB.name] does not have a keybind signal defined.")
Fail("[initial(KB.name)] does not have a keybind signal defined.")
+2 -2
View File
@@ -10,6 +10,6 @@
var/list/paths = subtypesof(/obj/item/stack) - blacklist
for(var/stackpath in paths)
var/obj/item/stack/stack = stackpath
if(!initial(stack.merge_type))
var/obj/item/stack/stack = new stackpath
if(!stack.merge_type)
Fail("([stack]) lacks set merge_type variable!")
+1 -1
View File
@@ -11,7 +11,7 @@
/datum/unit_test/metabolization/proc/test_reagent(mob/living/carbon/C, reagent_type)
C.reagents.add_reagent(reagent_type, 10)
C.reagents.metabolize(C, can_overdose = TRUE)
C.reagents.metabolize(C, SSMOBS_DT, 1, can_overdose = TRUE)
C.reagents.clear_reagents()
/datum/unit_test/metabolization/Destroy()
+5 -1
View File
@@ -53,7 +53,8 @@
TEST_ASSERT(!isnull(alice.get_bodypart(BODY_ZONE_HEAD)), "Alice has no head after prosthetic replacement")
TEST_ASSERT_EQUAL(alice.get_visible_name(), "Bob", "Bob's head was transplanted onto Alice's body, but their name is not Bob")
/*
i couldn't actually find anything in the parts of the code it's calling preventing two surgeries, so it's probably somewhere else
/datum/unit_test/multiple_surgeries/Run()
var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human)
var/mob/living/carbon/human/patient_zero = allocate(/mob/living/carbon/human)
@@ -65,10 +66,12 @@
var/datum/surgery/organ_manipulation/surgery_for_zero = new
INVOKE_ASYNC(surgery_step, /datum/surgery_step/proc/initiate, user, patient_zero, BODY_ZONE_CHEST, scalpel, surgery_for_zero)
sleep(1)
TEST_ASSERT(surgery_for_zero.step_in_progress, "Surgery on patient zero was not initiated")
var/datum/surgery/organ_manipulation/surgery_for_one = new
// Without waiting for the incision to complete, try to start a new surgery
TEST_ASSERT(!surgery_step.initiate(user, patient_one, BODY_ZONE_CHEST, scalpel, surgery_for_one), "Was allowed to start a second surgery without the rod of asclepius")
TEST_ASSERT(!surgery_for_one.step_in_progress, "Surgery for patient one is somehow in progress, despite not initiating")
@@ -76,6 +79,7 @@
user.apply_status_effect(STATUS_EFFECT_HIPPOCRATIC_OATH)
INVOKE_ASYNC(surgery_step, /datum/surgery_step/proc/initiate, user, patient_one, BODY_ZONE_CHEST, scalpel, surgery_for_one)
TEST_ASSERT(surgery_for_one.step_in_progress, "Surgery on patient one was not initiated, despite having rod of asclepius")
*/
/datum/unit_test/tend_wounds/Run()
var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human)
+1 -1
View File
@@ -1,8 +1,8 @@
/datum/unit_test/auto_teleporter_linking/Run()
// Put down the teleporter machinery
var/obj/machinery/teleport/hub/hub = allocate(/obj/machinery/teleport/hub)
var/obj/machinery/teleport/station/station = allocate(/obj/machinery/teleport/station, locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z))
var/obj/machinery/computer/teleporter/computer = allocate(/obj/machinery/computer/teleporter, locate(run_loc_bottom_left.x + 2, run_loc_bottom_left.y, run_loc_bottom_left.z))
var/obj/machinery/teleport/station/station = allocate(/obj/machinery/teleport/station, locate(run_loc_bottom_left.x + 1, run_loc_bottom_left.y, run_loc_bottom_left.z))
TEST_ASSERT_EQUAL(hub.power_station, station, "Hub didn't link to the station")
TEST_ASSERT_EQUAL(station.teleporter_console, computer, "Station didn't link to the teleporter console")
+1 -1
View File
@@ -9,7 +9,7 @@
/obj/vehicle/ridden/atv/Initialize()
. = ..()
var/datum/component/riding/D = LoadComponent(/datum/component/riding)
D.vehicle_move_delay = 1
D.vehicle_move_delay = CONFIG_GET(number/movedelay/run_delay)
D.set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(0, 4), TEXT_WEST = list( 0, 4)))
D.set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER)
D.set_vehicle_dir_layer(NORTH, OBJ_LAYER)
@@ -0,0 +1,155 @@
/obj/vehicle/ridden/wheelchair/motorized
name = "Hoverchair"
desc = "A chair with thrusters. It seems to have a motor in it."
icon = 'icons/obj/vehicles.dmi'
icon_state = "wheelchair_motorized"
max_integrity = 150
var/speed = 2
var/power_efficiency = 1
var/power_usage = 25
var/panel_open = FALSE
var/list/required_parts = list(/obj/item/stock_parts/manipulator,
/obj/item/stock_parts/manipulator,
/obj/item/stock_parts/capacitor)
var/obj/item/stock_parts/cell/power_cell
/obj/vehicle/ridden/wheelchair/motorized/CheckParts(list/parts_list)
..()
refresh_parts()
/obj/vehicle/ridden/wheelchair/motorized/proc/refresh_parts()
speed = 1 // Should never be under 1
for(var/obj/item/stock_parts/manipulator/M in contents)
speed += M.rating
for(var/obj/item/stock_parts/capacitor/C in contents)
power_efficiency = C.rating
var/datum/component/riding/D = GetComponent(/datum/component/riding)
D.vehicle_move_delay = round((CONFIG_GET(number/movedelay/run_delay) * 2) / speed, world.tick_lag)
/obj/vehicle/ridden/wheelchair/motorized/obj_destruction(damage_flag)
var/turf/T = get_turf(src)
for(var/atom/movable/A in contents)
A.forceMove(T)
if(isliving(A))
var/mob/living/L = A
L.update_mobility()
..()
/obj/vehicle/ridden/wheelchair/motorized/driver_move(mob/living/user, direction)
if(istype(user))
if(!canmove)
return FALSE
if(!power_cell)
to_chat(user, "<span class='warning'>There seems to be no cell installed in [src].</span>")
canmove = FALSE
addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
return FALSE
if(power_cell.charge < power_usage / max(power_efficiency, 1))
to_chat(user, "<span class='warning'>The display on [src] blinks 'Out of Power'.</span>")
canmove = FALSE
addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
return FALSE
if(user.get_num_arms() < arms_required)
to_chat(user, "<span class='warning'>You don't have enough arms to operate the motor controller!</span>")
canmove = FALSE
addtimer(VARSET_CALLBACK(src, canmove, TRUE), 20)
return FALSE
power_cell.use(power_usage / max(power_efficiency, 1))
return ..()
/obj/vehicle/ridden/wheelchair/motorized/post_buckle_mob(mob/living/user)
. = ..()
density = TRUE
/obj/vehicle/ridden/wheelchair/motorized/post_unbuckle_mob()
. = ..()
density = FALSE
/obj/vehicle/ridden/wheelchair/motorized/attack_hand(mob/living/user)
if(power_cell && panel_open)
power_cell.update_icon()
user.put_in_hands(power_cell)
power_cell = null
to_chat(user, "<span class='notice'>You remove the power cell from [src].</span>")
return
return ..()
/obj/vehicle/ridden/wheelchair/motorized/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_SCREWDRIVER)
I.play_tool_sound(src)
panel_open = !panel_open
user.visible_message("<span class='notice'>[user] [panel_open ? "opens" : "closes"] the maintenance panel on [src].</span>", "<span class='notice'>You [panel_open ? "open" : "close"] the maintenance panel.</span>")
return
if(panel_open)
if(istype(I, /obj/item/stock_parts/cell))
if(power_cell)
to_chat(user, "<span class='warning'>There is a power cell already installed.</span>")
else
I.forceMove(src)
power_cell = I
to_chat(user, "<span class='notice'>You install the [I].</span>")
refresh_parts()
return
if(istype(I, /obj/item/stock_parts))
var/obj/item/stock_parts/B = I
var/P
for(var/obj/item/stock_parts/A in contents)
for(var/D in required_parts)
if(ispath(A.type, D))
P = D
break
if(istype(B, P) && istype(A, P))
if(B.get_part_rating() > A.get_part_rating())
B.forceMove(src)
user.put_in_hands(A)
user.visible_message("<span class='notice'>[user] replaces [A] with [B] in [src].</span>", "<span class='notice'>You replace [A] with [B].</span>")
break
refresh_parts()
return
return ..()
/obj/vehicle/ridden/wheelchair/motorized/wrench_act(mob/living/user, obj/item/I)
to_chat(user, "<span class='notice'>You begin to detach the thrusters...</span>")
if(I.use_tool(src, user, 40, volume=50))
to_chat(user, "<span class='notice'>You detach the thrusters and deconstruct the chair.</span>")
new /obj/item/stack/rods(drop_location(), 8)
new /obj/item/stack/sheet/plasteel(drop_location(), 10)
var/turf/T = get_turf(src)
for(var/atom/movable/A in contents)
A.forceMove(T)
if(isliving(A))
var/mob/living/L = A
L.update_mobility()
qdel(src)
return TRUE
/obj/vehicle/ridden/wheelchair/motorized/examine(mob/user)
. = ..()
if(panel_open)
. += "There is a small screen on it, [(in_range(user, src) || isobserver(user)) ? "[power_cell ? "it reads:" : "but it is dark."]" : "but you can't see it from here."]"
if(!power_cell || (!in_range(user, src) && !isobserver(user)))
return
. += "Speed: [speed]"
. += "Energy efficiency: [power_efficiency]"
. += "Power: [power_cell.charge] out of [power_cell.maxcharge]"
/obj/vehicle/ridden/wheelchair/motorized/Bump(atom/movable/M)
. = ..()
// If the speed is higher than delay_multiplier throw the person on the wheelchair away
if(M.density && speed > 2 && has_buckled_mobs())
var/mob/living/H = buckled_mobs[1]
var/atom/throw_target = get_edge_target_turf(H, pick(GLOB.cardinals))
unbuckle_mob(H)
H.throw_at(throw_target, 2, 3)
H.Knockdown(100)
H.adjustStaminaLoss(40)
if(isliving(M))
var/mob/living/D = M
throw_target = get_edge_target_turf(D, pick(GLOB.cardinals))
D.throw_at(throw_target, 2, 3)
D.Knockdown(80)
D.adjustStaminaLoss(35)
visible_message("<span class='danger'>[src] crashes into [M], sending [H] and [D] flying!</span>")
else
visible_message("<span class='danger'>[src] crashes into [M], sending [H] flying!</span>")
playsound(src, 'sound/effects/bang.ogg', 50, 1)
+12 -5
View File
@@ -26,8 +26,8 @@
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE, CALLBACK(src, .proc/can_user_rotate),CALLBACK(src, .proc/can_be_rotated),null)
/obj/vehicle/ridden/wheelchair/obj_destruction(damage_flag)
new /obj/item/stack/rods(drop_location(), 1)
new /obj/item/stack/sheet/metal(drop_location(), 1)
new /obj/item/stack/rods(drop_location(), 8)
new /obj/item/stack/sheet/metal(drop_location(), 2)
..()
/obj/vehicle/ridden/wheelchair/Destroy()
@@ -53,7 +53,10 @@
/obj/vehicle/ridden/wheelchair/Moved()
. = ..()
cut_overlays()
playsound(src, 'sound/effects/roll.ogg', 75, 1)
if(istype(src, /obj/vehicle/ridden/wheelchair/motorized))
playsound(src, 'sound/effects/chairwhoosh.ogg', 75, 1)
else
playsound(src, 'sound/effects/roll.ogg', 75, 1)
if(has_buckled_mobs())
handle_rotation_overlayed()
@@ -88,8 +91,12 @@
/obj/vehicle/ridden/wheelchair/proc/handle_rotation_overlayed()
cut_overlays()
var/image/V = image(icon = icon, icon_state = "wheelchair_overlay", layer = FLY_LAYER, dir = src.dir)
add_overlay(V)
if(istype(src, /obj/vehicle/ridden/wheelchair/motorized))
var/image/V = image(icon = icon, icon_state = "wheelchair_noverlay", layer = FLY_LAYER, dir = src.dir)
add_overlay(V)
else
var/image/V = image(icon = icon, icon_state = "wheelchair_overlay", layer = FLY_LAYER, dir = src.dir)
add_overlay(V)
+1 -1
View File
@@ -21,7 +21,7 @@
/obj/item/clothing/suit/jacket/puffer/vest = 4,
/obj/item/clothing/suit/jacket/puffer = 4,
/obj/item/clothing/suit/hooded/cloak/david = 4,
/obj/item/clothing/neck/cancloak/polychromic = 4,
/obj/item/clothing/neck/cloak/cancloak/polychromic = 4,
/obj/item/clothing/suit/bomber = 5,
/obj/item/clothing/under/suit/turtle/teal = 3,
/obj/item/clothing/under/suit/turtle/grey = 3,
+1 -1
View File
@@ -150,7 +150,7 @@
SEND_SOUND(M,prey_digest)
play_sound = pick(pred_digest)
if(M.vore_flags & ABSORBED)
if(M.vore_flags & ABSORBED || !(M.vore_flags & ABSORBABLE)) //Negative.
continue
if(M.nutrition >= 100) //Drain them until there's no nutrients left. Slowly "absorb" them.
+67 -6
View File
@@ -1,17 +1,24 @@
///////////////////// Mob Living /////////////////////
/mob/living
var/vore_flags = 0
var/showvoreprefs = TRUE // Determines if the mechanical vore preferences button will be displayed on the mob or not.
var/obj/belly/vore_selected // Default to no vore capability.
var/list/vore_organs = list() // List of vore containers inside a mob
var/vore_taste = null // What the character tastes like
// Determines if the mechanical vore preferences button will be displayed on the mob or not.
var/showvoreprefs = TRUE
/// Default to no vore capability.
var/obj/belly/vore_selected
/// List of vore containers inside a mob
var/list/vore_organs = list()
/// What the character tastes like
var/vore_taste = null
/// What the character smells like
var/vore_smell = null
/// Next time vore sounds get played for the prey, do not change manually as it is intended to be set automatically
var/next_preyloop
//
// Hook for generic creation of stuff on new creatures
//
/hook/living_new/proc/vore_setup(mob/living/M)
add_verb(M, list(/mob/living/proc/preyloop_refresh, /mob/living/proc/lick, /mob/living/proc/escapeOOC))
add_verb(M, list(/mob/living/proc/preyloop_refresh, /mob/living/proc/lick, /mob/living/proc/smell, /mob/living/proc/escapeOOC))
if(M.vore_flags & NO_VORE) //If the mob isn't supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach.
return TRUE
@@ -256,6 +263,7 @@
client.prefs.vore_flags = vore_flags // there's garbage data in here, but it doesn't matter
client.prefs.vore_taste = vore_taste
client.prefs.vore_smell = vore_smell
var/list/serialized = list()
for(var/belly in vore_organs)
@@ -264,6 +272,8 @@
client.prefs.belly_prefs = serialized
client.prefs.save_character()
return TRUE
//
@@ -274,8 +284,9 @@
to_chat(src,"<span class='warning'>You attempted to apply your vore prefs but somehow you're in this character without a client.prefs variable. Tell a dev.</span>")
return FALSE
ENABLE_BITFIELD(vore_flags,VOREPREF_INIT)
COPY_SPECIFIC_BITFIELDS(vore_flags,client.prefs.vore_flags,DIGESTABLE | DEVOURABLE | FEEDING | LICKABLE)
COPY_SPECIFIC_BITFIELDS(vore_flags, client.prefs.vore_flags, DIGESTABLE | DEVOURABLE | FEEDING | LICKABLE | SMELLABLE | ABSORBABLE | MOBVORE)
vore_taste = client.prefs.vore_taste
vore_smell = client.prefs.vore_smell
release_vore_contents(silent = TRUE)
QDEL_LIST(vore_organs)
@@ -379,6 +390,56 @@
else
taste_message += "a plain old normal [src]"
return taste_message
//
// Equally important as the above
//
/mob/living/proc/smell()
set name = "Smell Someone"
set category = "Vore"
set desc = "Smell someone nearby!"
if(incapacitated(ignore_restraints = TRUE))
to_chat(src, "<span class='warning'>You can't do that while incapacitated.</span>")
return
if(!CheckActionCooldown())
to_chat(src, "<span class='warning'>You can't do that so fast, slow down.</span>")
return
DelayNextAction(CLICK_CD_MELEE, flush = TRUE)
var/list/smellable = list()
for(var/mob/living/L in view(1))
if(L != src && (!L.ckey || L.client?.prefs.vore_flags & SMELLABLE) && Adjacent(L))
LAZYADD(smellable, L)
for(var/mob/living/listed in smellable)
smellable[listed] = new /mutable_appearance(listed)
if(!smellable)
return
var/mob/living/sniffed = show_radial_menu(src, src, smellable, radius = 40, require_near = TRUE)
if(QDELETED(sniffed) || (sniffed.ckey && !(sniffed.client?.prefs.vore_flags & SMELLABLE)) || !Adjacent(sniffed) || incapacitated(ignore_restraints = TRUE))
return
visible_message("<span class='warning'>[src] smells [sniffed]!</span>","<span class='notice'>You smell [sniffed]. They smell like [sniffed.get_smell_message()].</span>","<b>Sniff!</b>")
/mob/living/proc/get_smell_message(allow_generic = TRUE, datum/species/mrace)
if(!vore_smell && !allow_generic)
return FALSE
var/smell_message = ""
if(vore_smell && (vore_smell != ""))
smell_message += "[vore_smell]"
else
if(ishuman(src))
var/mob/living/carbon/human/H = src
smell_message += "a normal [H.custom_species ? H.custom_species : H.dna.species]"
else
smell_message += "a plain old normal [src]"
return smell_message
// Check if an object is capable of eating things, based on vore_organs
//
/proc/has_vore_belly(var/mob/living/O)
File diff suppressed because it is too large Load Diff