mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-30 00:21:11 +01:00
Merge branch 'Aurorastation:master' into boneyard
This commit is contained in:
@@ -15,6 +15,15 @@ They should also be used for when you want to effect the ENTIRE mob, like having
|
||||
|
||||
return COMPONENT_BULLET_BLOCKED
|
||||
|
||||
/obj/aura/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
var/result = ..()
|
||||
if(result == BULLET_ACT_BLOCK) //The bullet was blocked, don't check the remaining auras.
|
||||
return AURA_FALSE|AURA_CANCEL
|
||||
else if(result == BULLET_ACT_FORCE_PIERCE) //The bullet was forced to pierce, check the remaining auras to see if they block.
|
||||
return AURA_FALSE
|
||||
else
|
||||
return
|
||||
|
||||
/obj/aura/Destroy()
|
||||
if(user)
|
||||
user.remove_aura(src)
|
||||
|
||||
@@ -55,13 +55,11 @@
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/Initialize(mapload)
|
||||
. = ..()
|
||||
if (!mapload) // Round-start goo should stick around.
|
||||
QDEL_IN(src, 2 MINUTES)
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/post_sweep(var/mob/user)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.apply_radiation(3)
|
||||
H.rad_act(30)
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
|
||||
ABSTRACT_TYPE(/obj/effect/decal/cleanable/greenglow/radioactive)
|
||||
@@ -71,6 +69,13 @@ ABSTRACT_TYPE(/obj/effect/decal/cleanable/greenglow/radioactive)
|
||||
light_power = 0.6
|
||||
light_color = "#64C864"
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/radioactive/post_sweep(var/mob/user)
|
||||
if(radioactivity)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
H.rad_act(radioactivity)
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/radioactive/antagonist_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "Characters directly adjacent to or on top of this object will be exposed to <b>[radioactivity] IU/s</b> of radiation. Radiation falls off (approximately) by 75% for every tile away you move."
|
||||
@@ -123,7 +128,6 @@ ABSTRACT_TYPE(/obj/effect/decal/cleanable/greenglow/radioactive)
|
||||
/obj/effect/decal/cleanable/greenglow/radioactive/process()
|
||||
SSradiation.radiate(src, radioactivity)
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/cobweb
|
||||
name = "cobweb"
|
||||
desc = "Somebody should remove that."
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
layer = ABOVE_DOOR_LAYER
|
||||
var/obj/item/plastique/parent
|
||||
|
||||
/obj/effect/plastic_explosive/feedback_hints(mob/user, distance, is_adjacent)
|
||||
@@ -16,8 +17,8 @@
|
||||
|
||||
/obj/effect/plastic_explosive/Initialize(var/atom/owner_pos, var/atom/target, var/obj/item/plastique/c4)
|
||||
. = ..()
|
||||
parent = c4
|
||||
if(parent)
|
||||
parent = c4
|
||||
parent.forceMove(src)
|
||||
name = parent.name
|
||||
desc = parent.desc
|
||||
@@ -46,8 +47,8 @@
|
||||
/obj/effect/plastic_explosive/attack_hand(mob/living/user)
|
||||
to_chat(user, SPAN_WARNING("\The [src] is solidly attached, it doesn't budge!"))
|
||||
|
||||
/obj/effect/plastic_explosive/attackby(obj/item/attacking_item, mob/user)
|
||||
return parent.attackby(attacking_item, user)
|
||||
/obj/effect/plastic_explosive/attackby(obj/item/attacking_item, mob/user, click_parameters)
|
||||
return parent.attackby(attacking_item, user, click_parameters)
|
||||
|
||||
/obj/effect/plastic_explosive/big
|
||||
name = "bundled plastic explosives"
|
||||
|
||||
@@ -47,12 +47,12 @@
|
||||
return
|
||||
if(emagged)
|
||||
if(insults)
|
||||
user.audible_message("<B>[user]</B> broadcasts, <FONT size=5>\"[pick(insultmsg)]\"</FONT>", "<B>[user]</B> speaks into \the [src].", 14)
|
||||
speak(pick(insultmsg), user)
|
||||
insults--
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("*BZZZZzzzzzt*"))
|
||||
else
|
||||
user.audible_message("<B>[user]</B> broadcasts, <FONT size=5>\"[message]\"</FONT>", "<B>[user]</B> speaks into \the [src].", 14)
|
||||
speak(message, user)
|
||||
if(activation_sound)
|
||||
playsound(loc, activation_sound, 100, 0, 1)
|
||||
for (var/mob/living/carbon/human/C in range(user, 2) - user)
|
||||
@@ -63,6 +63,9 @@
|
||||
spamcheck = world.time + 50
|
||||
return
|
||||
|
||||
/obj/item/megaphone/proc/speak(var/msg, var/mob/living/user)
|
||||
user.say(msg, user.get_default_language(), "broadcasts")
|
||||
|
||||
/obj/item/megaphone/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(!emagged)
|
||||
to_chat(user, SPAN_WARNING("You overload \the [src]'s voice synthesizer."))
|
||||
|
||||
@@ -238,6 +238,8 @@
|
||||
/obj/item/clothing/suit/space/void/atmos = /obj/item/clothing/suit/space/void/atmos/himeo/tajara,
|
||||
/obj/item/clothing/head/helmet/space/void/atmos = /obj/item/clothing/head/helmet/space/void/atmos/himeo/tajara,
|
||||
|
||||
/obj/item/rig/industrial = /obj/item/rig/industrial/himeo/dequipped,
|
||||
|
||||
/obj/item/rig_assembly/industrial = /obj/item/rig_assembly/industrial/himeo
|
||||
)
|
||||
|
||||
|
||||
@@ -1,10 +1,96 @@
|
||||
#define MICROPHONE_LISTEN_RANGE 5
|
||||
/obj/item/radio/microphone
|
||||
name = "handheld microphone"
|
||||
desc = "A handheld microphone, used for on-the-fly interviewing. Pose for the fans!"
|
||||
icon_state = "microphone"
|
||||
item_state = "microphone"
|
||||
canhear_range = MICROPHONE_LISTEN_RANGE
|
||||
item_flags = ITEM_FLAG_NO_BLUDGEON
|
||||
/// If we have specific people we want to be able to speak into the microphone.
|
||||
var/directed_listening = TRUE
|
||||
/// A lazylist of the people allowed to talk into the microphone. Essentially acts as a filter.
|
||||
var/list/mob/living/listeners
|
||||
/// If the messages end with these endings, bypass the listener check.
|
||||
var/static/list/word_bypasses = list("!", "!!", "?!", "!?")
|
||||
|
||||
/obj/item/radio/microphone/Initialize()
|
||||
. = ..()
|
||||
set_frequency(ENT_FREQ)
|
||||
internal_channels = list(num2text(ENT_FREQ) = list())
|
||||
|
||||
/obj/item/radio/microphone/Destroy()
|
||||
LAZYNULL(listeners)
|
||||
return ..()
|
||||
|
||||
/obj/item/radio/microphone/AltClick(mob/user)
|
||||
. = ..()
|
||||
directed_listening = !directed_listening
|
||||
to_chat(user, SPAN_NOTICE("You are now [directed_listening ? "" : "no longer "]listening to specific people."))
|
||||
|
||||
/obj/item/radio/microphone/get_examine_text(mob/user, distance, is_adjacent, infix, suffix, get_extended)
|
||||
. = ..()
|
||||
. += SPAN_NOTICE("You are [directed_listening ? "" : SPAN_BOLD("not ")]listening to specific people with the microphone.")
|
||||
if(directed_listening)
|
||||
if(LAZYLEN(listeners))
|
||||
. += SPAN_NOTICE("You are angling the microphone specifically towards the following people: [SPAN_BOLD(english_list(listeners))].")
|
||||
else
|
||||
. += SPAN_NOTICE("You are not angling the microphone towards anyone.")
|
||||
|
||||
/obj/item/radio/microphone/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. = ..()
|
||||
. += "By default, your microphone will not allow anyone other than you to speak into it. [SPAN_BOLD("Alt-Click")] to disable this functionality."
|
||||
. += "You can [SPAN_BOLD("click")] someone with the microphone in hand to allow them to speak into it. [SPAN_BOLD("Click")] them again to disallow them again."
|
||||
. += "If someone moves more than 5 tiles away from your microphone, they will automatically be removed from the list."
|
||||
|
||||
/obj/item/radio/microphone/pickup(mob/user)
|
||||
. = ..()
|
||||
add_listener(user)
|
||||
|
||||
/obj/item/radio/microphone/dropped(mob/user)
|
||||
. = ..()
|
||||
remove_listener(user)
|
||||
|
||||
/obj/item/radio/microphone/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
. = ..()
|
||||
if(!isliving(target))
|
||||
return
|
||||
|
||||
if(get_dist(target, get_turf(src)) < MICROPHONE_LISTEN_RANGE)
|
||||
if(!(target in listeners))
|
||||
to_chat(user, SPAN_NOTICE("You angle the microphone to allow [target] to speak into it."))
|
||||
add_listener(target)
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("You angle the microphone away from [target]."))
|
||||
remove_listener(target)
|
||||
|
||||
/**
|
||||
* Add a mob to the list of listeners allowed to speak into the microphone.
|
||||
*/
|
||||
/obj/item/radio/microphone/proc/add_listener(mob/living/target_mob)
|
||||
LAZYDISTINCTADD(listeners, target_mob)
|
||||
RegisterSignal(target_mob, COMSIG_MOVABLE_MOVED, PROC_REF(check_listener_distance))
|
||||
|
||||
/**
|
||||
* Remove a mob from the list of listeners allowed to speak into the microphone.
|
||||
*/
|
||||
/obj/item/radio/microphone/proc/remove_listener(mob/living/target_mob)
|
||||
UnregisterSignal(target_mob, COMSIG_MOVABLE_MOVED)
|
||||
LAZYREMOVE(listeners, target_mob)
|
||||
|
||||
/**
|
||||
* Checks if the mob is too far from the microphone, at which point we stop listening to them.
|
||||
**/
|
||||
/obj/item/radio/microphone/proc/check_listener_distance(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
if(get_dist(source, get_turf(src)) > MICROPHONE_LISTEN_RANGE)
|
||||
LAZYREMOVE(listeners, source)
|
||||
if(ismob(loc))
|
||||
var/mob/M = loc
|
||||
to_chat(M, SPAN_NOTICE("[source] moves away from the microphone."))
|
||||
|
||||
/obj/item/radio/microphone/hear_talk(mob/M, msg, var/verb = "says", datum/language/speaking)
|
||||
var/message_ending = copytext(msg, length(msg) - 1, length(msg)) //copies the last 2 letters
|
||||
if(directed_listening && ((M in listeners) || (message_ending in word_bypasses)))
|
||||
return ..()
|
||||
|
||||
#undef MICROPHONE_LISTEN_RANGE
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
icon = 'icons/obj/item/tvcamera.dmi'
|
||||
icon_state = "camcorder"
|
||||
item_state = "camcorder"
|
||||
contained_sprite = TRUE
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = SLOT_BELT
|
||||
var/channel = "General News Feed"
|
||||
|
||||
@@ -320,12 +320,35 @@
|
||||
update_icon()
|
||||
|
||||
/obj/item/weldingtool/use_tool(atom/target, mob/living/user, delay, amount, volume, datum/callback/extra_checks)
|
||||
var/welding_blind = user.is_blind()
|
||||
if(welding_blind)
|
||||
delay *= 3
|
||||
|
||||
var/image/welding_sparks = image('icons/effects/effects.dmi', welding_state)
|
||||
welding_sparks.plane = ABOVE_LIGHTING_PLANE
|
||||
target.AddOverlays(welding_sparks)
|
||||
. = ..()
|
||||
target.CutOverlays(welding_sparks)
|
||||
|
||||
if(. && welding_blind && prob(80))
|
||||
to_chat(user, SPAN_WARNING("Unable to see your work, you botch the weld!"))
|
||||
if(prob(50))
|
||||
var/burn_zone
|
||||
if(ishuman(user))
|
||||
switch(get_equip_slot())
|
||||
if(slot_l_hand)
|
||||
burn_zone = BP_L_HAND
|
||||
if(slot_r_hand)
|
||||
burn_zone = BP_R_HAND
|
||||
else
|
||||
burn_zone = pick(BP_L_HAND, BP_R_HAND)
|
||||
user.apply_damage(rand(5, 10), DAMAGE_BURN, burn_zone, src)
|
||||
user.visible_message(
|
||||
SPAN_DANGER("[user] jerks back after burning themselves with \the [src]!"),
|
||||
SPAN_DANGER("Your blind welding slips, burning your hand!")
|
||||
)
|
||||
return FALSE
|
||||
|
||||
/obj/item/weldingtool/proc/update_torch()
|
||||
if(welding)
|
||||
AddOverlays("[initial(icon_state)]-on")
|
||||
@@ -439,7 +462,7 @@
|
||||
user.visible_message(SPAN_NOTICE("\The [user] finishes repairing the physical damage on \the [target]'s [affecting.name]."))
|
||||
return
|
||||
|
||||
if(do_mob(user, target, 30))
|
||||
if(use_tool(target, user, 30, volume = 15))
|
||||
if(use(0))
|
||||
var/static/list/repair_messages = list(
|
||||
"patches some dents",
|
||||
@@ -951,4 +974,3 @@
|
||||
var/mutable_appearance/handle = mutable_appearance('icons/obj/tools.dmi', "hammer_handle")
|
||||
handle.color = pick(COLOR_BLUE, COLOR_RED, COLOR_PURPLE, COLOR_BROWN, COLOR_GREEN, COLOR_CYAN, COLOR_YELLOW)
|
||||
AddOverlays(handle)
|
||||
|
||||
|
||||
@@ -244,6 +244,36 @@
|
||||
id_card.citizenship = SSrecords.get_citizenship_record_name(citizenship)
|
||||
id_card.mob_id = WEAKREF(src)
|
||||
id_card.employer_faction = employer_faction
|
||||
INVOKE_ASYNC(id_card, TYPE_PROC_REF(/obj/item/card/id, load_mining_points))
|
||||
|
||||
/obj/item/card/id/proc/load_mining_points()
|
||||
var/mob/living/carbon/human/card_owner = mob_id?.resolve()
|
||||
if(!card_owner?.character_id)
|
||||
return
|
||||
|
||||
var/datum/persistent_record/saved_balance = SSpersistence.historyGetLastRecord(
|
||||
/singleton/persistent_type/history/character/mining_point_balance,
|
||||
card_owner.character_id
|
||||
)
|
||||
if(!saved_balance)
|
||||
return
|
||||
|
||||
mining_points = clamp(text2num(saved_balance.value), 0, MINING_POINTS_CARRYOVER_MAX)
|
||||
|
||||
/obj/item/card/id/proc/save_mining_points()
|
||||
var/mob/living/carbon/human/card_owner = mob_id?.resolve()
|
||||
if(!card_owner?.character_id)
|
||||
return
|
||||
|
||||
SSpersistence.historyAddCharacterRecord(
|
||||
/singleton/persistent_type/history/character/mining_point_balance,
|
||||
card_owner.character_id,
|
||||
"[clamp(mining_points, 0, MINING_POINTS_CARRYOVER_MAX)]"
|
||||
)
|
||||
|
||||
/obj/item/card/id/proc/adjust_mining_points(amount)
|
||||
mining_points = max(0, mining_points + amount)
|
||||
save_mining_points()
|
||||
|
||||
/obj/item/card/id/proc/dat()
|
||||
var/dat = ("<table><tr><td>")
|
||||
|
||||
@@ -231,15 +231,17 @@
|
||||
return INITIALIZE_HINT_NORMAL
|
||||
|
||||
/obj/item/nullrod/clockworkstave
|
||||
name = "\improper clockwork stave"
|
||||
desc = "A long, wooden stave with a gear and triangle at the top, utilized by the clergy of the Trinary Perfection. The ornate pieces atop the stave are often delicately \
|
||||
hand-crafted by synthetics from the monastic Order of Pitters and exported off the planet of Axiom."
|
||||
name = "\improper stave of ecclesiastical office"
|
||||
desc = "A long brass stave used as the marker of the holder of some ecclesiastical \
|
||||
office in the church of the Trinary Perfection. Priests, bishops, and government \
|
||||
officials often bear such a staff; all faithful Trinarists ought listen when one \
|
||||
holding it makes their voice heard."
|
||||
icon = 'icons/obj/trinary_stave.dmi'
|
||||
icon_state = "trinary_stave"
|
||||
item_state = "trinary_stave"
|
||||
contained_sprite = TRUE
|
||||
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = SLOT_BACK
|
||||
|
||||
/obj/item/nullrod/verb/change(mob/living/user)
|
||||
set name = "Reassemble Null Item"
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
console_networks = list("MINE")
|
||||
req_access = list()
|
||||
|
||||
/obj/item/circuitboard/security/public
|
||||
name = T_BOARD("public camera monitor")
|
||||
build_path = /obj/structure/machinery/computer/security/terminal/public
|
||||
console_networks = list(NETWORK_EXPEDITION, NETWORK_NEWS)
|
||||
req_access = list()
|
||||
|
||||
/obj/item/circuitboard/security/construct(var/obj/structure/machinery/computer/security/C)
|
||||
if (..(C))
|
||||
C.console_networks = console_networks.Copy()
|
||||
|
||||
@@ -143,11 +143,23 @@
|
||||
origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 3)
|
||||
board_type = BOARD_MACHINE
|
||||
req_components = list(
|
||||
"/obj/item/stock_parts/capacitor" = 2,
|
||||
"/obj/item/stock_parts/capacitor" = 3,
|
||||
"/obj/item/stock_parts/micro_laser" = 1,
|
||||
"/obj/item/stack/cable_coil" = 5
|
||||
)
|
||||
|
||||
/obj/item/circuitboard/microwave
|
||||
name = T_BOARD("microwave")
|
||||
desc = "The circuitboard for a microwave."
|
||||
build_path = /obj/structure/machinery/appliance/cooker/microwave
|
||||
origin_tech = list(TECH_MAGNET = 2, TECH_ENGINEERING = 3)
|
||||
board_type = BOARD_MACHINE
|
||||
req_components = list(
|
||||
"/obj/item/stock_parts/capacitor" = 3,
|
||||
"/obj/item/stock_parts/scanning_module" = 1,
|
||||
"/obj/item/stack/cable_coil" = 5
|
||||
)
|
||||
|
||||
/obj/item/circuitboard/candymachine
|
||||
name = T_BOARD("candy machine")
|
||||
desc = "The circuitboard for a candy machine."
|
||||
|
||||
@@ -51,32 +51,29 @@
|
||||
|
||||
/obj/item/circuitboard/protolathe
|
||||
name = T_BOARD("protolathe")
|
||||
build_path = /obj/structure/machinery/r_n_d/protolathe
|
||||
build_path = /obj/structure/machinery/r_n_d/fabricator/protolathe
|
||||
board_type = BOARD_MACHINE
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2)
|
||||
req_components = list(
|
||||
"/obj/item/stock_parts/matter_bin" = 2,
|
||||
"/obj/item/stock_parts/manipulator" = 2,
|
||||
"/obj/item/reagent_containers/glass/beaker" = 2)
|
||||
|
||||
|
||||
/obj/item/circuitboard/circuit_imprinter
|
||||
name = T_BOARD("circuit imprinter")
|
||||
build_path = /obj/structure/machinery/r_n_d/circuit_imprinter
|
||||
build_path = /obj/structure/machinery/r_n_d/fabricator/circuit_imprinter
|
||||
board_type = BOARD_MACHINE
|
||||
origin_tech = list(TECH_ENGINEERING = 2, TECH_DATA = 2)
|
||||
req_components = list(
|
||||
"/obj/item/stock_parts/matter_bin" = 1,
|
||||
"/obj/item/stock_parts/manipulator" = 1,
|
||||
"/obj/item/reagent_containers/glass/beaker" = 2)
|
||||
|
||||
/obj/item/circuitboard/mechfab
|
||||
name = T_BOARD("mechatronic fabricator")
|
||||
build_path = /obj/structure/machinery/mecha_part_fabricator
|
||||
build_path = /obj/structure/machinery/r_n_d/fabricator/mecha_part_fabricator
|
||||
board_type = BOARD_MACHINE
|
||||
origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 3)
|
||||
req_components = list(
|
||||
"/obj/item/stock_parts/matter_bin" = 2,
|
||||
"/obj/item/stock_parts/manipulator" = 1,
|
||||
"/obj/item/stock_parts/micro_laser" = 1,
|
||||
"/obj/item/stock_parts/console_screen" = 1)
|
||||
@@ -91,11 +88,3 @@
|
||||
"/obj/item/stock_parts/capacitor" = 1,
|
||||
"/obj/item/stack/cable_coil" = 1,
|
||||
"/obj/item/stock_parts/console_screen" = 1)
|
||||
|
||||
/obj/item/circuitboard/ntnet_relay
|
||||
name = T_BOARD("NTNet Quantum Relay")
|
||||
build_path = /obj/structure/machinery/ntnet_relay
|
||||
board_type = BOARD_MACHINE
|
||||
origin_tech = list(TECH_DATA = 4)
|
||||
req_components = list(
|
||||
"/obj/item/stack/cable_coil" = 15)
|
||||
|
||||
@@ -60,3 +60,18 @@
|
||||
"/obj/item/stock_parts/subspace/filter" = 1,
|
||||
"/obj/item/stock_parts/subspace/crystal" = 1,
|
||||
"/obj/item/stock_parts/micro_laser/high" = 2)
|
||||
|
||||
/obj/item/circuitboard/ntnet_relay
|
||||
name = T_BOARD("NTNet Bluespace Relay")
|
||||
build_path = /obj/structure/machinery/ntnet_relay
|
||||
board_type = BOARD_MACHINE
|
||||
origin_tech = list(TECH_DATA = 4)
|
||||
req_components = list(
|
||||
"/obj/item/stack/cable_coil" = 15,
|
||||
"/obj/item/stock_parts/subspace/filter" = 1,
|
||||
"/obj/item/stock_parts/subspace/crystal" = 1,
|
||||
"/obj/item/stock_parts/micro_laser/high" = 2)
|
||||
|
||||
/obj/item/circuitboard/ntnet_relay/field
|
||||
name = T_BOARD("NTNet Field Relay")
|
||||
build_path = /obj/structure/machinery/ntnet_relay/field
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
/obj/item/plastique/Destroy()
|
||||
qdel(wires)
|
||||
wires = null
|
||||
qdel(target)
|
||||
target = null
|
||||
return ..()
|
||||
|
||||
@@ -195,11 +194,40 @@
|
||||
desc = "A small explosive laced with radium. The explosion is small, but the radioactive material will remain for a fair while."
|
||||
timer = 30 SECONDS
|
||||
|
||||
/obj/item/plastique/dirty/explode(turf/location)
|
||||
/obj/item/plastique/dirty/explode(turf/location) //Does not call parent because we need a different order of operations.
|
||||
if(!target)
|
||||
target = get_atom_on_turf(src)
|
||||
if(!target)
|
||||
target = src
|
||||
if(target)
|
||||
if (istype(target, /turf/simulated/wall))
|
||||
var/turf/simulated/wall/W = target
|
||||
W.dismantle_wall(1, no_product = TRUE)
|
||||
else if(istype(target, /mob/living))
|
||||
target.ex_act(2) // c4 can't gib mobs anymore.
|
||||
target.rad_act(800) //A dirty bomb going off on top of you completely irradiates you, radsuit or not.
|
||||
else
|
||||
target.ex_act(1)
|
||||
|
||||
if(location)
|
||||
SSradiation.radiate(src, 250)
|
||||
new /obj/effect/decal/cleanable/greenglow/radioactive/medium(get_turf(src))
|
||||
..()
|
||||
explosion(location, devastation_range, heavy_impact_range, light_impact_range, 3, spreading = 0)
|
||||
SSradiation.radiate(location, 250)
|
||||
new /obj/effect/decal/cleanable/greenglow/radioactive/extreme(location)
|
||||
|
||||
for(var/turf/T in RANGE_TURFS(4, location))
|
||||
if(T == location)
|
||||
continue
|
||||
|
||||
if(T in RANGE_TURFS(1, location)) //High radioactive puddles 1 tile from the epicenter, medium up to 4 tiles away.
|
||||
if(prob(75))
|
||||
new /obj/effect/decal/cleanable/greenglow/radioactive/high(T)
|
||||
else if(prob(25))
|
||||
new /obj/effect/decal/cleanable/greenglow/radioactive/medium(T)
|
||||
|
||||
var/obj/effect/plastic_explosive/effect = locate(/obj/effect/plastic_explosive) in get_turf(src)
|
||||
if(effect)
|
||||
qdel(effect)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/plastique/strong
|
||||
name = "bundled plastic explosives"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
throw_speed = 4
|
||||
throw_range = 20
|
||||
obj_flags = OBJ_FLAG_CONDUCTABLE
|
||||
pass_flags_self = PASSTABLE | PASSRAILING
|
||||
slot_flags = SLOT_BELT
|
||||
contained_sprite = 1
|
||||
var/active = 0
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
if(content["material"])
|
||||
set_material(content["material"])
|
||||
max_butts = round(material.hardness/10)
|
||||
update_icon()
|
||||
var/fill_count = content["fill_count"]
|
||||
if(fill_count)
|
||||
if(fill_count > max_butts)
|
||||
|
||||
@@ -39,6 +39,13 @@
|
||||
* If the object may be accessed while equipped anywhere on a character, including hands.
|
||||
*/
|
||||
var/equip_access = TRUE
|
||||
/**
|
||||
* If the object should have a delay to open, for more cumbersome bags such as duffels.
|
||||
* If set to zero seconds, no delay is applied. Define a value in seconds if a delay
|
||||
* should be applied and the delay will be equal to the value of this variable.
|
||||
* Only applies while on a character mob, not while the bag is on the floor.
|
||||
*/
|
||||
var/access_delay = 0 SECONDS
|
||||
|
||||
/obj/item/storage/backpack/antagonist_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
@@ -144,6 +151,8 @@
|
||||
/obj/item/storage/backpack/open(mob/user)
|
||||
if (!worn_check())
|
||||
return
|
||||
if(access_delay && !isturf(loc) && !do_after(user, access_delay))
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/storage/backpack/proc/worn_check(no_message = FALSE)
|
||||
@@ -153,7 +162,7 @@
|
||||
return TRUE //not equipped
|
||||
if(!worn_access && (slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back) == src)
|
||||
if(!no_message)
|
||||
to_chat(M, SPAN_WARNING("Your arms are not long enough to open \the [src] while it is on your back!"))
|
||||
to_chat(M, SPAN_WARNING("You cannot access the contents of \the [src] while it is on your back!"))
|
||||
if(use_sound)
|
||||
playsound(loc, use_sound, 50, 1, -5)
|
||||
if(animated)
|
||||
@@ -161,7 +170,7 @@
|
||||
return FALSE
|
||||
if(!equip_access && (ismob(loc)))
|
||||
if(!no_message)
|
||||
to_chat(M, SPAN_WARNING("\The [src] is too cumbersome to handle, you're going to have to set it down somewhere!"))
|
||||
to_chat(M, SPAN_WARNING("\The [src] is too cumbersome to access in your hands, you're going to have to set it down somewhere!"))
|
||||
if(use_sound)
|
||||
playsound(loc, use_sound, 50, 1, -5)
|
||||
if(animated)
|
||||
@@ -630,10 +639,16 @@
|
||||
icon_state = "duffel"
|
||||
item_state = "duffel"
|
||||
worn_access = FALSE
|
||||
equip_access = FALSE
|
||||
access_delay = 1 SECOND
|
||||
max_storage_space = DEFAULT_DUFFELBAG_STORAGE
|
||||
straps = TRUE
|
||||
|
||||
/obj/item/storage/backpack/duffel/mechanics_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "Duffel bags store a greater capacity than any other kind of backpack or satchel."
|
||||
. += "Duffel bags cannot be accessed while on a character's back, but can be accessed while in their hand or on the floor."
|
||||
. += "Duffel bags are laborious to use! There is a short delay on accessing them while in your hands."
|
||||
|
||||
/obj/item/storage/backpack/duffel/cap
|
||||
name = "captain's duffel bag"
|
||||
desc = "A rare and special duffel bag for only the most air-headed of SCC personnel."
|
||||
@@ -696,7 +711,6 @@
|
||||
icon_state = "duffel-syndie"
|
||||
item_state = "duffel-syndie"
|
||||
worn_access = TRUE
|
||||
equip_access = TRUE
|
||||
empty_delay = 0.8 SECOND
|
||||
|
||||
/obj/item/storage/backpack/duffel/cmo
|
||||
|
||||
@@ -574,7 +574,7 @@
|
||||
|
||||
var/open = 0 // Is the box open?
|
||||
var/ismessy = 0 // Fancy mess on the lid
|
||||
var/obj/item/reagent_containers/food/snacks/sliceable/pizza/pizza // Content pizza
|
||||
var/obj/item/reagent_containers/food/snacks/pizza // Content pizza
|
||||
var/pizza_type
|
||||
var/list/boxes = list() // If the boxes are stacked, they come here
|
||||
var/boxtag = ""
|
||||
@@ -699,7 +699,7 @@
|
||||
|
||||
return
|
||||
|
||||
if(istype(attacking_item, /obj/item/reagent_containers/food/snacks/sliceable/pizza/)) // Long ass fucking object name
|
||||
if(istype(attacking_item, /obj/item/reagent_containers/food/snacks/sliceable/pizza/) || istype(attacking_item, /obj/item/reagent_containers/food/snacks/variable/pizza)) // Long ass fucking object name
|
||||
|
||||
if(src.open)
|
||||
user.drop_from_inventory(attacking_item, src)
|
||||
|
||||
@@ -336,6 +336,8 @@
|
||||
/obj/item/storage/box/fancy/tray/machinist
|
||||
name = "machinist operation tray"
|
||||
desc = "A tray of various tools for use by machinists in repairing robots."
|
||||
// So additional tools can be added.
|
||||
max_storage_space = 23
|
||||
can_hold = list(
|
||||
/obj/item/surgery/cautery,
|
||||
/obj/item/surgery/circular_saw,
|
||||
|
||||
@@ -524,6 +524,7 @@
|
||||
unbuckle()
|
||||
return
|
||||
|
||||
capturing_mob.captured = TRUE
|
||||
captured = WEAKREF(capturing_mob)
|
||||
|
||||
playsound(src, 'sound/weapons/beartrap_shut.ogg', 100, 1)
|
||||
@@ -674,10 +675,10 @@
|
||||
if(captured_mob)
|
||||
captured_mob.bullet_act(arglist(args))
|
||||
|
||||
/obj/item/trap/animal/proc/release(var/mob/user, var/turf/target)
|
||||
/obj/item/trap/animal/proc/release(var/mob/user, var/turf/target, var/transferring = FALSE)
|
||||
if(!target)
|
||||
target = src.loc
|
||||
if(user)
|
||||
if(user && !transferring)
|
||||
visible_message(SPAN_NOTICE("[user] opens \the [src]."))
|
||||
|
||||
var/mob/captured_mob = captured ? captured.resolve() : null
|
||||
@@ -690,10 +691,12 @@
|
||||
var/mob/living/living_mob = captured_mob
|
||||
msg = SPAN_WARNING("[living_mob] runs out of \the [src].")
|
||||
|
||||
captured_mob.captured = FALSE
|
||||
unbuckle()
|
||||
captured = null
|
||||
visible_message(msg)
|
||||
shake_animation()
|
||||
if(!transferring)
|
||||
visible_message(msg)
|
||||
shake_animation()
|
||||
update_icon()
|
||||
layer = initial(layer)
|
||||
|
||||
@@ -779,6 +782,17 @@
|
||||
if(.)
|
||||
sync_captured_mob()
|
||||
|
||||
/obj/item/trap/animal/post_buckle(atom/movable/MA)
|
||||
if(MA == buckled || !isliving(MA))
|
||||
return
|
||||
|
||||
var/mob/living/released_mob = MA
|
||||
released_mob.captured = FALSE
|
||||
if(captured?.resolve() == released_mob)
|
||||
captured = null
|
||||
layer = initial(layer)
|
||||
update_icon()
|
||||
|
||||
/obj/item/trap/animal/attack_hand(mob/user)
|
||||
if(user.loc == src || captured)
|
||||
return
|
||||
|
||||
@@ -106,6 +106,10 @@
|
||||
var/persistent_objects_author_ckey = null
|
||||
// Expiration time used when saving/updating a persistent type, this can be changed depending on the use case by assigning a new value
|
||||
var/persistent_objects_expiration_time_days = PERSISTENT_DEFAULT_EXPIRATION_DAYS
|
||||
// Database timestamp when the tracked object was created
|
||||
var/persistent_objects_created_at = null
|
||||
// Database timestamp when the tracked object will expire
|
||||
var/persistent_objects_expires_at = null
|
||||
/* END PERSISTENCE VARS */
|
||||
|
||||
/// for easy reference of talking atoms
|
||||
@@ -258,7 +262,10 @@
|
||||
return
|
||||
|
||||
/mob/proc/unset_machine()
|
||||
var/was_viewing_machine_remote_view = is_viewing_camera() || is_viewing_overmap()
|
||||
src.machine = null
|
||||
if(was_viewing_machine_remote_view)
|
||||
reset_view(null)
|
||||
|
||||
/mob/proc/set_machine(var/obj/O)
|
||||
if(src.machine)
|
||||
|
||||
@@ -255,20 +255,6 @@
|
||||
/obj/item/pizzabox/pepperoni,
|
||||
)
|
||||
|
||||
//Sometimes the chef will have spare oil in storage.
|
||||
//Sometimes they wont, and will need to order it from cargo
|
||||
//Variety is the spice of life!
|
||||
/obj/random/cookingoil
|
||||
name = "random cooking oil"
|
||||
desc = "Has a 50% chance of spawning a tank of cooking oil, otherwise nothing."
|
||||
icon = 'icons/obj/reagent_dispensers.dmi'
|
||||
icon_state = "oiltank"
|
||||
spawn_nothing_percentage = 50
|
||||
|
||||
spawnlist = list(
|
||||
/obj/structure/reagent_dispensers/cookingoil
|
||||
)
|
||||
|
||||
/obj/random/chocolate
|
||||
name = "random chocolate"
|
||||
desc = "This is a random chocolate."
|
||||
@@ -287,3 +273,13 @@
|
||||
/obj/item/reagent_containers/food/snacks/chocolate_bar/laughterbar = 1,
|
||||
/obj/item/storage/box/fancy/readies
|
||||
)
|
||||
|
||||
/obj/random/cookingoil
|
||||
name = "random cooking oil"
|
||||
desc = "Has a 50% chance of spawning a tank of cooking oil, otherwise nothing."
|
||||
icon = 'icons/obj/reagent_dispensers.dmi'
|
||||
icon_state = "oiltank"
|
||||
spawn_nothing_percentage = 50
|
||||
spawnlist = list(
|
||||
/obj/structure/reagent_dispensers/cookingoil
|
||||
)
|
||||
|
||||
@@ -120,10 +120,11 @@
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
if(hitting_projectile.get_structure_damage() > 5)
|
||||
var/structure_damage = hitting_projectile.get_structure_damage()
|
||||
if(structure_damage > 5)
|
||||
bullet_ping(hitting_projectile)
|
||||
|
||||
add_damage(hitting_projectile.damage, hitting_projectile.damage_flags(), hitting_projectile.damage_type, hitting_projectile.armor_penetration, hitting_projectile)
|
||||
add_damage(structure_damage, hitting_projectile.damage_flags(), hitting_projectile.damage_type, hitting_projectile.armor_penetration, hitting_projectile)
|
||||
|
||||
/obj/structure/proc/climb_on()
|
||||
|
||||
|
||||
@@ -370,6 +370,9 @@ Class Procs:
|
||||
attack_hand(user)
|
||||
|
||||
/obj/structure/machinery/attackby(obj/item/attacking_item, mob/user)
|
||||
if(default_part_replacement(user, attacking_item))
|
||||
return TRUE
|
||||
|
||||
if(obj_flags & OBJ_FLAG_SIGNALER)
|
||||
if(issignaler(attacking_item))
|
||||
if(signaler)
|
||||
@@ -488,23 +491,43 @@ Class Procs:
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/machinery/proc/get_part_replacement_type(obj/item/part)
|
||||
var/obj/item/circuitboard/board = locate(/obj/item/circuitboard) in component_parts
|
||||
var/replacement_type
|
||||
|
||||
if(board?.req_components)
|
||||
for(var/component_type in board.req_components)
|
||||
var/board_part_type = ispath(component_type) ? component_type : text2path(component_type)
|
||||
if(!ispath(board_part_type, /obj/item/stock_parts) && !ispath(board_part_type, /obj/item/reagent_containers/glass))
|
||||
continue
|
||||
if(istype(part, board_part_type) && (!replacement_type || ispath(board_part_type, replacement_type)))
|
||||
replacement_type = board_part_type
|
||||
|
||||
if(replacement_type)
|
||||
return replacement_type
|
||||
|
||||
for(var/component_type in component_types)
|
||||
var/component_part_type = ispath(component_type) ? component_type : text2path(component_type)
|
||||
if(!ispath(component_part_type, /obj/item/stock_parts) && !ispath(component_part_type, /obj/item/reagent_containers/glass))
|
||||
continue
|
||||
if(istype(part, component_part_type) && (!replacement_type || ispath(component_part_type, replacement_type)))
|
||||
replacement_type = component_part_type
|
||||
|
||||
return replacement_type
|
||||
|
||||
/obj/structure/machinery/proc/default_part_replacement(var/mob/user, var/obj/item/storage/part_replacer/R)
|
||||
if(!LAZYLEN(component_parts))
|
||||
return FALSE
|
||||
else if(istype(R))
|
||||
var/parts_replaced = FALSE
|
||||
if(panel_open)
|
||||
var/obj/item/circuitboard/CB = locate(/obj/item/circuitboard) in component_parts
|
||||
var/P
|
||||
for(var/obj/item/reagent_containers/glass/G in component_parts)
|
||||
for(var/D in CB.req_components)
|
||||
var/T = text2path(D)
|
||||
if(ispath(G.type, T))
|
||||
P = T
|
||||
break
|
||||
var/replacement_type = get_part_replacement_type(G)
|
||||
if(!replacement_type)
|
||||
continue
|
||||
for(var/obj/item/reagent_containers/glass/B in R.contents)
|
||||
if(B.reagents && B.reagents.total_volume > 0) continue
|
||||
if(istype(B, P) && istype(G, P))
|
||||
if(istype(B, replacement_type))
|
||||
if(B.volume > G.volume)
|
||||
R.remove_from_storage(B, src)
|
||||
R.handle_item_insertion(G, 1)
|
||||
@@ -512,15 +535,14 @@ Class Procs:
|
||||
component_parts += B
|
||||
B.forceMove(src)
|
||||
to_chat(user, SPAN_NOTICE("[G.name] replaced with [B.name]."))
|
||||
parts_replaced = TRUE
|
||||
break
|
||||
for(var/obj/item/stock_parts/A in component_parts)
|
||||
for(var/D in CB.req_components)
|
||||
var/T = text2path(D)
|
||||
if(ispath(A.type, T))
|
||||
P = T
|
||||
break
|
||||
var/replacement_type = get_part_replacement_type(A)
|
||||
if(!replacement_type)
|
||||
continue
|
||||
for(var/obj/item/stock_parts/B in R.contents)
|
||||
if(istype(B, P) && istype(A, P))
|
||||
if(istype(B, replacement_type))
|
||||
if(B.rating > A.rating)
|
||||
R.remove_from_storage(B, src)
|
||||
R.handle_item_insertion(A, 1)
|
||||
@@ -530,9 +552,9 @@ Class Procs:
|
||||
to_chat(user, SPAN_NOTICE("[A.name] replaced with [B.name]."))
|
||||
parts_replaced = TRUE
|
||||
break
|
||||
RefreshParts()
|
||||
update_icon()
|
||||
if(parts_replaced) //only play sound when RPED actually replaces parts
|
||||
if(parts_replaced)
|
||||
RefreshParts()
|
||||
update_icon()
|
||||
playsound(src, 'sound/items/rped.ogg', 40, TRUE)
|
||||
return TRUE
|
||||
else
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
density = TRUE
|
||||
atom_flags = ATOM_FLAG_CHECKS_BORDER
|
||||
maxhealth = OBJECT_HEALTH_LOW
|
||||
pass_flags_self = LETPASSTHROW
|
||||
/// The type of stack the barricade dropped when disassembled if any.
|
||||
var/stack_type
|
||||
/// The amount of stack dropped when disassembled at full health
|
||||
@@ -83,11 +84,11 @@
|
||||
AddOverlays(image('icons/obj/barricades.dmi', icon_state = "[src.barricade_type]_closed_wire"))
|
||||
|
||||
..()
|
||||
|
||||
/obj/structure/barricade/proc/handle_barrier_chance()
|
||||
///Rolls a chance based on the percentage of the barricade's health remaining. Returns TRUE if the chance succeeds, FALSE if it fails. The chance is divided by the optional chance_divisor parameter, which defaults to 1.
|
||||
/obj/structure/barricade/proc/handle_barrier_chance(chance_divisor = 1)
|
||||
if(!anchored)
|
||||
return FALSE
|
||||
return prob(max(30,(100.0*health)/maxhealth))
|
||||
return prob(max(30,(100.0*health)/maxhealth) / chance_divisor)
|
||||
|
||||
/obj/structure/barricade/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(mover?.movement_type & PHASING)
|
||||
@@ -97,6 +98,16 @@
|
||||
if(istype(mover, /obj/projectile))
|
||||
return (check_cover(mover,target))
|
||||
if (get_dir(loc, target) == dir)
|
||||
if(mover.throwing)
|
||||
var/chance = (handle_barrier_chance(3))
|
||||
if(chance)
|
||||
visible_message(SPAN_WARNING("\The [mover] clips the top of \the [src] and bounces off!"))
|
||||
if(barricade_hitsound)
|
||||
playsound(src, barricade_hitsound, 20, 1)
|
||||
return !density
|
||||
else
|
||||
visible_message(SPAN_WARNING("\The [mover] sails over \the [src]!"))
|
||||
return TRUE
|
||||
return !density
|
||||
else
|
||||
return TRUE
|
||||
@@ -211,8 +222,6 @@
|
||||
return .
|
||||
|
||||
bullet_ping(hitting_projectile)
|
||||
var/damage_to_take = hitting_projectile.damage * hitting_projectile.anti_materiel_potential
|
||||
add_damage(damage_to_take, hitting_projectile.damage_flags(), hitting_projectile.damtype, hitting_projectile.armor_penetration, hitting_projectile)
|
||||
|
||||
/obj/structure/barricade/proc/barricade_deconstruct(deconstruct)
|
||||
if(deconstruct && is_wired)
|
||||
|
||||
@@ -357,8 +357,6 @@
|
||||
for(var/mob/living/L in contents)
|
||||
hitting_projectile.Impact(L)
|
||||
|
||||
damage(proj_damage)
|
||||
|
||||
/obj/structure/closet/attackby(obj/item/attacking_item, mob/user)
|
||||
if(istype(attacking_item, /obj/item/closet_teleporter))
|
||||
if(linked_teleporter)
|
||||
|
||||
@@ -126,7 +126,6 @@
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
health -= hitting_projectile.get_structure_damage()
|
||||
check_health()
|
||||
|
||||
/obj/structure/closet/statue/attack_generic(mob/user, damage, attack_message, environment_smash, armor_penetration, attack_flags, damage_type)
|
||||
|
||||
@@ -797,3 +797,8 @@
|
||||
new /obj/item/storage/box/unique/tea/messa(src)
|
||||
new /obj/item/reagent_containers/toothpaste(src)
|
||||
new /obj/item/reagent_containers/food/drinks/flask/vacuumflask/mouthwash(src)
|
||||
|
||||
/obj/structure/closet/crate/tool/machinist/fill()
|
||||
new /obj/item/reagent_containers/weldpack(src)
|
||||
new /obj/item/portable_whiteboard(src)
|
||||
new /obj/item/paint_sprayer(src)
|
||||
|
||||
@@ -40,10 +40,6 @@
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
var/damage = hitting_projectile.damage
|
||||
if(damage)
|
||||
add_damage(damage)
|
||||
|
||||
/obj/structure/displaycase/on_death()
|
||||
if(!destroyed)
|
||||
density = FALSE
|
||||
|
||||
@@ -171,7 +171,12 @@
|
||||
if(isfloor(user.loc))
|
||||
user.visible_message(SPAN_NOTICE("\The [user] deploys \the [src] on \the [get_turf(loc)]."), SPAN_NOTICE("You deploy \the [src] on \the [get_turf(loc)]."))
|
||||
user.drop_from_inventory(src)
|
||||
new flag_structure(user.loc, user.dir, deploy = TRUE, item_flag_path = flag_path)
|
||||
var/obj/structure/sign/flag/F = new flag_structure(user.loc, user.dir, deploy = TRUE, item_flag_path = flag_path)
|
||||
F.name = src.name
|
||||
F.desc = src.desc
|
||||
if(F.linked_flag)
|
||||
F.linked_flag.name = src.name
|
||||
F.linked_flag.desc = src.desc
|
||||
qdel(src)
|
||||
|
||||
/obj/item/flag/afterattack(var/atom/A, var/mob/user, var/adjacent)
|
||||
@@ -192,7 +197,12 @@
|
||||
|
||||
user.visible_message(SPAN_NOTICE("\The [user] fastens \the [src] to \the [A]."), SPAN_NOTICE("You fasten \the [src] to \the [A]."))
|
||||
user.drop_from_inventory(src)
|
||||
new flag_structure(user.loc, placement_dir, deploy = TRUE, item_flag_path = flag_path)
|
||||
var/obj/structure/sign/flag/F = new flag_structure(user.loc, user.dir, deploy = TRUE, item_flag_path = flag_path)
|
||||
F.name = src.name
|
||||
F.desc = src.desc
|
||||
if(F.linked_flag)
|
||||
F.linked_flag.name = src.name
|
||||
F.linked_flag.desc = src.desc
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -222,6 +232,8 @@
|
||||
else
|
||||
user.visible_message(SPAN_NOTICE("\The [user] unfastens \the [src] and folds it back up."), SPAN_NOTICE("You unfasten \the [src] and fold it back up."))
|
||||
var/obj/item/flag/F = new flag_item(get_turf(user))
|
||||
F.name = src.name
|
||||
F.desc = src.desc
|
||||
user.put_in_hands(F)
|
||||
else
|
||||
user.visible_message(SPAN_NOTICE("\The [user] unfastens the tattered remnants of \the [src]."), SPAN_NOTICE("You unfasten the tattered remains of \the [src]."))
|
||||
@@ -3719,6 +3731,58 @@
|
||||
/obj/structure/sign/flag/venus/large/west/Initialize(mapload)
|
||||
. = ..(mapload, WEST)
|
||||
|
||||
// Eris
|
||||
/obj/item/flag/eris
|
||||
name = "\improper Erisian Banner"
|
||||
desc = "The banner of the Sovereign Solarian Union of Eris and Dysnomia, a pair of distant dwarf worlds in the Sol System, dominated by the dual influence of the system’s largest communications array and the Solarian Navy."
|
||||
desc_extended = "The banner of Eris and Dysnomia features a bicolor of white and purple, separated by a gold stripe, with a golden ring and diamond at its center. Four purple stars are arranged along the top, while four white stars line the bottom.<br> \
|
||||
The white field evokes the planetoid’s isolation beyond the Kuiper Belt, while the purple pays tribute to the Solarian Navy and its significant influence on Erisian history. The gold stripe represents the vital flow of interstellar communication that passes through Eris. At the center, the golden emblem symbolizes the unity of Eris and Dysnomia: the circle for Eris, the diamond for Dysnomia, and the surrounding ring for their shared infrastructure and mutual dependence.<br> \
|
||||
The eight stars represent the primary habitats across the Union, four in purple for those on Eris and Dysnomia themselves, and four in white for the orbital habitats positioned among their Lagrange points."
|
||||
flag_path = "eris"
|
||||
flag_structure = /obj/structure/sign/flag/eris
|
||||
|
||||
/obj/structure/sign/flag/eris
|
||||
name = "\improper Erisian Banner"
|
||||
desc = "The banner of the Sovereign Solarian Union of Eris and Dysnomia, a pair of distant dwarf worlds in the Sol System, dominated by the dual influence of the system’s largest communications array and the Solarian Navy."
|
||||
desc_extended = "The banner of Eris and Dysnomia features a bicolor of white and purple, separated by a gold stripe, with a golden ring and diamond at its center. Four purple stars are arranged along the top, while four white stars line the bottom.<br> \
|
||||
The white field evokes the planetoid’s isolation beyond the Kuiper Belt, while the purple pays tribute to the Solarian Navy and its significant influence on Erisian history. The gold stripe represents the vital flow of interstellar communication that passes through Eris. At the center, the golden emblem symbolizes the unity of Eris and Dysnomia: the circle for Eris, the diamond for Dysnomia, and the surrounding ring for their shared infrastructure and mutual dependence.<br> \
|
||||
The eight stars represent the primary habitats across the Union, four in purple for those on Eris and Dysnomia themselves, and four in white for the orbital habitats positioned among their Lagrange points."
|
||||
flag_path = "eris"
|
||||
icon_state = "eris"
|
||||
flag_item = /obj/item/flag/eris
|
||||
|
||||
/obj/item/flag/eris/l
|
||||
name = "\improper Erisian Flag"
|
||||
desc = "The flag of the Sovereign Solarian Union of Eris and Dysnomia, a pair of distant dwarf worlds in the Sol System, dominated by the dual influence of the system’s largest communications array and the Solarian Navy."
|
||||
desc_extended = "The flag of Eris and Dysnomia features a bicolor of white and purple, separated by a gold stripe, with a golden ring and diamond at its center. Four purple stars are arranged along the top, while four white stars line the bottom.<br> \
|
||||
The white field evokes the planetoid’s isolation beyond the Kuiper Belt, while the purple pays tribute to the Solarian Navy and its significant influence on Erisian history. The gold stripe represents the vital flow of interstellar communication that passes through Eris. At the center, the golden emblem symbolizes the unity of Eris and Dysnomia: the circle for Eris, the diamond for Dysnomia, and the surrounding ring for their shared infrastructure and mutual dependence.<br> \
|
||||
The eight stars represent the primary habitats across the Union, four in purple for those on Eris and Dysnomia themselves, and four in white for the orbital habitats positioned among their Lagrange points."
|
||||
flag_size = TRUE
|
||||
flag_structure = /obj/structure/sign/flag/eris/large
|
||||
|
||||
/obj/structure/sign/flag/eris/large
|
||||
name = "\improper Erisian Flag"
|
||||
desc = "The flag of the Sovereign Solarian Union of Eris and Dysnomia, a pair of distant dwarf worlds in the Sol System, dominated by the dual influence of the system’s largest communications array and the Solarian Navy."
|
||||
desc_extended = "The flag of Eris and Dysnomia features a bicolor of white and purple, separated by a gold stripe, with a golden ring and diamond at its center. Four purple stars are arranged along the top, while four white stars line the bottom.<br> \
|
||||
The white field evokes the planetoid’s isolation beyond the Kuiper Belt, while the purple pays tribute to the Solarian Navy and its significant influence on Erisian history. The gold stripe represents the vital flow of interstellar communication that passes through Eris. At the center, the golden emblem symbolizes the unity of Eris and Dysnomia: the circle for Eris, the diamond for Dysnomia, and the surrounding ring for their shared infrastructure and mutual dependence.<br> \
|
||||
The eight stars represent the primary habitats across the Union, four in purple for those on Eris and Dysnomia themselves, and four in white for the orbital habitats positioned among their Lagrange points."
|
||||
icon_state = "eris_l"
|
||||
flag_path = "eris"
|
||||
flag_size = TRUE
|
||||
flag_item = /obj/item/flag/eris/l
|
||||
|
||||
/obj/structure/sign/flag/eris/large/north/Initialize(mapload)
|
||||
. = ..(mapload, NORTH)
|
||||
|
||||
/obj/structure/sign/flag/eris/large/south/Initialize(mapload)
|
||||
. = ..(mapload, SOUTH)
|
||||
|
||||
/obj/structure/sign/flag/eris/large/east/Initialize(mapload)
|
||||
. = ..(mapload, EAST)
|
||||
|
||||
/obj/structure/sign/flag/eris/large/west/Initialize(mapload)
|
||||
. = ..(mapload, WEST)
|
||||
|
||||
//Hiskyn
|
||||
/obj/item/flag/hiskyn
|
||||
name = "\improper Hiskyn's Revanchists flag"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
maxhealth = OBJECT_HEALTH_MEDIUM
|
||||
color = COLOR_GRAY20
|
||||
build_amt = 4
|
||||
pass_flags_self = PASSRAILING
|
||||
pass_flags_self = PASSRAILING | LETPASSTHROW
|
||||
layer = WINDOW_FRAME_LAYER
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
@@ -54,6 +54,10 @@
|
||||
return TRUE
|
||||
if(istype(mover, /obj/structure/closet/crate))
|
||||
return TRUE
|
||||
if(istype(mover,/obj/projectile))
|
||||
return TRUE
|
||||
if(mover.throwing)
|
||||
return TRUE
|
||||
if(istype(mover) && mover.pass_flags & PASSTABLE)
|
||||
return TRUE
|
||||
if(locate(/obj/structure/window_frame) in get_turf(mover))
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
/obj/structure/girder/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
|
||||
//Girders only provide partial cover. There's a chance that the projectiles will just pass through. (unless you are trying to shoot the girder)
|
||||
if(hitting_projectile.original != src && !prob(cover))
|
||||
return BULLET_ACT_HIT //pass through
|
||||
return BULLET_ACT_FORCE_PIERCE //pass through
|
||||
|
||||
var/damage = hitting_projectile.get_structure_damage()
|
||||
if(!damage)
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
add_damage(hitting_projectile.damage)
|
||||
|
||||
/obj/structure/gore/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
|
||||
@@ -96,8 +96,6 @@
|
||||
|
||||
bullet_ping(hitting_projectile)
|
||||
|
||||
health -= proj_damage
|
||||
|
||||
if(health <= 0)
|
||||
deflate(TRUE)
|
||||
return
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
density = TRUE
|
||||
light_system = MOVABLE_LIGHT
|
||||
maxhealth = OBJECT_HEALTH_LOW
|
||||
should_use_health = FALSE
|
||||
obj_flags = OBJ_FLAG_SIGNALER | OBJ_FLAG_CONDUCTABLE
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
|
||||
|
||||
@@ -157,8 +157,6 @@
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
add_damage(hitting_projectile.get_structure_damage(), hitting_projectile.damage_flags(), hitting_projectile.damage_type, hitting_projectile.armor_penetration, hitting_projectile)
|
||||
|
||||
/obj/structure/machinery/camera/ex_act(severity)
|
||||
if(src.invuln)
|
||||
return
|
||||
@@ -381,14 +379,23 @@
|
||||
alarm_on = 0
|
||||
GLOB.camera_alarm.clearAlarm(loc, src)
|
||||
|
||||
//if false, then the camera is listed as DEACTIVATED and cannot be used
|
||||
/// If FALSE, then the camera is listed as DEACTIVATED and cannot be used
|
||||
/obj/structure/machinery/camera/proc/can_use()
|
||||
if(!status)
|
||||
return 0
|
||||
if(stat & (EMPED|BROKEN))
|
||||
return 0
|
||||
if(is_wireless_jammed())
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/// Only used below, but has separate proc for potential future use.
|
||||
/obj/structure/machinery/camera/proc/is_wireless_camera()
|
||||
return !isturf(loc)
|
||||
|
||||
/obj/structure/machinery/camera/proc/is_wireless_jammed()
|
||||
return is_wireless_camera() && get_turf(src) && within_jamming_range(src)
|
||||
|
||||
/obj/structure/machinery/camera/proc/can_see()
|
||||
var/list/see = null
|
||||
var/turf/pos = get_turf(src)
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
|
||||
state = 4
|
||||
var/obj/structure/machinery/camera/C = new(src.loc)
|
||||
QDEL_NULL(C.assembly)
|
||||
src.forceMove(C)
|
||||
C.assembly = src
|
||||
|
||||
@@ -106,6 +107,10 @@
|
||||
C.replace_networks(uniquelist(tempnetwork))
|
||||
|
||||
C.c_tag = input
|
||||
C.setPowerUsage()
|
||||
if(C.isMotion() && !(SSmachinery.processing[C]))
|
||||
START_PROCESSING_MACHINE(C, MACHINERY_PROCESS_SELF)
|
||||
C.update_coverage()
|
||||
|
||||
for(var/i = 5; i >= 0; i -= 1)
|
||||
var/direct = tgui_input_list(user, "Direction?", "Assembling Camera", list("Confirm", "NORTH", "EAST", "SOUTH", "WEST"))
|
||||
@@ -127,20 +132,35 @@
|
||||
return TRUE
|
||||
|
||||
// Upgrades!
|
||||
if(is_type_in_list(attacking_item, possible_upgrades) && !is_type_in_list(attacking_item, upgrades)) // Is a possible upgrade and isn't in the camera already.
|
||||
var/upgrade_type
|
||||
for(var/possible_upgrade in possible_upgrades)
|
||||
if(istype(attacking_item, possible_upgrade))
|
||||
upgrade_type = possible_upgrade
|
||||
break
|
||||
|
||||
if(upgrade_type)
|
||||
if(state != 3)
|
||||
to_chat(user, SPAN_WARNING("You need to wire the assembly before installing upgrades."))
|
||||
return TRUE
|
||||
if(locate(upgrade_type) in upgrades)
|
||||
to_chat(user, SPAN_WARNING("\The [src] already has that upgrade installed."))
|
||||
return TRUE
|
||||
if(istype(attacking_item, /obj/item/stock_parts/scanning_module))
|
||||
var/obj/item/stock_parts/scanning_module/SM = attacking_item
|
||||
if(SM.rating < 2)
|
||||
to_chat(user, SPAN_WARNING("That scanning module doesn't seem advanced enough."))
|
||||
return
|
||||
return TRUE
|
||||
to_chat(user, "You attach \the [attacking_item] into the assembly inner circuits.")
|
||||
upgrades += attacking_item
|
||||
user.remove_from_mob(attacking_item)
|
||||
attacking_item.forceMove(src)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
// Taking out upgrades
|
||||
else if(attacking_item.tool_behaviour == TOOL_CROWBAR && upgrades.len)
|
||||
if(state != 3)
|
||||
to_chat(user, SPAN_WARNING("You need access to the wired circuits before removing upgrades."))
|
||||
return TRUE
|
||||
var/obj/U = locate(/obj) in upgrades
|
||||
if(U)
|
||||
to_chat(user, "You unattach an upgrade from the assembly.")
|
||||
|
||||
@@ -80,6 +80,9 @@ GLOBAL_LIST_INIT(engineering_networks, list(
|
||||
/obj/structure/machinery/camera/network/news
|
||||
network = list(NETWORK_NEWS)
|
||||
|
||||
/obj/structure/machinery/camera/network/expedition
|
||||
network = list(NETWORK_EXPEDITION)
|
||||
|
||||
// EMP
|
||||
|
||||
/obj/structure/machinery/camera/emp_proof/Initialize()
|
||||
|
||||
@@ -26,13 +26,23 @@
|
||||
camera_monitor_program = new("Compless")
|
||||
// Make sure that camera_monitor knows its been generated from a dedicated console; this will define its network access.
|
||||
camera_monitor_program.monitored_networks = console_networks
|
||||
camera_monitor_program.ntnet_endpoint = src
|
||||
camera_monitor_program.ntnet_endpoint_ethernet = TRUE
|
||||
|
||||
/obj/structure/machinery/computer/security/Destroy()
|
||||
reset_remote_viewers()
|
||||
if(camera_monitor_program)
|
||||
camera_monitor_program.reset_current()
|
||||
camera_monitor_program = null
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/structure/machinery/computer/security/proc/reset_remote_viewers()
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(M.machine == src && M.is_viewing_remote_view())
|
||||
M.unset_machine()
|
||||
M.reset_view(null)
|
||||
|
||||
/obj/structure/machinery/computer/security/attack_ai(var/mob/user as mob)
|
||||
if(!ai_can_interact(user))
|
||||
return
|
||||
@@ -41,6 +51,8 @@
|
||||
/obj/structure/machinery/computer/security/check_eye(var/mob/user as mob)
|
||||
if (user.stat || user.blinded || !operable())
|
||||
return -1
|
||||
if(camera_monitor_program?.current_camera)
|
||||
return camera_monitor_program.check_eye(user)
|
||||
if(!current_camera)
|
||||
return 0
|
||||
var/viewflag = current_camera.check_eye(user)
|
||||
@@ -51,6 +63,8 @@
|
||||
/obj/structure/machinery/computer/security/grants_equipment_vision(var/mob/user as mob)
|
||||
if(user.stat || user.blinded || !operable())
|
||||
return FALSE
|
||||
if(camera_monitor_program?.current_camera)
|
||||
return camera_monitor_program.grants_equipment_vision(user)
|
||||
if(!current_camera)
|
||||
return FALSE
|
||||
var/viewflag = current_camera.check_eye(user)
|
||||
@@ -91,7 +105,7 @@
|
||||
. = camera_monitor_program.ui_act(action, params, ui, state)
|
||||
|
||||
/obj/structure/machinery/computer/security/attack_hand(var/mob/user as mob)
|
||||
if (!(src.z in GetConnectedZlevels(starting_z_level)))
|
||||
if (!(src.z in GetConnectedZlevels(starting_z_level)) && !SSatlas.current_map.is_always_available_network_level(src.z))
|
||||
to_chat(user, "Unable to establish a connection.")
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN)) return
|
||||
@@ -115,9 +129,11 @@
|
||||
|
||||
if (user.stat || user.blinded || !operable())
|
||||
return 0
|
||||
if(!C.can_use())
|
||||
return 0
|
||||
set_current(C)
|
||||
|
||||
if (!(C.z in GetConnectedZlevels(starting_z_level)))
|
||||
if (!(C.z in GetConnectedZlevels(starting_z_level)) && !(SSatlas.current_map.is_always_available_network_level(src.z) && C.z == src.z))
|
||||
to_chat(user, SPAN_NOTICE("This camera is too far away to connect to!"))
|
||||
return FALSE
|
||||
|
||||
@@ -311,7 +327,7 @@
|
||||
req_access = list(150)
|
||||
|
||||
/obj/structure/machinery/computer/security/terminal
|
||||
name = "camera monitor terminal"
|
||||
name = "public camera monitor"
|
||||
icon = 'icons/obj/modular_computers/modular_terminal.dmi'
|
||||
icon_screen = "cameras"
|
||||
icon_keyboard = "security_key"
|
||||
@@ -320,3 +336,7 @@
|
||||
has_off_keyboards = TRUE
|
||||
can_pass_under = FALSE
|
||||
light_power_on = 1
|
||||
|
||||
/obj/structure/machinery/computer/security/terminal/public
|
||||
console_networks = list(NETWORK_EXPEDITION, NETWORK_NEWS)
|
||||
circuit = /obj/item/circuitboard/security/public
|
||||
|
||||
@@ -19,7 +19,10 @@ Deployable Kits
|
||||
density = TRUE
|
||||
layer = ABOVE_DOOR_LAYER // above door layer so it can appear on the airlocks like a proper barricade
|
||||
maxhealth = OBJECT_HEALTH_LOW
|
||||
|
||||
armor = list(
|
||||
MELEE = ARMOR_MELEE_RESISTANT,
|
||||
BULLET = ARMOR_BALLISTIC_PISTOL
|
||||
)
|
||||
var/force_material
|
||||
|
||||
/obj/structure/blocker/Initialize(mapload, var/material_name)
|
||||
@@ -46,13 +49,6 @@ Deployable Kits
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
var/damage_modifier = 0.4
|
||||
switch(hitting_projectile.damage_type)
|
||||
if(DAMAGE_BURN)
|
||||
damage_modifier = 1
|
||||
if(DAMAGE_BRUTE)
|
||||
damage_modifier = 0.75
|
||||
health -= hitting_projectile.damage * damage_modifier
|
||||
if(!check_dismantle())
|
||||
visible_message(SPAN_WARNING("\The [src] is hit by \the [hitting_projectile]!"))
|
||||
|
||||
@@ -76,11 +72,6 @@ Deployable Kits
|
||||
return TRUE
|
||||
else
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
switch(attacking_item.damtype)
|
||||
if(DAMAGE_BURN)
|
||||
src.health -= attacking_item.force * 1
|
||||
if(DAMAGE_BRUTE)
|
||||
src.health -= attacking_item.force * 0.75
|
||||
shake_animation()
|
||||
playsound(src.loc, material.hitsound, attacking_item.get_clamped_volume(), 1)
|
||||
if(check_dismantle())
|
||||
@@ -280,7 +271,7 @@ Deployable Kits
|
||||
|
||||
/obj/item/deployable_kit/attack_self(mob/user)
|
||||
to_chat(user, SPAN_NOTICE("You start assembling \the [src]..."))
|
||||
if(do_after(user, assembly_time, src, DO_REPAIR_CONSTRUCT))
|
||||
if(do_after(user, assembly_time, src, DO_DEPLOY))
|
||||
assemble_kit(user)
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -118,8 +118,6 @@
|
||||
var/door_frame_color = COLOR_GRAY20
|
||||
/// Color. The color of the stripe detail.
|
||||
var/stripe_color = null
|
||||
/// Color. The color of the symbol detail.
|
||||
var/symbol_color = null
|
||||
/// Color. The color of the window.
|
||||
var/window_color = null
|
||||
/// String (One of `MATERIAL_*`). The material used for the door's window if `glass` is set. Used to set `window_material` during init.
|
||||
@@ -523,6 +521,12 @@
|
||||
explosion_resistance = 20
|
||||
secured_wires = TRUE
|
||||
maxhealth = OBJECT_HEALTH_EXTREMELY_HIGH
|
||||
destroy_hits = 30
|
||||
armor = list(
|
||||
MELEE = ARMOR_MELEE_RESISTANT,
|
||||
BULLET = ARMOR_BALLISTIC_PISTOL,
|
||||
LASER = ARMOR_LASER_MEDIUM
|
||||
)
|
||||
features_powerloss_manual_override = FALSE
|
||||
ai_bolting_delay = 10
|
||||
ai_unbolt_delay = 5
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
dir = 1
|
||||
closed_layer = ABOVE_DOOR_LAYER
|
||||
explosion_resistance = 25
|
||||
destroy_hits = 40
|
||||
armor = list(
|
||||
MELEE = ARMOR_MELEE_MAJOR,
|
||||
BULLET = ARMOR_BALLISTIC_MEDIUM,
|
||||
LASER = ARMOR_LASER_RIFLE
|
||||
)
|
||||
pass_flags_self = PASSDOORS
|
||||
rad_resistance_modifier = 6
|
||||
|
||||
@@ -255,6 +261,12 @@
|
||||
icon_state = "shutter1"
|
||||
damage = SHUTTER_CRUSH_DAMAGE
|
||||
closed_layer = CLOSED_DOOR_LAYER
|
||||
destroy_hits = 20
|
||||
armor = list(
|
||||
MELEE = ARMOR_MELEE_RESISTANT,
|
||||
BULLET = ARMOR_BALLISTIC_PISTOL,
|
||||
LASER = ARMOR_LASER_MEDIUM
|
||||
)
|
||||
|
||||
/obj/structure/machinery/door/blast/shutters/open
|
||||
icon_state = "shutter0"
|
||||
|
||||
@@ -255,21 +255,25 @@
|
||||
var/damage = hitting_projectile.get_structure_damage()
|
||||
|
||||
// Emitter Blasts - these will eventually completely destroy the door, given enough time.
|
||||
if (damage > 90)
|
||||
destroy_hits -= (1 * hitting_projectile.anti_materiel_potential)
|
||||
if (damage >= 30 && health <= 0) //Midlaser damage.
|
||||
if (damage > 90)
|
||||
destroy_hits -= max(1, (1 * hitting_projectile.anti_materiel_potential)) //Double dip for strong projectiles, like emitters or the PEAC.
|
||||
destroy_hits -= max(1, (1 * hitting_projectile.anti_materiel_potential))
|
||||
if (destroy_hits <= 0)
|
||||
visible_message(SPAN_DANGER("\The [src.name] disintegrates!"))
|
||||
switch (hitting_projectile.damage_type)
|
||||
if(DAMAGE_BRUTE)
|
||||
new /obj/item/stack/material/steel(src.loc, 2)
|
||||
new /obj/item/stack/rods(src.loc, 3)
|
||||
for(var/i = 1 to 3)
|
||||
if(prob(50))
|
||||
new /obj/item/stack/material/steel(src.loc, 2)
|
||||
else
|
||||
new /obj/item/material/shard(src.loc, MATERIAL_STEEL)
|
||||
if(DAMAGE_BURN)
|
||||
new /obj/effect/decal/cleanable/ash(src.loc) // Turn it to ashes!
|
||||
new /obj/item/material/shard(src.loc, MATERIAL_STEEL)
|
||||
new /obj/particle_emitter/door_destruction(loc, 2 SECONDS)
|
||||
qdel(src)
|
||||
|
||||
if(damage)
|
||||
add_damage(damage)
|
||||
|
||||
/obj/structure/machinery/door/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
..()
|
||||
var/tforce = 0
|
||||
@@ -419,6 +423,8 @@
|
||||
update_icon()
|
||||
|
||||
/obj/structure/machinery/door/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
set_broken()
|
||||
|
||||
/obj/structure/machinery/door/proc/set_broken()
|
||||
|
||||
@@ -1,506 +0,0 @@
|
||||
/obj/structure/machinery/mecha_part_fabricator
|
||||
name = "synthetic fabricator"
|
||||
desc = "A general purpose fabricator that can be used to fabricate equipment for synthetics or exosuits."
|
||||
icon = 'icons/obj/machinery/robotics_fabricator.dmi'
|
||||
icon_state = "fab"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
idle_power_usage = 20
|
||||
active_power_usage = 5000
|
||||
req_access = list(ACCESS_ROBOTICS)
|
||||
component_types = list(
|
||||
/obj/item/circuitboard/mechfab,
|
||||
/obj/item/stock_parts/matter_bin = 2,
|
||||
/obj/item/stock_parts/manipulator,
|
||||
/obj/item/stock_parts/micro_laser,
|
||||
/obj/item/stock_parts/console_screen
|
||||
)
|
||||
manufacturer = "hephaestus"
|
||||
|
||||
/**
|
||||
* A `/list` of enqueued `/datum/design` to be printed, processed in the queue
|
||||
*/
|
||||
var/list/datum/design/queue = list()
|
||||
|
||||
/**
|
||||
* How much efficient (or inefficient) the protolathe is at manufacturing things
|
||||
*/
|
||||
var/mat_efficiency = 1
|
||||
|
||||
/**
|
||||
* The production speed of this specific protolathe, a factor
|
||||
*/
|
||||
var/production_speed = 1
|
||||
|
||||
var/list/materials = list(MATERIAL_STEEL = 0, MATERIAL_GLASS = 0, MATERIAL_GOLD = 0, MATERIAL_SILVER = 0, MATERIAL_DIAMOND = 0, MATERIAL_PHORON = 0, MATERIAL_URANIUM = 0, MATERIAL_PLASTEEL = 0, MATERIAL_ALUMINIUM = 0, MATERIAL_LEAD = 0)
|
||||
var/res_max_amount = 200000
|
||||
|
||||
var/datum/research/files
|
||||
|
||||
/// The looping sound for production.
|
||||
var/datum/looping_sound/synth_fab/fab_loop
|
||||
|
||||
var/list/categories = list()
|
||||
var/category = null
|
||||
var/sync_message = ""
|
||||
var/limb_manufacturer
|
||||
|
||||
///The timer id for the build callback, if we're building something
|
||||
var/build_callback_timer
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/upgrade_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "- Upgraded <b>matter bins</b> will increase material storage capacity."
|
||||
. += SPAN_NOTICE(" - The current storage capacity is <b>[res_max_amount / 2000]</b> sheets")
|
||||
. += "- Upgraded <b>micro-lasers</b> will increase fabrication speed."
|
||||
. += SPAN_NOTICE(" - The current speed increase is <b>[round((1 - (1 / production_speed)) * 100)]%</b>")
|
||||
. += "- Upgraded <b>manipulators</b> will improve material use efficiency."
|
||||
. += SPAN_NOTICE(" - The current cost reduction is <b>[round((1 - mat_efficiency) * 100)]%</b>")
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/antagonist_hints(mob/user, distance, is_adjacent)
|
||||
. += ..()
|
||||
. += "Click-drag someone with long hair onto this machine to start feeding it their hair! This will hurt and piss them off!"
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/Initialize()
|
||||
. = ..()
|
||||
|
||||
files = new /datum/research(src) //Setup the research data holder.
|
||||
fab_loop = new(src)
|
||||
limb_manufacturer = GLOB.basic_robolimb.company
|
||||
update_categories()
|
||||
update_icon()
|
||||
|
||||
/// Make sure the machine starts the round properly synced.
|
||||
/obj/structure/machinery/mecha_part_fabricator/LateInitialize()
|
||||
. = ..()
|
||||
sync()
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/update_icon()
|
||||
ClearOverlays()
|
||||
update_fab_audio()
|
||||
if(panel_open)
|
||||
AddOverlays("[icon_state]_panel")
|
||||
if(!(stat & (NOPOWER|BROKEN)))
|
||||
AddOverlays(emissive_appearance(icon, "[icon_state]_lights"))
|
||||
AddOverlays("[icon_state]_lights")
|
||||
if(build_callback_timer)
|
||||
AddOverlays("[icon_state]_working")
|
||||
AddOverlays(emissive_appearance(icon, "[icon_state]_lights_working"))
|
||||
AddOverlays("[icon_state]_lights_working")
|
||||
|
||||
/// Starts and stops the necessary audio.
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/update_fab_audio()
|
||||
if(!fab_loop)
|
||||
return
|
||||
|
||||
if(build_callback_timer)
|
||||
fab_loop.start()
|
||||
else
|
||||
fab_loop.stop()
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/dismantle()
|
||||
SSmaterials.normalize_material_amounts(materials)
|
||||
for(var/f in materials.Copy())
|
||||
eject_materials(f, materials[f])
|
||||
|
||||
//Stop the queue building if you're dismantling
|
||||
deltimer(build_callback_timer)
|
||||
|
||||
..()
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/RefreshParts()
|
||||
..()
|
||||
res_max_amount = 0
|
||||
|
||||
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
|
||||
res_max_amount += M.rating * 100000 // 200k -> 600k
|
||||
var/T = 0
|
||||
|
||||
for(var/obj/item/stock_parts/manipulator/M in component_parts)
|
||||
T += M.rating
|
||||
mat_efficiency = 1 - (T - 1) / 4 // 1 -> 0.5
|
||||
|
||||
for(var/obj/item/stock_parts/micro_laser/M in component_parts) // Not resetting T is intended; speed is affected by both
|
||||
T += M.rating
|
||||
production_speed = T / 2 // 1 -> 3
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/attack_hand(var/mob/user)
|
||||
if(..())
|
||||
return
|
||||
if(!allowed(user))
|
||||
to_chat(user, SPAN_WARNING("Access denied."))
|
||||
return
|
||||
do_hair_pull(user)
|
||||
|
||||
// Yes I'm doing this after do_hair_pull() intentionally, you can totally fail the skill check and still get your hair stuck in a blender.
|
||||
var/cancelled = FALSE
|
||||
SEND_SIGNAL(user, COMSIG_USE_MECH_FAB, &cancelled)
|
||||
if (cancelled)
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/ui_interact(mob/user, datum/tgui/ui)
|
||||
. = ..()
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "SyntheticFabricator", "Synthetic Fabricator", 1200, 800)
|
||||
ui.open()
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["manufacturer"] = manufacturer
|
||||
var/datum/design/current = queue.len ? queue[1] : null
|
||||
if(current)
|
||||
data["current"] = current.name
|
||||
data["queue"] = get_queue_names()
|
||||
data["buildable"] = get_build_options()
|
||||
data["category"] = category
|
||||
data["available_categories"] = list()
|
||||
for(var/possible_category in categories)
|
||||
data["available_categories"] += list(list("name" = possible_category))
|
||||
|
||||
if(GLOB.fabricator_robolimbs)
|
||||
var/list/T = list()
|
||||
for(var/A in GLOB.fabricator_robolimbs)
|
||||
var/datum/robolimb/R = GLOB.fabricator_robolimbs[A]
|
||||
T += list(list("name" = R.company, "type" = A))
|
||||
data["manufacturers"] = T
|
||||
data["selected_manufacturer"] = limb_manufacturer
|
||||
|
||||
data["materials"] = get_materials()
|
||||
data["maximum_resource_amount"] = res_max_amount
|
||||
data["sync"] = sync_message
|
||||
|
||||
//If we have something in the queue that we're trying to build, show the time left if the build is undergoing, otherwise null
|
||||
//the logic of displaying it is handled client-side
|
||||
if(current)
|
||||
if(build_callback_timer)
|
||||
data["timeleft"] = round(timeleft(build_callback_timer))
|
||||
else
|
||||
data["timeleft"] = null
|
||||
return data
|
||||
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("build")
|
||||
var/path = text2path(params["build"])
|
||||
add_to_queue(path)
|
||||
. = TRUE
|
||||
|
||||
if("remove")
|
||||
remove_from_queue(text2num(params["remove"]))
|
||||
. = TRUE
|
||||
|
||||
if("category")
|
||||
if(params["category"] in categories)
|
||||
category = params["category"]
|
||||
. = TRUE
|
||||
|
||||
if("manufacturer")
|
||||
if(params["manufacturer"] in GLOB.fabricator_robolimbs)
|
||||
limb_manufacturer = params["manufacturer"]
|
||||
. = TRUE
|
||||
|
||||
if("eject")
|
||||
eject_materials(params["eject"], text2num(params["amount"]))
|
||||
. = TRUE
|
||||
|
||||
if("sync")
|
||||
sync()
|
||||
. = TRUE
|
||||
else
|
||||
sync_message = ""
|
||||
|
||||
if(.)
|
||||
playsound(src, 'sound/machines/synthfab/synthfab_button.ogg', 50)
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/attackby(obj/item/attacking_item, mob/user)
|
||||
if(build_callback_timer)
|
||||
to_chat(user, SPAN_NOTICE("\The [src] is busy. Please wait for completion of previous operation."))
|
||||
return TRUE
|
||||
if(default_deconstruction_screwdriver(user, attacking_item))
|
||||
return TRUE
|
||||
if(default_deconstruction_crowbar(user, attacking_item))
|
||||
return TRUE
|
||||
if(default_part_replacement(user, attacking_item))
|
||||
return TRUE
|
||||
|
||||
if(!istype(attacking_item, /obj/item/stack/material))
|
||||
return ..()
|
||||
|
||||
var/obj/item/stack/material/M = attacking_item
|
||||
if(!M.material)
|
||||
return ..()
|
||||
var/material = SSmaterials.material_to_path(M.material, FALSE)
|
||||
if(!(material in list(MATERIAL_STEEL, MATERIAL_GLASS, MATERIAL_GOLD, MATERIAL_SILVER, MATERIAL_DIAMOND, MATERIAL_PHORON, MATERIAL_URANIUM, MATERIAL_PLASTEEL, MATERIAL_ALUMINIUM, MATERIAL_LEAD)))
|
||||
to_chat(user, SPAN_WARNING("\The [src] cannot hold [M.material.name]."))
|
||||
return TRUE
|
||||
|
||||
var/sname = "[M.name]"
|
||||
SSmaterials.normalize_material_amounts(materials)
|
||||
if((materials[material] || 0) + SHEET_MATERIAL_AMOUNT <= res_max_amount)
|
||||
if(M.amount >= 1)
|
||||
var/count = 0
|
||||
var/mutable_appearance/MA = mutable_appearance(icon, "material_insertion")
|
||||
MA.color = M.material.icon_colour
|
||||
//first play the insertion animation
|
||||
flick_overlay_view(MA, 1 SECONDS)
|
||||
|
||||
//now play the progress bar animation
|
||||
flick_overlay_view(mutable_appearance(icon, "fab_progress"), 1 SECONDS)
|
||||
|
||||
while((materials[material] || 0) + SHEET_MATERIAL_AMOUNT <= res_max_amount && M.amount >= 1)
|
||||
SSmaterials.add_material_amount(materials, material, M.perunit)
|
||||
M.use(1)
|
||||
count++
|
||||
to_chat(user, SPAN_NOTICE("You insert [count] [sname] into \the [src]."))
|
||||
|
||||
//Wake up, we have things to do (maybe)
|
||||
handle_queue()
|
||||
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("\The [src] cannot hold more [sname]."))
|
||||
return TRUE
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/mouse_drop_receive(atom/dropped, mob/user, params)
|
||||
var/mob/living/carbon/human/target = dropped
|
||||
if (!istype(target) || target.buckled_to || get_dist(user, src) > 1 || get_dist(user, target) > 1 || user.stat || istype(user, /mob/living/silicon/ai))
|
||||
return
|
||||
if(target == user)
|
||||
return
|
||||
src.add_fingerprint(user)
|
||||
var/target_loc = target.loc
|
||||
|
||||
if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
|
||||
if(isskrell(target) || isunathi(target))
|
||||
return
|
||||
|
||||
for(var/obj/item/protection in list(target.head))
|
||||
if(protection && (protection.flags_inv & BLOCKHAIR))
|
||||
return
|
||||
|
||||
var/datum/sprite_accessory/hair/hair_style = GLOB.hair_styles_list[target.h_style]
|
||||
if(hair_style.length < 4)
|
||||
return
|
||||
|
||||
user.visible_message(SPAN_WARNING("[user] starts feeding [target]'s hair into \the [src]!"), SPAN_WARNING("You start feeding [target]'s hair into \the [src]!"))
|
||||
if(!do_after(user, 5 SECONDS, target, DO_UNIQUE))
|
||||
return
|
||||
if(target_loc != target.loc)
|
||||
return
|
||||
if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
|
||||
user.visible_message(SPAN_WARNING("[user] feeds the [target]'s hair into the [src] and flicks it on!"), SPAN_ALERT("You turn the [src] on!"))
|
||||
do_hair_pull(target)
|
||||
user.attack_log += "\[[time_stamp()]\] <span class='warning'>Has fed [target.name]'s ([target.ckey]) hair into a [src].</span>"
|
||||
target.attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their hair fed into [src] by [user.name] ([user.ckey])</font>"
|
||||
msg_admin_attack("[key_name_admin(user)] fed [key_name_admin(target)] in a [src]. (<A href='byond://?_src_=holder;adminplayerobservecoodjump=1;X=[user.x];Y=[user.y];Z=[user.z]'>JMP</a>)",ckey=key_name(user),ckey_target=key_name(target))
|
||||
else
|
||||
return
|
||||
if(!do_after(user, 3.5 SECONDS, target, DO_UNIQUE))
|
||||
return
|
||||
if(target_loc != target.loc)
|
||||
return
|
||||
if(target != user && !user.restrained() && !user.stat && !user.weakened && !user.stunned && !user.paralysis)
|
||||
user.visible_message(SPAN_ALERT("[user] starts tugging on [target]'s head as the [src] keeps running!"), SPAN_ALERT("You start tugging on [target]'s head!"))
|
||||
do_hair_pull(target)
|
||||
spawn(10)
|
||||
user.visible_message(SPAN_ALERT("[user] stops the [src] and leaves [target] resting as they are."), SPAN_ALERT("You turn the [src] off and let go of [target]."))
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/emag_act(var/remaining_charges, var/mob/user)
|
||||
switch(emagged)
|
||||
if(0)
|
||||
emagged = 0.5
|
||||
visible_message("[icon2html(src, viewers(get_turf(src)))] <b>[src]</b> beeps: \"DB error \[Code 0x00F1\]\"")
|
||||
sleep(10)
|
||||
visible_message("[icon2html(src, viewers(get_turf(src)))] <b>[src]</b> beeps: \"Attempting auto-repair\"")
|
||||
sleep(15)
|
||||
visible_message("[icon2html(src, viewers(get_turf(src)))] <b>[src]</b> beeps: \"User DB corrupted \[Code 0x00FA\]. Truncating data structure...\"")
|
||||
sleep(30)
|
||||
visible_message("[icon2html(src, viewers(get_turf(src)))] <b>[src]</b> beeps: \"User DB truncated. Please contact your [SSatlas.current_map.company_name] system operator for future assistance.\"")
|
||||
req_access = null
|
||||
emagged = 1
|
||||
return 1
|
||||
if(0.5)
|
||||
visible_message("[icon2html(src, viewers(get_turf(src)))] <b>[src]</b> beeps: \"DB not responding \[Code 0x0003\]...\"")
|
||||
if(1)
|
||||
visible_message("[icon2html(src, viewers(get_turf(src)))] <b>[src]</b> beeps: \"No records in User DB\"")
|
||||
|
||||
/**
|
||||
* Adds a design to the queue
|
||||
*
|
||||
* * path: The path of the design to add
|
||||
*/
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/add_to_queue(path)
|
||||
var/datum/design/D = files.known_designs[path]
|
||||
if(!D)
|
||||
return
|
||||
queue += D
|
||||
|
||||
//Wake up, we have things to do
|
||||
handle_queue()
|
||||
|
||||
/**
|
||||
* Removes a design from the queue
|
||||
*
|
||||
* * index: The index of the design to remove
|
||||
*/
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/remove_from_queue(index)
|
||||
queue.Cut(index, index + 1)
|
||||
|
||||
//If we're removing the first thing in the queue, stop the build timer
|
||||
if(index == 1)
|
||||
deltimer(build_callback_timer)
|
||||
build_callback_timer = null
|
||||
|
||||
//Wake up, we have things to do
|
||||
handle_queue()
|
||||
|
||||
/**
|
||||
* Handle the construction queue
|
||||
*/
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/handle_queue()
|
||||
|
||||
//No work to do or already busy, stop
|
||||
if(!length(queue) || build_callback_timer)
|
||||
//If we don't have a build in progress, revert to idle power usage
|
||||
if(!build_callback_timer)
|
||||
update_use_power(POWER_USE_IDLE)
|
||||
|
||||
update_icon()
|
||||
return
|
||||
|
||||
//If there's no power, there's no building
|
||||
if(stat & NOPOWER)
|
||||
queue = list()
|
||||
return
|
||||
|
||||
//Get the first design in the queue
|
||||
var/datum/design/D = queue[1]
|
||||
|
||||
//If we can build it, process the request
|
||||
if(can_build(D))
|
||||
update_use_power(POWER_USE_ACTIVE)
|
||||
|
||||
//Add the callback timer for printing, and remove the design from the queue
|
||||
build_callback_timer = addtimer(CALLBACK(src, PROC_REF(build), D), (D.time / production_speed), TIMER_UNIQUE|TIMER_STOPPABLE)
|
||||
//No queue removal here because we show how long it takes to build in the UI
|
||||
|
||||
else
|
||||
visible_message(SPAN_NOTICE("[icon2html(src, viewers(get_turf(src)))] \The [src] flashes: Insufficient materials to complete build: [D.name]."))
|
||||
remove_from_queue(1)
|
||||
|
||||
update_icon()
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/can_build(var/datum/design/D)
|
||||
SSmaterials.normalize_material_amounts(materials)
|
||||
for(var/M in D.materials)
|
||||
var/material = SSmaterials.material_to_path(M, FALSE)
|
||||
if(!material)
|
||||
material = M
|
||||
if((materials[material] || 0) < D.materials[M] * mat_efficiency)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/**
|
||||
* Builds the given design, assuming all the necessary conditions are met
|
||||
*
|
||||
* * design_to_build: The design to build
|
||||
*/
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/build(datum/design/design_to_build)
|
||||
//Consume the materials
|
||||
SSmaterials.normalize_material_amounts(materials)
|
||||
for(var/M in design_to_build.materials)
|
||||
SSmaterials.remove_material_amount(materials, M, design_to_build.materials[M] * mat_efficiency)
|
||||
|
||||
intent_message(MACHINE_SOUND)
|
||||
|
||||
if(design_to_build.build_path)
|
||||
var/loc_offset = get_step(src, dir)
|
||||
var/obj/new_item = design_to_build.Fabricate(loc_offset, src)
|
||||
visible_message("\The <b>[src]</b> pings, indicating that \the [new_item] is complete.", "You hear a ping.", intent_message = PING_SOUND)
|
||||
if(mat_efficiency != 1)
|
||||
if(new_item.matter && new_item.matter.len > 0)
|
||||
for(var/i in new_item.matter)
|
||||
new_item.matter[i] = new_item.matter[i] * mat_efficiency
|
||||
|
||||
//We finished building, clear the timer and remove the thing from the queue
|
||||
build_callback_timer = null
|
||||
remove_from_queue(1)
|
||||
|
||||
//Do the queue handling for the next item, or to stop
|
||||
handle_queue()
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/get_queue_names()
|
||||
. = list()
|
||||
for(var/i = 1 to queue.len)
|
||||
var/datum/design/D = queue[i]
|
||||
. += list(list("name" = D.name, "time" = get_design_time(D), "index" = i))
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/get_build_options()
|
||||
. = list()
|
||||
for(var/path in files.known_designs)
|
||||
var/datum/design/D = files.known_designs[path]
|
||||
if(!D.build_path || !(D.build_type & MECHFAB) || !D.category || (D.category != category))
|
||||
continue
|
||||
. += list(list("name" = D.name, "desc" = D.desc, "type" = D.type, "category" = D.category, "resources" = get_design_resourses(D), "time" = get_design_time(D)))
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/get_design_resourses(var/datum/design/D)
|
||||
var/list/F = list()
|
||||
for(var/T in D.materials)
|
||||
F += "[SSmaterials.material_display_name(T)]: [D.materials[T] * mat_efficiency]"
|
||||
return english_list(F, and_text = ", ")
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/get_design_time(var/datum/design/D)
|
||||
return time2text(round(10 * D.time / production_speed), "mm:ss")
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/update_categories()
|
||||
categories = list()
|
||||
for(var/path in files.known_designs)
|
||||
var/datum/design/D = files.known_designs[path]
|
||||
if(!D.build_path || !(D.build_type & MECHFAB) || !D.category)
|
||||
continue
|
||||
categories |= D.category
|
||||
if(!category || !(category in categories))
|
||||
category = categories[1]
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/get_materials()
|
||||
. = list()
|
||||
SSmaterials.normalize_material_amounts(materials)
|
||||
for(var/T in materials)
|
||||
. += list(list("name" = SSmaterials.material_display_name(T), "amount" = materials[T]))
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/eject_materials(var/material, var/amount)
|
||||
if(!amount)
|
||||
return
|
||||
SSmaterials.normalize_material_amounts(materials)
|
||||
material = SSmaterials.material_to_path(material, FALSE)
|
||||
if(!material)
|
||||
return
|
||||
var/stack_type = SSmaterials.material_stack_type(material)
|
||||
if(!stack_type)
|
||||
return
|
||||
|
||||
var/real_amount = min(round(amount / SHEET_MATERIAL_AMOUNT), round((materials[material] || 0) / SHEET_MATERIAL_AMOUNT))
|
||||
if(real_amount < 1)
|
||||
return
|
||||
var/obj/item/stack/material/S = new stack_type(loc, real_amount)
|
||||
S.update_icon()
|
||||
SSmaterials.remove_material_amount(materials, material, real_amount * SHEET_MATERIAL_AMOUNT)
|
||||
|
||||
/obj/structure/machinery/mecha_part_fabricator/proc/sync()
|
||||
sync_message = "Error: no console found."
|
||||
for(var/obj/structure/machinery/computer/rdconsole/RDC in get_area(src))
|
||||
if(!RDC.sync)
|
||||
continue
|
||||
for(var/id in RDC.files.known_tech)
|
||||
var/datum/tech/T = RDC.files.known_tech[id]
|
||||
files.AddTech2Known(T)
|
||||
files.RefreshResearch()
|
||||
sync_message = "Sync complete."
|
||||
update_categories()
|
||||
@@ -1,4 +1,7 @@
|
||||
GLOBAL_VAR(bomb_set)
|
||||
// Security needs time to respond to it
|
||||
#define MIN_BOMB_TIMER 600
|
||||
#define MAX_BOMB_TIMER 900
|
||||
|
||||
/obj/structure/machinery/nuclearbomb
|
||||
name = "\improper Nuclear Fission Explosive"
|
||||
@@ -11,7 +14,7 @@ GLOBAL_VAR(bomb_set)
|
||||
var/deployable = 0
|
||||
var/extended = 0
|
||||
var/lighthack = 0
|
||||
var/timeleft = 120
|
||||
var/timeleft = MIN_BOMB_TIMER
|
||||
var/timing = 0
|
||||
var/alerted = 0
|
||||
var/r_code = "ADMIN"
|
||||
@@ -268,7 +271,7 @@ GLOBAL_VAR(bomb_set)
|
||||
switch(action)
|
||||
if("time")
|
||||
timeleft += text2num(params["value"])
|
||||
timeleft = clamp(timeleft, 120, 600)
|
||||
timeleft = clamp(timeleft, MIN_BOMB_TIMER, MAX_BOMB_TIMER)
|
||||
return TRUE
|
||||
if("timer")
|
||||
if(timing == -1)
|
||||
@@ -282,6 +285,9 @@ GLOBAL_VAR(bomb_set)
|
||||
if(wires.is_cut(WIRE_TIMING))
|
||||
to_chat(usr, SPAN_WARNING("Nothing happens, something might be wrong with the wiring."))
|
||||
return TRUE
|
||||
if(!area_safety_check())
|
||||
audible_message(SPAN_WARNING("\The [src] emits a beep, \"Deployment aborted: local radiation shielding prevents reliable detonation coupling.\""), "\The [src]'s deployment light blinks red once and disables.")
|
||||
return TRUE
|
||||
if(!timing && !safety)
|
||||
timing = 1
|
||||
log_and_message_admins("engaged a nuclear bomb")
|
||||
@@ -290,7 +296,7 @@ GLOBAL_VAR(bomb_set)
|
||||
else
|
||||
secure_device()
|
||||
if(alerted == 0)
|
||||
set_security_level(SEC_LEVEL_DELTA)
|
||||
set_security_level(SEC_LEVEL_DELTA, TRUE, get_area(src))
|
||||
alerted = 1
|
||||
return TRUE
|
||||
if("safety")
|
||||
@@ -307,7 +313,13 @@ GLOBAL_VAR(bomb_set)
|
||||
anchored = 0
|
||||
visible_message(SPAN_WARNING("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut."))
|
||||
return TRUE
|
||||
if(!isinspace())
|
||||
if(isinspace())
|
||||
to_chat(usr, SPAN_WARNING("There is nothing to anchor to!"))
|
||||
return TRUE
|
||||
if(!area_safety_check())
|
||||
audible_message(SPAN_WARNING("\The [src] emits a beep, \"Deployment aborted: local radiation shielding prevents reliable detonation coupling.\""), "\The [src]'s deployment light blinks red once and disables.")
|
||||
return TRUE
|
||||
else
|
||||
anchored = !anchored
|
||||
if(anchored)
|
||||
visible_message(SPAN_WARNING("With a steely snap, bolts slide out of [src] and anchor it to the flooring."))
|
||||
@@ -316,8 +328,6 @@ GLOBAL_VAR(bomb_set)
|
||||
secure_device()
|
||||
visible_message(SPAN_WARNING("The anchoring bolts slide back into the depths of [src]."))
|
||||
playsound(src, 'sound/machines/boltsup.ogg', 30, 0, extrarange = SILENCED_SOUND_EXTRARANGE)
|
||||
else
|
||||
to_chat(usr, SPAN_WARNING("There is nothing to anchor to!"))
|
||||
return TRUE
|
||||
|
||||
/obj/structure/machinery/nuclearbomb/proc/secure_device()
|
||||
@@ -326,12 +336,22 @@ GLOBAL_VAR(bomb_set)
|
||||
|
||||
GLOB.bomb_set--
|
||||
timing = 0
|
||||
timeleft = clamp(timeleft, 120, 600)
|
||||
timeleft = clamp(timeleft, MIN_BOMB_TIMER, MAX_BOMB_TIMER)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/machinery/nuclearbomb/ex_act(severity)
|
||||
return
|
||||
|
||||
// Is it in a valid area
|
||||
/obj/structure/machinery/nuclearbomb/proc/area_safety_check()
|
||||
var/area/A = get_area(src)
|
||||
// It needs to be the game map and not in a rad shielded area.
|
||||
// That keeps it out of maintenance and other areas we don't want it deployed in
|
||||
if(A.area_flags & AREA_FLAG_RAD_SHIELDED || !A.station_area)
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
#define NUKERANGE 80
|
||||
/obj/structure/machinery/nuclearbomb/proc/explode()
|
||||
if (src.safety)
|
||||
@@ -347,10 +367,9 @@ GLOBAL_VAR(bomb_set)
|
||||
sleep(100)
|
||||
|
||||
var/off_station = 0
|
||||
var/turf/bomb_location = get_turf(src)
|
||||
if(bomb_location && is_station_level(bomb_location.z))
|
||||
if( (bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE)) )
|
||||
off_station = 1
|
||||
// This should really not be necessary, but lets do it just to be safe.
|
||||
if(!area_safety_check() && isinspace())
|
||||
off_station = 1
|
||||
else
|
||||
off_station = 2
|
||||
|
||||
@@ -365,7 +384,7 @@ GLOBAL_VAR(bomb_set)
|
||||
if(SSticker.mode)
|
||||
SSticker.mode.explosion_in_progress = 0
|
||||
if(off_station == 1)
|
||||
to_world("<b>A nuclear device was set off, but the explosion was out of reach of the [station_name(TRUE)]!</b>")
|
||||
to_world("<b>A nuclear device was set off, but the explosion was unable to destroy the [station_name(TRUE)]!</b>")
|
||||
else if(off_station == 2)
|
||||
to_world("<b>A nuclear device was set off, but the device was not on the [station_name(TRUE)]!</b>")
|
||||
else
|
||||
@@ -469,3 +488,6 @@ GLOBAL_VAR(bomb_set)
|
||||
continue
|
||||
T.icon_state = target_icon_state
|
||||
last_turf_state = target_icon_state
|
||||
|
||||
#undef MIN_BOMB_TIMER
|
||||
#undef MAX_BOMB_TIMER
|
||||
|
||||
@@ -500,8 +500,6 @@
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
add_damage(damage)
|
||||
|
||||
/obj/structure/machinery/porta_turret/emp_act(severity)
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
/obj/item/clothing/mask/smokable/ecig,
|
||||
/obj/item/inductive_charger/handheld,
|
||||
/obj/item/auto_cpr,
|
||||
/obj/item/personal_shield
|
||||
/obj/item/personal_shield,
|
||||
/obj/item/electronic_assembly
|
||||
)
|
||||
var/icon_state_charged = "recharger100"
|
||||
var/icon_state_charging = "recharger"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
var/icon_update_tick = 0 // Used to rebuild the overlay only once every 10 ticks
|
||||
|
||||
///Multiplier applied to all operations of giving power to cells, represents entropy, efficiency increases with upgrades
|
||||
var/charging_efficiency = 1.3
|
||||
var/charging_efficiency = 2
|
||||
|
||||
///Watts, Power rating drawn from internal cell to recharge occupant's cell 60 kW unupgraded
|
||||
var/charging_power
|
||||
@@ -229,7 +229,7 @@
|
||||
man_rating += P.rating
|
||||
cell = locate(/obj/item/cell) in component_parts
|
||||
|
||||
charging_efficiency = 1.3 + 0.030 * cap_rating
|
||||
charging_efficiency = 2 + 0.030 * cap_rating
|
||||
charging_power = 30000 + 12000 * cap_rating
|
||||
restore_power_active = 10000 + 10000 * cap_rating
|
||||
restore_power_passive = 5000 + 1000 * cap_rating
|
||||
|
||||
@@ -69,7 +69,10 @@
|
||||
return ..()
|
||||
|
||||
/obj/structure/machinery/stasis_cage/process(seconds_per_tick)
|
||||
if (use_power || !cell || !cell.charge)
|
||||
if (!use_power || !cell || !cell.charge)
|
||||
if (isanimal(contained))
|
||||
var/mob/living/simple_animal/SA = contained
|
||||
SA.in_stasis = FALSE
|
||||
return
|
||||
cell.use(2 * seconds_per_tick)
|
||||
if (contained)
|
||||
@@ -100,7 +103,10 @@
|
||||
release()
|
||||
|
||||
/obj/structure/machinery/stasis_cage/proc/release()
|
||||
if (contained)
|
||||
if(contained)
|
||||
if(isanimal(contained))
|
||||
var/mob/living/simple_animal/SA = contained
|
||||
SA.in_stasis = FALSE
|
||||
contained.dropInto(src)
|
||||
contained = null
|
||||
playsound(get_turf(src), 'sound/machines/airlock.ogg', 40)
|
||||
@@ -249,6 +255,12 @@
|
||||
playsound(src, 'sound/machines/AirlockClose.ogg', 100)
|
||||
add_fingerprint(user)
|
||||
if (do_after(user, 2 SECONDS, src))
|
||||
if(QDELETED(target) || contained || broken || !use_power)
|
||||
return
|
||||
if(target.buckled_to)
|
||||
target.buckled_to.unbuckle()
|
||||
if(istype(target.buckled_to, /obj/item/trap/animal))
|
||||
var/obj/item/trap/animal/animal_trap = target.buckled_to
|
||||
animal_trap.release(transferring = TRUE)
|
||||
else
|
||||
target.buckled_to.unbuckle()
|
||||
contain(user, target)
|
||||
|
||||
@@ -178,6 +178,11 @@
|
||||
|
||||
var/list/receive = get_hearers_in_radio_ranges(radios)
|
||||
|
||||
// Electronic radio headsets expose received traffic to their built-in
|
||||
// command receiver independently of whether a mob can hear the message.
|
||||
for(var/obj/item/radio/headset/circuitry/circuit_headset in radios)
|
||||
circuit_headset.receive_circuit_radio_command(data["name"], message, get_frequency_name(frequency))
|
||||
|
||||
// Cut out admins which have radio chatter disabled
|
||||
for (var/mob/R in receive)
|
||||
if(R.client && R.client.holder && !(R.client.prefs.toggles & CHAT_RADIO))
|
||||
|
||||
@@ -19,15 +19,18 @@
|
||||
vend_id = "robo-tools"
|
||||
products = list(
|
||||
/obj/item/stack/cable_coil = 4,
|
||||
/obj/item/flash/synthetic = 4,
|
||||
/obj/item/flash/synthetic = 10,
|
||||
/obj/item/cell/high = 12,
|
||||
/obj/item/assembly/prox_sensor = 8,
|
||||
/obj/item/assembly/signaler = 20,
|
||||
/obj/item/healthanalyzer = 3,
|
||||
/obj/item/surgery/scalpel = 2,
|
||||
/obj/item/surgery/hemostat = 2,
|
||||
/obj/item/storage/firstaid/empty = 2,
|
||||
/obj/item/surgery/circular_saw = 2,
|
||||
/obj/item/screwdriver = 5,
|
||||
/obj/item/crowbar = 5
|
||||
/obj/item/crowbar = 5,
|
||||
/obj/item/mmi = 2
|
||||
)
|
||||
contraband = list(
|
||||
/obj/item/flash = 2
|
||||
|
||||
@@ -506,6 +506,14 @@
|
||||
/obj/item/clothing/suit/storage/tajaran/messa = 3,
|
||||
/obj/item/clothing/suit/storage/tajaran/matake = 2,
|
||||
/obj/item/clothing/suit/storage/tajaran/azubarre = 2,
|
||||
/obj/item/clothing/suit/storage/hooded/trinary_robes = 1,
|
||||
/obj/item/clothing/suit/storage/hooded/trinary_robes/templeist = 1,
|
||||
/obj/item/clothing/suit/storage/hooded/trinary_robes/habit = 1,
|
||||
/obj/item/clothing/head/trinary = 1,
|
||||
/obj/item/clothing/accessory/poncho/trinary/shouldercape = 1,
|
||||
/obj/item/clothing/accessory/poncho/trinary/pellegrina = 1,
|
||||
/obj/item/clothing/accessory/poncho/trinary = 1,
|
||||
/obj/item/clothing/accessory/badge/trinary = 1,
|
||||
/obj/item/clothing/head/chaplain_hood = 3,
|
||||
/obj/item/clothing/head/nun_hood = 3,
|
||||
/obj/item/clothing/head/hijab = 3,
|
||||
@@ -515,6 +523,7 @@
|
||||
/obj/item/clothing/mask/trinary_mask = 3,
|
||||
/obj/item/clothing/mask/gas/unathi = 3,
|
||||
/obj/item/clothing/mask/tajara = 3,
|
||||
/obj/item/clothing/ears/antenna/trinary_halo = 1,
|
||||
/obj/item/clothing/accessory/apron/dharmela = 2,
|
||||
/obj/item/clothing/shoes/sneakers/black = 3,
|
||||
/obj/item/storage/box/fancy/candle_box = 3,
|
||||
|
||||
@@ -202,7 +202,6 @@
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
health -= hitting_projectile.damage
|
||||
bullet_ping(hitting_projectile)
|
||||
CheckHealth()
|
||||
|
||||
|
||||
@@ -114,8 +114,6 @@
|
||||
if(. != BULLET_ACT_HIT)
|
||||
return .
|
||||
|
||||
add_damage(proj_damage, hitting_projectile.damage_flags(), hitting_projectile.damage_type, hitting_projectile.armor_penetration, hitting_projectile)
|
||||
|
||||
/obj/structure/window/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1)
|
||||
|
||||
Reference in New Issue
Block a user