This commit is contained in:
Putnam3145
2022-08-07 17:59:28 -07:00
382 changed files with 5255 additions and 2567 deletions
+4
View File
@@ -212,6 +212,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
// airlock_wires = /datum/wires/airlock/maint
sound_environment = SOUND_AREA_TUNNEL_ENCLOSED
minimap_color = "#454545"
//Maintenance - Departmental
@@ -435,6 +436,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/hallway
nightshift_public_area = NIGHTSHIFT_AREA_PUBLIC
sound_environment = SOUND_AREA_STANDARD_STATION
minimap_color = "#aaaaaa"
/area/hallway/primary
name = "Primary Hallway"
@@ -490,6 +492,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/hallway/secondary/exit
name = "Escape Shuttle Hallway"
icon_state = "escape"
minimap_color = "#baa0a0"
/area/hallway/secondary/exit/departure_lounge
name = "Departure Lounge"
@@ -498,6 +501,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
/area/hallway/secondary/entry
name = "Arrival Shuttle Hallway"
icon_state = "entry"
minimap_color = "#a0a0ba"
/area/hallway/secondary/service
name = "Service Hallway"
+4
View File
@@ -124,6 +124,10 @@
/// Color on minimaps, if it's null (which is default) it makes one at random.
var/minimap_color
var/minimap_color2 // if this isn't null, then this will show as a checkerboard pattern mixed in with the above. works even if the above is null (for better or worse)
var/minimap_show_walls = TRUE
/**
* These two vars allow for multiple unique areas to be linked to a master area
* and share some functionalities such as APC powernet nodes, fire alarms etc, without sacrificing
+3
View File
@@ -9,6 +9,9 @@
ambientsounds = RUINS
sound_environment = SOUND_ENVIRONMENT_STONEROOM
var/valid_territory = FALSE // hey so what if we did not allow things like cult summons to appear on ruins
minimap_color = "#775940"
minimap_color2 = "#6b5d48"
minimap_show_walls = FALSE
/area/ruin/unpowered
+16 -5
View File
@@ -518,7 +518,7 @@
. = list("[get_examine_string(user, TRUE)].")
if(desc)
. += desc
. += "<hr>[desc]"
if(custom_materials)
var/list/materials_list = list()
@@ -702,7 +702,7 @@
var/blood_id = get_blood_id()
if(!(blood_id in GLOB.blood_reagent_types))
return
return list("color" = BLOOD_COLOR_HUMAN, "ANIMAL DNA" = "Y-")
return list("color" = BLOOD_COLOR_HUMAN, "blendmode" = BLEND_MULTIPLY, "ANIMAL DNA" = "Y-")
/mob/living/carbon/get_blood_dna_list()
var/blood_id = get_blood_id()
@@ -711,14 +711,16 @@
var/list/blood_dna = list()
if(dna)
blood_dna["color"] = dna.species.exotic_blood_color //so when combined, the list grows with the number of colors
blood_dna["blendmode"] = dna.species.exotic_blood_blend_mode
blood_dna[dna.unique_enzymes] = dna.blood_type
else
blood_dna["color"] = BLOOD_COLOR_HUMAN
blood_dna["blendmode"] = BLEND_MULTIPLY
blood_dna["UNKNOWN DNA"] = "X*"
return blood_dna
/mob/living/carbon/alien/get_blood_dna_list()
return list("color" = BLOOD_COLOR_XENO, "UNKNOWN DNA" = "X*")
return list("color" = BLOOD_COLOR_XENO, "blendmode" = BLEND_MULTIPLY, "UNKNOWN DNA" = "X*")
//to add a mob's dna info into an object's blood_DNA list.
/atom/proc/transfer_mob_blood_dna(mob/living/L)
@@ -737,6 +739,7 @@
var/old = blood_DNA["color"]
blood_DNA["color"] = BlendRGB(blood_DNA["color"], new_blood_dna["color"])
changed = old != blood_DNA["color"]
blood_DNA["blendmode"] = new_blood_dna["blendmode"]
if(blood_DNA.len == old_length)
return FALSE
return changed
@@ -756,6 +759,7 @@
blood_DNA["color"] = blood_dna["color"]
else
blood_DNA["color"] = BlendRGB(blood_DNA["color"], blood_dna["color"])
blood_DNA["blendmode"] = blood_dna["blendmode"]
//to add blood from a mob onto something, and transfer their dna info
/atom/proc/add_mob_blood(mob/living/M)
@@ -826,6 +830,11 @@
/atom/proc/blood_DNA_to_color()
return (blood_DNA && blood_DNA["color"]) || BLOOD_COLOR_HUMAN
/atom/proc/blood_DNA_to_blend()
if(blood_DNA && !isnull(blood_DNA["blendmode"]))
return blood_DNA["blendmode"]
return BLEND_MULTIPLY
/atom/proc/clean_blood()
. = blood_DNA? TRUE : FALSE
blood_DNA = null
@@ -1192,6 +1201,8 @@
log_mecha(log_text)
if(LOG_SHUTTLE)
log_shuttle(log_text)
if(LOG_ECON)
log_econ(log_text)
else
stack_trace("Invalid individual logging type: [message_type]. Defaulting to [LOG_GAME] (LOG_GAME).")
log_game(log_text)
@@ -1295,7 +1306,7 @@
filters += filter(arglist(arguments))
UNSETEMPTY(filter_data)
/atom/proc/transition_filter(name, time, list/new_params, easing, loop)
/atom/proc/transition_filter(name, time, list/new_params, easing, loop, parallel = TRUE)
var/filter = get_filter(name)
if(!filter)
return
@@ -1306,7 +1317,7 @@
for(var/thing in new_params)
params[thing] = new_params[thing]
animate(filter, new_params, time = time, easing = easing, loop = loop)
animate(filter, new_params, time = time, easing = easing, loop = loop, flags = (parallel ? ANIMATION_PARALLEL : 0))
for(var/param in params)
filter_data[name][param] = params[param]
+29 -4
View File
@@ -64,6 +64,16 @@
/// last time we yelled
var/last_yell = 0
// Text-to-bark sounds
var/sound/vocal_bark
var/vocal_bark_id
var/vocal_pitch = 1
var/vocal_pitch_range = 0.2 //Actual pitch is (pitch - (vocal_pitch_range*0.5)) to (pitch + (vocal_pitch_range*0.5))
var/vocal_volume = 70 //Baseline. This gets modified by yelling and other factors
var/vocal_speed = 4 //Lower values are faster, higher values are slower
var/vocal_current_bark //When barks are queued, this gets passed to the bark proc. If vocal_current_bark doesn't match the args passed to the bark proc (if passed at all), then the bark simply doesn't play. Basic curtailing of spam~
/atom/movable/Initialize(mapload)
. = ..()
switch(blocks_emissive)
@@ -217,6 +227,10 @@
if(NAMEOF(src, glide_size))
set_glide_size(var_value)
. = TRUE
if(NAMEOF(src, vocal_bark))
if(isfile(var_value))
vocal_bark = sound(var_value) //bark() expects vocal_bark to already be a sound datum, for performance reasons. adminbus QoL!
. = TRUE
if(!isnull(.))
datum_flags |= DF_VAR_EDITED
@@ -604,11 +618,11 @@
if(throwing && !throw_override)
return
if(on && !(movement_type & FLOATING))
animate(src, pixel_y = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
animate(pixel_y = -2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
animate(src, pixel_z = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
animate(pixel_z = -4, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
setMovetype(movement_type | FLOATING)
else if (!on && (movement_type & FLOATING))
animate(src, pixel_y = initial(pixel_y), time = 10)
animate(src, pixel_z = initial(pixel_y), time = 10)
setMovetype(movement_type & ~FLOATING)
floating_need_update = FALSE // assume it's done
@@ -696,6 +710,17 @@
var/datum/language_holder/LH = get_language_holder()
return LH.update_atom_languages(src)
/// Sets the vocal bark for the atom, using the bark's ID
/atom/movable/proc/set_bark(id)
if(!id)
return FALSE
var/datum/bark/B = GLOB.bark_list[id]
if(!B)
return FALSE
vocal_bark = sound(initial(B.soundpath))
vocal_bark_id = id
return vocal_bark
/* End language procs */
@@ -774,4 +799,4 @@
M.Turn(pick(-30, 30))
animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = M, easing = CUBIC_EASING)
sleep(1)
animate(I, alpha = 0, transform = matrix(), time = 1)
animate(I, alpha = 0, transform = matrix(), time = 1, flags = ANIMATION_PARALLEL)
+34
View File
@@ -104,6 +104,10 @@ Class Procs:
anchored = TRUE
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
vocal_bark_id = "synth"
vocal_pitch = 0.6
vocal_volume = 40
var/stat = 0
var/use_power = IDLE_POWER_USE
//0 = dont run the auto
@@ -312,6 +316,36 @@ Class Procs:
return TRUE // If we passed all of those checks, woohoo! We can interact with this machine.
/obj/machinery/proc/can_transact(obj/item/card/id/thecard, allowdepartment, silent)
if(!istype(thecard))
if(!silent)
say("No card found.")
return FALSE
else if (!thecard.registered_account)
if(!silent)
say("No account found.")
return FALSE
else if(!allowdepartment && !thecard.registered_account.account_job)
if(!silent)
say("Departmental accounts have been blacklisted from personal expenses due to embezzlement.")
return FALSE
return TRUE
/obj/machinery/proc/attempt_transact(obj/item/card/id/thecard, transaction_cost)
if(!istype(thecard))
return FALSE
var/datum/bank_account/account = thecard.registered_account
if(!istype(account))
return FALSE
if(transaction_cost)
if(!account.adjust_money(-transaction_cost))
return FALSE
var/datum/bank_account/D = SSeconomy.get_dep_account(payment_department)
if(D)
D.adjust_money(transaction_cost)
return TRUE
/obj/machinery/proc/check_nap_violations()
if(!SSeconomy.full_ancap)
return TRUE
+14 -3
View File
@@ -62,14 +62,15 @@
if(!is_operational())
return
if(shocked && !(stat & NOPOWER))
shock(user,50)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Autolathe", capitalize(src.name))
ui.open()
if(shocked && !(stat & NOPOWER))
if(shock(user,50))
ui.close() //close the window if they got zapped successfully as to prevent them from getting zapped infinitely.
/obj/machinery/autolathe/ui_data(mob/user)
var/list/data = list()
data["materials"] = list()
@@ -298,6 +299,16 @@
wires.interact(user)
return STOP_ATTACK_PROC_CHAIN
/obj/machinery/autolathe/wirecutter_act(mob/living/user, obj/item/I)
. = ..()
if(busy)
balloon_alert(user, "it's busy!")
return STOP_ATTACK_PROC_CHAIN
if(panel_open)
wires.interact(user)
return STOP_ATTACK_PROC_CHAIN
/obj/machinery/autolathe/proc/AfterMaterialInsert(obj/item/item_inserted, id_inserted, amount_inserted)
if(istype(item_inserted, /obj/item/stack/ore/bluespace_crystal))
use_power(MINERAL_MATERIAL_AMOUNT / 10)
+94 -68
View File
@@ -1,6 +1,10 @@
#define COLORMATE_TINT 1
#define COLORMATE_HSV 2
#define COLORMATE_MATRIX 3
/obj/machinery/gear_painter
name = "\improper Color Mate"
desc = "A machine to give your apparel a fresh new color! Recommended to use with white items for best results."
desc = "A machine to give your apparel a fresh new color!"
icon = 'icons/obj/vending.dmi'
icon_state = "colormate"
// light_mask = "colormate-light-mask"
@@ -10,7 +14,11 @@
var/atom/movable/inserted
var/activecolor = "#FFFFFF"
var/list/color_matrix_last
var/matrix_mode = FALSE
var/active_mode = COLORMATE_HSV
var/build_hue = 0
var/build_sat = 1
var/build_val = 1
/// Allow holder'd mobs
var/allow_mobs = TRUE
/// Minimum lightness for normal mode
@@ -71,8 +79,8 @@
return
if(!QDELETED(H))
H.release()
insert_mob(victim, user)
temp = "[victim] has been inserted."
SStgui.update_uis(src)
if(is_type_in_list(I, allowed_types) && is_operational())
@@ -85,7 +93,6 @@
inserted = I
update_icon()
temp = "[I] has been inserted."
SStgui.update_uis(src)
else
@@ -134,7 +141,7 @@
/obj/machinery/gear_painter/ui_data(mob/user)
. = list()
.["matrixactive"] = matrix_mode
.["activemode"] = active_mode
.["matrixcolors"] = list(
"rr" = color_matrix_last[1],
"rg" = color_matrix_last[2],
@@ -149,6 +156,9 @@
"cg" = color_matrix_last[11],
"cb" = color_matrix_last[12]
)
.["buildhue"] = build_hue
.["buildsat"] = build_sat
.["buildval"] = build_val
if(temp)
.["temp"] = temp
if(inserted)
@@ -166,7 +176,7 @@
if(inserted)
switch(action)
if("switch_modes")
matrix_mode = text2num(params["mode"])
active_mode = text2num(params["mode"])
return TRUE
if("choose_color")
var/chosen_color = input(usr, "Choose a color: ", "Colormate color picking", activecolor) as color|null
@@ -174,14 +184,11 @@
activecolor = chosen_color
return TRUE
if("paint")
if(!check_valid_color(activecolor, usr))
return TRUE
inserted.add_atom_colour(activecolor, FIXED_COLOUR_PRIORITY)
playsound(src, 'sound/effects/spray3.ogg', 50, 1)
do_paint(usr)
temp = "Painted Successfully!"
return TRUE
if("drop")
temp = "Ejected \the [inserted]!"
temp = ""
drop_item()
return TRUE
if("clear")
@@ -192,76 +199,95 @@
if("set_matrix_color")
color_matrix_last[params["color"]] = params["value"]
return TRUE
if("matrix_paint")
var/list/cm = rgb_construct_color_matrix(
text2num(color_matrix_last[1]),
text2num(color_matrix_last[2]),
text2num(color_matrix_last[3]),
text2num(color_matrix_last[4]),
text2num(color_matrix_last[5]),
text2num(color_matrix_last[6]),
text2num(color_matrix_last[7]),
text2num(color_matrix_last[8]),
text2num(color_matrix_last[9]),
text2num(color_matrix_last[10]),
text2num(color_matrix_last[11]),
text2num(color_matrix_last[12])
)
if(!check_valid_color(cm, usr))
return TRUE
inserted.add_atom_colour(cm, FIXED_COLOUR_PRIORITY)
playsound(src, 'sound/effects/spray3.ogg', 50, 1)
temp = "Matrix Painted Successfully!"
if("set_hue")
build_hue = clamp(text2num(params["buildhue"]), 0, 360)
return TRUE
if("set_sat")
build_sat = clamp(text2num(params["buildsat"]), -10, 10)
return TRUE
if("set_val")
build_val = clamp(text2num(params["buildval"]), -10, 10)
return TRUE
/obj/machinery/gear_painter/proc/do_paint(mob/user)
var/color_to_use
switch(active_mode)
if(COLORMATE_TINT)
color_to_use = activecolor
if(COLORMATE_MATRIX)
color_to_use = rgb_construct_color_matrix(
text2num(color_matrix_last[1]),
text2num(color_matrix_last[2]),
text2num(color_matrix_last[3]),
text2num(color_matrix_last[4]),
text2num(color_matrix_last[5]),
text2num(color_matrix_last[6]),
text2num(color_matrix_last[7]),
text2num(color_matrix_last[8]),
text2num(color_matrix_last[9]),
text2num(color_matrix_last[10]),
text2num(color_matrix_last[11]),
text2num(color_matrix_last[12])
)
if(COLORMATE_HSV)
color_to_use = color_matrix_hsv(build_hue, build_sat, build_val)
color_matrix_last = color_to_use
if(!color_to_use || !check_valid_color(color_to_use, user))
to_chat(user, "<span class='notice'>Invalid color.</span>")
return FALSE
inserted.add_atom_colour(color_to_use, FIXED_COLOUR_PRIORITY)
playsound(src, 'sound/effects/spray3.ogg', 50, 1)
return TRUE
/// Produces the preview image of the item, used in the UI, the way the color is not stacking is a sin.
/obj/machinery/gear_painter/proc/build_preview()
if(inserted) //sanity
if(matrix_mode)
var/list/cm = rgb_construct_color_matrix(
text2num(color_matrix_last[1]),
text2num(color_matrix_last[2]),
text2num(color_matrix_last[3]),
text2num(color_matrix_last[4]),
text2num(color_matrix_last[5]),
text2num(color_matrix_last[6]),
text2num(color_matrix_last[7]),
text2num(color_matrix_last[8]),
text2num(color_matrix_last[9]),
text2num(color_matrix_last[10]),
text2num(color_matrix_last[11]),
text2num(color_matrix_last[12])
)
if(!check_valid_color(cm, usr))
temp = "Failed to generate preview: Invalid color!"
return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE)
var/list/cm
switch(active_mode)
if(COLORMATE_MATRIX)
cm = rgb_construct_color_matrix(
text2num(color_matrix_last[1]),
text2num(color_matrix_last[2]),
text2num(color_matrix_last[3]),
text2num(color_matrix_last[4]),
text2num(color_matrix_last[5]),
text2num(color_matrix_last[6]),
text2num(color_matrix_last[7]),
text2num(color_matrix_last[8]),
text2num(color_matrix_last[9]),
text2num(color_matrix_last[10]),
text2num(color_matrix_last[11]),
text2num(color_matrix_last[12])
)
if(!check_valid_color(cm, usr))
return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE)
var/cur_color = inserted.color
inserted.color = null
inserted.color = cm
var/icon/preview = getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE)
inserted.color = cur_color
if(COLORMATE_TINT)
if(!check_valid_color(activecolor, usr))
return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE)
. = preview
if(COLORMATE_HSV)
cm = color_matrix_hsv(build_hue, build_sat, build_val)
color_matrix_last = cm
if(!check_valid_color(cm, usr))
return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE)
else
if(!check_valid_color(activecolor, usr))
temp = "Failed to generate preview: Invalid color!"
return getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE)
var/cur_color = inserted.color
inserted.color = null
inserted.color = (active_mode == COLORMATE_TINT ? activecolor : cm)
var/icon/preview = getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE)
inserted.color = cur_color
temp = ""
var/cur_color = inserted.color
inserted.color = null
inserted.color = activecolor
var/icon/preview = getFlatIcon(inserted, defdir=SOUTH, no_anim=TRUE)
inserted.color = cur_color
. = preview
. = preview
/obj/machinery/gear_painter/proc/check_valid_color(list/cm, mob/user)
if(!islist(cm)) // normal
var/list/HSV = ReadHSV(RGBtoHSV(cm))
if(HSV[3] < minimum_normal_lightness)
temp = "[cm] is far too dark (min lightness [minimum_normal_lightness]!"
temp = "[cm] is too dark (Minimum lightness: [minimum_normal_lightness])"
return FALSE
return TRUE
else // matrix
@@ -275,6 +301,6 @@
COLORTEST("FFFFFF", cm)
#undef COLORTEST
if(passed < minimum_matrix_tests)
temp = "[english_list(color)] is not allowed (passed [passed] out of 4, minimum [minimum_matrix_tests], minimum lightness [minimum_matrix_lightness])."
temp = "Matrix is too dark. (passed [passed] out of [minimum_matrix_tests] required tests. Minimum lightness: [minimum_matrix_lightness])."
return FALSE
return TRUE
+103 -41
View File
@@ -6,17 +6,22 @@
verb_say = "states"
density = TRUE
req_one_access = list(ACCESS_BAR, ACCESS_KITCHEN, ACCESS_HYDROPONICS, ACCESS_ENGINE, ACCESS_CARGO, ACCESS_THEATRE)
payment_department = ACCOUNT_SRV
var/active = FALSE
var/list/rangers = list()
var/stop = 0
var/volume = 70
var/datum/track/selection = null
var/queuecost = PRICE_CHEAP //Set to -1 to make this jukebox require access for queueing
var/datum/track/playing = null
var/datum/track/selectedtrack = null
var/list/queuedplaylist = list()
var/queuecooldown //This var exists solely to prevent accidental repeats of John Mulaney's 'What's New Pussycat?' incident. Intentional, however......
/obj/machinery/jukebox/disco
name = "radiant dance machine mark IV"
desc = "The first three prototypes were discontinued after mass casualty incidents."
icon_state = "disco"
req_access = list(ACCESS_ENGINE)
req_one_access = list(ACCESS_ENGINE)
anchored = FALSE
var/list/spotlights = list()
var/list/sparkles = list()
@@ -24,7 +29,7 @@
/obj/machinery/jukebox/disco/indestructible
name = "radiant dance machine mark V"
desc = "Now redesigned with data gathered from the extensive disco and plasma research."
req_access = null
req_one_access = null
anchored = TRUE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
flags_1 = NODECONSTRUCT_1
@@ -46,6 +51,16 @@
return
return ..()
/obj/machinery/jukebox/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
queuecost = PRICE_FREE
req_one_access = null
to_chat(user, "<span class='notice'>You've bypassed [src]'s audio volume limiter, and enabled free play.</span>")
return TRUE
/obj/machinery/jukebox/update_icon_state()
if(active)
icon_state = "[initial(icon_state)]-active"
@@ -56,7 +71,7 @@
if(!anchored)
to_chat(user,"<span class='warning'>This device must be anchored by a wrench!</span>")
return UI_CLOSE
if(!allowed(user) && !isobserver(user))
if((queuecost < 0 && !allowed(user)) && !isobserver(user))
to_chat(user,"<span class='warning'>Error: Access Denied.</span>")
user.playsound_local(src, 'sound/misc/compiler-failure.ogg', 25, TRUE)
return UI_CLOSE
@@ -77,18 +92,21 @@
data["active"] = active
data["songs"] = list()
for(var/datum/track/S in SSjukeboxes.songs)
var/list/track_data = list(
name = S.song_name
)
var/list/track_data = list(name = S.song_name)
data["songs"] += list(track_data)
data["queued_tracks"] = list()
for(var/datum/track/S in queuedplaylist)
var/list/track_data = list(name = S.song_name)
data["queued_tracks"] += list(track_data)
data["track_selected"] = null
data["track_length"] = null
data["track_beat"] = null
if(selection)
data["track_selected"] = selection.song_name
data["track_length"] = DisplayTimeText(selection.song_length)
data["track_beat"] = selection.song_beat
if(playing)
data["track_selected"] = playing.song_name
data["track_length"] = DisplayTimeText(playing.song_length)
data["volume"] = volume
data["is_emagged"] = (obj_flags & EMAGGED)
data["cost_for_play"] = queuecost
data["has_access"] = allowed(user)
return data
/obj/machinery/jukebox/ui_act(action, list/params)
@@ -100,57 +118,91 @@
if("toggle")
if(QDELETED(src))
return
if(!active)
if(stop > world.time)
to_chat(usr, "<span class='warning'>Error: The device is still resetting from the last activation, it will be ready again in [DisplayTimeText(stop-world.time)].</span>")
playsound(src, 'sound/misc/compiler-failure.ogg', 50, TRUE)
return
if(!allowed(usr))
return
if(!active && !playing)
activate_music()
START_PROCESSING(SSobj, src)
return TRUE
else
stop = 0
return TRUE
if("select_track")
if(active)
to_chat(usr, "<span class='warning'>Error: You cannot change the song until the current one is over.</span>")
return TRUE
if("add_to_queue")
if(QDELETED(src))
return
if(world.time < queuecooldown)
return
if(!istype(selectedtrack, /datum/track))
return
if(!allowed(usr) && queuecost)
var/obj/item/card/id/C
if(isliving(usr))
var/mob/living/L = usr
C = L.get_idcard(TRUE)
if(!can_transact(C))
queuecooldown = world.time + (1 SECONDS)
playsound(src, 'sound/misc/compiler-failure.ogg', 25, TRUE)
return
if(!attempt_transact(C, queuecost))
say("Insufficient funds.")
queuecooldown = world.time + (1 SECONDS)
playsound(src, 'sound/misc/compiler-failure.ogg', 25, TRUE)
return
to_chat(usr, "<span class='notice'>You spend [queuecost] credits to queue [selectedtrack.song_name].</span>")
log_econ("[queuecost] credits were inserted into [src] by [key_name(usr)] (ID: [C.registered_name]) to queue [selectedtrack.song_name].")
queuedplaylist += selectedtrack
if(active)
say("[selectedtrack.song_name] has been added to the queue.")
else if(!playing)
activate_music()
playsound(src, 'sound/machines/ping.ogg', 50, TRUE)
queuecooldown = world.time + (3 SECONDS)
return TRUE
if("select_track")
var/list/available = list()
for(var/datum/track/S in SSjukeboxes.songs)
available[S.song_name] = S
var/selected = params["track"]
if(QDELETED(src) || !selected || !istype(available[selected], /datum/track))
return
selection = available[selected]
selectedtrack = available[selected]
return TRUE
if("set_volume")
if(!allowed(usr))
return
var/new_volume = params["volume"]
if(new_volume == "reset")
volume = initial(volume)
return TRUE
else if(new_volume == "min")
volume = 0
return TRUE
else if(new_volume == "max")
volume = 100
return TRUE
volume = ((obj_flags & EMAGGED) ? 210 : 100)
else if(text2num(new_volume) != null)
volume = text2num(new_volume)
return TRUE
volume = clamp(0, text2num(new_volume), ((obj_flags & EMAGGED) ? 210 : 100))
var/wherejuke = SSjukeboxes.findjukeboxindex(src)
if(wherejuke)
SSjukeboxes.updatejukebox(wherejuke, jukefalloff = volume/35)
return TRUE
/obj/machinery/jukebox/proc/activate_music()
var/jukeboxslottotake = SSjukeboxes.addjukebox(src, selection, 2)
if(playing || !queuedplaylist.len)
return FALSE
playing = queuedplaylist[1]
var/jukeboxslottotake = SSjukeboxes.addjukebox(src, playing, volume/35)
if(jukeboxslottotake)
active = TRUE
update_icon()
START_PROCESSING(SSobj, src)
stop = world.time + selection.song_length
stop = world.time + playing.song_length
queuedplaylist.Cut(1, 2)
say("Now playing: [playing.song_name]")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, TRUE)
return TRUE
else
return FALSE
/obj/machinery/jukebox/disco/activate_music()
..()
. = ..()
if(!.)
return
dance_setup()
lights_spin()
@@ -243,7 +295,7 @@
S.pixel_y = 7
S.forceMove(get_turf(src))
sleep(7)
if(selection.song_name == "Engineering's Ultimate High-Energy Hustle")
if(playing.song_name == "Engineering's Ultimate High-Energy Hustle")
sleep(280)
for(var/obj/reveal in sparkles)
reveal.alpha = 255
@@ -299,7 +351,7 @@
continue
if(prob(2)) // Unique effects for the dance floor that show up randomly to mix things up
INVOKE_ASYNC(src, .proc/hierofunk)
sleep(selection.song_beat)
sleep(playing.song_beat)
#undef DISCO_INFENO_RANGE
@@ -431,6 +483,7 @@
return
SSjukeboxes.removejukebox(position)
STOP_PROCESSING(SSobj, src)
playing = null
rangers = list()
/obj/machinery/jukebox/disco/dance_over()
@@ -439,12 +492,21 @@
QDEL_LIST(sparkles)
/obj/machinery/jukebox/process()
if(active && world.time >= stop)
active = FALSE
dance_over()
playsound(src,'sound/machines/terminal_off.ogg',50,1)
update_icon()
stop = world.time + 100
if(active)
if(world.time >= stop)
active = FALSE
dance_over()
if(stop && queuedplaylist.len)
activate_music()
else
playsound(src,'sound/machines/terminal_off.ogg',50,1)
update_icon()
playing = null
stop = 0
else if(volume > 140) // BOOM BOOM BOOM BOOM
for(var/mob/living/carbon/C in hearers(round(volume/35), src)) // I WANT YOU IN MY ROOM
if(istype(C)) // LETS SPEND THE NIGHT TOGETHER
C.adjustEarDamage(max((((volume/35) - sqrt(get_dist(C, src) * 4)) - C.get_ear_protection())*0.1, 0)) // FROM NOW UNTIL FOREVER
/obj/machinery/jukebox/disco/process()
+1
View File
@@ -1356,6 +1356,7 @@
/obj/machinery/door/airlock/proc/remove_electrify()
secondsElectrified = NOT_ELECTRIFIED
unelectrify_timerid = null
diag_hud_set_electrified()
/obj/machinery/door/airlock/proc/set_electrified(seconds, mob/user)
secondsElectrified = seconds
+7 -3
View File
@@ -203,9 +203,13 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
point_gain = (BOMB_TARGET_POINTS * 2 * orig_light) / (orig_light + BOMB_TARGET_SIZE)
/*****The Point Capper*****/
if(point_gain > linked_techweb.largest_bomb_value)
var/old_tech_largest_bomb_value = linked_techweb.largest_bomb_value //held so we can pull old before we do math
linked_techweb.largest_bomb_value = point_gain
var/list/largest_values = linked_techweb.largest_values
if(!(LARGEST_BOMB in largest_values))
largest_values[LARGEST_BOMB] = 0
if(point_gain > largest_values[LARGEST_BOMB])
var/old_tech_largest_bomb_value = largest_values[LARGEST_BOMB] //held so we can pull old before we do math
linked_techweb.largest_values[LARGEST_BOMB] = point_gain
point_gain -= old_tech_largest_bomb_value
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_SCI)
if(D)
+4 -4
View File
@@ -230,13 +230,13 @@
if(beaker)
if(beaker.reagents && beaker.reagents.reagent_list.len)
. += "\t<span class='notice'>Attached is \a [beaker] with [beaker.reagents.total_volume] units of liquid.</span>\n"
. += "<span class='notice'>Attached is \a [beaker] with [beaker.reagents.total_volume] units of liquid.</span>\n"
else
. += "\t<span class='notice'>Attached is an empty [beaker.name].</span>\n"
. += "<span class='notice'>Attached is an empty [beaker.name].</span>\n"
else
. += "\t<span class='notice'>No chemicals are attached.</span>\n"
. += "<span class='notice'>No chemicals are attached.</span>\n"
. += "\t<span class='notice'>[attached ? attached : "No one"] is attached.</span>"
. += "<span class='notice'>[attached ? attached : "No one"] is attached.</span>"
/obj/machinery/iv_drip/telescopic
name = "telescopic IV drip"
@@ -13,6 +13,17 @@
#define TURRET_FLAG_SHOOT_BORGS (1<<6) // checks if it can shoot cyborgs
#define TURRET_FLAG_SHOOT_HEADS (1<<7) // checks if it can shoot at heads of staff
DEFINE_BITFIELD(turret_flags, list(
"TURRET_FLAG_AUTH_WEAPONS" = TURRET_FLAG_AUTH_WEAPONS,
"TURRET_FLAG_SHOOT_ALL" = TURRET_FLAG_SHOOT_ALL,
"TURRET_FLAG_SHOOT_ALL_REACT" = TURRET_FLAG_SHOOT_ALL_REACT,
"TURRET_FLAG_SHOOT_ANOMALOUS" = TURRET_FLAG_SHOOT_ANOMALOUS,
"TURRET_FLAG_SHOOT_BORGS" = TURRET_FLAG_SHOOT_BORGS,
"TURRET_FLAG_SHOOT_CRIMINALS" = TURRET_FLAG_SHOOT_CRIMINALS,
"TURRET_FLAG_SHOOT_HEADS" = TURRET_FLAG_SHOOT_HEADS,
"TURRET_FLAG_SHOOT_UNSHIELDED" = TURRET_FLAG_SHOOT_UNSHIELDED,
))
/obj/machinery/porta_turret
name = "turret"
icon = 'icons/obj/turrets.dmi'
+46
View File
@@ -29,10 +29,12 @@
var/obj/effect/overlay/status_display_text/message1_overlay
var/obj/effect/overlay/status_display_text/message2_overlay
var/mutable_appearance/ai_vtuber_overlay
var/current_picture = ""
var/current_mode = SD_BLANK
var/message1 = ""
var/message2 = ""
var/mob/living/silicon/ai/master
/obj/item/wallframe/status_display
name = "status display frame"
@@ -122,6 +124,10 @@
if(overlay && message == overlay.message)
return null
// if an AI is controlling, we don't update the overlay
if(master)
return
if(overlay)
qdel(overlay)
@@ -147,6 +153,10 @@
remove_messages()
return
if(master)
remove_messages()
return
switch(current_mode)
if(SD_BLANK)
remove_messages()
@@ -493,6 +503,42 @@
user.emote(initial(emote.key))
break
// ai vtuber moment
/obj/machinery/status_display/AICtrlClick(mob/living/silicon/ai/user)
if(!isAI(user) || master || (user.current && !istype(user.current, /obj/machinery/status_display))) // don't let two AIs control the same one, don't let AI control two things at once
return
if(!user.client.prefs.custom_holoform_icon)
to_chat(user, span_notice("You have no custom holoform set!"))
return
// move AI to the location, set master, update overlays (removes messages)
user.current = src
user.eyeobj.setLoc(get_turf(src))
icon_state = initial(icon_state)
user.controlled_display = src
master = user
update_overlays()
update_appearance()
// we set the avatar here
var/icon/I = icon(user.client.prefs.custom_holoform_icon)
I.Crop(1,16,32,32)
ai_vtuber_overlay = mutable_appearance(I)
ai_vtuber_overlay.blend_mode = BLEND_ADD
ai_vtuber_overlay.pixel_y = 8
update_overlays()
add_overlay(ai_vtuber_overlay)
// tell the user how to speak
to_chat(user, span_notice("Use :q to relay messages through the status display."))
// modified version of how holopads 'hear' and relay to AIs
/obj/machinery/status_display/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(master && !radio_freq && master.controlled_display == src)
master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
/obj/machinery/status_display/ai/process()
if(stat & NOPOWER)
update_appearance()
@@ -3,6 +3,7 @@
desc = "They look bloody and gruesome."
icon_state = "gibbl5"
layer = LOW_OBJ_LAYER
blend_mode = BLEND_DEFAULT
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
mergeable_decal = FALSE
bloodiness = 0 //This isn't supposed to be bloody.
@@ -3,6 +3,7 @@
desc = "It's gooey. Perhaps it's the chef's cooking?"
icon = 'icons/effects/blood.dmi'
icon_state = "floor1"
blend_mode = BLEND_MULTIPLY
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
blood_state = BLOOD_STATE_BLOOD
bloodiness = BLOOD_AMOUNT_PER_DECAL
@@ -33,16 +34,20 @@
. = ..()
if(!fixed_color)
add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
blend_mode = blood_DNA_to_blend()
/obj/effect/decal/cleanable/blood/PersistenceSave(list/data)
. = ..()
data["color"] = color
data["blendmode"] = blend_mode
/obj/effect/decal/cleanable/blood/PersistenceLoad(list/data)
. = ..()
if(data["color"])
fixed_color = TRUE
add_atom_colour(data["color"], FIXED_COLOUR_PRIORITY)
if(data["blendmode"])
blend_mode = data["blendmode"]
name = "dried blood"
desc = "Looks like it's been here a while. Eew"
bloodiness = 0
@@ -82,8 +87,8 @@
/obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose
name = "blood"
icon = 'icons/effects/blood.dmi'
icon_state = "ltrails_1"
desc = "Your instincts say you shouldn't be following these."
blend_mode = BLEND_MULTIPLY
random_icon_states = null
beauty = -50
persistent = TRUE
@@ -95,6 +100,7 @@
. = ..()
data["dir"] = dir
data["color"] = color
data["blendmode"] = blend_mode
/obj/effect/decal/cleanable/trail_holder/PersistenceLoad(list/data)
. = ..()
@@ -103,11 +109,14 @@
if(data["color"])
fixed_color = TRUE
add_atom_colour(data["color"], FIXED_COLOUR_PRIORITY)
if(data["blendmode"])
blend_mode = data["blendmode"]
/obj/effect/decal/cleanable/trail_holder/update_icon()
. = ..()
if(!fixed_color)
add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
blend_mode = blood_DNA_to_blend()
/obj/effect/cleanable/trail_holder/Initialize(mapload)
. = ..()
+1
View File
@@ -1,4 +1,5 @@
GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/effects/fire.dmi', "fire"))
GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons/effects/welding_effect.dmi', "welding_sparks", GASFIRE_LAYER, ABOVE_LIGHTING_PLANE))
GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// if true, everyone item when created will have its name changed to be
+6 -5
View File
@@ -601,11 +601,12 @@
H.adjustOxyLoss(H.health - HALFWAYCRITDEATH, 0)
else
var/overall_damage = total_brute + total_burn + H.getToxLoss() + H.getOxyLoss()
var/mobhealth = H.health
H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), 0)
H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), 0)
H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0)
H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0)
if(overall_damage)
var/mobhealth = H.health
H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), 0)
H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), 0)
H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0)
H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0)
H.updatehealth() // Previous "adjust" procs don't update health, so we do it manually.
user.visible_message("<span class='notice'>[req_defib ? "[defib]" : "[src]"] pings: Resuscitation successful.</span>")
playsound(src, 'sound/machines/defib_success.ogg', 50, 0)
+32 -33
View File
@@ -145,32 +145,29 @@ GENETICS SCANNER
mob_status = "<span class='alert'><b>Deceased</b></span>"
oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss
var/msg = "<span class='info'>*---------*\nAnalyzing results for [M]:\n\tOverall status: [mob_status]"
var/msg = "<span class='info'>Analyzing results for [M]:\n<blockquote class='notice'>Overall status: [mob_status]"
// Damage descriptions
if(brute_loss > 10)
msg += "\n\t<span class='alert'>[brute_loss > 50 ? "Severe" : "Minor"] tissue damage detected.</span>"
msg += "\n<span class='alert'>[brute_loss > 50 ? "Severe" : "Minor"] tissue damage detected.</span>"
if(fire_loss > 10)
msg += "\n\t<span class='alert'>[fire_loss > 50 ? "Severe" : "Minor"] burn damage detected.</span>"
msg += "\n<span class='alert'>[fire_loss > 50 ? "Severe" : "Minor"] burn damage detected.</span>"
if(oxy_loss > 10)
msg += "\n\t<span class='info'><span class='alert'>[oxy_loss > 50 ? "Severe" : "Minor"] oxygen deprivation detected.</span>"
msg += "\n<span class='info'><span class='alert'>[oxy_loss > 50 ? "Severe" : "Minor"] oxygen deprivation detected.</span>"
if(tox_loss > 10)
msg += "\n\t<span class='alert'>[tox_loss > 50 ? "Severe" : "Minor"] amount of [HAS_TRAIT(M, TRAIT_ROBOTIC_ORGANISM) ? "system corruption" : "toxin damage"] detected.</span>"
msg += "\n<span class='alert'>[tox_loss > 50 ? "Severe" : "Minor"] amount of [HAS_TRAIT(M, TRAIT_ROBOTIC_ORGANISM) ? "system corruption" : "toxin damage"] detected.</span>"
if(M.getStaminaLoss())
msg += "\n\t<span class='alert'>Subject appears to be suffering from fatigue.</span>"
msg += "\n<span class='alert'>Subject appears to be suffering from fatigue.</span>"
if(advanced)
msg += "\n\t<span class='info'>Fatigue Level: [M.getStaminaLoss()]%.</span>"
msg += "\n<span class='info'>Fatigue Level: [M.getStaminaLoss()]%.</span>"
if (M.getCloneLoss())
msg += "\n\t<span class='alert'>Subject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage.</span>"
msg += "\n<span class='alert'>Subject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage.</span>"
if(advanced)
msg += "\n\t<span class='info'>Cellular Damage Level: [M.getCloneLoss()].</span>"
msg += "\n<span class='info'>Cellular Damage Level: [M.getCloneLoss()].</span>"
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(advanced && H.has_dna())
msg += "\n\t<span class='info'>Genetic Stability: [H.dna.stability]%.</span>"
to_chat(user, msg)
msg = ""
msg += "\n<span class='info'>Genetic Stability: [H.dna.stability]%.</span>"
// Body part damage report
var/list/dmgreport = list()
@@ -178,7 +175,7 @@ GENETICS SCANNER
var/mob/living/carbon/C = M
var/list/damaged = C.get_damaged_bodyparts(1,1)
if(length(damaged)>0 || oxy_loss>0 || tox_loss>0 || fire_loss>0)
dmgreport += "<table style='margin-left:33px'><tr><font face='Verdana'>\
dmgreport += "<table><tr><font face='Verdana'>\
<td style='width: 90px;'><font color='#0000CC'>Damage:</font></td>\
<td style='width: 55px;'><font color='red'><b>Brute</b></font></td>\
<td style='width: 45px;'><font color='orange'><b>Burn</b></font></td>\
@@ -196,7 +193,7 @@ GENETICS SCANNER
<td><font color='red'>[(org.brute_dam > 0) ? "[org.brute_dam]" : "0"]</font></td>\
<td><font color='orange'>[(org.burn_dam > 0) ? "[org.burn_dam]" : "0"]</font></td></tr>"
dmgreport += "</table>"
to_chat(user, dmgreport.Join())
msg += "\n[dmgreport.Join()]"
//Organ damages report
@@ -317,7 +314,7 @@ GENETICS SCANNER
damage_message += " <font color='red'>Minor [O.name] failure detected.</span>"
if(temp_message || damage_message)
msg += "\t<b><span class='info'>[uppertext(O.name)]:</b></span> [damage_message] [temp_message]\n"
msg += "\n<b><span class='info'>[uppertext(O.name)]:</b></span> [damage_message] [temp_message]\n"
@@ -332,24 +329,24 @@ GENETICS SCANNER
var/has_liver = C.dna && !(NOLIVER in C.dna.species.species_traits)
var/has_stomach = C.dna && !(NOSTOMACH in C.dna.species.species_traits)
if(!M.getorganslot(ORGAN_SLOT_EYES))
msg += "\t<span class='alert'><b>Subject does not have eyes.</b></span>\n"
msg += "<span class='alert'><b>Subject does not have eyes.</b></span>\n"
if(!M.getorganslot(ORGAN_SLOT_EARS))
msg += "\t<span class='alert'><b>Subject does not have ears.</b></span>\n"
msg += "<span class='alert'><b>Subject does not have ears.</b></span>\n"
if(!M.getorganslot(ORGAN_SLOT_BRAIN))
msg += "\t<span class='alert'><b>Subject's brain function is non-existent!</b></span>\n"
msg += "<span class='alert'><b>Subject's brain function is non-existent!</b></span>\n"
if(has_liver && !M.getorganslot(ORGAN_SLOT_LIVER))
msg += "\t<span class='alert'><b>Subject's liver is missing!</b></span>\n"
msg += "<span class='alert'><b>Subject's liver is missing!</b></span>\n"
if(blooded && !M.getorganslot(ORGAN_SLOT_HEART))
msg += "\t<span class='alert'><b>Subject's heart is missing!</b></span>\n"
msg += "<span class='alert'><b>Subject's heart is missing!</b></span>\n"
if(breathes && !M.getorganslot(ORGAN_SLOT_LUNGS))
msg += "\t<span class='alert'><b>Subject's lungs have collapsed from trauma!</b></span>\n"
msg += "<span class='alert'><b>Subject's lungs have collapsed from trauma!</b></span>\n"
if(has_stomach && !M.getorganslot(ORGAN_SLOT_STOMACH))
msg += "\t<span class='alert'><b>Subject's stomach is missing!</span>\n"
msg += "<span class='alert'><b>Subject's stomach is missing!</span>\n"
if(M.radiation)
msg += "\t<span class='alert'>Subject is irradiated.</span>\n"
msg += "\t<span class='info'>Radiation Level: [M.radiation] rad</span>\n"
msg += "<span class='alert'>Subject is irradiated.</span>\n"
msg += "<span class='info'>Radiation Level: [M.radiation] rad</span>\n"
@@ -383,11 +380,11 @@ GENETICS SCANNER
else if (S.flying_species != initial(S.flying_species))
mutant = TRUE
msg += "\t<span class='info'>Reported Species: [H.spec_trait_examine_font()][H.dna.custom_species ? H.dna.custom_species : S.name]</font></span>\n"
msg += "\t<span class='info'>Base Species: [H.spec_trait_examine_font()][S.name]</font></span>\n"
msg += "\n<span class='info'>Reported Species: [H.spec_trait_examine_font()][H.dna.custom_species ? H.dna.custom_species : S.name]</font></span>\n"
msg += "<span class='info'>Base Species: [H.spec_trait_examine_font()][S.name]</font></span>\n"
if(mutant)
msg += "\t<span class='info'>Subject has mutations present.</span>\n"
msg += "\t<span class='info'>Body temperature: [round(M.bodytemperature-T0C,0.1)] &deg;C ([round(M.bodytemperature*1.8-459.67,0.1)] &deg;F)</span>\n"
msg += "<span class='info'>Subject has mutations present.</span>\n"
msg += "<span class='info'>Body temperature: [round(M.bodytemperature-T0C,0.1)] &deg;C ([round(M.bodytemperature*1.8-459.67,0.1)] &deg;F)</span>\n"
// Time of death
if(M.tod && (M.stat == DEAD || ((HAS_TRAIT(M, TRAIT_FAKEDEATH)) && !advanced)))
@@ -452,14 +449,14 @@ GENETICS SCANNER
if(cyberimp_detect)
msg += "<span class='notice'>Detected cybernetic modifications:</span>\n"
msg += "<span class='notice'>[cyberimp_detect]</span>\n"
msg += "<span class='notice'>*---------*</span>"
msg += "</blockquote>"
to_chat(user, msg)
SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, FALSE)
/proc/chemscan(mob/living/user, mob/living/M)
if(istype(M))
if(M.reagents)
var/msg = "<span class='info'>*---------*\n"
var/msg = "<blockquote class='purple'>"
if(M.reagents.reagent_list.len)
var/list/datum/reagent/reagents = list()
for(var/datum/reagent/R in M.reagents.reagent_list)
@@ -498,7 +495,7 @@ GENETICS SCANNER
if(95 to INFINITY)
msg += "<span class='danger'>Subject contains a extremely dangerous amount of toxic isomers.</span>\n"
msg += "*---------*</span>"
msg += "</blockquote>"
to_chat(user, msg)
/obj/item/healthanalyzer/verb/toggle_mode()
@@ -529,12 +526,14 @@ GENETICS SCANNER
var/render_list = ""
for(var/i in patient.get_wounded_bodyparts())
if(render_list == "")
render_list += "<blockquote class='warning'>"
var/obj/item/bodypart/wounded_part = i
render_list += "<span class='alert ml-1'><b>Warning: Physical trauma[LAZYLEN(wounded_part.wounds) > 1? "s" : ""] detected in [wounded_part.name]</b>"
for(var/k in wounded_part.wounds)
var/datum/wound/W = k
render_list += "<div class='ml-2'>[W.get_scanner_description()]</div>\n"
render_list += "</span>"
render_list += "</blockquote>"
if(render_list == "")
if(istype(scanner))
@@ -205,6 +205,10 @@
if(!throw_item(target, I, user))
break
if(user)
shake_camera(user, (pressureSetting * 0.75 + 1), (pressureSetting * 0.75))
/obj/item/pneumatic_cannon/proc/throw_item(turf/target, obj/item/I, mob/user)
if(!istype(I))
return FALSE
@@ -22,8 +22,8 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
new/datum/stack_recipe("spout flask", /obj/item/glasswork/glass_base/spouty, 20), \
new/datum/stack_recipe("small bulb flask", /obj/item/glasswork/glass_base/flask_small, 5), \
new/datum/stack_recipe("large bottle flask", /obj/item/glasswork/glass_base/flask_large, 15), \
new/datum/stack_recipe("tea cup", /obj/item/glasswork/glass_base/tea_plate, 5), \
new/datum/stack_recipe("tea plate", /obj/item/glasswork/glass_base/tea_cup, 5), \
new/datum/stack_recipe("tea cup", /obj/item/glasswork/glass_base/tea_cup, 5), \
new/datum/stack_recipe("tea plate", /obj/item/glasswork/glass_base/tea_plate, 5), \
)), \
))
@@ -561,4 +561,4 @@
singular_name = "catwalk floor tile"
desc = "Flooring that shows its contents underneath. Engineers love it!"
icon_state = "catwalk_tile"
turf_type = /turf/open/floor/plating/catwalk_floor
turf_type = /turf/open/floor/catwalk_floor
@@ -119,6 +119,11 @@
dyn_explosion(T, plasmaAmount/5)//20 plasma in a standard welder has a 4 power explosion. no breaches, but enough to kill/dismember holder
qdel(src)
/obj/item/weldingtool/use_tool(atom/target, mob/living/user, delay, amount, volume, datum/callback/extra_checks, skill_gain_mult)
target.add_overlay(GLOB.welding_sparks)
. = ..()
target.cut_overlay(GLOB.welding_sparks)
/obj/item/weldingtool/attack(mob/living/carbon/human/H, mob/user)
if(!istype(H))
return ..()
+2
View File
@@ -7,6 +7,8 @@
var/obj_flags = CAN_BE_HIT
var/set_obj_flags // ONLY FOR MAPPING: Sets flags from a string list, handled in Initialize. Usage: set_obj_flags = "EMAGGED;!CAN_BE_HIT" to set EMAGGED and clear CAN_BE_HIT.
var/minimap_override_color // allows this obj to set its own color on the minimap
var/damtype = BRUTE
var/force = 0
+1 -1
View File
@@ -65,7 +65,7 @@
/obj/structure/proc/do_climb(atom/movable/A)
if(climbable)
density = FALSE
. = step(A,get_dir(A,src.loc))
. = step(A, (A.loc == loc ? dir : get_dir(A,src.loc)))
density = TRUE
/obj/structure/proc/climb_structure(mob/living/user)
@@ -156,9 +156,10 @@
for(var/atom/movable/AM in L)
if(AM != src && insert(AM) == -1) // limit reached
break
// for(var/i in reverseRange(L.GetAllContents()))
// var/atom/movable/thing = i
// SEND_SIGNAL(thing, COMSIG_TRY_STORAGE_HIDE_ALL)
// todo: this should be unnecessary, storage should auto close on move wtf
for(var/i in reverseRange(L.GetAllContents()))
var/atom/movable/thing = i
SEND_SIGNAL(thing, COMSIG_TRY_STORAGE_HIDE_ALL)
/obj/structure/closet/proc/open(mob/living/user, force = FALSE)
if(!can_open(user, force))
@@ -64,6 +64,7 @@
new /obj/item/clothing/under/rank/security/officer/blueshirt/seccorp/hoscorp(src)
new /obj/item/clothing/suit/armor/vest/leather(src)
new /obj/item/clothing/suit/armor/hos(src)
new /obj/item/clothing/suit/armor/hos/platecarrier(src)
new /obj/item/clothing/under/rank/security/head_of_security/skirt(src)
new /obj/item/clothing/under/rank/security/head_of_security/alt(src)
new /obj/item/clothing/under/rank/security/head_of_security/alt/skirt(src)
+29 -1
View File
@@ -31,14 +31,42 @@ GLOBAL_LIST_INIT(freqtospan, list(
/atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args)
/atom/movable/proc/bark(list/hearers, distance, volume, pitch, queue_time)
if(queue_time && vocal_current_bark != queue_time)
return
if(SEND_SIGNAL(src, COMSIG_MOVABLE_BARK, hearers, distance, volume, pitch))
return //bark interception. this probably counts as some flavor of BDSM
if(!vocal_bark)
if(!vocal_bark_id || !set_bark(vocal_bark_id)) //just-in-time bark generation
return
volume = min(volume, 100)
var/turf/T = get_turf(src)
for(var/mob/M in hearers)
M.playsound_local(T, vol = volume, vary = TRUE, frequency = pitch, max_distance = distance, falloff_distance = 0, falloff_exponent = BARK_SOUND_FALLOFF_EXPONENT(distance), S = vocal_bark, distance_multiplier = 1)
/atom/movable/proc/can_speak()
return 1
/atom/movable/proc/send_speech(message, range = 7, atom/movable/source = src, bubble_type, list/spans, datum/language/message_language = null, message_mode)
var/rendered = compose_message(src, message_language, message, , spans, message_mode, source)
for(var/_AM in get_hearers_in_view(range, source))
var/list/hearers = get_hearers_in_view(range, source)
for(var/_AM in hearers)
var/atom/movable/AM = _AM
AM.Hear(rendered, src, message_language, message, , spans, message_mode, source)
if(SEND_SIGNAL(src, COMSIG_MOVABLE_QUEUE_BARK, hearers, args) || vocal_bark || vocal_bark_id)
for(var/mob/M in hearers)
if(!M.client)
continue
if(!(M.client.prefs.toggles & SOUND_BARK))
hearers -= M
var/barks = min(round((LAZYLEN(message) / vocal_speed)) + 1, BARK_MAX_BARKS)
var/total_delay
vocal_current_bark = world.time //this is juuuuust random enough to reliably be unique every time send_speech() is called, in most scenarios
for(var/i in 1 to barks)
if(total_delay > BARK_MAX_TIME)
break
addtimer(CALLBACK(src, .proc/bark, hearers, range, vocal_volume, BARK_DO_VARY(vocal_pitch, vocal_pitch_range), vocal_current_bark), total_delay)
total_delay += rand(DS2TICKS(vocal_speed / BARK_SPEED_BASELINE), DS2TICKS(vocal_speed / BARK_SPEED_BASELINE) + DS2TICKS(vocal_speed / BARK_SPEED_BASELINE)) TICKS
/atom/movable/proc/compose_message(atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, face_name = FALSE, atom/movable/source)
if(!source)
+11 -4
View File
@@ -110,13 +110,20 @@ distance_multiplier - Can be used to multiply the distance at which the sound is
*/
/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff_exponent = SOUND_FALLOFF_EXPONENT, channel = 0, pressure_affected = TRUE, sound/S, max_distance,
falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = SOUND_DEFAULT_DISTANCE_MULTIPLIER, envwet = -10000, envdry = 0)
if(!client || !can_hear())
falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = SOUND_DEFAULT_DISTANCE_MULTIPLIER, envwet = -10000, envdry = 0, virtual_hearer)
if(audiovisual_redirect)
virtual_hearer = get_turf(src)
audiovisual_redirect.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, max_distance, falloff_distance, distance_multiplier, max(0, envwet), -10000, virtual_hearer)
//No return here, as we want to deliberately support the possibility of shenanigans in which mobs with clients can have active AV redirects to completely different players
if(!client)
return
if(!S)
S = sound(get_sfx(soundin))
if(!can_hear() && !(S.status & SOUND_UPDATE)) //This is primarily to make sure sound updates still go through when a spaceman's deaf
return
S.wait = 0 //No queue
S.channel = channel || SSsounds.random_available_channel()
S.volume = vol
@@ -131,7 +138,7 @@ distance_multiplier - Can be used to multiply the distance at which the sound is
S.frequency = get_rand_frequency()
if(isturf(turf_source))
var/turf/T = get_turf(src)
var/turf/T = virtual_hearer || get_turf(src)
//sound volume falloff with distance
var/distance = get_dist(T, turf_source)
@@ -173,7 +180,7 @@ distance_multiplier - Can be used to multiply the distance at which the sound is
var/dz = turf_source.y - T.y // Hearing from infront/behind
S.z = dz * distance_multiplier
var/dy = (turf_source.z - T.z) * 5 * distance_multiplier // Hearing from above / below, multiplied by 5 because we assume height is further along coords.
S.y = dy + 1
S.y = dy + distance_multiplier
S.falloff = isnull(max_distance)? FALLOFF_SOUNDS : max_distance //use max_distance, else just use 1 as we are a direct sound so falloff isnt relevant.
+20 -4
View File
@@ -73,16 +73,26 @@
/turf/closed/indestructible/splashscreen
name = "Space Station 13"
icon = 'icons/blank_title.png'
desc = null
icon = 'icons/blanks/blank_title.png'
icon_state = ""
layer = FLY_LAYER
plane = SPLASHSCREEN_PLANE
bullet_bounce_sound = null
/turf/closed/indestructible/splashscreen/New()
INITIALIZE_IMMEDIATE(/turf/closed/indestructible/splashscreen)
/turf/closed/indestructible/splashscreen/Initialize(mapload)
. = ..()
SStitle.splash_turf = src
if(SStitle.icon)
icon = SStitle.icon
..()
handle_generic_titlescreen_sizes()
///helper proc that will center the screen if the icon is changed to a generic width, to make admins have to fudge around with pixel_x less. returns null
/turf/closed/indestructible/splashscreen/proc/handle_generic_titlescreen_sizes()
var/icon/size_check = icon(SStitle.icon, icon_state)
var/width = size_check.Width()
pixel_x = (672 - width) * 0.5 //The title screen is mapped with the expectation that it's 672x480. Should probably turn the title screen size into a define some time!
/turf/closed/indestructible/splashscreen/vv_edit_var(var_name, var_value)
. = ..()
@@ -90,7 +100,13 @@
switch(var_name)
if(NAMEOF(src, icon))
SStitle.icon = icon
handle_generic_titlescreen_sizes()
/turf/closed/indestructible/start_area
name = null
desc = null
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/turf/closed/indestructible/riveted
icon = 'icons/turf/walls/riveted.dmi'
icon_state = "riveted"
+14 -8
View File
@@ -5,7 +5,7 @@
* you can crowbar it to interact with the underneath stuff without destroying the tile...
* unless you want to!
*/
/turf/open/floor/plating/catwalk_floor
/turf/open/floor/catwalk_floor
icon = 'icons/turf/floors/catwalk_plating.dmi'
icon_state = "catwalk_below"
floor_tile = /obj/item/stack/tile/catwalk
@@ -16,29 +16,35 @@
barefootstep = FOOTSTEP_CATWALK
clawfootstep = FOOTSTEP_CATWALK
heavyfootstep = FOOTSTEP_CATWALK
intact = FALSE
var/covered = TRUE
/turf/open/floor/plating/catwalk_floor/Initialize(mapload)
/turf/open/floor/catwalk_floor/Initialize(mapload)
. = ..()
layer = CATWALK_LAYER
update_icon(UPDATE_OVERLAYS)
/turf/open/floor/plating/catwalk_floor/update_overlays()
/turf/open/floor/catwalk_floor/update_overlays()
. = ..()
var/static/catwalk_overlay
var/static/image/catwalk_overlay
if(isnull(catwalk_overlay))
catwalk_overlay = iconstate2appearance(icon, "catwalk_above")
catwalk_overlay = new()
catwalk_overlay.icon = icon
catwalk_overlay.icon_state = "catwalk_above"
catwalk_overlay.plane = GAME_PLANE
catwalk_overlay.layer = CATWALK_LAYER
catwalk_overlay = catwalk_overlay.appearance
if(covered)
. += catwalk_overlay
/turf/open/floor/plating/catwalk_floor/screwdriver_act(mob/living/user, obj/item/tool)
/turf/open/floor/catwalk_floor/screwdriver_act(mob/living/user, obj/item/tool)
. = ..()
covered = !covered
user.balloon_alert(user, "[!covered ? "cover removed" : "cover added"]")
update_icon(UPDATE_OVERLAYS)
/turf/open/floor/plating/catwalk_floor/pry_tile(obj/item/crowbar, mob/user, silent)
/turf/open/floor/catwalk_floor/crowbar_act(mob/user, obj/item/I)
if(covered)
user.balloon_alert(user, "remove cover first!")
return FALSE
. = ..()
return pry_tile(I, user)
+1
View File
@@ -117,6 +117,7 @@ GLOBAL_LIST(topic_status_cache)
GLOB.world_asset_log = "[GLOB.log_directory]/asset.log"
GLOB.world_attack_log = "[GLOB.log_directory]/attack.log"
GLOB.world_victim_log = "[GLOB.log_directory]/victim.log"
GLOB.world_econ_log = "[GLOB.log_directory]/econ.log"
GLOB.world_pda_log = "[GLOB.log_directory]/pda.log"
GLOB.world_telecomms_log = "[GLOB.log_directory]/telecomms.log"
GLOB.world_manifest_log = "[GLOB.log_directory]/manifest.log"