# Conflicts:
#	tgstation.dme
This commit is contained in:
zerothebigboy
2021-06-20 03:29:50 -04:00
284 changed files with 90888 additions and 77430 deletions
+9
View File
@@ -793,6 +793,15 @@
small_icon = 'icons/mob/lavaland/lavaland_monsters.dmi'
small_icon_state = "ash_whelp"
/datum/action/small_sprite/megafauna/colossus
small_icon_state = "Basilisk"
/datum/action/small_sprite/megafauna/bubblegum
small_icon_state = "goliath2"
/datum/action/small_sprite/megafauna/legion
small_icon_state = "mega_legion"
/datum/action/small_sprite/Trigger()
..()
if(!small)
@@ -52,7 +52,7 @@
/datum/crafting_recipe/armwraps
name = "Armwraps"
result = /obj/item/clothing/gloves/fingerless/pugilist
result = /obj/item/clothing/gloves/fingerless/pugilist/crafted
time = 60
tools = list(TOOL_WIRECUTTER)
reqs = list(/obj/item/stack/sheet/cloth = 4,
+1 -1
View File
@@ -159,7 +159,7 @@
/datum/component/embedded/proc/jostleCheck()
var/mob/living/carbon/victim = parent
var/damage = weapon.w_class * pain_mult
var/damage = weapon.w_class * jostle_pain_mult
var/pain_chance_current = jostle_chance
if(victim.m_intent == MOVE_INTENT_WALK || !(victim.mobility_flags & MOBILITY_STAND))
pain_chance_current *= 0.5
+64
View File
@@ -170,6 +170,7 @@
/**
* Used to rid ourselves
*/
///Deletes nanites!
/datum/component/nanites/proc/delete_nanites()
if(can_be_deleted)
qdel(src)
@@ -214,6 +215,7 @@
return SEND_SIGNAL(src, COMSIG_NANITE_INTERNAL_VIRAL_PREVENTION_CHECK)
//Syncs the nanite component to another, making it so programs are the same with the same programming (except activation status)
///Syncs the nanite component to another, making it so programs are the same with the same programming (except activation status)
/datum/component/nanites/proc/sync(datum/signal_source, datum/component/nanites/source, full_overwrite = TRUE, copy_activation = FALSE)
var/list/programs_to_remove = programs.Copy() - permanent_programs
var/list/programs_to_add = source.programs.Copy()
@@ -233,6 +235,7 @@
var/datum/nanite_program/SNP = X
add_program(null, SNP.copy())
///Syncs the nanites to their assigned cloud copy, if it is available. If it is not, there is a small chance of a software error instead.
/datum/component/nanites/proc/cloud_sync()
if(cloud_id)
var/datum/nanite_cloud_backup/backup = SSnanites.get_cloud_backup(cloud_id)
@@ -246,6 +249,7 @@
var/datum/nanite_program/NP = pick(programs)
NP.software_error()
///Adds a nanite program, replacing existing unique programs of the same type. A source program can be specified to copy its programming onto the new one.
/datum/component/nanites/proc/add_program(datum/source, datum/nanite_program/new_program, datum/nanite_program/source_program)
for(var/X in programs)
var/datum/nanite_program/NP = X
@@ -268,11 +272,68 @@
adjust_nanites(null, -amount)
return (nanite_volume > 0)
///Modifies the current nanite volume, then checks if the nanites are depleted or exceeding the maximum amount
/datum/component/nanites/proc/adjust_nanites(datum/source, amount)
nanite_volume = clamp(nanite_volume + amount, 0, max_nanites)
SIGNAL_HANDLER
nanite_volume += amount
if(nanite_volume > max_nanites)
reject_excess_nanites()
if(nanite_volume <= 0) //oops we ran out
nanites_depleted()
/**
* Handles how nanites leave the host's body if they find out that they're currently exceeding the maximum supported amount
*
* IC explanation:
* Normally nanites simply discard excess volume by slowing replication or 'sweating' it out in imperceptible amounts,
* but if there is a large excess volume, likely due to a programming change that leaves them unable to support their current volume,
* the nanites attempt to leave the host as fast as necessary to prevent nanite poisoning. This can range from minor oozing to nanites
* rapidly bursting out from every possible pathway, causing temporary inconvenience to the host.
*/
/datum/component/nanites/proc/reject_excess_nanites()
var/excess = nanite_volume - max_nanites
nanite_volume = max_nanites
switch(excess)
if(0 to NANITE_EXCESS_MINOR) //Minor excess amount, the extra nanites are quietly expelled without visible effects
return
if((NANITE_EXCESS_MINOR + 0.1) to NANITE_EXCESS_VOMIT) //Enough nanites getting rejected at once to be visible to the naked eye
host_mob.visible_message("<span class='warning'>A grainy grey slurry starts oozing out of [host_mob].</span>", "<span class='warning'>A grainy grey slurry starts oozing out of your skin.</span>", null, 4);
if((NANITE_EXCESS_VOMIT + 0.1) to NANITE_EXCESS_BURST) //Nanites getting rejected in massive amounts, but still enough to make a semi-orderly exit through vomit
if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob
host_mob.visible_message("<span class='warning'>[host_mob] vomits a grainy grey slurry!</span>", "<span class='warning'>You suddenly vomit a metallic-tasting grainy grey slurry!</span>", null);
C.vomit(0, FALSE, TRUE, FLOOR(excess / 100, 1), FALSE, VOMIT_NANITE, FALSE, TRUE, 0)
else
host_mob.visible_message("<span class='warning'>A metallic grey slurry bursts out of [host_mob]'s skin!</span>", "<span class='userdanger'>A metallic grey slurry violently bursts out of your skin!</span>", null);
if(isturf(host_mob.drop_location()))
var/turf/T = host_mob.drop_location()
T.add_vomit_floor(host_mob, VOMIT_NANITE, 0)
if((NANITE_EXCESS_BURST + 0.1) to INFINITY) //Way too many nanites, they just leave through the closest exit before they harm/poison the host
host_mob.visible_message("<span class='warning'>A torrent of metallic grey slurry violently bursts out of [host_mob]'s face and floods out of [host_mob.p_their()] skin!</span>",
"<span class='userdanger'>A torrent of metallic grey slurry violently bursts out of your eyes, ears, and mouth, and floods out of your skin!</span>");
host_mob.blind_eyes(15) //nanites coming out of your eyes
host_mob.Paralyze(120)
if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob
var/obj/item/organ/ears/ears = C.getorganslot(ORGAN_SLOT_EARS)
if(ears)
ears.adjustEarDamage(0, 30) //nanites coming out of your ears
C.vomit(0, FALSE, TRUE, 2, FALSE, VOMIT_NANITE, FALSE, TRUE, 0) //nanites coming out of your mouth
//nanites everywhere
if(isturf(host_mob.drop_location()))
var/turf/T = host_mob.drop_location()
T.add_vomit_floor(host_mob, VOMIT_NANITE, 0)
for(var/turf/adjacent_turf in oview(host_mob, 1))
if(adjacent_turf.density || !adjacent_turf.Adjacent(T))
continue
adjacent_turf.add_vomit_floor(host_mob, VOMIT_NANITE, 0)
///Updates the nanite volume bar visible in diagnostic HUDs
/datum/component/nanites/proc/set_nanite_bar(remove = FALSE)
var/image/holder = host_mob.hud_list[DIAG_NANITE_FULL_HUD]
var/icon/I = icon(host_mob.icon, host_mob.icon_state, host_mob.dir)
@@ -347,6 +408,9 @@
/datum/component/nanites/proc/set_max_volume(datum/source, amount)
max_nanites = max(1, max_nanites)
SIGNAL_HANDLER
max_nanites = max(1, amount)
/datum/component/nanites/proc/set_cloud(datum/source, amount)
cloud_id = clamp(amount, 0, 100)
@@ -37,7 +37,7 @@
to_chat(M, "<span class='notice'>You start dumping out tier/cell rating [lowest_rating] parts from [parent].</span>")
var/turf/T = get_turf(A)
var/datum/progressbar/progress = new(M, length(things), T)
while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress)))
while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress, TRUE, M)))
stoplag(1)
qdel(progress)
A.do_squish(0.8, 1.2)
@@ -81,7 +81,7 @@
to_chat(M, "<span class='notice'>You start dumping out tier/cell rating [lowest_rating] parts from [parent].</span>")
var/turf/T = get_turf(A)
var/datum/progressbar/progress = new(M, length(things), T)
while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress)))
while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress, TRUE, M)))
stoplag(1)
qdel(progress)
A.do_squish(0.8, 1.2)
+23 -10
View File
@@ -271,20 +271,20 @@
var/turf/T = get_turf(A)
var/list/things = contents()
var/datum/progressbar/progress = new(M, length(things), T)
while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress)))
while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress, TRUE, M)))
stoplag(1)
qdel(progress)
A.do_squish(0.8, 1.2)
/datum/component/storage/proc/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress, trigger_on_found = TRUE)
/datum/component/storage/proc/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress, trigger_on_found = TRUE, mob/user)
var/atom/real_location = real_location()
for(var/obj/item/I in things)
things -= I
if(I.loc != real_location)
continue
remove_from_storage(I, target)
if(trigger_on_found && I.on_found())
if(trigger_on_found && user && (user.active_storage != src) && I.on_found(user))
return FALSE
remove_from_storage(I, target)
if(TICK_CHECK)
progress.update(progress.goal - length(things))
return TRUE
@@ -429,7 +429,7 @@
return FALSE
// this must come before the screen objects only block, dunno why it wasn't before
if(over_object == M)
user_show_to_mob(M)
user_show_to_mob(M, trigger_on_found = TRUE)
return
if(isrevenant(M))
RevenantThrow(over_object, M, source)
@@ -448,15 +448,28 @@
return
A.add_fingerprint(M)
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE)
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE, trigger_on_found = FALSE)
var/atom/A = parent
if(!istype(M))
return FALSE
A.add_fingerprint(M)
if(!force && (check_locked(null, M) || !M.CanReach(parent, view_only = TRUE)))
return FALSE
if(trigger_on_found)
if(check_on_found(M))
return
ui_show(M)
/**
* Check if we should trigger on_found()
* If this returns TRUE, it means an on_found() returned TRUE and immediately broke the chain.
* In most contexts, this should mean to stop.
*/
/datum/component/storage/proc/check_on_found(mob/user)
for(var/obj/item/I in contents())
if(I.on_found(user))
return TRUE
/datum/component/storage/proc/mousedrop_receive(datum/source, atom/movable/O, mob/M)
if(isitem(O))
var/obj/item/I = O
@@ -579,8 +592,8 @@
/datum/component/storage/proc/show_to_ghost(datum/source, mob/dead/observer/M)
return user_show_to_mob(M, TRUE)
/datum/component/storage/proc/signal_show_attempt(datum/source, mob/showto, force = FALSE)
return user_show_to_mob(showto, force)
/datum/component/storage/proc/signal_show_attempt(datum/source, mob/showto, force = FALSE, trigger_on_found = TRUE)
return user_show_to_mob(showto, force, trigger_on_found = trigger_on_found)
/datum/component/storage/proc/on_check()
return TRUE
@@ -649,7 +662,7 @@
if(A.loc == user)
. = COMPONENT_NO_ATTACK_HAND
if(!check_locked(source, user, TRUE))
ui_show(user)
user_show_to_mob(user, trigger_on_found = TRUE)
A.do_jiggle()
/datum/component/storage/proc/signal_on_pickup(datum/source, mob/user)
@@ -679,7 +692,7 @@
var/atom/A = parent
if(!quickdraw)
A.add_fingerprint(user)
user_show_to_mob(user)
user_show_to_mob(user, trigger_on_found = TRUE)
if(rustle_sound)
playsound(A, "rustle", 50, 1, -5)
return TRUE
+12 -1
View File
@@ -7,8 +7,9 @@
var/left_hand
var/inv_slots
var/proctype //if present, will be invoked on headwear generation.
var/escape_on_find = FALSE //if present, will be released upon the item being 'found' (i.e. opening a container or pocket with it present)
/datum/element/mob_holder/Attach(datum/target, worn_state, alt_worn, right_hand, left_hand, inv_slots = NONE, proctype)
/datum/element/mob_holder/Attach(datum/target, worn_state, alt_worn, right_hand, left_hand, inv_slots = NONE, proctype, escape_on_find)
. = ..()
if(!isliving(target))
@@ -20,6 +21,7 @@
src.left_hand = left_hand
src.inv_slots = inv_slots
src.proctype = proctype
src.escape_on_find = escape_on_find
RegisterSignal(target, COMSIG_CLICK_ALT, .proc/mob_try_pickup)
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/on_examine)
@@ -55,6 +57,8 @@
to_chat(user, "<span class='notice'>You pick [source] up.</span>")
source.drop_all_held_items()
var/obj/item/clothing/head/mob_holder/holder = new(get_turf(source), source, worn_state, alt_worn, right_hand, left_hand, inv_slots)
holder.escape_on_find = escape_on_find
if(proctype)
INVOKE_ASYNC(src, proctype, source, holder, user)
user.put_in_hands(holder)
@@ -78,6 +82,7 @@
w_class = WEIGHT_CLASS_BULKY
dynamic_hair_suffix = ""
var/mob/living/held_mob
var/escape_on_find
/obj/item/clothing/head/mob_holder/Initialize(mapload, mob/living/target, worn_state, alt_worn, right_hand, left_hand, slots = NONE)
. = ..()
@@ -189,3 +194,9 @@
if(ismob(location))
return location.loc.remove_air(amount)
return location.remove_air(amount)
// escape when found if applicable
/obj/item/clothing/head/mob_holder/on_found(mob/living/finder)
if(escape_on_find)
finder.visible_message("[finder] accidentally releases the [held_mob]!")
release()
+4 -4
View File
@@ -16,7 +16,7 @@
if(revinfo)
commit = revinfo.commit
originmastercommit = revinfo.origin_commit
date = rustg_git_commit_date(commit)
date = revinfo.timestamp || rustg_git_commit_date(commit)
// goes to DD log and config_error.txt
log_world(get_log_message())
@@ -29,8 +29,8 @@
for(var/line in testmerge)
var/datum/tgs_revision_information/test_merge/tm = line
msg += "Test merge active of PR #[tm.number] commit [tm.pull_request_commit]"
SSblackbox.record_feedback("associative", "testmerged_prs", 1, list("number" = "[tm.number]", "commit" = "[tm.pull_request_commit]", "title" = "[tm.title]", "author" = "[tm.author]"))
msg += "Test merge active of PR #[tm.number] commit [tm.head_commit]"
SSblackbox.record_feedback("associative", "testmerged_prs", 1, list("number" = "[tm.number]", "commit" = "[tm.head_commit]", "title" = "[tm.title]", "author" = "[tm.author]"))
if(commit && commit != originmastercommit)
msg += "HEAD: [commit]"
@@ -45,7 +45,7 @@
. = header ? "The following pull requests are currently test merged:<br>" : ""
for(var/line in testmerge)
var/datum/tgs_revision_information/test_merge/tm = line
var/cm = tm.pull_request_commit
var/cm = tm.head_commit
var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext_char(cm, 1, 11))
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
continue
+9 -8
View File
@@ -8,23 +8,24 @@
time_coeff = 5
instability = 30
/datum/mutation/human/space_adaptation/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "space_adapt", -MUTATIONS_LAYER))
/datum/mutation/human/space_adaptation/get_visual_indicator()
return visual_indicators[type][1]
/datum/mutation/human/space_adaptation/on_acquiring(mob/living/carbon/human/owner)
if(..())
return
ADD_TRAIT(owner, TRAIT_RESISTCOLD, "cold_resistance")
ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance")
owner.add_filter("space_glow", 2, list("type" = "outline", "color" = "#ffe46bd8", "size" = 1))
addtimer(CALLBACK(src, .proc/glow_loop, owner), rand(1,19))
/datum/mutation/human/space_adaptation/proc/glow_loop(mob/living/carbon/human/owner)
var/filter = owner.get_filter("space_glow")
if(filter)
animate(filter, alpha = 190, time = 15, loop = -1)
animate(alpha = 110, time = 25)
/datum/mutation/human/space_adaptation/on_losing(mob/living/carbon/human/owner)
if(..())
return
REMOVE_TRAIT(owner, TRAIT_RESISTCOLD, "cold_resistance")
REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "cold_resistance")
owner.remove_filter("space_glow")
+1 -1
View File
@@ -642,7 +642,7 @@
O.Remove()
if(iscarbon(owner))
var/mob/living/carbon/C = owner
C.vomit(0, toxic = TRUE)
C.vomit(0)
O.forceMove(get_turf(owner))
if(isliving(owner))
var/mob/living/L = owner
+98
View File
@@ -207,3 +207,101 @@
if(!key_valid)
GLOB.topic_status_cache = .
/datum/world_topic/jsonstatus
keyword = "jsonstatus"
/datum/world_topic/jsonstatus/Run(list/input, addr)
. = list()
.["mode"] = "hidden" // GLOB.master_mode - woops we don't want people to know if there's secret/extended :)
.["round_id"] = "[GLOB.round_id]"
.["players"] = GLOB.clients.len
var/list/adm = get_admin_counts()
var/list/presentmins = adm["present"]
var/list/afkmins = adm["afk"]
.["admins"] = presentmins.len + afkmins.len //equivalent to the info gotten from adminwho
.["security_level"] = "[NUM2SECLEVEL(GLOB.security_level)]"
.["round_duration"] = WORLDTIME2TEXT("hh:mm:ss")
.["map"] = SSmapping.config.map_name
return json_encode(.)
/datum/world_topic/jsonplayers
keyword = "jsonplayers"
/datum/world_topic/jsonplayers/Run(list/input, addr)
. = list()
for(var/client/C in GLOB.clients)
if(C.holder?.fakekey)
. += C.holder.fakekey
continue
. += C.key
return json_encode(.)
/datum/world_topic/jsonmanifest
keyword = "jsonmanifest"
/datum/world_topic/jsonmanifest/Run(list/input, addr)
var/list/command = list()
var/list/security = list()
var/list/engineering = list()
var/list/medical = list()
var/list/science = list()
var/list/cargo = list()
var/list/civilian = list()
var/list/misc = list()
for(var/datum/data/record/R in GLOB.data_core.general)
var/name = R.fields["name"]
var/rank = R.fields["rank"]
var/real_rank = rank // make_list_rank(R.fields["real_rank"])
if(real_rank in GLOB.security_positions)
security[name] = rank
else if(real_rank in GLOB.engineering_positions)
engineering[name] = rank
else if(real_rank in GLOB.medical_positions)
medical[name] = rank
else if(real_rank in GLOB.science_positions)
science[name] = rank
else if(real_rank in GLOB.supply_positions)
cargo[name] = rank
else if(real_rank in GLOB.civilian_positions)
civilian[name] = rank
else
misc[name] = rank
// mixed departments, /datum/department when
if(real_rank in GLOB.command_positions)
command[name] = rank
. = list()
.["Command"] = command
.["Security"] = security
.["Engineering"] = engineering
.["Medical"] = medical
.["Science"] = science
.["Cargo"] = cargo
.["Civilian"] = civilian
.["Misc"] = misc
return json_encode(.)
/datum/world_topic/jsonrevision
keyword = "jsonrevision"
/datum/world_topic/jsonrevision/Run(list/input, addr)
var/datum/getrev/revdata = GLOB.revdata
var/list/data = list(
"date" = copytext(revdata.date, 1, 11),
"dd_version" = world.byond_version,
"dd_build" = world.byond_build,
"dm_version" = DM_VERSION,
"dm_build" = DM_BUILD,
"revision" = revdata.commit,
"round_id" = "[GLOB.round_id]",
"testmerge_base_url" = "[CONFIG_GET(string/githuburl)]/pull/"
)
if (revdata.testmerge.len)
for (var/datum/tgs_revision_information/test_merge/TM in revdata.testmerge)
data["testmerges"] += list(list(
"id" = TM.number,
"desc" = TM.title,
"author" = TM.author
))
return json_encode(data)