Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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//////////
|
||||
//////////////////////////////////////
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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.")
|
||||
|
||||
@@ -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!")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,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")
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user