Merge branch 'master' into 91-files-changed-fml

This commit is contained in:
Detective-Google
2020-05-02 17:16:18 -05:00
committed by GitHub
80 changed files with 1987 additions and 1900 deletions

View File

@@ -81,7 +81,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
)
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/DB_ban_panel, /client/proc/stickybanpanel))
GLOBAL_PROTECT(admin_verbs_ban)
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/set_round_end_sound))
GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_sound, /client/proc/manual_play_web_sound, /client/proc/set_round_end_sound))
GLOBAL_PROTECT(admin_verbs_sounds)
GLOBAL_LIST_INIT(admin_verbs_fun, list(
/client/proc/cmd_admin_dress,

View File

@@ -138,6 +138,49 @@
SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Internet Sound")
/client/proc/manual_play_web_sound()
set category = "Fun"
set name = "Manual Play Internet Sound"
if(!check_rights(R_SOUNDS))
return
var/web_sound_input = input("Enter content stream URL (fetch this from local youtube-dl!)", "Play Internet Sound via direct URL") as text|null
if(istext(web_sound_input))
if(!length(web_sound_input))
log_admin("[key_name(src)] stopped web sound")
message_admins("[key_name(src)] stopped web sound")
var/mob/M
for(var/i in GLOB.player_list)
M = i
M?.client?.chatOutput?.stopMusic()
return
else
if(web_sound_input && !findtext(web_sound_input, GLOB.is_http_protocol))
to_chat(src, "<span class='boldwarning'>BLOCKED: Content URL not using http(s) protocol</span>")
return
var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num
if(isnull(freq))
return
if(!freq)
freq = 1
SSblackbox.record_feedback("nested tally", "played_url", 1, list("[ckey]", "[web_sound_input]"))
var/logstr = "[key_name(src)] played web sound at freq [freq]: [web_sound_input]"
log_admin(logstr)
message_admins(logstr)
var/mob/M
var/client/C
var/datum/chatOutput/O
for(var/i in GLOB.player_list)
M = i
C = M.client
if(!(C?.prefs?.toggles & SOUND_MIDI))
continue
O = C.chatOutput
if(!O || O.broken || !O.loaded)
continue
O.sendMusic(web_sound_input, freq)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Manual Play Internet Sound")
/client/proc/set_round_end_sound(S as sound)
set category = "Fun"
set name = "Set Round End Sound"

View File

@@ -42,7 +42,7 @@
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
report += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
report += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</B></span>"
else if(completion <= 0)
report += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE

View File

@@ -14,10 +14,10 @@
set waitfor = FALSE // Don't make on_gain() wait for this function to finish. This lets this code run on the side.
var/notice_healing
while(owner && !AmFinalDeath()) // owner.has_antag_datum(ANTAG_DATUM_BLOODSUCKER) == src
if(owner.current.stat == CONSCIOUS && !poweron_feed && !HAS_TRAIT(owner.current, TRAIT_DEATHCOMA)) // Deduct Blood
if(owner.current.stat == CONSCIOUS && !poweron_feed && !HAS_TRAIT(owner.current, TRAIT_FAKEDEATH)) // Deduct Blood
AddBloodVolume(passive_blood_drain) // -.1 currently
if(HandleHealing(1)) // Heal
if(notice_healing == FALSE && owner.current.blood_volume > 0)
if(!notice_healing && owner.current.blood_volume > 0)
to_chat(owner, "<span class='notice'>The power of your blood begins knitting your wounds...</span>")
notice_healing = TRUE
else if(notice_healing == TRUE)
@@ -25,7 +25,7 @@
HandleStarving() // Death
HandleDeath() // Standard Update
update_hud()// Daytime Sleep in Coffin
if(SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_DEATHCOMA, "bloodsucker"))
if(SSticker.mode.is_daylight() && !HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker"))
if(istype(owner.current.loc, /obj/structure/closet/crate/coffin))
Torpor_Begin()
// Wait before next pass
@@ -83,7 +83,7 @@
// NOTE: Mult of 0 is just a TEST to see if we are injured and need to go into Torpor!
//It is called from your coffin on close (by you only)
var/actual_regen = regen_rate + additional_regen
if(poweron_masquerade == TRUE || owner.current.AmStaked())
if(poweron_masquerade|| owner.current.AmStaked())
return FALSE
if(owner.current.reagents.has_reagent(/datum/reagent/consumable/garlic))
return FALSE
@@ -101,8 +101,8 @@
var/mob/living/carbon/C = owner.current
var/costMult = 1 // Coffin makes it cheaper
var/fireheal = 0 // BURN: Heal in Coffin while Fakedeath, or when damage above maxhealth (you can never fully heal fire)
var/amInCoffinWhileTorpor = istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_FAKEDEATH)) // Check for mult 0 OR death coma. (mult 0 means we're testing from coffin)
if(amInCoffinWhileTorpor)
// Check for mult 0 OR death coma. (mult 0 means we're testing from coffin)
if(istype(C.loc, /obj/structure/closet/crate/coffin) && (mult == 0 || HAS_TRAIT(C, TRAIT_FAKEDEATH)))
mult *= 4 // Increase multiplier if we're sleeping in a coffin.
fireheal = min(C.getFireLoss(), regen_rate) // NOTE: Burn damage ONLY heals in torpor.
C.ExtinguishMob()
@@ -112,6 +112,9 @@
CheckVampOrgans() // Heart, Eyes
if(check_limbs(costMult))
return TRUE
else if(owner.current.stat >= UNCONSCIOUS) //Faster regeneration and slight burn healing while unconcious
mult *= 2
fireheal = min(C.getFireLoss(), regen_rate * 0.2)
// BRUTE: Always Heal
var/bruteheal = min(C.getBruteLoss(), actual_regen)
@@ -120,8 +123,6 @@
if(bruteheal + fireheal + toxinheal > 0) // Just a check? Don't heal/spend, and return.
if(mult == 0)
return TRUE
if(owner.current.stat >= UNCONSCIOUS) //Faster regeneration while unconcious, so you dont have to wait all day
mult *= 2
// We have damage. Let's heal (one time)
C.adjustBruteLoss(-bruteheal * mult, forced = TRUE)// Heal BRUTE / BURN in random portions throughout the body.
C.adjustFireLoss(-fireheal * mult, forced = TRUE)
@@ -146,12 +147,6 @@
to_chat(C, "<span class='notice'>Your flesh knits as it regrows your [L]!</span>")
playsound(C, 'sound/magic/demon_consume.ogg', 50, TRUE)
return TRUE
/*for(var/obj/item/bodypart/BP in C.bodyparts)
if(!istype(BP) && !BP.status == 2)
return FALSE
to_chat(C, "<span class='notice'>Your body expels the [BP]!</span>")
BP.drop_limb()
return TRUE */
/datum/antagonist/bloodsucker/proc/CureDisabilities()
var/mob/living/carbon/C = owner.current
@@ -176,7 +171,7 @@
// EMPTY: Frenzy!
// BLOOD_VOLUME_GOOD: [336] Pale (handled in bloodsucker_integration.dm
// BLOOD_VOLUME_BAD: [224] Jitter
if(owner.current.blood_volume < BLOOD_VOLUME_BAD && !prob(0.5))
if(owner.current.blood_volume < BLOOD_VOLUME_BAD && !prob(0.5 && HAS_TRAIT(owner, TRAIT_FAKEDEATH)) && !poweron_masquerade)
owner.current.Jitter(3)
// BLOOD_VOLUME_SURVIVE: [122] Blur Vision
if(owner.current.blood_volume < BLOOD_VOLUME_BAD / 2)
@@ -230,16 +225,16 @@
Torpor_Begin()
to_chat(owner, "<span class='danger'>Your immortal body will not yet relinquish your soul to the abyss. You enter Torpor.</span>")
sleep(30) //To avoid spam
if(poweron_masquerade == TRUE)
if(poweron_masquerade)
to_chat(owner, "<span class='warning'>Your wounds will not heal until you disable the <span class='boldnotice'>Masquerade</span> power.</span>")
// End Torpor:
else // No damage, OR toxin healed AND brute healed and NOT in coffin (since you cannot heal burn)
if(total_damage <= 0 || total_toxloss <= 0 && total_brute <= 0 && !istype(owner.current.loc, /obj/structure/closet/crate/coffin))
// Not Daytime, Not in Torpor
if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker"))
// Not Daytime, Not in Torpor, enough health to not die the moment you end torpor
if(!SSticker.mode.is_daylight() && HAS_TRAIT_FROM(owner.current, TRAIT_FAKEDEATH, "bloodsucker") && total_damage < owner.current.getMaxHealth())
Torpor_End()
// Fake Unconscious
if(poweron_masquerade == TRUE && total_damage >= owner.current.getMaxHealth() - HEALTH_THRESHOLD_FULLCRIT)
if(poweron_masquerade && total_damage >= owner.current.getMaxHealth() - HEALTH_THRESHOLD_FULLCRIT)
owner.current.Unconscious(20, 1)
/datum/antagonist/bloodsucker/proc/Torpor_Begin(amInCoffin = FALSE)
@@ -249,6 +244,7 @@
ADD_TRAIT(owner.current, TRAIT_NODEATH, "bloodsucker") // Without this, you'll just keep dying while you recover.
ADD_TRAIT(owner.current, TRAIT_RESISTHIGHPRESSURE, "bloodsucker") // So you can heal in space. Otherwise you just...heal forever.
ADD_TRAIT(owner.current, TRAIT_RESISTLOWPRESSURE, "bloodsucker")
owner.current.Jitter(0)
// Visuals
owner.current.update_sight()
owner.current.reload_fullscreen()
@@ -256,6 +252,9 @@
for(var/datum/action/bloodsucker/power in powers)
if(power.active && !power.can_use_in_torpor)
power.DeactivatePower()
if(owner.current.suiciding)
owner.current.suiciding = FALSE //Youll die but not for long.
to_chat(owner.current, "<span class='warning'>Your body keeps you going, even as you try to end yourself.</span>")
/datum/antagonist/bloodsucker/proc/Torpor_End()
owner.current.stat = SOFT_CRIT

View File

@@ -45,15 +45,15 @@
// (FINAL LIL WARNING)
while(time_til_cycle > 5)
sleep(10)
if (cancel_me)
if(cancel_me)
return
//sleep(TIME_BLOODSUCKER_DAY_FINAL_WARN - 50)
warn_daylight(3,"<span class = 'userdanger'>Seek cover, for Sol rises!</span>")
// Part 3: Night Ending
while (time_til_cycle > 0)
while(time_til_cycle > 0)
sleep(10)
if (cancel_me)
if(cancel_me)
return
//sleep(50)
warn_daylight(4,"<span class = 'userdanger'>Solar flares bombard the station with deadly UV light!</span><br><span class = ''>Stay in cover for the next [TIME_BLOODSUCKER_DAY / 60] minutes or risk Final Death!</span>",\
@@ -69,11 +69,11 @@
while(time_til_cycle > 0)
punish_vamps()
sleep(TIME_BLOODSUCKER_BURN_INTERVAL)
if (cancel_me)
if(cancel_me)
return
//daylight_time -= TIME_BLOODSUCKER_BURN_INTERVAL
// Issue Level Up!
if(!issued_XP && time_til_cycle <= 15)
if(!issued_XP && time_til_cycle <= 5)
issued_XP = TRUE
vamps_rank_up()

View File

@@ -227,7 +227,7 @@
// Traits
for(var/T in defaultTraits)
REMOVE_TRAIT(owner.current, T, BLOODSUCKER_TRAIT)
if(had_toxlover == TRUE)
if(had_toxlover)
ADD_TRAIT(owner.current, TRAIT_TOXINLOVER, SPECIES_TRAIT)
// Traits: Species

View File

@@ -18,14 +18,11 @@
. = ..()
if(!.)
return
// must have nobody around to see the cloak
var/watchers = viewers(9,get_turf(owner))
for(var/mob/living/M in watchers)
for(var/mob/living/M in viewers(9, owner))
if(M != owner)
to_chat(owner, "<span class='warning'>You may only vanish into the shadows unseen.</span>")
return FALSE
return TRUE
/datum/action/bloodsucker/cloak/ActivatePower()

View File

@@ -52,6 +52,7 @@
REMOVE_TRAIT(user, TRAIT_NOHARDCRIT, "bloodsucker")
REMOVE_TRAIT(user, TRAIT_NOSOFTCRIT, "bloodsucker")
REMOVE_TRAIT(user, TRAIT_VIRUSIMMUNE, "bloodsucker")
REMOVE_TRAIT(user, TRAIT_NOBREATH, "bloodsucker")
var/obj/item/organ/heart/vampheart/H = user.getorganslot(ORGAN_SLOT_HEART)
var/obj/item/organ/eyes/vassal/bloodsucker/E = user.getorganslot(ORGAN_SLOT_EYES)
E.flash_protect = 0
@@ -93,6 +94,7 @@
ADD_TRAIT(user, TRAIT_NOHARDCRIT, "bloodsucker")
ADD_TRAIT(user, TRAIT_NOSOFTCRIT, "bloodsucker")
ADD_TRAIT(user, TRAIT_VIRUSIMMUNE, "bloodsucker")
ADD_TRAIT(user, TRAIT_NOBREATH, "bloodsucker")
// HEART
var/obj/item/organ/heart/H = user.getorganslot(ORGAN_SLOT_HEART)

View File

@@ -28,7 +28,7 @@
/datum/action/bloodsucker/targeted/trespass/CheckValidTarget(atom/A)
// Can't target my tile
if (A == get_turf(owner) || get_turf(A) == get_turf(owner))
if(A == get_turf(owner) || get_turf(A) == get_turf(owner))
return FALSE
return TRUE // All we care about is destination. Anything you click is fine.
@@ -43,13 +43,13 @@
// Are either tiles WALLS?
var/turf/from_turf = get_turf(owner)
var/this_dir // = get_dir(from_turf, target_turf)
for (var/i=1 to 2)
for(var/i=1 to 2)
// Keep Prev Direction if we've reached final turf
if (from_turf != final_turf)
if(from_turf != final_turf)
this_dir = get_dir(from_turf, final_turf) // Recalculate dir so we don't overshoot on a diagonal.
from_turf = get_step(from_turf, this_dir)
// ERROR! Wall!
if (iswallturf(from_turf))
if(iswallturf(from_turf))
if (display_error)
var/wallwarning = (i == 1) ? "in the way" : "at your destination"
to_chat(owner, "<span class='warning'>There is a solid wall [wallwarning].</span>")
@@ -84,7 +84,7 @@
user.next_move = world.time + mist_delay
user.Stun(mist_delay, ignore_canstun = TRUE)
user.notransform = TRUE
user.density = 0
user.density = FALSE
var/invis_was = user.invisibility
user.invisibility = INVISIBILITY_MAXIMUM
@@ -94,7 +94,7 @@
sleep(mist_delay / 2)
// Move & Freeze
if (isturf(target_turf))
if(isturf(target_turf))
do_teleport(owner, target_turf, no_effects=TRUE, channel = TELEPORT_CHANNEL_QUANTUM) // in teleport.dm?
user.next_move = world.time + mist_delay / 2
user.Stun(mist_delay / 2, ignore_canstun = TRUE)

View File

@@ -111,7 +111,7 @@
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</B></span>"
else if(completion <= 0)
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE

View File

@@ -563,7 +563,7 @@
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</B></span>"
else if(completion <= 0)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
changelingwin = FALSE

View File

@@ -441,7 +441,7 @@
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</B></span>"
else if(completion <= 0)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
else

View File

@@ -55,7 +55,7 @@
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
result += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
result += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</B></span>"
else if(completion <= 0)
result += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE

View File

@@ -239,7 +239,7 @@
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</B></span>"
else if(completion <= 0)
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
traitorwin = FALSE

View File

@@ -269,7 +269,7 @@
if(objective.completable)
var/completion = objective.check_completion()
if(completion >= 1)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</B></span>"
else if(completion <= 0)
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
wizardwin = FALSE

View File

@@ -3,14 +3,35 @@
desc = "A small electronic device able to control a blast door remotely."
icon_state = "control"
attachable = TRUE
var/id = null
var/can_change_id = 0
/// Our ID. Make the first character ! if you want to obfuscate it as a mapper via randomization.
var/id
/// Can the ID be changed if used in hand?
var/can_change_id = FALSE
/// Show ID?
var/show_id = TRUE
var/cooldown = FALSE //Door cooldowns
/obj/item/assembly/control/Initialize(mapload)
if(mapload && id)
if(copytext(id, 1, 2) == "!")
id = SSmapping.get_obfuscated_id(id)
return ..()
/obj/item/assembly/control/examine(mob/user)
. = ..()
if(id)
if(id && show_id)
. += "<span class='notice'>Its channel ID is '[id]'.</span>"
if(can_change_id)
. += "<span class='notice'>Use in hand to change ID.</span>"
/obj/item/assembly/control/attack_self(mob/living/user)
. = ..()
if(!can_change_id)
return
var/new_id
new_id = input(user, "Set ID", "Set ID", show_id? id : null) as text|null
if(!isnull(new_id)) //0/"" is considered !, so check null instead of just !.
id = new_id
/obj/item/assembly/control/activate()
cooldown = TRUE
@@ -22,7 +43,6 @@
INVOKE_ASYNC(M, openclose ? /obj/machinery/door/poddoor.proc/open : /obj/machinery/door/poddoor.proc/close)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
/obj/item/assembly/control/airlock
name = "airlock controller"
desc = "A small electronic device able to control an airlock remotely."
@@ -123,7 +143,6 @@
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
/obj/item/assembly/control/crematorium
name = "crematorium controller"
desc = "An evil-looking remote controller for a crematorium."
@@ -135,3 +154,14 @@
C.cremate(usr)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
/obj/item/assembly/control/electrochromatic
name = "electrochromatic window controller"
desc = "Toggles linked electrochromatic windows."
can_change_id = TRUE
/// Stores our status to prevent windows from desyncing.
var/on = FALSE
/obj/item/assembly/control/electrochromatic/activate()
on = !on
do_electrochromatic_toggle(on, id)

View File

@@ -192,6 +192,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
anchored = TRUE // should only appear in vis_contents, but to be safe
layer = FLY_LAYER
appearance_flags = TILE_BOUND
vis_flags = NONE
/obj/effect/overlay/gas/New(state, alph)
. = ..()

View File

@@ -225,6 +225,7 @@
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
return
target_temperature = min_temperature
to_chat(user,"<span class='notice'>You minimize the temperature on the [src].</span>")
investigate_log("was set to [target_temperature] K by [key_name(usr)]", INVESTIGATE_ATMOS)
message_admins("[src.name] was minimized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
return TRUE
@@ -257,6 +258,7 @@
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
return
target_temperature = max_temperature
to_chat(user,"<span class='notice'>You maximize the temperature on the [src].</span>")
investigate_log("was set to [target_temperature] K by [key_name(usr)]", INVESTIGATE_ATMOS)
message_admins("[src.name] was maximized by [ADMIN_LOOKUPFLW(usr)] at [ADMIN_COORDJMP(T)], [A]")
return TRUE

View File

@@ -262,7 +262,15 @@
return
random_look(owner)
/obj/item/clothing/under/chameleon
// Forgive me for my sins...
#define CHAMELEON_CLOTHING_DEFINE(path) \
##path/syndicate/Initialize(mapload){\
. = ..();\
AddComponent(/datum/component/identification/syndicate, ID_COMPONENT_DEL_ON_IDENTIFY, ID_COMPONENT_EFFECT_NO_ACTIONS, ID_COMPONENT_IDENTIFY_WITH_DECONSTRUCTOR);\
}\
##path
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/under/chameleon)
//starts off as black
name = "black jumpsuit"
icon_state = "black"
@@ -300,7 +308,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/suit/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/suit/chameleon)
name = "armor"
desc = "A slim armored vest that protects against most types of damage."
icon_state = "armor"
@@ -329,7 +337,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/glasses/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/glasses/chameleon)
name = "Optical Meson Scanner"
desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting condition."
icon_state = "meson"
@@ -357,7 +365,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/gloves/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/gloves/chameleon)
desc = "These gloves will protect the wearer from electric shock."
name = "insulated gloves"
icon_state = "yellow"
@@ -368,6 +376,9 @@
var/datum/action/item_action/chameleon/change/chameleon_action
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/gloves/chameleon/insulated)
siemens_coefficient = 0
/obj/item/clothing/gloves/chameleon/Initialize()
. = ..()
chameleon_action = new(src)
@@ -386,7 +397,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/head/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/head/chameleon)
name = "grey cap"
desc = "It's a baseball hat in a tasteful grey colour."
icon_state = "greysoft"
@@ -429,7 +440,7 @@
var/datum/action/item_action/chameleon/drone/randomise/randomise_action = new(src)
randomise_action.UpdateButtonIcon()
/obj/item/clothing/mask/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/mask/chameleon)
name = "gas mask"
desc = "A face-covering mask that can be connected to an air supply. While good for concealing your identity, it isn't good for blocking gas flow." //More accurate
icon_state = "gas_alt"
@@ -486,7 +497,7 @@
/obj/item/clothing/mask/chameleon/drone/attack_self(mob/user)
to_chat(user, "<span class='notice'>[src] does not have a voice changer.</span>")
/obj/item/clothing/shoes/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/shoes/chameleon)
name = "black shoes"
icon_state = "black"
desc = "A pair of black shoes."
@@ -511,7 +522,7 @@
return
chameleon_action.emp_randomise()
/obj/item/clothing/shoes/chameleon/noslip
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/shoes/chameleon/noslip)
name = "black shoes"
icon_state = "black"
desc = "A pair of black shoes."
@@ -521,7 +532,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/storage/backpack/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/storage/backpack/chameleon)
name = "backpack"
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -542,7 +553,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/storage/belt/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/storage/belt/chameleon)
name = "toolbelt"
desc = "Holds tools."
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -570,7 +581,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/radio/headset/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/radio/headset/chameleon)
name = "radio headset"
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -591,7 +602,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/pda/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/pda/chameleon)
name = "PDA"
var/datum/action/item_action/chameleon/change/pda/chameleon_action
@@ -613,7 +624,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/stamp/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/stamp/chameleon)
var/datum/action/item_action/chameleon/change/chameleon_action
/obj/item/stamp/chameleon/Initialize()
@@ -627,7 +638,7 @@
. = ..()
chameleon_action.emp_randomise(INFINITY)
/obj/item/clothing/neck/cloak/chameleon
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/neck/cloak/chameleon)
name = "black tie"
desc = "A neosilk clip-on tie."
icon = 'icons/obj/clothing/neck.dmi'

View File

@@ -23,6 +23,9 @@
/datum/round_event/wormholes/start()
for(var/turf/open/floor/T in world)
if(is_station_level(T.z))
var/area/A = get_area(T)
if(A.outdoors)
continue
pick_turfs += T
for(var/i = 1, i <= number_of_wormholes, i++)

View File

@@ -937,3 +937,20 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
spawners_menu = new(src)
spawners_menu.ui_interact(src)
/mob/dead/observer/verb/game_info()
set name = "Game info"
set desc = "Shows various info relating to the game mode, antagonists etc."
set category = "Ghost"
if(!started_as_observer && can_reenter_corpse)
to_chat(src, "You cannot see this info unless you are an observer or you've chosen Do Not Resuscitate!")
return
var/list/stuff = list("[SSticker.mode.name]")
stuff += "Antagonists:\n"
for(var/datum/antagonist/A in GLOB.antagonists)
if(A.owner)
stuff += "[A.owner] the [A.name]"
var/ghost_info = SSticker.mode.ghost_info()
if(ghost_info)
stuff += ghost_info
to_chat(src,stuff.Join("\n"))

View File

@@ -101,7 +101,7 @@ GLOBAL_LIST_INIT(dwarf_last, world.file2list("strings/names/dwarf_last.txt")) //
/obj/item/organ/dwarfgland/on_life() //Primary loop to hook into to start delayed loops for other loops..
. = ..()
if(!owner || owner.stat == DEAD)
if(owner && owner.stat != DEAD)
dwarf_cycle_ticker()
//Handles the delayed tick cycle by just adding on increments per each on_life() tick

View File

@@ -264,6 +264,9 @@
if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/medbot/coming.ogg',"Wait [H.name]! I want to help!" = 'sound/voice/medbot/help.ogg',"[H.name], you appear to be injured!" = 'sound/voice/medbot/injured.ogg')
var/message = pick(messagevoice)
if(prob(1) && ISINRANGE_EX(H.getFireLoss(), 0, 20))
message = "Notices your minor burns*OwO what's this?"
messagevoice[message] = 'sound/voice/medbot/owo.ogg'
speak(message)
playsound(loc, messagevoice[message], 50, 0)
last_newpatient_speak = world.time

View File

@@ -97,6 +97,8 @@
body_color = "brown"
icon_state = "mouse_brown"
GLOBAL_VAR(tom_existed)
//TOM IS ALIVE! SQUEEEEEEEE~K :)
/mob/living/simple_animal/mouse/brown/Tom
name = "Tom"
@@ -106,6 +108,10 @@
response_harm = "splats"
gold_core_spawnable = NO_SPAWN
/mob/living/simple_animal/mouse/brown/Tom/Initialize()
. = ..()
GLOB.tom_existed = TRUE
/obj/item/reagent_containers/food/snacks/deadmouse
name = "dead mouse"
desc = "It looks like somebody dropped the bass on it. A lizard's favorite meal."

View File

@@ -10,6 +10,8 @@
throwforce = 10
blocks_emissive = EMISSIVE_BLOCK_GENERIC
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
var/lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
var/datum/mind/mind
var/list/datum/action/actions = list()

View File

@@ -4,8 +4,8 @@
fire_sound = 'sound/weapons/ionrifle.ogg'
/obj/item/ammo_casing/energy/ion/hos
projectile_type = /obj/item/projectile/ion/weak
e_cost = 300
projectile_type = /obj/item/projectile/ion
e_cost = 200
/obj/item/ammo_casing/energy/declone
projectile_type = /obj/item/projectile/energy/declone

View File

@@ -74,3 +74,11 @@
materials = list(/datum/material/glass = 20)
build_path = /obj/item/stock_parts/cell/emergency_light
category = list("initial", "Electronics")
/datum/design/electrochromatic_control
name = "Electrochromatic Control Circuit"
id = "electrochromatic_control_circuit"
build_type = AUTOLATHE
materials = list(/datum/material/iron = 100, /datum/material/glass = 100)
build_path = /obj/item/assembly/control/electrochromatic
category = list("initial", "Electronics")

View File

@@ -1,5 +1,5 @@
/datum/design/autoylathe
build_type = AUTOYLATHE
build_type = TOYLATHE
/datum/design/autoylathe/mech
category = list("initial", "Figurines")
@@ -558,7 +558,7 @@
/datum/design/foam_x9
name = "Foam Force X9 Rifle"
id = "foam_x9"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 4000, /datum/material/iron = 500)
build_path = /obj/item/gun/ballistic/automatic/x9/toy
category = list("initial", "Rifles")
@@ -566,7 +566,7 @@
/datum/design/foam_dart
name = "Box of Foam Darts"
id = "foam_dart"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 500, /datum/material/iron = 100)
build_path = /obj/item/ammo_box/foambox
category = list("initial", "Misc")
@@ -574,7 +574,7 @@
/datum/design/foam_magpistol
name = "Foam Force Magpistol"
id = "magfoam_launcher"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 2000, /datum/material/iron = 250)
build_path = /obj/item/gun/ballistic/shotgun/toy/mag
category = list("initial", "Pistols")
@@ -582,7 +582,7 @@
/datum/design/foam_magrifle
name = "Foam Force MagRifle"
id = "foam_magrifle"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 4000, /datum/material/iron = 500)
build_path = /obj/item/gun/ballistic/automatic/toy/magrifle
category = list("initial", "Rifles")
@@ -590,7 +590,7 @@
/datum/design/foam_hyperburst
name = "MagTag Hyper Rifle"
id = "foam_hyperburst"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 4000, /datum/material/iron = 2000, /datum/material/glass = 1000)
build_path = /obj/item/gun/energy/laser/practice/hyperburst
category = list("initial", "Rifles")
@@ -598,7 +598,7 @@
/datum/design/foam_sp
name = "Foam Force Stealth Pistol"
id = "foam_sp"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 2000, /datum/material/iron = 1000)
build_path = /obj/item/gun/ballistic/automatic/toy/pistol/stealth
category = list("initial", "Pistols")
@@ -606,7 +606,7 @@
/datum/design/toyray
name = "RayTag Gun"
id = "toyray"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 2000, /datum/material/iron = 1000, /datum/material/glass = 1000)
build_path = /obj/item/gun/energy/laser/practice/raygun
category = list("initial", "Pistols")
@@ -614,7 +614,7 @@
/datum/design/am4c
name = "Foam Force AM4-C Rifle"
id = "foam_am4c"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 4000, /datum/material/iron = 500)
build_path = /obj/item/gun/ballistic/automatic/AM4C
category = list("initial", "Rifles")
@@ -622,7 +622,7 @@
/datum/design/foam_f3
name = "Replica F3 Justicar"
id = "foam_f3"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 2000, /datum/material/iron = 250)
build_path = /obj/item/toy/gun/justicar
category = list("initial", "Pistols")
@@ -630,7 +630,7 @@
/datum/design/toy_blaster
name = "pump-action plastic blaster"
id = "toy_blaster"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 2000, /datum/material/iron = 750, /datum/material/glass = 1000)
build_path = /obj/item/gun/energy/pumpaction/toy
category = list("initial", "Rifles")
@@ -638,7 +638,7 @@
/datum/design/capammo
name = "Box of Caps"
id = "capammo"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/iron = 10, /datum/material/glass = 10)
build_path = /obj/item/toy/ammo/gun
category = list("initial", "Misc")
@@ -646,7 +646,7 @@
/datum/design/foam_smg
name = "Foam Force SMG"
id = "foam_smg"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 2000, /datum/material/iron = 250)
build_path = /obj/item/gun/ballistic/automatic/toy/unrestricted
category = list("initial", "Pistols")
@@ -654,7 +654,7 @@
/datum/design/foam_pistol
name = "Foam Force Pistol"
id = "foam_pistol"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 2000, /datum/material/iron = 250)
build_path = /obj/item/gun/ballistic/automatic/toy/pistol/unrestricted
category = list("initial", "Pistols")
@@ -662,7 +662,7 @@
/datum/design/foam_shotgun
name = "Foam Force Shotgun"
id = "foam_shotgun"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 4000, /datum/material/iron = 500)
build_path = /obj/item/gun/ballistic/shotgun/toy/unrestricted
category = list("initial", "Rifles")
@@ -670,7 +670,7 @@
/datum/design/foam_dartred
name = "Box of Lastag Red Foam Darts"
id = "redfoam_dart"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 500, /datum/material/iron = 100)
build_path = /obj/item/ammo_box/foambox/tag/red
category = list("initial", "Misc")
@@ -678,7 +678,7 @@
/datum/design/foam_dartblue
name = "Box of Lastag Blue Foam Darts"
id = "bluefoam_dart"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 500, /datum/material/iron = 100)
build_path = /obj/item/ammo_box/foambox/tag/blue
category = list("initial", "Misc")
@@ -686,7 +686,7 @@
/datum/design/foam_bow
name = "Foam Force Crossbow"
id = "foam_bow"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 2000, /datum/material/iron = 250)
build_path = /obj/item/gun/ballistic/shotgun/toy/crossbow
category = list("initial", "Pistols")
@@ -694,7 +694,7 @@
/datum/design/foam_c20
name = "Donksoft C20R"
id = "foam_c20"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 4000, /datum/material/iron = 500)
build_path = /obj/item/gun/ballistic/automatic/c20r/toy/unrestricted
category = list("hacked", "Rifles")
@@ -702,7 +702,7 @@
/datum/design/foam_l6
name = "Donksoft LMG"
id = "foam_LMG"
build_type = AUTOYLATHE
build_type = TOYLATHE
materials = list(/datum/material/plastic = 4000, /datum/material/iron = 500)
build_path = /obj/item/gun/ballistic/automatic/l6_saw/toy/unrestricted
category = list("hacked", "Rifles")

View File

@@ -111,6 +111,6 @@
name = "Machine Design (Autoylathe)"
desc = "The circuit board for an autoylathe."
id = "autoylathe"
build_path = /obj/item/circuitboard/machine/autoylathe
build_path = /obj/item/circuitboard/machine/autolathe/toy
departmental_flags = DEPARTMENTAL_FLAG_ALL
category = list("Misc. Machinery")

View File

@@ -101,7 +101,7 @@ Note: Must be placed within 3 tiles of the R&D Console
if(!istype(loaded_item) || !istype(linked_console))
return FALSE
if (id && id != RESEARCH_MATERIAL_RECLAMATION_ID)
if (id && id != RESEARCH_MATERIAL_RECLAMATION_ID && id != RESEARCH_DEEP_SCAN_ID)
var/datum/techweb_node/TN = SSresearch.techweb_node_by_id(id)
if(!istype(TN))
return FALSE
@@ -125,7 +125,7 @@ Note: Must be placed within 3 tiles of the R&D Console
if(destroy_item(loaded_item))
linked_console.stored_research.boost_with_path(SSresearch.techweb_node_by_id(TN.id), dpath)
else
else if(id == RESEARCH_MATERIAL_RECLAMATION_ID)
var/list/point_value = techweb_item_point_check(loaded_item)
if(linked_console.stored_research.deconstructed_items[loaded_item.type])
point_value = list()
@@ -143,6 +143,15 @@ Note: Must be placed within 3 tiles of the R&D Console
if(destroy_item(loaded_item))
linked_console.stored_research.add_point_list(point_value)
linked_console.stored_research.deconstructed_items[loaded_type] = point_value
else if(id == RESEARCH_DEEP_SCAN_ID)
var/list/return_list = list()
. = SEND_SIGNAL(loaded_item, COMSIG_ITEM_DECONSTRUCTOR_DEEPSCAN, src, user, return_list)
flick("d_analyzer_process", src)
if(. & COMPONENT_DEEPSCAN_UNCOVERED_INFORMATION)
say("New information uncovered from item deep scan[length(return_list)? ": [english_list(return_list)]" : ""].")
else
say("Item deep scan uncovered no new information.")
return TRUE
/obj/machinery/rnd/destructive_analyzer/proc/unload_item()

View File

@@ -160,7 +160,7 @@
if(!host_mob.client) //less brainpower
points *= 0.25
SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = points))
/datum/nanite_program/researchplus
name = "Neural Network"
desc = "The nanites link the host's brains together forming a neural research network, that becomes more efficient with the amount of total hosts."
@@ -184,7 +184,7 @@
SSnanites.neural_network_count--
else
SSnanites.neural_network_count -= 0.25
/datum/nanite_program/researchplus/active_effect()
if(!iscarbon(host_mob))
return
@@ -234,7 +234,7 @@
var/spread_cooldown = 0
/datum/nanite_program/spreading/active_effect()
if(spread_cooldown < world.time)
if(world.time < spread_cooldown)
return
spread_cooldown = world.time + 50
var/list/mob/living/target_hosts = list()

View File

@@ -47,6 +47,9 @@ Nothing else in the console has ID requirements.
var/research_control = TRUE
/// Long action cooldown to prevent spam
var/last_long_action = 0
/obj/machinery/computer/rdconsole/production
circuit = /obj/item/circuitboard/computer/rdconsole/production
research_control = FALSE
@@ -583,10 +586,8 @@ Nothing else in the console has ID requirements.
l += "<table><tr><td>[icon2html(linked_destroy.loaded_item, usr)]</td><td><b>[linked_destroy.loaded_item.name]</b> <A href='?src=[REF(src)];eject_item=1'>Eject</A></td></tr></table>[RDSCREEN_NOBREAK]"
l += "Select a node to boost by deconstructing this item. This item can boost:"
var/anything = FALSE
var/list/boostable_nodes = techweb_item_boost_check(linked_destroy.loaded_item)
for(var/id in boostable_nodes)
anything = TRUE
var/list/worth = boostable_nodes[id]
var/datum/techweb_node/N = SSresearch.techweb_node_by_id(id)
@@ -620,7 +621,6 @@ Nothing else in the console has ID requirements.
// point deconstruction and material reclamation use the same ID to prevent accidentally missing the points
var/list/point_values = techweb_item_point_check(linked_destroy.loaded_item)
if(point_values)
anything = TRUE
l += "<div class='statusDisplay'>[RDSCREEN_NOBREAK]"
if (stored_research.deconstructed_items[linked_destroy.loaded_item.type])
l += "<span class='linkOff'>Point Deconstruction</span>"
@@ -636,10 +636,8 @@ Nothing else in the console has ID requirements.
for (var/M in materials)
l += "* [CallMaterialName(M)] x [materials[M]]"
l += "</div>[RDSCREEN_NOBREAK]"
anything = TRUE
if (!anything)
l += "Nothing!"
l += "<div class='statusDisplay'><A href='?src=[REF(src)];deconstruct=[RESEARCH_DEEP_SCAN_ID]'>Nondestructive Deep Scan</A></div>"
l += "</div>"
return l
@@ -926,6 +924,9 @@ Nothing else in the console has ID requirements.
screen = RDSCREEN_MENU
say("Ejecting Technology Disk")
if(ls["deconstruct"])
if((last_long_action + 1 SECONDS) > world.time)
return
last_long_action = world.time
if(QDELETED(linked_destroy))
say("No Destructive Analyzer Linked!")
return
@@ -1037,7 +1038,7 @@ Nothing else in the console has ID requirements.
autolathe_friendly = FALSE
D.category -= "Imported"
if(D.build_type & (AUTOLATHE|PROTOLATHE|CRAFTLATHE)) // Specifically excludes circuit imprinter and mechfab
if(D.build_type & (AUTOLATHE|PROTOLATHE|TOYLATHE)) // Specifically excludes circuit imprinter and mechfab
D.build_type = autolathe_friendly ? (D.build_type | AUTOLATHE) : D.build_type
D.category |= "Imported"
d_disk.blueprints[slot] = D

View File

@@ -344,6 +344,7 @@
/datum/techweb/specialized/autounlocking
var/design_autounlock_buildtypes = NONE
var/design_autounlock_skip_types = NONE
var/design_autounlock_categories = list("initial") //if a design has a buildtype that matches the abovea and either has a category in this or this is null, unlock it.
var/node_autounlock_ids = list() //autounlock nodes of this type.
@@ -356,7 +357,7 @@
research_node_id(id, TRUE, FALSE)
for(var/id in SSresearch.techweb_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(id)
if(D.build_type & design_autounlock_buildtypes)
if(D.build_type & (design_autounlock_buildtypes & allowed_buildtypes) && !(D.build_type & design_autounlock_skip_types))
for(var/i in D.category)
if(i in design_autounlock_categories)
add_design_by_id(D.id)
@@ -364,7 +365,16 @@
/datum/techweb/specialized/autounlocking/autolathe
design_autounlock_buildtypes = AUTOLATHE
allowed_buildtypes = AUTOLATHE
allowed_buildtypes = AUTOLATHE|TOYLATHE
/datum/techweb/specialized/autounlocking/autolathe/public
design_autounlock_skip_types = NO_PUBLIC_LATHE
/datum/techweb/specialized/autounlocking/autolathe/toy
design_autounlock_buildtypes = TOYLATHE
/datum/techweb/specialized/autounlocking/autolathe/toy/public
design_autounlock_skip_types = NO_PUBLIC_LATHE
/datum/techweb/specialized/autounlocking/limbgrower
design_autounlock_buildtypes = LIMBGROWER
@@ -381,10 +391,6 @@
/datum/techweb/specialized/autounlocking/exofab
allowed_buildtypes = MECHFAB
/datum/techweb/specialized/autounlocking/autoylathe
design_autounlock_buildtypes = AUTOYLATHE
allowed_buildtypes = AUTOYLATHE
/datum/techweb/specialized/autounlocking/autobottler
design_autounlock_buildtypes = AUTOBOTTLER
allowed_buildtypes = AUTOBOTTLER

View File

@@ -13,7 +13,7 @@
/obj/item/organ/appendix/on_life()
. = ..()
if(.)
if(. || !owner)
return
owner.adjustToxLoss(4, TRUE, TRUE) //forced to ensure people don't use it to gain tox as slime person

View File

@@ -26,7 +26,7 @@
/obj/item/organ/liver/on_life()
. = ..()
if(!.)//can't process reagents with a failing liver
if(!. || !owner)//can't process reagents with a failing liver
return
if(filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER))

View File

@@ -108,7 +108,7 @@
var/datum/gas_mixture/enviro = T.return_air()
local_temp = enviro.temperature
else if(istype(loc, /mob/) && !owner)
else if(!owner && ismob(loc))
var/mob/M = loc
if(is_type_in_typecache(M.loc, GLOB.freezing_objects))
if(!(organ_flags & ORGAN_FROZEN))
@@ -137,9 +137,7 @@
/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing or synthetic
if(organ_flags & ORGAN_FAILING || !owner)
return FALSE
if(is_cold())
return FALSE
if(damage)
if(!is_cold() && damage)
///Damage decrements by a percent of its maxhealth
var/healing_amount = -(maxHealth * healing_factor)
///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's satiety

View File

@@ -579,39 +579,36 @@ GLOBAL_LIST_EMPTY(vending_products)
if(!R || !istype(R) || !R.product_path)
vend_ready = TRUE
return
if(R.amount <= 0)
to_chat(usr, "<span class='warning'>Sold out.</span>")
vend_ready = TRUE
return
if(R in hidden_records)
if(!extended_inventory)
vend_ready = TRUE
return
else if(R in coin_records)
if(!(coin))
to_chat(usr, "<span class='warning'>You need to a coin to get this item!</span>")
if(!coin)
to_chat(usr, "<span class='warning'>You need to insert a coin to get this item!</span>")
vend_ready = TRUE
return
if(coin && coin.string_attached)
if(!prob(50))
to_chat(usr, "<span class='warning'>You weren't able to pull [coin] out fast enough, the machine ate it, string and all!</span>")
QDEL_NULL(coin)
return
if(!usr.CanReach(src))
to_chat(usr, "<span class='notice'>You successfully pull [coin] out of [src] to the floor.</span>")
coin = null
if(!usr.put_in_hands(coin))
if(prob(50))
if(usr.put_in_hands(coin))
to_chat(usr, "<span class='notice'>You successfully pull [coin] out before [src] could swallow it.</span>")
coin = null
else
to_chat(usr, "<span class='warning'>You couldn't pull [coin] out because your hands are full!</span>")
QDEL_NULL(coin)
to_chat(usr, "<span class='notice'>You successfully pull [coin] out before [src] could swallow it.</span>")
coin = null
QDEL_NULL(coin)
else
to_chat(usr, "<span class='warning'>You weren't able to pull [coin] out fast enough, the machine ate it, string and all!</span>")
QDEL_NULL(coin)
else
QDEL_NULL(coin)
else if(!(R in product_records))
vend_ready = TRUE
message_admins("Vending machine exploit attempted by [ADMIN_LOOKUPFLW(usr)]!")
return
if(R.amount <= 0)
to_chat(usr, "<span class='warning'>Sold out.</span>")
vend_ready = TRUE
return
else
R.amount--
if(((last_reply + 200) <= world.time) && vend_reply)
speak(vend_reply)
last_reply = world.time
@@ -623,8 +620,7 @@ GLOBAL_LIST_EMPTY(vending_products)
to_chat(usr, "<span class='notice'>You take [R.name] out of the slot.</span>")
else
to_chat(usr, "<span class='warning'>[capitalize(R.name)] falls onto the floor!</span>")
R.amount--
SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[R.product_path]"))
vend_ready = TRUE
return