Merge remote-tracking branch 'upstream/master' into AnPrimAssistants

This commit is contained in:
lolman360
2020-09-01 11:23:57 +10:00
520 changed files with 18663 additions and 10921 deletions
+106
View File
@@ -0,0 +1,106 @@
/datum/accent
/datum/accent/proc/modify_speech(list/speech_args, datum/source, mob/living/carbon/owner) //transforms the message in some way
return speech_args
/datum/accent/lizard/modify_speech(list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
var/static/regex/lizard_hiss = new("s+", "g")
var/static/regex/lizard_hiSS = new("S+", "g")
if(message[1] != "*")
message = lizard_hiss.Replace(message, "sss")
message = lizard_hiSS.Replace(message, "SSS")
speech_args[SPEECH_MESSAGE] = message
return speech_args
/datum/accent/fly/modify_speech(list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
var/static/regex/fly_buzz = new("z+", "g")
var/static/regex/fly_buZZ = new("Z+", "g")
if(message[1] != "*")
message = fly_buzz.Replace(message, "zzz")
message = fly_buZZ.Replace(message, "ZZZ")
speech_args[SPEECH_MESSAGE] = message
return speech_args
/datum/accent/abductor/modify_speech(list/speech_args, datum/source)
var/message = speech_args[SPEECH_MESSAGE]
var/mob/living/carbon/human/user = source
var/rendered = "<span class='abductor'><b>[user.name]:</b> [message]</span>"
user.log_talk(message, LOG_SAY, tag="abductor")
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
var/obj/item/organ/tongue/T = H.getorganslot(ORGAN_SLOT_TONGUE)
if(!T || T.type != type)
continue
if(H.dna && H.dna.species.id == "abductor" && user.dna && user.dna.species.id == "abductor")
var/datum/antagonist/abductor/A = user.mind.has_antag_datum(/datum/antagonist/abductor)
if(!A || !(H.mind in A.team.members))
continue
to_chat(H, rendered)
for(var/mob/M in GLOB.dead_mob_list)
var/link = FOLLOW_LINK(M, user)
to_chat(M, "[link] [rendered]")
speech_args[SPEECH_MESSAGE] = ""
return speech_args
/datum/accent/zombie/modify_speech(list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
var/list/message_list = splittext(message, " ")
var/maxchanges = max(round(message_list.len / 1.5), 2)
for(var/i = rand(maxchanges / 2, maxchanges), i > 0, i--)
var/insertpos = rand(1, message_list.len - 1)
var/inserttext = message_list[insertpos]
if(!(copytext(inserttext, -3) == "..."))//3 == length("...")
message_list[insertpos] = inserttext + "..."
if(prob(20) && message_list.len > 3)
message_list.Insert(insertpos, "[pick("BRAINS", "Brains", "Braaaiinnnsss", "BRAAAIIINNSSS")]...")
speech_args[SPEECH_MESSAGE] = jointext(message_list, " ")
return speech_args
/datum/accent/alien/modify_speech(list/speech_args, datum/source)
playsound(source, "hiss", 25, 1, 1)
return speech_args
/datum/accent/fluffy/modify_speech(list/speech_args)
var/message = speech_args[SPEECH_MESSAGE]
if(message[1] != "*")
message = replacetext(message, "ne", "nye")
message = replacetext(message, "nu", "nyu")
message = replacetext(message, "na", "nya")
message = replacetext(message, "no", "nyo")
message = replacetext(message, "ove", "uv")
message = replacetext(message, "l", "w")
message = replacetext(message, "r", "w")
speech_args[SPEECH_MESSAGE] = lowertext(message)
return speech_args
/datum/accent/bone
var/span_flag
/datum/accent/bone/modify_speech(list/speech_args)
speech_args[SPEECH_SPANS] = span_flag
return speech_args
//bone tongues either have the sans accent or the papyrus accent
/datum/accent/bone/sans
span_flag = SPAN_SANS
/datum/accent/bone/papyrus
span_flag = SPAN_PAPYRUS
/datum/accent/robot/modify_speech(list/speech_args)
speech_args[SPEECH_SPANS] = SPAN_ROBOT
/datum/accent/dullahan/modify_speech(list/speech_args, datum/source, mob/living/carbon/owner)
if(owner)
if(isdullahan(owner))
var/datum/species/dullahan/D = owner.dna.species
if(isobj(D.myhead.loc))
var/obj/O = D.myhead.loc
O.say(speech_args[SPEECH_MESSAGE])
speech_args[SPEECH_MESSAGE] = ""
return speech_args
+17 -20
View File
@@ -8,14 +8,14 @@
var/window_options = "can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
var/stylesheets[0]
var/scripts[0]
var/title_image
var/head_elements
var/body_elements
var/head_content = ""
var/content = ""
var/static/datum/asset/simple/namespaced/common/common_asset = get_asset_datum(/datum/asset/simple/namespaced/common)
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
/datum/browser/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null)
user = nuser
window_id = nwindow_id
@@ -27,7 +27,6 @@
height = nheight
if (nref)
ref = nref
add_stylesheet("common", 'html/browser/common.css') // this CSS sheet is common to all UIs
/datum/browser/proc/add_head_content(nhead_content)
head_content = nhead_content
@@ -35,22 +34,21 @@
/datum/browser/proc/set_window_options(nwindow_options)
window_options = nwindow_options
/datum/browser/proc/set_title_image(ntitle_image)
//title_image = ntitle_image
/datum/browser/proc/add_stylesheet(name, file)
if(istype(name, /datum/asset/spritesheet))
var/datum/asset/spritesheet/sheet = name
stylesheets["spritesheet_[sheet.name].css"] = "data/spritesheets/[sheet.name]"
else
var/asset_name = "[name].css"
stylesheets[asset_name] = file
if(!SSassets.cache[asset_name])
register_asset(asset_name, file)
if (!SSassets.cache[asset_name])
SSassets.transport.register_asset(asset_name, file)
/datum/browser/proc/add_script(name, file)
scripts["[ckey(name)].js"] = file
register_asset("[ckey(name)].js", file)
SSassets.transport.register_asset("[ckey(name)].js", file)
/datum/browser/proc/set_content(ncontent)
content = ncontent
@@ -60,15 +58,13 @@
/datum/browser/proc/get_header()
var/file
head_content += "<link rel='stylesheet' type='text/css' href='[common_asset.get_url_mappings()["common.css"]]'>"
for (file in stylesheets)
head_content += "<link rel='stylesheet' type='text/css' href='[file]'>"
head_content += "<link rel='stylesheet' type='text/css' href='[SSassets.transport.get_asset_url(file)]'>"
for (file in scripts)
head_content += "<script type='text/javascript' src='[file]'></script>"
var/title_attributes = "class='uiTitle'"
if (title_image)
title_attributes = "class='uiTitle icon' style='background-image: url([title_image]);'"
head_content += "<script type='text/javascript' src='[SSassets.transport.get_asset_url(file)]'></script>"
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
@@ -79,7 +75,7 @@
</head>
<body scroll=auto>
<div class='uiWrapper'>
[title ? "<div class='uiTitleWrapper'><div [title_attributes]><tt>[title]</tt></div></div>" : ""]
[title ? "<div class='uiTitleWrapper'><div class='uiTitle'><tt>[title]</tt></div></div>" : ""]
<div class='uiContent'>
"}
//" This is here because else the rest of the file looks like a string in notepad++.
@@ -105,10 +101,11 @@
var/window_size = ""
if(width && height)
window_size = "size=[width]x[height];"
common_asset.send(user)
if(stylesheets.len)
send_asset_list(user, stylesheets)
SSassets.transport.send_assets(user, stylesheets)
if(scripts.len)
send_asset_list(user, scripts)
SSassets.transport.send_assets(user, scripts)
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
if(use_onclose)
setup_onclose()
@@ -169,7 +166,7 @@
return Button3
//Same shit, but it returns the button number, could at some point support unlimited button amounts.
/proc/askuser(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
/proc/askuser(mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
@@ -188,7 +185,7 @@
var/selectedbutton = 0
var/stealfocus
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, StealFocus = 1, Timeout = 6000)
/datum/browser/modal/New(nuser, nwindow_id, ntitle = 0, nwidth = 0, nheight = 0, atom/nref = null, StealFocus = 1, Timeout = 6000)
..()
stealfocus = StealFocus
if (!StealFocus)
+22
View File
@@ -0,0 +1,22 @@
// This used to be in paper.dm, it was some snowflake code that was
// used ONLY on april's fool. I moved it to a component so it could be
// used in other places
/datum/component/honkspam
dupe_mode = COMPONENT_DUPE_UNIQUE
var/spam_flag = FALSE
/datum/component/honkspam/Initialize()
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/interact)
/datum/component/honkspam/proc/reset_spamflag()
spam_flag = FALSE
/datum/component/honkspam/proc/interact(mob/user)
if(!spam_flag)
spam_flag = TRUE
var/obj/item/parent_item = parent
playsound(parent_item.loc, 'sound/items/bikehorn.ogg', 50, TRUE)
addtimer(CALLBACK(src, .proc/reset_spamflag), 2 SECONDS)
+87
View File
@@ -0,0 +1,87 @@
/**
The label component.
This component is used to manage labels applied by the hand labeler.
Atoms can only have one instance of this component, and therefore only one label at a time.
This is to avoid having names like "Backpack (label1) (label2) (label3)". This is annoying and abnoxious to read.
When a player clicks the atom with a hand labeler to apply a label, this component gets applied to it.
If the labeler is off, the component will be removed from it, and the label will be removed from its name.
*/
/datum/component/label
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
/// The name of the label the player is applying to the parent.
var/label_name
/datum/component/label/Initialize(_label_name)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
label_name = _label_name
apply_label()
/datum/component/label/RegisterWithParent()
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/OnAttackby)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/Examine)
/datum/component/label/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE))
/**
This proc will fire after the parent is hit by a hand labeler which is trying to apply another label.
Since the parent already has a label, it will remove the old one from the parent's name, and apply the new one.
*/
/datum/component/label/InheritComponent(datum/component/label/new_comp , i_am_original, _label_name)
remove_label()
if(new_comp)
label_name = new_comp.label_name
else
label_name = _label_name
apply_label()
/**
This proc will trigger when any object is used to attack the parent.
If the attacking object is not a hand labeler, it will return.
If the attacking object is a hand labeler it will restore the name of the parent to what it was before this component was added to it, and the component will be deleted.
Arguments:
* source: The parent.
* attacker: The object that is hitting the parent.
* user: The mob who is wielding the attacking object.
*/
/datum/component/label/proc/OnAttackby(datum/source, obj/item/attacker, mob/user)
// If the attacking object is not a hand labeler or its mode is 1 (has a label ready to apply), return.
// The hand labeler should be off (mode is 0), in order to remove a label.
var/obj/item/hand_labeler/labeler = attacker
if(!istype(labeler) || labeler.mode)
return
remove_label()
playsound(parent, 'sound/items/poster_ripped.ogg', 20, TRUE)
to_chat(user, "<span class='warning'>You remove the label from [parent].</span>")
qdel(src) // Remove the component from the object.
/**
This proc will trigger when someone examines the parent.
It will attach the text found in the body of the proc to the `examine_list` and display it to the player examining the parent.
Arguments:
* source: The parent.
* user: The mob exmaining the parent.
* examine_list: The current list of text getting passed from the parent's normal examine() proc.
*/
/datum/component/label/proc/Examine(datum/source, mob/user, list/examine_list)
examine_list += "<span class='notice'>It has a label with some words written on it. Use a hand labeler to remove it.</span>"
/// Applies a label to the name of the parent in the format of: "parent_name (label)"
/datum/component/label/proc/apply_label()
var/atom/owner = parent
owner.name += " ([label_name])"
/// Removes the label from the parent's name
/datum/component/label/proc/remove_label()
var/atom/owner = parent
owner.name = replacetext(owner.name, "([label_name])", "") // Remove the label text from the parent's name, wherever it's located.
owner.name = trim(owner.name) // Shave off any white space from the beginning or end of the parent's name.
+1 -1
View File
@@ -1,4 +1,4 @@
//Thing meant for allowing datums and objects to access a NTnet network datum.
//Thing meant for allowing datums and objects to access an NTnet network datum.
/datum/proc/ntnet_receive(datum/netdata/data)
return
+5 -5
View File
@@ -32,6 +32,7 @@
RegisterSignal(A, COMSIG_COMPONENT_CLEAN_ACT, .proc/clean_react)
if(description)
RegisterSignal(A, COMSIG_PARENT_EXAMINE, .proc/examine)
RegisterSignal(A, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlay, TRUE)
num_decals_per_atom[A]++
apply(A)
@@ -39,21 +40,20 @@
/datum/element/decal/Detach(datum/target)
var/atom/A = target
num_decals_per_atom[A]--
apply(A, TRUE)
if(!num_decals_per_atom[A])
UnregisterSignal(A, list(COMSIG_ATOM_DIR_CHANGE, COMSIG_COMPONENT_CLEAN_ACT, COMSIG_PARENT_EXAMINE, COMSIG_ATOM_UPDATE_OVERLAYS))
LAZYREMOVE(num_decals_per_atom, A)
apply(A)
return ..()
/datum/element/decal/proc/apply(atom/target, removing = FALSE)
if(num_decals_per_atom[target] == 1 && !removing)
RegisterSignal(target, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_overlay, TRUE)
/datum/element/decal/proc/apply(atom/target)
target.update_icon()
if(isitem(target))
addtimer(CALLBACK(target, /obj/item/.proc/update_slot_icon), 0, TIMER_UNIQUE)
/datum/element/decal/proc/apply_overlay(atom/source, list/overlay_list)
pic.dir = first_dir == NORTH ? source.dir : turn(first_dir, dir2angle(source.dir))
if(first_dir)
pic.dir = turn(first_dir, -dir2angle(source.dir))
for(var/i in 1 to num_decals_per_atom[source])
overlay_list += pic
+3 -2
View File
@@ -102,8 +102,9 @@
/datum/emote/proc/can_run_emote(mob/user, status_check = TRUE, intentional = FALSE)
. = TRUE
if(!is_type_in_typecache(user, mob_type_allowed_typecache))
return FALSE
if(mob_type_allowed_typecache) //empty list = anyone can use it unless specifically blacklisted
if(!is_type_in_typecache(user, mob_type_allowed_typecache))
return FALSE
if(is_type_in_typecache(user, mob_type_blacklist_typecache))
return FALSE
if(status_check && !is_type_in_typecache(user, mob_type_ignore_stat_typecache))
+31 -5
View File
@@ -103,13 +103,21 @@ GLOBAL_LIST_EMPTY(explosions)
// 3/7/14 will calculate to 80 + 35
var/far_dist = 0
far_dist += heavy_impact_range * 5
far_dist += heavy_impact_range * 15 // Large explosions carry further
far_dist += devastation_range * 20
if(!silent)
var/frequency = get_rand_frequency()
var/sound/explosion_sound = sound(get_sfx("explosion"))
var/sound/far_explosion_sound = sound('sound/effects/explosionfar.ogg')
var/sound/creaking_explosion_sound = sound(get_sfx("explosion_creaking"))
var/sound/hull_creaking_sound = sound(get_sfx("hull_creaking"))
var/sound/explosion_echo_sound = sound('sound/effects/explosion_distant.ogg')
var/on_station = SSmapping.level_trait(epicenter.z, ZTRAIT_STATION)
var/creaking_explosion = FALSE
if(prob(devastation_range*30+heavy_impact_range*5) && on_station) // Huge explosions are near guaranteed to make the station creak and whine, smaller ones might.
creaking_explosion = TRUE // prob over 100 always returns true
for(var/mob/M in GLOB.player_list)
// Double check for client
@@ -126,11 +134,29 @@ GLOBAL_LIST_EMPTY(explosions)
shake_camera(M, 25, clamp(baseshakeamount, 0, 10))
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
else if(dist <= far_dist)
var/far_volume = clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
M.playsound_local(epicenter, null, far_volume, 1, frequency, falloff = 5, S = far_explosion_sound)
if(baseshakeamount > 0)
var/far_volume = clamp(far_dist/2, 40, 60) // Volume is based on explosion size and dist
if(creaking_explosion)
M.playsound_local(epicenter, null, far_volume, 1, frequency, S = creaking_explosion_sound, distance_multiplier = 0)
else if(prob(75))
M.playsound_local(epicenter, null, far_volume, 1, frequency, S = far_explosion_sound, distance_multiplier = 0) // Far sound
else
M.playsound_local(epicenter, null, far_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0) // Echo sound
if(baseshakeamount > 0 || devastation_range)
if(!baseshakeamount) // Devastating explosions rock the station and ground
baseshakeamount = devastation_range*3
shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5))
else if(M.can_hear() && !isspaceturf(get_turf(M)) && heavy_impact_range) // Big enough explosions echo throughout the hull
var/echo_volume = 40
if(devastation_range)
baseshakeamount = devastation_range
shake_camera(M, 10, clamp(baseshakeamount*0.25, 0, 2.5))
echo_volume = 60
M.playsound_local(epicenter, null, echo_volume, 1, frequency, S = explosion_echo_sound, distance_multiplier = 0)
if(creaking_explosion) // 5 seconds after the bang, the station begins to creak
addtimer(CALLBACK(M, /mob/proc/playsound_local, epicenter, null, rand(25, 40), 1, frequency, null, null, FALSE, hull_creaking_sound, null, null, null, null, 0), 5 SECONDS)
EX_PREPROCESS_CHECK_TICK
//postpone processing for a bit
+2
View File
@@ -90,6 +90,8 @@
to_chat(user, "<span class='boldnotice'>You catch some drifting memories of their past conversations...</span>")
for(var/spoken_memory in recent_speech)
to_chat(user, "<span class='notice'>[recent_speech[spoken_memory]]</span>")
if(usr in GLOB.rockpaperscissors_players)
to_chat(user, "<span class='notice'>They're planning on playing [GLOB.rockpaperscissors_players[usr][1]]</span>")
if(iscarbon(M))
var/mob/living/carbon/human/H = M
to_chat(user, "<span class='boldnotice'>You find that their intent is to [H.a_intent]...</span>")
+60 -1
View File
@@ -580,4 +580,63 @@
/datum/status_effect/regenerative_core/on_remove()
. = ..()
REMOVE_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "regenerative_core")
owner.updatehealth()
owner.updatehealth()
/datum/status_effect/panacea
id = "Anatomic Panacea"
duration = 100
tick_interval = 10
alert_type = /obj/screen/alert/status_effect/panacea
/obj/screen/alert/status_effect/panacea
name = "Panacea"
desc = "We purge the impurities from our body."
icon_state = "panacea"
// Changeling's anatomic panacea now in buff form. Directly fixes issues instead of injecting chems
/datum/status_effect/panacea/tick()
var/mob/living/carbon/M = owner
//Heal brain damage and toxyloss, alongside trauma
owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, -8)
owner.adjustToxLoss(-6, forced = TRUE)
M.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
//Purges 50 rads per tick
if(owner.radiation > 0)
owner.radiation -= min(owner.radiation, 50)
//Mutadone effects
owner.jitteriness = 0
if(owner.has_dna())
M.dna.remove_all_mutations(mutadone = TRUE)
if(!QDELETED(owner)) //We were a monkey, now a human
..()
// Purges toxins
for(var/datum/reagent/toxin/R in owner.reagents.reagent_list)
owner.reagents.remove_reagent(R.type, 5)
//Antihol effects
M.reagents.remove_all_type(/datum/reagent/consumable/ethanol, 10, 0, 1)
M.drunkenness = max(M.drunkenness - 10, 0)
owner.dizziness = 0
owner.drowsyness = 0
owner.slurring = 0
owner.confused = 0
//Organ and disease cure moved from panacea.dm to buff proc
var/list/bad_organs = list(
owner.getorgan(/obj/item/organ/body_egg),
owner.getorgan(/obj/item/organ/zombie_infection))
for(var/o in bad_organs)
var/obj/item/organ/O = o
if(!istype(O))
continue
O.Remove()
if(iscarbon(owner))
var/mob/living/carbon/C = owner
C.vomit(0, toxic = TRUE)
O.forceMove(get_turf(owner))
if(isliving(owner))
var/mob/living/L = owner
for(var/thing in L.diseases)
var/datum/disease/D = thing
if(D.severity == DISEASE_SEVERITY_POSITIVE)
continue
D.cure()