Merge branch 'master' into cool-ipcs

This commit is contained in:
Timothy Teakettle
2020-09-16 05:09:02 +01:00
2723 changed files with 184768 additions and 215036 deletions
+9 -1
View File
@@ -16,6 +16,8 @@
/// If it's valid territory for gangs/cults to summon
var/valid_territory = TRUE
/// malf ais can hack this
var/valid_malf_hack = TRUE
/// if blobs can spawn there and if it counts towards their score.
var/blob_allowed = TRUE
/// whether servants can warp into this area from Reebe
@@ -516,7 +518,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
used_environ += amount
/area/Entered(atom/movable/M)
/area/Entered(atom/movable/M, atom/OldLoc)
set waitfor = FALSE
SEND_SIGNAL(src, COMSIG_AREA_ENTERED, M)
SEND_SIGNAL(M, COMSIG_ENTER_AREA, src) //The atom that enters the area
@@ -524,6 +526,11 @@ GLOBAL_LIST_EMPTY(teleportlocs)
return
var/mob/living/L = M
var/turf/oldTurf = get_turf(OldLoc)
var/area/A = oldTurf?.loc
if(A && (A.has_gravity != has_gravity))
L.update_gravity(L.mob_has_gravity())
if(!L.ckey)
return
@@ -567,6 +574,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
power_environ = FALSE
always_unpowered = FALSE
valid_territory = FALSE
valid_malf_hack = FALSE
blob_allowed = FALSE
addSorted()
+110 -55
View File
@@ -26,7 +26,6 @@
var/list/atom_colours //used to store the different colors on an atom
//its inherent color, the colored paint applied on it, special color effect etc...
var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
var/list/remove_overlays // a very temporary list of overlays to remove
var/list/add_overlays // a very temporary list of overlays to add
@@ -48,6 +47,7 @@
var/rad_insulation = RAD_NO_INSULATION
///The custom materials this atom is made of, used by a lot of things like furniture, walls, and floors (if I finish the functionality, that is.)
///The list referenced by this var can be shared by multiple objects and should not be directly modified. Instead, use [set_custom_materials][/atom/proc/set_custom_materials].
var/list/custom_materials
///Bitfield for how the atom handles materials.
var/material_flags = NONE
@@ -69,6 +69,9 @@
/// A luminescence-shifted value of the last color calculated for chatmessage overlays
var/chat_color_darkened
///Mobs that are currently do_after'ing this atom, to be cleared from on Destroy()
var/list/targeted_by
/atom/New(loc, ...)
//atom creation method that preloads variables at creation
if(GLOB.use_preloader && (src.type == GLOB._preloader.target_path))//in case the instanciated atom is creating other atoms in New()
@@ -100,6 +103,8 @@
stack_trace("Warning: [src]([type]) initialized multiple times!")
flags_1 |= INITIALIZED_1
if(loc)
SEND_SIGNAL(loc, COMSIG_ATOM_CREATED, src) /// Sends a signal that the new atom `src`, has been created at `loc`
//atom color stuff
if(color)
add_atom_colour(color, FIXED_COLOUR_PRIORITY)
@@ -114,11 +119,8 @@
if (canSmoothWith)
canSmoothWith = typelist("canSmoothWith", canSmoothWith)
var/temp_list = list()
for(var/i in custom_materials)
temp_list[SSmaterials.GetMaterialRef(i)] = custom_materials[i] //Get the proper instanced version
custom_materials = null //Null the list to prepare for applying the materials properly
set_custom_materials(temp_list)
// apply materials properly from the default custom_materials value
set_custom_materials(custom_materials)
ComponentInitialize()
@@ -142,7 +144,11 @@
qdel(reagents)
LAZYCLEARLIST(overlays)
LAZYCLEARLIST(priority_overlays)
for(var/i in targeted_by)
var/mob/M = i
LAZYREMOVE(M.do_afters, src)
targeted_by = null
QDEL_NULL(light)
@@ -219,7 +225,7 @@
/atom/proc/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
SEND_SIGNAL(src, COMSIG_ATOM_HULK_ATTACK, user)
if(does_attack_animation)
user.changeNext_move(CLICK_CD_MELEE)
user.DelayNextAction(CLICK_CD_MELEE)
log_combat(user, src, "punched", "hulk powers")
user.do_attack_animation(src, ATTACK_EFFECT_SMASH)
@@ -368,6 +374,20 @@
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, .)
/**
* Called when a mob examines (shift click or verb) this atom twice (or more) within EXAMINE_MORE_TIME (default 1.5 seconds)
*
* This is where you can put extra information on something that may be superfluous or not important in critical gameplay
* moments, while allowing people to manually double-examine to take a closer look
*
* Produces a signal [COMSIG_PARENT_EXAMINE_MORE]
*/
/atom/proc/examine_more(mob/user)
. = list()
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE_MORE, user, .)
if(!LAZYLEN(.)) // lol ..length
return list("<span class='notice'><i>You examine [src] closer, but find nothing of interest...</i></span>")
/// Updates the icon of the atom
/atom/proc/update_icon()
// I expect we're going to need more return flags and options in this proc
@@ -438,7 +458,7 @@
var/blood_id = get_blood_id()
if(!(blood_id in GLOB.blood_reagent_types))
return
return list("ANIMAL DNA" = "Y-")
return list("color" = BLOOD_COLOR_HUMAN, "ANIMAL DNA" = "Y-")
/mob/living/carbon/get_blood_dna_list()
var/blood_id = get_blood_id()
@@ -446,13 +466,15 @@
return
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[dna.unique_enzymes] = dna.blood_type
else
blood_dna["color"] = BLOOD_COLOR_HUMAN
blood_dna["UNKNOWN DNA"] = "X*"
return blood_dna
/mob/living/carbon/alien/get_blood_dna_list()
return list("UNKNOWN DNA" = "X*")
return list("color" = BLOOD_COLOR_XENO, "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)
@@ -463,18 +485,33 @@
LAZYINITLIST(blood_DNA) //if our list of DNA doesn't exist yet, initialise it.
var/old_length = blood_DNA.len
blood_DNA |= new_blood_dna
var/changed = FALSE
if(!blood_DNA["color"])
blood_DNA["color"] = new_blood_dna["color"]
changed = TRUE
else
var/old = blood_DNA["color"]
blood_DNA["color"] = BlendRGB(blood_DNA["color"], new_blood_dna["color"])
changed = old != blood_DNA["color"]
if(blood_DNA.len == old_length)
return FALSE
return TRUE
return changed
//to add blood dna info to the object's blood_DNA list
/atom/proc/transfer_blood_dna(list/blood_dna, list/datum/disease/diseases)
LAZYINITLIST(blood_DNA)
var/old_length = blood_DNA.len
blood_DNA |= blood_dna
if(blood_DNA.len > old_length)
return TRUE
. = TRUE
//some new blood DNA was added
if(!blood_dna["color"])
return
if(!blood_DNA["color"])
blood_DNA["color"] = blood_dna["color"]
else
blood_DNA["color"] = BlendRGB(blood_DNA["color"], blood_dna["color"])
//to add blood from a mob onto something, and transfer their dna info
/atom/proc/add_mob_blood(mob/living/M)
@@ -543,28 +580,7 @@
return TRUE
/atom/proc/blood_DNA_to_color()
var/list/colors = list()//first we make a list of all bloodtypes present
for(var/bloop in blood_DNA)
if(colors[blood_DNA[bloop]])
colors[blood_DNA[bloop]]++
else
colors[blood_DNA[bloop]] = 1
var/final_rgb = BLOOD_COLOR_HUMAN //a default so we don't have white blood graphics if something messed up
if(colors.len)
var/sum = 0 //this is all shitcode, but it works; trust me
final_rgb = bloodtype_to_color(colors[1])
sum = colors[colors[1]]
if(colors.len > 1)
var/i = 2
while(i <= colors.len)
var/tmp = colors[colors[i]]
final_rgb = BlendRGB(final_rgb, bloodtype_to_color(colors[i]), tmp/(tmp+sum))
sum += tmp
i++
return final_rgb
return (blood_DNA && blood_DNA["color"]) || BLOOD_COLOR_HUMAN
/atom/proc/clean_blood()
. = blood_DNA? TRUE : FALSE
@@ -733,7 +749,7 @@
flags_1 |= ADMIN_SPAWNED_1
. = ..()
switch(var_name)
if("color")
if(NAMEOF(src, color))
add_atom_colour(color, ADMIN_COLOUR_PRIORITY)
/atom/vv_get_dropdown()
@@ -922,6 +938,8 @@
log_game(log_text)
if(LOG_GAME)
log_game(log_text)
if(LOG_SHUTTLE)
log_shuttle(log_text)
else
stack_trace("Invalid individual logging type: [message_type]. Defaulting to [LOG_GAME] (LOG_GAME).")
log_game(log_text)
@@ -942,15 +960,16 @@
if(source != target)
target.log_talk(message, message_type, tag="[tag] from [key_name(source)]", log_globally=FALSE)
/*
Proc for attack log creation, because really why not
1 argument is the actor performing the action
2 argument is the target of the action
3 is a verb describing the action (e.g. punched, throwed, kicked, etc.)
4 is a tool with which the action was made (usually an item)
5 is any additional text, which will be appended to the rest of the log line
*/
/**
* Log a combat message in the attack log
*
* Arguments:
* * atom/user - argument is the actor performing the action
* * atom/target - argument is the target of the action
* * what_done - is a verb describing the action (e.g. punched, throwed, kicked, etc.)
* * atom/object - is a tool with which the action was made (usually an item)
* * addition - is any additional text, which will be appended to the rest of the log line
*/
/proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null)
var/ssource = key_name(user)
var/starget = key_name(target)
@@ -974,6 +993,39 @@ Proc for attack log creation, because really why not
var/reverse_message = "has been [what_done] by [ssource][postfix]"
target.log_message(reverse_message, LOG_ATTACK, color="orange", log_globally=FALSE)
/**
* log_wound() is for when someone is *attacked* and suffers a wound. Note that this only captures wounds from damage, so smites/forced wounds aren't logged, as well as demotions like cuts scabbing over
*
* Note that this has no info on the attack that dealt the wound: information about where damage came from isn't passed to the bodypart's damaged proc. When in doubt, check the attack log for attacks at that same time
* TODO later: Add logging for healed wounds, though that will require some rewriting of healing code to prevent admin heals from spamming the logs. Not high priority
*
* Arguments:
* * victim- The guy who got wounded
* * suffered_wound- The wound, already applied, that we're logging. It has to already be attached so we can get the limb from it
* * dealt_damage- How much damage is associated with the attack that dealt with this wound.
* * dealt_wound_bonus- The wound_bonus, if one was specified, of the wounding attack
* * dealt_bare_wound_bonus- The bare_wound_bonus, if one was specified *and applied*, of the wounding attack. Not shown if armor was present
* * base_roll- Base wounding ability of an attack is a random number from 1 to (dealt_damage ** WOUND_DAMAGE_EXPONENT). This is the number that was rolled in there, before mods
*/
/proc/log_wound(atom/victim, datum/wound/suffered_wound, dealt_damage, dealt_wound_bonus, dealt_bare_wound_bonus, base_roll)
if(QDELETED(victim) || !suffered_wound)
return
var/message = "has suffered: [suffered_wound][suffered_wound.limb ? " to [suffered_wound.limb.name]" : null]"// maybe indicate if it's a promote/demote?
if(dealt_damage)
message += " | Damage: [dealt_damage]"
// The base roll is useful since it can show how lucky someone got with the given attack. For example, dealing a cut
if(base_roll)
message += " (rolled [base_roll]/[dealt_damage ** WOUND_DAMAGE_EXPONENT])"
if(dealt_wound_bonus)
message += " | WB: [dealt_wound_bonus]"
if(dealt_bare_wound_bonus)
message += " | BWB: [dealt_bare_wound_bonus]"
victim.log_message(message, LOG_ATTACK, color="blue")
// Filter stuff
/atom/proc/add_filter(name,priority,list/params)
LAZYINITLIST(filter_data)
@@ -1006,26 +1058,21 @@ Proc for attack log creation, because really why not
///Sets the custom materials for an item.
/atom/proc/set_custom_materials(var/list/materials, multiplier = 1)
if(!materials)
materials = custom_materials
if(custom_materials) //Only runs if custom materials existed at first. Should usually be the case but check anyways
for(var/i in custom_materials)
var/datum/material/custom_material = SSmaterials.GetMaterialRef(i)
custom_material.on_removed(src, material_flags) //Remove the current materials
if(!length(materials))
custom_materials = null
return
custom_materials = list() //Reset the list
if(material_flags)
for(var/x in materials)
var/datum/material/custom_material = SSmaterials.GetMaterialRef(x)
custom_material.on_applied(src, materials[x] * multiplier * material_modifier, material_flags)
for(var/x in materials)
var/datum/material/custom_material = SSmaterials.GetMaterialRef(x)
if(material_flags & MATERIAL_EFFECTS)
custom_material.on_applied(src, materials[custom_material] * multiplier * material_modifier, material_flags)
custom_materials[custom_material] += materials[x] * multiplier
custom_materials = SSmaterials.FindOrCreateMaterialCombo(materials, multiplier)
/**
* Returns true if this atom has gravity for the passed in turf
@@ -1072,3 +1119,11 @@ Proc for attack log creation, because really why not
max_grav = max(G.setting,max_grav)
return max_grav
return SSmapping.level_trait(T.z, ZTRAIT_GRAVITY)
/**
* Causes effects when the atom gets hit by a rust effect from heretics
*
* Override this if you want custom behaviour in whatever gets hit by the rust
*/
/atom/proc/rust_heretic_act()
return
+11 -4
View File
@@ -120,25 +120,25 @@
if((var_name in careful_edits) && (var_value % world.icon_size) != 0)
return FALSE
switch(var_name)
if("x")
if(NAMEOF(src, x))
var/turf/T = locate(var_value, y, z)
if(T)
forceMove(T)
return TRUE
return FALSE
if("y")
if(NAMEOF(src, y))
var/turf/T = locate(x, var_value, z)
if(T)
forceMove(T)
return TRUE
return FALSE
if("z")
if(NAMEOF(src, z))
var/turf/T = locate(x, y, var_value)
if(T)
forceMove(T)
return TRUE
return FALSE
if("loc")
if(NAMEOF(src, loc))
if(istype(var_value, /atom))
forceMove(var_value)
return TRUE
@@ -646,3 +646,10 @@
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)
/atom/movable/proc/set_anchored(anchorvalue) //literally only for plumbing ran
SHOULD_CALL_PARENT(TRUE)
if(anchored == anchorvalue)
return
. = anchored
anchored = anchorvalue
+2
View File
@@ -6,6 +6,7 @@
// To be removed on step_ conversion
// All this work to prevent a second bump
/atom/movable/Move(atom/newloc, direct=0)
set waitfor = FALSE //n o
. = FALSE
if(!newloc || newloc == loc)
return
@@ -52,6 +53,7 @@
////////////////////////////////////////
/atom/movable/Move(atom/newloc, direct)
set waitfor = FALSE //n o
var/atom/movable/pullee = pulling
var/turf/T = loc
if(!moving_from_pull)
+24 -77
View File
@@ -38,7 +38,8 @@ Credit where due:
5. Xhuis from /tg/ for coding the first iteration of the mode, and the new, reworked version
6. ChangelingRain from /tg/ for maintaining the gamemode for months after its release prior to its rework
7. Clockwork cult code as of now, at least the one being pulled from Citadel Station's master branch, is being, or already is, fixed by Coolgat3 and Avunia.
8. Modern clockwork cult code mixed with original clockwork code, with various changes to make it less of a fustercluck, done by KeRSe. \
Fixes and assistance done by TimothyTeakettle, Kevinz000, and Deltafire15. -Very glad for the help they gave.
*/
///////////
@@ -133,7 +134,7 @@ Credit where due:
config_tag = "clockwork_cult"
antag_flag = ROLE_SERVANT_OF_RATVAR
false_report_weight = 10
required_players = 35
required_players = 24 //Fixing this directly for now since apparently config machine for forcing modes broke.
required_enemies = 3
recommended_enemies = 5
enemy_minimum_age = 7
@@ -143,13 +144,12 @@ Credit where due:
announce_text = "Servants of Ratvar are trying to summon the Justiciar!\n\
<span class='brass'>Servants</span>: Construct defenses to protect the Ark. Sabotage the station!\n\
<span class='notice'>Crew</span>: Stop the servants before they can summon the Clockwork Justiciar."
var/servants_to_serve = list()
var/list/servants_to_serve = list() //Yes this list is made out of list
var/roundstart_player_count
var/ark_time //In minutes, how long the Ark waits before activation; this is equal to 30 + (number of players / 5) (max 40 mins.)
var/datum/team/clockcult/main_clockcult
/datum/game_mode/clockwork_cult/pre_setup()
/datum/game_mode/clockwork_cult/pre_setup() //Gamemode and job code is pain. Have fun codediving all of that stuff, whoever works on this next - Delta
var/list/errorList = list()
var/list/reebes = SSmapping.LoadGroup(errorList, "Reebe", "map_files/generic", "City_of_Cogs.dmm", default_traits = ZTRAITS_REEBE, silent = TRUE)
if(errorList.len) // reebe failed to load
@@ -162,38 +162,36 @@ Credit where due:
restricted_jobs += protected_jobs
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/starter_servants = 4 //Guaranteed four servants
var/starter_servants = 4 //Try to go for at least four
var/number_players = num_players()
roundstart_player_count = number_players
if(number_players > 30) //plus one servant for every additional 10 players above 30
number_players -= 30
starter_servants += round(number_players / 10)
starter_servants = min(starter_servants, 8) //max 8 servants (that sould only happen with a ton of players)
GLOB.clockwork_vitality += 50 * starter_servants //some starter Vitality to help recover from initial fuck ups
starter_servants = min(starter_servants, 8) //max 8 servants (that sould only happen with a ton of players)
while(starter_servants)
if(!antag_candidates.len)
break //Skip setup, DO NOT RUNTIME
var/datum/mind/servant = antag_pick(antag_candidates)
servants_to_serve += servant
antag_candidates -= servant
servant.assigned_role = ROLE_SERVANT_OF_RATVAR
servant.special_role = ROLE_SERVANT_OF_RATVAR
servant.restricted_roles = restricted_jobs
starter_servants--
ark_time = 30 + round((roundstart_player_count / 5)) //In minutes, how long the Ark will wait before activation
ark_time = min(ark_time, 35) //35 minute maximum for the activation timer
return 1
if(!servants_to_serve.len) //Uh oh, something went wrong
setup_error = "There are no clockcult candidates! (Or something went very wrong)"
return FALSE
GLOB.clockwork_vitality += 50 * servants_to_serve.len //some starter Vitality to help recover from initial fuck ups
return TRUE //Haha yes it works time to not touch it any more than that.
/datum/game_mode/clockwork_cult/post_setup()
for(var/S in servants_to_serve)
var/datum/mind/servant = S
log_game("[key_name(servant)] was made an initial servant of Ratvar")
var/mob/living/L = servant.current
var/turf/T = pick(GLOB.servant_spawns)
L.forceMove(T)
GLOB.servant_spawns -= T
greet_servant(L)
equip_servant(L)
add_servant_of_ratvar(L, TRUE)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar //that's a mouthful
G.final_countdown(ark_time)
..()
return 1
@@ -201,22 +199,23 @@ Credit where due:
if(!M)
return 0
to_chat(M, "<span class='bold large_brass'>You are a servant of Ratvar, the Clockwork Justiciar!</span>")
to_chat(M, "<span class='brass'>You have approximately <b>[ark_time]</b> minutes until the Ark activates.</span>")
to_chat(M, "<span class='brass'>Unlock <b>Script</b> scripture by converting a new servant.</span>")
to_chat(M, "<span class='brass'><b>Application</b> scripture will be unlocked halfway until the Ark's activation.</span>")
to_chat(M, "<span class='brass'>Unlock <b>Script</b> scripture by converting a new servant or when 35kw of power is reached.</span>")
to_chat(M, "<span class='brass'><b>Application</b> scripture will be unlocked when 50kw of power is reached.</span>")
M.playsound_local(get_turf(M), 'sound/ambience/antag/clockcultalr.ogg', 100, FALSE, pressure_affected = FALSE)
return 1
/datum/game_mode/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob, with one of each component
/datum/game_mode/proc/equip_servant(mob/living/M) //Grants a clockwork slab to the mob
if(!M || !ishuman(M))
return FALSE
var/mob/living/carbon/human/L = M
L.equipOutfit(/datum/outfit/servant_of_ratvar)
var/obj/item/clockwork/slab/S = new
var/slot = "At your feet"
var/list/slots = list("In your left pocket" = SLOT_L_STORE, "In your right pocket" = SLOT_R_STORE, "In your backpack" = SLOT_IN_BACKPACK, "On your belt" = SLOT_BELT)
var/list/slots = list("In your left pocket" = SLOT_L_STORE, "In your right pocket" = SLOT_R_STORE, "In your backpack" = SLOT_IN_BACKPACK)
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/obj/item/clockwork/replica_fabricator/F = new
if(H.equip_to_slot_or_del(F, SLOT_IN_BACKPACK))
to_chat(H, "<span class='brass'>You have been equipped with a replica fabricator, an advanced tool that can convert objects like doors, tables or even coats into clockwork equivalents.</span>")
slot = H.equip_in_one_of_slots(S, slots)
if(slot == "In your backpack")
slot = "In your [H.back.name]"
@@ -224,10 +223,8 @@ Credit where due:
if(!S.forceMove(get_turf(L)))
qdel(S)
if(S && !QDELETED(S))
to_chat(L, "<span class='bold large_brass'>There is a paper in your backpack! It'll tell you if anything's changed, as well as what to expect.</span>")
to_chat(L, "<span class='alloy'>[slot] is a <b>clockwork slab</b>, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \
as a servant, you can find a concise tutorial in the Recollection category of its interface.</span>")
to_chat(L, "<span class='alloy italics'>If you want more information, you can read <a href=\"https://tgstation13.org/wiki/Clockwork_Cult\">the wiki page</a> to learn more.</span>")
as a servant, you can read <a href=\"https://citadel-station.net/wikimain/index.php?title=Clockwork_Cult\">the wiki page</a> to learn more.</span>")
return TRUE
return FALSE
@@ -278,7 +275,7 @@ Credit where due:
gloves = /obj/item/clothing/gloves/color/yellow
belt = /obj/item/storage/belt/utility/servant
backpack_contents = list(/obj/item/storage/box/engineer = 1, \
/obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/paper/servant_primer = 1, /obj/item/reagent_containers/food/drinks/bottle/holyoil = 1)
/obj/item/clockwork/replica_fabricator = 1, /obj/item/stack/tile/brass/fifty = 1, /obj/item/reagent_containers/food/drinks/bottle/holyoil = 1)
id = /obj/item/pda
var/plasmaman //We use this to determine if we should activate internals in post_equip()
@@ -305,53 +302,3 @@ Credit where due:
PDA.update_label()
PDA.id_check(H, W)
H.sec_hud_set_ID()
//This paper serves as a quick run-down to the cult as well as a changelog to refer to.
//Check strings/clockwork_cult_changelog.txt for the changelog, and update it when you can!
/obj/item/paper/servant_primer
name = "The Ark And You: A Primer On Servitude"
color = "#DAAA18"
info = "<b>DON'T PANIC.</b><br><br>\
Here's a quick primer on what you should know here.\
<ol>\
<li>You're in a place called Reebe right now. The crew can't get here normally.</li>\
<li>In the north is your base camp, with supplies, consoles, and the Ark. In the south is an inaccessible area that the crew can walk between \
once they arrive (more on that later.) Everything between that space is an open area.</li>\
<li>Your job as a servant is to build fortifications and defenses to protect the Ark and your base once the Ark activates. You can do this \
however you like, but work with your allies and coordinate your efforts.</li>\
<li>Once the Ark activates, the station will be alerted. Portals to Reebe will open up in nearly every room. When they take these portals, \
the crewmembers will arrive in the area that you can't access, but can get through it freely - whereas you can't. Treat this as the \"spawn\" of the \
crew and defend it accordingly.</li>\
</ol>\
<hr>\
Here is the layout of Reebe, from left to right:\
<ul>\
<li><b>Dressing Room:</b> Contains clothing, a dresser, and a mirror. There are spare slabs and absconders here.</li>\
<li><b>Listening Station:</b> Contains intercoms, a telecomms relay, and a list of frequencies.</li>\
<li><b>Ark Chamber:</b> Houses the Ark.</li>\
<li><b>Observation Room:</b> Contains five camera observers. These can be used to watch the station through its cameras, as well as to teleport down \
to most areas. To do this, use the Warp action while hovering over the tile you want to warp to.</li>\
<li><b>Infirmary:</b> Contains sleepers and basic medical supplies for superficial wounds. The sleepers can consume Vitality to heal any occupants. \
This room is generally more useful during the preparation phase; when defending the Ark, scripture is more useful.</li>\
</ul>\
<hr>\
<h2>Things that have changed:</h2>\
<ul>\
CLOCKCULTCHANGELOG\
</ul>\
<hr>\
<b>Good luck!</b>"
/obj/item/paper/servant_primer/Initialize()
. = ..()
var/changelog = world.file2list("strings/clockwork_cult_changelog.txt")
var/changelog_contents = ""
for(var/entry in changelog)
changelog_contents += "<li>[entry]</li>"
info = replacetext(info, "CLOCKCULTCHANGELOG", changelog_contents)
/obj/item/paper/servant_primer/oui_getcontent(mob/target)
if(!is_servant_of_ratvar(target) && !isobserver(target))
return "<HTML><HEAD><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)]<HR>[stamps]</BODY></HTML>"
return ..()
@@ -51,4 +51,4 @@
H.dna.add_mutation(CLOWNMUT)
H.dna.add_mutation(SMILE)
H.gain_trauma(/datum/brain_trauma/mild/phobia, TRAUMA_RESILIENCE_LOBOTOMY, "clowns") //MWA HA HA
H.gain_trauma(/datum/brain_trauma/mild/phobia/clowns, TRAUMA_RESILIENCE_LOBOTOMY) //MWA HA HA
@@ -58,6 +58,7 @@
if(visualsOnly)
return
H.dna.add_mutation(SMILE)
H.faction |= "clown"
/datum/outfit/syndicate/clownop/leader
name = "Clown Operative Leader - Basic"
@@ -62,7 +62,7 @@
hitsound = null
attack_verb_on = list("slipped")
clumsy_check = FALSE
sharpness = IS_BLUNT
sharpness = SHARP_NONE
sword_color = "yellow"
heat = 0
light_color = "#ffff00"
@@ -191,6 +191,24 @@
SSticker.mode_result = "loss - rev heads killed"
SSticker.news_report = REVS_LOSE
//////////////////////////////////////////////
// //
// HERETIC SMUGGLER //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/latejoin/heretic_smuggler
name = "Heretic Smuggler"
antag_datum = /datum/antagonist/heretic
antag_flag = ROLE_HERETIC
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
restricted_roles = list("AI","Cyborg")
required_candidates = 1
weight = 4
cost = 10
requirements = list(40,30,20,10,10,10,10,10,10,10)
repeatable = TRUE
//////////////////////////////////////////////
// //
// BLOODSUCKERS //
@@ -143,6 +143,46 @@
changeling.add_antag_datum(new_antag)
return TRUE
//////////////////////////////////////////////
// //
// ELDRITCH CULT //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/heretics
name = "Heretics"
antag_flag = ROLE_HERETIC
antag_datum = /datum/antagonist/heretic
protected_roles = list("Prisoner","Security Officer", "Warden", "Detective", "Head of Security", "Captain")
restricted_roles = list("AI", "Cyborg")
required_candidates = 1
weight = 3
cost = 20
scaling_cost = 15
requirements = list(50,45,45,40,35,20,20,15,10,10)
antag_cap = list(1,1,1,1,2,2,2,2,3,3)
/datum/dynamic_ruleset/roundstart/heretics/pre_execute()
. = ..()
var/num_ecult = antag_cap[indice_pop] * (scaled_times + 1)
for (var/i = 1 to num_ecult)
var/mob/picked_candidate = pick_n_take(candidates)
assigned += picked_candidate.mind
picked_candidate.mind.restricted_roles = restricted_roles
picked_candidate.mind.special_role = ROLE_HERETIC
return TRUE
/datum/dynamic_ruleset/roundstart/heretics/execute()
for(var/c in assigned)
var/datum/mind/cultie = c
var/datum/antagonist/heretic/new_antag = new antag_datum()
cultie.add_antag_datum(new_antag)
return TRUE
//////////////////////////////////////////////
// //
// WIZARDS //
@@ -50,10 +50,6 @@ Property weights are:
for(var/r in SSevents.running)
var/datum/round_event/R = r
threat += R.threat()
for(var/mob/living/simple_animal/hostile/H in GLOB.mob_living_list)
var/turf/T = get_turf(H)
if(H.stat != DEAD && is_station_level(T.z) && !("Station" in H.faction))
threat += H.threat()
for(var/obj/item/phylactery/P in GLOB.poi_list)
threat += 25 // can't be giving them too much of a break
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
@@ -91,6 +87,8 @@ Property weights are:
mean += 2.5
if(CHAOS_MAX)
mean += 5
else
voters += 0.5
if(voters)
GLOB.dynamic_curve_centre += (mean/voters)
if(flags & USE_PREV_ROUND_WEIGHTS)
@@ -128,7 +126,8 @@ Property weights are:
for(var/property in property_weights)
if(property in rule.property_weights) // just treat it as 0 if it's not in there
property_weight += rule.property_weights[property] * property_weights[property]
drafted_rules[rule] = (rule.get_weight() * property_weight)*rule.weight_mult
if(property_weight > 0)
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult
return drafted_rules
/datum/dynamic_storyteller/proc/midround_draft()
@@ -140,25 +139,26 @@ Property weights are:
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
continue
rule.trim_candidates()
var/threat_weight = 1
if(!(rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
pick this particular ruleset.
Let's use a toy example: there's 60 threat level and 10 threat spent.
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
is 2.26 times as likely to be picked, all other things considered.
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
*/
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
if (rule.ready())
var/property_weight = 0
for(var/property in property_weights)
if(property in rule.property_weights)
if(property in rule.property_weights) // just treat it as 0 if it's not in there
property_weight += rule.property_weights[property] * property_weights[property]
drafted_rules[rule] = round(((rule.get_weight() * property_weight)*rule.weight_mult*threat_weight)*1000,1)
if(property_weight > 0)
var/threat_weight = 1
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
pick this particular ruleset.
Let's use a toy example: there's 60 threat level and 10 threat spent.
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
is 2.26 times as likely to be picked, all other things considered.
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
*/
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight
return drafted_rules
/datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer)
@@ -175,28 +175,29 @@ Property weights are:
rule.candidates = list(newPlayer)
rule.trim_candidates()
var/threat_weight = 1
if(!(rule.flags & MINOR_RULESET))
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
if (rule.ready())
var/property_weight = 0
for(var/property in property_weights)
if(property in rule.property_weights)
property_weight += rule.property_weights[property] * property_weights[property]
drafted_rules[rule] = round(((rule.get_weight() * property_weight)*rule.weight_mult*threat_weight)*1000,1)
if(property_weight > 0)
var/threat_weight = 1
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
drafted_rules[rule] = rule.get_weight() * property_weight * rule.weight_mult * threat_weight
return drafted_rules
/datum/dynamic_storyteller/proc/event_draft()
var/list/drafted_rules = list()
for(var/datum/dynamic_ruleset/event/rule in mode.events)
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && (mode.threat_level - mode.threat) >= rule.cost)
if(rule.ready())
var/property_weight = 0
for(var/property in property_weights)
if(property in rule.property_weights)
property_weight += rule.property_weights[property] * property_weights[property]
drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && (mode.threat_level + 20 - mode.threat) >= rule.cost && rule.ready())
var/property_weight = 0
for(var/property in property_weights)
if(property in rule.property_weights)
property_weight += rule.property_weights[property] * property_weights[property]
if(property_weight > 0)
drafted_rules[rule] = rule.get_weight() + property_weight * rule.weight_mult
return drafted_rules
@@ -313,9 +314,8 @@ Property weights are:
/datum/dynamic_storyteller/random/event_draft()
var/list/drafted_rules = list()
for(var/datum/dynamic_ruleset/event/rule in mode.events)
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level))
if(rule.ready())
drafted_rules[rule] = 1
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && rule.ready())
drafted_rules[rule] = 1
return drafted_rules
/datum/dynamic_storyteller/story
@@ -330,7 +330,7 @@ Property weights are:
/datum/dynamic_storyteller/story/calculate_threat()
var/current_time = (world.time / SSautotransfer.targettime)*180
mode.threat_level = round(mode.initial_threat_level*(sin(current_time)+0.25),0.1)
mode.threat_level = round((mode.initial_threat_level*(sin(current_time)/2)+0.75),0.1)
return ..()
/datum/dynamic_storyteller/classic
@@ -0,0 +1,67 @@
/datum/game_mode/heretics
name = "heresy"
config_tag = "heresy"
antag_flag = ROLE_HERETIC
false_report_weight = 5
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to heretic role blacklist
required_players = 15
required_enemies = 1
recommended_enemies = 4
reroll_friendly = 1
enemy_minimum_age = 0
round_ends_with_antag_death = 0
announce_span = "danger"
announce_text = "Heretics have been spotted on the station!\n\
<span class='danger'>Heretics</span>: Accomplish your objectives.\n\
<span class='notice'>Crew</span>: Do not let the madman succeed!"
var/ecult_possible = 4 //hard limit on culties if scaling is turned off
var/num_ecult = 1
var/list/culties = list()
/datum/game_mode/heretics/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/esc = CONFIG_GET(number/ecult_scaling_coeff)
if(esc)
num_ecult = min(max(1, min(round(num_players() / (esc * 2)) + 2, round(num_players() / esc))),4)
else
num_ecult = max(1, min(num_players(), ecult_possible))
for(var/i in 1 to num_ecult)
if(!antag_candidates.len)
break
var/datum/mind/cultie = antag_pick(antag_candidates)
antag_candidates -= cultie
cultie.special_role = ROLE_HERETIC
cultie.restricted_roles = restricted_jobs
culties += cultie
var/enough_heretics = culties.len > 0
if(!enough_heretics)
setup_error = "Not enough heretic candidates"
return FALSE
else
for(var/antag in culties)
return TRUE
/datum/game_mode/heretics/post_setup()
for(var/c in culties)
var/datum/mind/cultie = c
log_game("[key_name(cultie)] has been selected as a heretic!")
var/datum/antagonist/heretic/new_antag = new()
cultie.add_antag_datum(new_antag)
return ..()
/datum/game_mode/heretics/generate_report()
return "Cybersun Industries has announced that they have successfully raided a high-security library. The library contained a very dangerous book that was \
shown to posses anomalous properties. We suspect that the book has been copied over, Stay vigilant!"
+2
View File
@@ -543,6 +543,8 @@
/datum/game_mode/proc/get_remaining_days(client/C)
if(!C)
return 0
if(C.prefs?.db_flags & DB_FLAG_EXEMPT)
return 0
if(!CONFIG_GET(flag/use_age_restriction_for_jobs))
return 0
if(!isnum(C.player_age))
+1 -1
View File
@@ -149,7 +149,7 @@
add_fingerprint(user)
return ..()
/obj/machinery/dominator/attack_hand(mob/user)
/obj/machinery/dominator/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(operating || (stat & BROKEN))
examine(user)
return
+35 -1
View File
@@ -201,10 +201,13 @@ GLOBAL_LIST_EMPTY(objectives)
return won || ..()
/datum/objective/assassinate/once/process()
won = check_completion()
won = check_midround_completion()
if(won)
STOP_PROCESSING(SSprocessing,src)
/datum/objective/assassinate/once/proc/check_midround_completion()
return won || !considered_alive(target) //The target afking / logging off for a bit during the round doesn't complete it, but them being afk at roundend does.
/datum/objective/assassinate/internal
var/stolen = 0 //Have we already eliminated this target?
@@ -842,6 +845,37 @@ GLOBAL_LIST_EMPTY(possible_items_special)
/datum/objective/destroy/internal
var/stolen = FALSE //Have we already eliminated this target?
/datum/objective/steal_five_of_type
name = "steal five of"
explanation_text = "Steal at least five items!"
var/list/wanted_items = list(/obj/item)
/datum/objective/steal_five_of_type/New()
..()
wanted_items = typecacheof(wanted_items)
/datum/objective/steal_five_of_type/summon_guns
name = "steal guns"
explanation_text = "Steal at least five guns!"
wanted_items = list(/obj/item/gun)
/datum/objective/steal_five_of_type/summon_magic
name = "steal magic"
explanation_text = "Steal at least five magical artefacts!"
wanted_items = list(/obj/item/spellbook, /obj/item/gun/magic, /obj/item/clothing/suit/space/hardsuit/wizard, /obj/item/scrying, /obj/item/antag_spawner/contract, /obj/item/necromantic_stone)
/datum/objective/steal_five_of_type/check_completion()
var/list/datum/mind/owners = get_owners()
var/stolen_count = 0
for(var/datum/mind/M in owners)
if(!isliving(M.current))
continue
var/list/all_items = M.current.GetAllContents() //this should get things in cheesewheels, books, etc.
for(var/obj/I in all_items) //Check for wanted items
if(is_type_in_typecache(I, wanted_items))
stolen_count++
return stolen_count >= 5
//Created by admin tools
/datum/objective/custom
name = "custom"
+7 -2
View File
@@ -36,7 +36,7 @@
targetitem = /obj/item/gun/energy/e_gun/hos
difficulty = 10
excludefromjob = list("Head Of Security")
altitems = list(/obj/item/gun/ballistic/revolver/mws, /obj/item/choice_beacon/hosgun) //We now look for eather the alt verson of the hos gun or the beacon picker.
altitems = list(/obj/item/gun/ballistic/revolver/mws, /obj/item/choice_beacon/hosgun) //We now look for either the alt verson of the hos gun or the beacon picker.
/datum/objective_item/steal/handtele
name = "a hand teleporter."
@@ -94,6 +94,11 @@
targetitem = /obj/item/documents //Any set of secret documents. Doesn't have to be NT's
difficulty = 5
/datum/objective_item/steal/blackbox
name = "the black box from the onboard blackbox recording device. Take care to wear the proper safety equipment when extracting the black box as the telecommunications array is likely to be under inhospitable conditions."
targetitem = /obj/item/blackbox //steal the forbidden ssblackbox
difficulty = 10
/datum/objective_item/steal/nuke_core
name = "the heavily radioactive plutonium core from the onboard self-destruct. Take care to wear the proper safety equipment when extracting the core!"
targetitem = /obj/item/nuke_core
@@ -125,7 +130,7 @@
/datum/objective_item/steal/plasma/check_special_completion(obj/item/tank/T)
var/target_amount = text2num(name)
var/found_amount = 0
found_amount += T.air_contents.gases[/datum/gas/plasma]
found_amount += T.air_contents.get_moles(/datum/gas/plasma)
return found_amount>=target_amount
+1 -1
View File
@@ -7,7 +7,7 @@
/obj/structure/door_assembly
var/datum/airlock_maker/maker = null
/obj/structure/door_assembly/attack_hand()
/obj/structure/door_assembly/on_attack_hand()
. = ..()
if(.)
return
+9 -1
View File
@@ -44,7 +44,7 @@
/datum/game_mode/wizard/are_special_antags_dead()
for(var/datum/mind/wizard in wizards)
for(var/datum/mind/wizard in wizards | apprentices)
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
return FALSE
@@ -58,6 +58,14 @@
return TRUE
/datum/game_mode/wizard/check_finished()
. = ..()
if(.)
finished = TRUE
else if(gamemode_ready && are_special_antags_dead() && !CONFIG_GET(keyed_list/continuous)[config_tag])
finished = TRUE
. = TRUE
/datum/game_mode/wizard/set_round_result()
..()
if(finished)
+1 -4
View File
@@ -107,10 +107,7 @@
stat |= BROKEN
update_icon()
/obj/machinery/pdapainter/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/pdapainter/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!storedpda)
to_chat(user, "<span class='notice'>[src] is empty.</span>")
+58 -173
View File
@@ -12,9 +12,9 @@
density = FALSE
state_open = TRUE
circuit = /obj/item/circuitboard/machine/sleeper
req_access = list(ACCESS_CMO) //Used for reagent deletion and addition of non medicines
var/efficiency = 1
var/min_health = 30
var/min_health = -25
var/list/available_chems
var/controls_inside = FALSE
var/list/possible_chems = list(
@@ -31,32 +31,13 @@
/obj/machinery/sleeper/Initialize()
. = ..()
create_reagents(500, NO_REACT)
// if(mapload)
// component_parts -= circuit
// QDEL_NULL(circuit)
occupant_typecache = GLOB.typecache_living
update_icon()
reset_chem_buttons()
RefreshParts()
add_inital_chems()
new_occupant_dir = dir
/obj/machinery/sleeper/setDir(newdir)
. = ..()
new_occupant_dir = dir
/obj/machinery/sleeper/on_deconstruction()
var/obj/item/reagent_containers/sleeper_buffer/buffer = new (loc)
buffer.volume = reagents.maximum_volume
buffer.reagents.maximum_volume = reagents.maximum_volume
reagents.trans_to(buffer.reagents, reagents.total_volume)
/obj/machinery/sleeper/proc/add_inital_chems()
for(var/i in available_chems)
var/datum/reagent/R = reagents.has_reagent(i)
if(!R)
reagents.add_reagent(i, (20))
continue
if(R.volume < 20)
reagents.add_reagent(i, (20 - R.volume))
/obj/machinery/sleeper/RefreshParts()
var/E
@@ -73,15 +54,11 @@
available_chems |= possible_chems[i]
reset_chem_buttons()
//Total container size 500 - 2000u
if(reagents)
reagents.maximum_volume = (500*E)
/obj/machinery/sleeper/update_icon_state()
icon_state = initial(icon_state)
if(state_open)
icon_state += "-open"
icon_state = "[initial(icon_state)]-open"
else
icon_state = initial(icon_state)
/obj/machinery/sleeper/container_resist(mob/living/user)
visible_message("<span class='notice'>[occupant] emerges from [src]!</span>",
@@ -98,10 +75,12 @@
/obj/machinery/sleeper/open_machine()
if(!state_open && !panel_open)
// flick("[initial(icon_state)]-anim", src)
..()
/obj/machinery/sleeper/close_machine(mob/user)
if((isnull(user) || istype(user)) && state_open && !panel_open)
// flick("[initial(icon_state)]-anim", src)
..(user)
var/mob/living/mob_occupant = occupant
if(mob_occupant && mob_occupant.stat != DEAD)
@@ -112,46 +91,23 @@
if (. & EMP_PROTECT_SELF)
return
if(is_operational() && occupant)
var/datum/reagent/R = pick(reagents.reagent_list)
var/datum/reagent/R = pick(reagents.reagent_list) //cit specific
inject_chem(R.type, occupant)
open_machine()
//Is this too much?
//Is this too much? Cit specific
if(severity == EMP_HEAVY)
var/chem = pick(available_chems)
available_chems -= chem
available_chems += get_random_reagent_id()
reset_chem_buttons()
/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/reagent_containers/sleeper_buffer))
var/obj/item/reagent_containers/sleeper_buffer/SB = I
if((SB.reagents.total_volume + reagents.total_volume) < reagents.maximum_volume)
SB.reagents.trans_to(reagents, SB.reagents.total_volume)
visible_message("[user] places the [SB] into the [src].")
qdel(SB)
return
else
SB.reagents.trans_to(reagents, SB.reagents.total_volume)
visible_message("[user] adds as much as they can to the [src] from the [SB].")
return
if(istype(I, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = I
if(RC.reagents.total_volume == 0)
to_chat(user, "<span class='notice'>The [I] is empty!</span>")
for(var/datum/reagent/R in RC.reagents.reagent_list)
if((obj_flags & EMAGGED) || (allowed(usr)))
break
if(!istype(R, /datum/reagent/medicine))
visible_message("The [src] gives out a hearty boop and rejects the [I]. The Sleeper's screen flashes with a pompous \"Medicines only, please.\"")
return
RC.reagents.trans_to(reagents, 1000)
visible_message("[user] adds as much as they can to the [src] from the [I].")
return
/obj/machinery/sleeper/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
if(user.stat || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
return
if(isliving(user))
var/mob/living/L = user
if(!(L.mobility_flags & MOBILITY_STAND))
return
close_machine(target)
/obj/machinery/sleeper/screwdriver_act(mob/living/user, obj/item/I)
@@ -187,31 +143,29 @@
visible_message("<span class='notice'>[usr] pries open [src].</span>", "<span class='notice'>You pry open [src].</span>")
open_machine()
/obj/machinery/sleeper/ui_state(mob/user)
if(controls_inside)
return GLOB.contained_state
return GLOB.default_state
/obj/machinery/sleeper/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Sleeper", name)
ui.open()
/obj/machinery/sleeper/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, !hasSiliconAccessInArea(user)))
if(!user.canUseTopic(src, !issilicon(user)))
return
if(state_open)
close_machine()
else
open_machine()
return TRUE
/obj/machinery/sleeper/examine(mob/user)
. = ..()
. += "<span class='notice'>Alt-click [src] to [state_open ? "close" : "open"] it.</span>"
/obj/machinery/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
if(controls_inside && state == GLOB.notcontained_state)
state = GLOB.default_state // If it has a set of controls on the inside, make it actually controllable by the mob in it.
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "sleeper", name, 550, 700, master_ui, state)
ui.open()
/obj/machinery/sleeper/process()
..()
check_nap_violations()
@@ -221,22 +175,13 @@
/obj/machinery/sleeper/ui_data()
var/list/data = list()
var/chemical_list = list()
var/blood_percent = 0
data["occupied"] = occupant ? 1 : 0
data["open"] = state_open
data["blood_levels"] = blood_percent
data["blood_status"] = "Patient either has no blood, or does not require it to function."
data["chemical_list"] = chemical_list
data["chems"] = list()
for(var/chem in available_chems)
var/datum/reagent/R = reagents.has_reagent(chem)
R = GLOB.chemical_reagents_list[chem]
data["synthchems"] += list(list("name" = R.name, "id" = R.type, "synth_allowed" = synth_allowed(chem)))
for(var/datum/reagent/R in reagents.reagent_list)
data["chems"] += list(list("name" = R.name, "id" = R.type, "vol" = R.volume, "purity" = R.purity, "allowed" = chem_allowed(R.type)))
var/datum/reagent/R = GLOB.chemical_reagents_list[chem]
data["chems"] += list(list("name" = R.name, "id" = R.type, "allowed" = chem_allowed(chem)))
data["occupant"] = list()
var/mob/living/mob_occupant = occupant
@@ -264,40 +209,10 @@
data["occupant"]["fireLoss"] = mob_occupant.getFireLoss()
data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss()
data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN)
if(mob_occupant.reagents.reagent_list.len)
data["occupant"]["reagents"] = list()
if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len)
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
chemical_list += list(list("name" = R.name, "volume" = R.volume))
else
chemical_list = "Patient has no reagents."
data["occupant"]["failing_organs"] = list()
var/mob/living/carbon/C = mob_occupant
if(C)
for(var/obj/item/organ/Or in C.getFailingOrgans())
if(istype(Or, /obj/item/organ/brain))
continue
data["occupant"]["failing_organs"] += list(list("name" = Or.name))
if(istype(C)) //Non-carbons shouldn't be able to enter sleepers, but this is to prevent runtimes if something ever breaks
if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner.
blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100)
var/blood_id = C.get_blood_id()
var/blood_warning = ""
if(blood_percent < 80)
blood_warning = "Patient has low blood levels."
if(blood_percent < 60)
blood_warning = "Patient has DANGEROUSLY low blood levels."
if(blood_id)
var/blood_type = C.dna.blood_type
if(!(blood_id in GLOB.blood_reagent_types)) // special blood substance
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
if(R)
blood_type = R.name
else
blood_type = blood_id
data["blood_status"] = "Patient has [blood_type] type blood. [blood_warning]"
data["blood_levels"] = blood_percent
data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume))
return data
/obj/machinery/sleeper/ui_act(action, params)
@@ -314,37 +229,14 @@
. = TRUE
if("inject")
var/chem = text2path(params["chem"])
var/amount = text2num(params["volume"])
if(!is_operational() || !mob_occupant || isnull(chem))
return
if(mob_occupant.health < min_health && chem != /datum/reagent/medicine/epinephrine)
return
if(inject_chem(chem, usr, amount))
if(inject_chem(chem, usr))
. = TRUE
if(scrambled_chems && prob(5))
to_chat(usr, "<span class='warning'>Chemical system re-route detected, results may not be as expected!</span>")
if("synth")
var/chem = text2path(params["chem"])
if(!is_operational())
return
reagents.add_reagent(chem_buttons[chem], 10) //other_purity = 0.75 for when the mechanics are in
if("purge")
var/chem = text2path(params["chem"])
if(allowed(usr))
if(!is_operational())
return
reagents.remove_reagent(chem, 1000)
return
if(chem in available_chems)
if(!is_operational())
return
/*var/datum/reagent/R = reagents.has_reagent(chem) //For when purity effects are in
if(R.purity < 0.8)*/
reagents.remove_reagent(chem, 1000)
else
visible_message("<span class='warning'>Access Denied.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
/obj/machinery/sleeper/emag_act(mob/user)
. = ..()
@@ -353,10 +245,9 @@
to_chat(user, "<span class='warning'>You scramble the sleeper's user interface!</span>")
return TRUE
//trans to
/obj/machinery/sleeper/proc/inject_chem(chem, mob/user, volume = 10)
if(chem_allowed(chem))
reagents.trans_id_to(occupant, chem, volume)//emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU
/obj/machinery/sleeper/proc/inject_chem(chem, mob/user)
if((chem in available_chems) && chem_allowed(chem))
occupant.reagents.add_reagent(chem_buttons[chem], 10) //emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU
if(user)
log_combat(user, occupant, "injected [chem] into", addition = "via [src]")
return TRUE
@@ -369,14 +260,6 @@
var/occ_health = mob_occupant.health > min_health || chem == /datum/reagent/medicine/epinephrine
return amount && occ_health
/obj/machinery/sleeper/proc/synth_allowed(chem)
var/datum/reagent/R = reagents.has_reagent(chem)
if(!R)
return TRUE
if(R.volume < 50)
return TRUE
return FALSE
/obj/machinery/sleeper/proc/reset_chem_buttons()
scrambled_chems = FALSE
LAZYINITLIST(chem_buttons)
@@ -416,22 +299,6 @@
component_parts += new /obj/item/stack/cable_coil(null)
RefreshParts()
/obj/machinery/sleeper/clockwork
name = "soothing sleeper"
desc = "A large cryogenics unit built from brass. Its surface is pleasantly cool the touch."
icon_state = "sleeper_clockwork"
enter_message = "<span class='bold inathneq_small'>You hear the gentle hum and click of machinery, and are lulled into a sense of peace.</span>"
possible_chems = list(list("epinephrine", "salbutamol", "bicaridine", "kelotane", "oculine", "inacusiate", "mannitol"))
/obj/machinery/sleeper/clockwork/process()
if(occupant && isliving(occupant))
var/mob/living/L = occupant
if(GLOB.clockwork_vitality) //If there's Vitality, the sleeper has passive healing
GLOB.clockwork_vitality = max(0, GLOB.clockwork_vitality - 1)
L.adjustBruteLoss(-1)
L.adjustFireLoss(-1)
L.adjustOxyLoss(-5)
/obj/machinery/sleeper/old
icon_state = "oldpod"
@@ -442,8 +309,6 @@
idle_power_usage = 3000
circuit = /obj/item/circuitboard/machine/sleeper/party
var/leddit = FALSE //Get it like reddit and lead alright fine
ui_x = 310
ui_y = 400
controls_inside = TRUE
possible_chems = list(
@@ -476,3 +341,23 @@
/obj/machinery/sleeper/party/emag_act(mob/user)
..()
leddit = TRUE
/obj/machinery/sleeper/clockwork
name = "soothing sleeper"
desc = "A large cryogenics unit built from brass. Its surface is pleasantly cool the touch."
icon_state = "sleeper_clockwork"
enter_message = "<span class='bold inathneq_small'>You hear the gentle hum and click of machinery, and are lulled into a sense of peace.</span>"
possible_chems = list(
list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/salbutamol, /datum/reagent/medicine/bicaridine, /datum/reagent/medicine/kelotane, /datum/reagent/medicine/oculine, /datum/reagent/medicine/inacusiate, /datum/reagent/medicine/mannitol)
) //everything is available at start
fair_market_price = 0 //it's free
/obj/machinery/sleeper/clockwork/process()
..()
if(occupant && isliving(occupant))
var/mob/living/L = occupant
if(GLOB.clockwork_vitality) //If there's Vitality, the sleeper has passive healing
GLOB.clockwork_vitality = max(0, GLOB.clockwork_vitality - 1)
L.adjustBruteLoss(-1)
L.adjustFireLoss(-1)
L.adjustOxyLoss(-5)
+9 -3
View File
@@ -92,6 +92,7 @@ Class Procs:
pressure_resistance = 15
max_integrity = 200
layer = BELOW_OBJ_LAYER //keeps shit coming out of the machine from ending up underneath it.
flags_1 = DEFAULT_RICOCHET_1
flags_ricochet = RICOCHET_HARD
ricochet_chance_mod = 0.3
@@ -116,12 +117,13 @@ Class Procs:
var/new_occupant_dir = SOUTH //The direction the occupant will be set to look at when entering the machine.
var/speed_process = FALSE // Process as fast as possible?
var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created
var/wire_compatible = FALSE
// For storing and overriding ui id and dimensions
var/tgui_id // ID of TGUI interface
var/ui_style // ID of custom TGUI style (optional)
var/ui_x
var/ui_y
var/init_process = TRUE //Stop processing from starting on init
var/interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_SET_MACHINE
var/fair_market_price = 69
@@ -138,7 +140,7 @@ Class Procs:
circuit = new circuit
circuit.apply_default_parts(src)
if(!speed_process)
if(!speed_process && init_process)
START_PROCESSING(SSmachines, src)
else
START_PROCESSING(SSfastprocess, src)
@@ -313,7 +315,7 @@ Class Procs:
if(user.a_intent != INTENT_HARM)
return attack_hand(user)
else
user.changeNext_move(CLICK_CD_MELEE)
user.DelayNextAction(CLICK_CD_MELEE)
user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
user.visible_message("<span class='danger'>[user.name] smashes against \the [src.name] with its paws.</span>", null, null, COMBAT_MESSAGE_RANGE)
take_damage(4, BRUTE, "melee", 1)
@@ -432,6 +434,7 @@ Class Procs:
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [src].</span>")
setAnchored(!anchored)
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
SEND_SIGNAL(src, COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH, anchored)
return SUCCESSFUL_UNFASTEN
return FAILED_UNFASTEN
return CANT_UNFASTEN
@@ -546,3 +549,6 @@ Class Procs:
. = . % 9
AM.pixel_x = -8 + ((.%3)*8)
AM.pixel_y = -8 + (round( . / 3)*8)
/obj/machinery/rust_heretic_act()
take_damage(500, BRUTE, "melee", 1)
+2 -5
View File
@@ -122,10 +122,7 @@
else
icon_state = "airlock_sensor_off"
/obj/machinery/airlock_sensor/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/airlock_sensor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
var/datum/signal/signal = new(list(
"tag" = master_tag,
"command" = "cycle"
@@ -161,4 +158,4 @@
/obj/machinery/airlock_sensor/Destroy()
SSradio.remove_object(src,frequency)
return ..()
return ..()
+46 -61
View File
@@ -39,7 +39,7 @@ GLOBAL_LIST_EMPTY(announcement_systems)
icon_state = (panel_open ? "AAS_Off_Open" : "AAS_Off")
/obj/machinery/announcement_system/update_overlays()
. =..()
. = ..()
if(arrivalToggle)
. += greenlight
@@ -54,19 +54,15 @@ GLOBAL_LIST_EMPTY(announcement_systems)
GLOB.announcement_systems -= src //"OH GOD WHY ARE THERE 100,000 LISTED ANNOUNCEMENT SYSTEMS?!!"
return ..()
/obj/machinery/announcement_system/power_change()
..()
update_icon()
/obj/machinery/announcement_system/attackby(obj/item/P, mob/user, params)
if(istype(P, /obj/item/screwdriver))
if(P.tool_behaviour == TOOL_SCREWDRIVER)
P.play_tool_sound(src)
panel_open = !panel_open
to_chat(user, "<span class='notice'>You [panel_open ? "open" : "close"] the maintenance hatch of [src].</span>")
update_icon()
else if(default_deconstruction_crowbar(P))
return
else if(istype(P, /obj/item/multitool) && panel_open && (stat & BROKEN))
else if(P.tool_behaviour == TOOL_MULTITOOL && panel_open && (stat & BROKEN))
to_chat(user, "<span class='notice'>You reset [src]'s firmware.</span>")
stat &= ~BROKEN
update_icon()
@@ -88,10 +84,6 @@ GLOBAL_LIST_EMPTY(announcement_systems)
message = CompileText(arrival, user, rank)
else if(message_type == "NEWHEAD" && newheadToggle)
message = CompileText(newhead, user, rank)
//CITADEL EDIT for cryopods
else if(message_type == "CRYOSTORAGE")
message = CompileText("%PERSON, %RANK has been moved to cryo storage.", user, rank)
//END EDIT
else if(message_type == "ARRIVALS_BROKEN")
message = "The arrivals shuttle has been damaged. Docking for repairs..."
@@ -101,63 +93,58 @@ GLOBAL_LIST_EMPTY(announcement_systems)
for(var/channel in channels)
radio.talk_into(src, message, channel)
//config stuff
/obj/machinery/announcement_system/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "AutomatedAnnouncement")
ui.open()
/obj/machinery/announcement_system/ui_interact(mob/user)
/obj/machinery/announcement_system/ui_data()
var/list/data = list()
data["arrival"] = arrival
data["arrivalToggle"] = arrivalToggle
data["newhead"] = newhead
data["newheadToggle"] = newheadToggle
return data
/obj/machinery/announcement_system/ui_act(action, param)
. = ..()
if(!user.canUseTopic(src, !hasSiliconAccessInArea(user)))
if(.)
return
if(!usr.canUseTopic(src, !issilicon(usr)))
return
if(stat & BROKEN)
visible_message("<span class='warning'>[src] buzzes.</span>", "<span class='italics'>You hear a faint buzz.</span>")
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1)
visible_message("<span class='warning'>[src] buzzes.</span>", "<span class='hear'>You hear a faint buzz.</span>")
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, TRUE)
return
var/contents = "Arrival Announcement: <A href='?src=[REF(src)];ArrivalT-Topic=1'>([(arrivalToggle ? "On" : "Off")])</a><br>\n<A href='?src=[REF(src)];ArrivalTopic=1'>[arrival]</a><br><br>\n"
contents += "Departmental Head Announcement: <A href='?src=[REF(src)];NewheadT-Topic=1'>([(newheadToggle ? "On" : "Off")])</a><br>\n<A href='?src=[REF(src)];NewheadTopic=1'>[newhead]</a><br><br>\n"
var/datum/browser/popup = new(user, "announcement_config", "Automated Announcement Configuration", 370, 220)
popup.set_content(contents)
popup.open()
/obj/machinery/announcement_system/Topic(href, href_list)
if(..())
return
if(!usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
if(stat & BROKEN)
visible_message("<span class='warning'>[src] buzzes.</span>", "<span class='italics'>You hear a faint buzz.</span>")
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 1)
return
if(href_list["ArrivalTopic"])
var/NewMessage = stripped_input(usr, "Enter in the arrivals announcement configuration.", "Arrivals Announcement Config", arrival)
if(!usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
if(NewMessage)
arrival = NewMessage
else if(href_list["NewheadTopic"])
var/NewMessage = stripped_input(usr, "Enter in the departmental head announcement configuration.", "Head Departmental Announcement Config", newhead)
if(!usr.canUseTopic(src, !hasSiliconAccessInArea(usr)))
return
if(NewMessage)
newhead = NewMessage
else if(href_list["NewheadT-Topic"])
newheadToggle = !newheadToggle
update_icon()
else if(href_list["ArrivalT-Topic"])
arrivalToggle = !arrivalToggle
update_icon()
switch(action)
if("ArrivalText")
var/NewMessage = trim(html_encode(param["newText"]), MAX_MESSAGE_LEN)
if(!usr.canUseTopic(src, !issilicon(usr)))
return
if(NewMessage)
arrival = NewMessage
log_game("The arrivals announcement was updated: [NewMessage] by:[key_name(usr)]")
if("NewheadText")
var/NewMessage = trim(html_encode(param["newText"]), MAX_MESSAGE_LEN)
if(!usr.canUseTopic(src, !issilicon(usr)))
return
if(NewMessage)
newhead = NewMessage
log_game("The head announcement was updated: [NewMessage] by:[key_name(usr)]")
if("NewheadToggle")
newheadToggle = !newheadToggle
update_icon()
if("ArrivalToggle")
arrivalToggle = !arrivalToggle
update_icon()
add_fingerprint(usr)
interact(usr)
/obj/machinery/announcement_system/attack_robot(mob/living/silicon/user)
. = attack_ai(user)
/obj/machinery/announcement_system/attack_ai(mob/user)
if(!user.canUseTopic(src, !hasSiliconAccessInArea(user)))
if(!user.canUseTopic(src, !issilicon(user)))
return
if(stat & BROKEN)
to_chat(user, "<span class='warning'>[src]'s firmware appears to be malfunctioning!</span>")
@@ -165,8 +152,8 @@ GLOBAL_LIST_EMPTY(announcement_systems)
interact(user)
/obj/machinery/announcement_system/proc/act_up() //does funny breakage stuff
stat |= BROKEN
update_icon()
if(!obj_break()) // if badmins flag this unbreakable or its already broken
return
arrival = pick("#!@%ERR-34%2 CANNOT LOCAT@# JO# F*LE!", "CRITICAL ERROR 99.", "ERR)#: DA#AB@#E NOT F(*ND!")
newhead = pick("OV#RL()D: \[UNKNOWN??\] DET*#CT)D!", "ER)#R - B*@ TEXT F*O(ND!", "AAS.exe is not responding. NanoOS is searching for a solution to the problem.")
@@ -177,9 +164,7 @@ GLOBAL_LIST_EMPTY(announcement_systems)
act_up()
/obj/machinery/announcement_system/emag_act()
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
act_up()
return TRUE
+1 -4
View File
@@ -100,10 +100,7 @@
stat |= BROKEN
update_icon()
/obj/machinery/aug_manipulator/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/aug_manipulator/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
add_fingerprint(user)
if(storedpart)
+5 -18
View File
@@ -46,29 +46,16 @@
"Dinnerware",
"Imported"
)
var/list/allowed_materials = list(
/datum/material/iron,
/datum/material/glass,
/datum/material/gold,
/datum/material/silver,
/datum/material/diamond,
/datum/material/uranium,
/datum/material/plasma,
/datum/material/bluespace,
/datum/material/bananium,
/datum/material/titanium,
/datum/material/runite,
/datum/material/plastic,
/datum/material/adamantine,
/datum/material/mythril,
/datum/material/wood
)
var/list/allowed_materials
/// Base print speed
var/base_print_speed = 10
/obj/machinery/autolathe/Initialize()
AddComponent(/datum/component/material_container, allowed_materials, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
var/list/mats = allowed_materials
if(!mats)
mats = SSmaterials.materialtypes_by_category[MAT_CATEGORY_RIGID]
AddComponent(/datum/component/material_container, mats, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
. = ..()
wires = new /datum/wires/autolathe(src)
stored_research = new stored_research
+10 -7
View File
@@ -3,6 +3,7 @@
desc = "A machine used to deposit and withdraw station funds."
icon = 'goon/icons/obj/goon_terminals.dmi'
idle_power_usage = 100
var/siphoning = FALSE
var/next_warning = 0
var/obj/item/radio/radio
@@ -38,7 +39,6 @@
return
return ..()
/obj/machinery/computer/bank_machine/process()
..()
if(siphoning)
@@ -51,7 +51,7 @@
end_syphon()
return
playsound(src.loc, 'sound/items/poster_being_created.ogg', 100, 1)
playsound(src, 'sound/items/poster_being_created.ogg', 100, TRUE)
syphoning_credits += 200
D.adjust_money(-200)
if(next_warning < world.time && prob(15))
@@ -60,17 +60,20 @@
radio.talk_into(src, message, radio_channel)
next_warning = world.time + minimum_time_between_warnings
/obj/machinery/computer/bank_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/bank_machine/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "bank_machine", name, 320, 165, master_ui, state)
ui = new(user, src, "BankMachine", name)
ui.open()
/obj/machinery/computer/bank_machine/ui_data(mob/user)
var/list/data = list()
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
data["current_balance"] = D.account_balance
if(D)
data["current_balance"] = D.account_balance
else
data["current_balance"] = 0
data["siphoning"] = siphoning
data["station_name"] = station_name()
+11 -2
View File
@@ -43,7 +43,11 @@
board.one_access = 1
board.accesses = req_one_access
/obj/machinery/button/update_icon_state()
setup_device()
/obj/machinery/button/update_icon()
cut_overlays()
if(panel_open)
icon_state = "button-open"
else if(stat & (NOPOWER|BROKEN))
@@ -129,7 +133,12 @@
A.id = id
initialized_button = 1
/obj/machinery/button/attack_hand(mob/user)
/obj/machinery/button/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
if(id && istype(device, /obj/item/assembly/control))
var/obj/item/assembly/control/A = device
A.id = "[idnum][id]"
/obj/machinery/button/on_attack_hand(mob/user)
. = ..()
if(.)
return
+6 -1
View File
@@ -72,6 +72,11 @@
if(mapload && is_station_level(z) && prob(3) && !start_active)
toggle_cam()
/obj/machinery/camera/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
for(var/i in network)
network -= i
network += "[idnum][i]"
/obj/machinery/camera/Destroy()
if(can_use())
toggle_cam(null, 0) //kick anyone viewing out and remove from the camera chunks
@@ -230,7 +235,7 @@
itemname = P.name
info = P.notehtml
to_chat(U, "<span class='notice'>You hold \the [itemname] up to the camera...</span>")
U.changeNext_move(CLICK_CD_MELEE)
U.DelayNextAction(CLICK_CD_MELEE)
for(var/mob/O in GLOB.player_list)
if(isAI(O))
var/mob/living/silicon/ai/AI = O
+11 -4
View File
@@ -79,10 +79,7 @@
charging = null
update_icon()
/obj/machinery/cell_charger/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/cell_charger/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!charging)
return
@@ -103,8 +100,18 @@
removecell()
/obj/machinery/cell_charger/attack_ai(mob/user)
if(!charging)
return
charging.forceMove(loc)
to_chat(user, "<span class='notice'>You remotely disconnect the battery port and eject [charging] from [src].</span>")
removecell()
return
/obj/machinery/cell_charger/attack_robot(mob/user)
attack_ai(user)
/obj/machinery/cell_charger/emp_act(severity)
. = ..()
+62 -58
View File
@@ -26,6 +26,7 @@
var/efficiency
var/datum/mind/clonemind
var/get_clone_mind = CLONEPOD_GET_MIND
var/grab_ghost_when = CLONER_MATURE_CLONE
var/internal_radio = TRUE
@@ -74,31 +75,6 @@
speed_coeff = max(1, speed_coeff)
heal_level = clamp((efficiency * 10) + 10, MINIMUM_HEAL_LEVEL, 100)
//The return of data disks?? Just for transferring between genetics machine/cloning machine.
//TO-DO: Make the genetics machine accept them.
/obj/item/disk/data
name = "cloning data disk"
icon_state = "datadisk0" //Gosh I hope syndies don't mistake them for the nuke disk.
var/list/fields = list()
var/list/mutations = list()
var/max_mutations = 6
var/read_only = 0 //Well,it's still a floppy disk
//Disk stuff.
/obj/item/disk/data/Initialize()
. = ..()
icon_state = "datadisk[rand(0,6)]"
add_overlay("datadisk_gene")
/obj/item/disk/data/attack_self(mob/user)
read_only = !read_only
to_chat(user, "<span class='notice'>You flip the write-protect tab to [read_only ? "protected" : "unprotected"].</span>")
/obj/item/disk/data/examine(mob/user)
. = ..()
. += "The write-protect tab is set to [read_only ? "protected" : "unprotected"]."
//Clonepod
/obj/machinery/clonepod/examine(mob/user)
@@ -134,43 +110,44 @@
return examine(user)
//Start growing a human clone in the pod!
/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, mutation_index, mindref, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance)
/obj/machinery/clonepod/proc/growclone(ckey, clonename, ui, mutation_index, mindref, blood_type, datum/species/mrace, list/features, factions, list/quirks, datum/bank_account/insurance, list/traumas)
if(panel_open)
return FALSE
if(mess || attempting)
return FALSE
clonemind = locate(mindref) in SSticker.minds
if(!istype(clonemind)) //not a mind
return FALSE
if(!QDELETED(clonemind.current))
if(clonemind.current.stat != DEAD) //mind is associated with a non-dead body
if(get_clone_mind == CLONEPOD_GET_MIND)
clonemind = locate(mindref) in SSticker.minds
if(!istype(clonemind)) //not a mind
return FALSE
if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding.
if(!QDELETED(clonemind.current))
if(clonemind.current.stat != DEAD) //mind is associated with a non-dead body
return FALSE
if(clonemind.current.suiciding) // Mind is associated with a body that is suiciding.
return FALSE
if(AmBloodsucker(clonemind.current)) //If the mind is a bloodsucker
return FALSE
if(clonemind.active) //somebody is using that mind
if( ckey(clonemind.key)!=ckey )
return FALSE
else
// get_ghost() will fail if they're unable to reenter their body
var/mob/dead/observer/G = clonemind.get_ghost()
if(!G)
return FALSE
if(G.suiciding) // The ghost came from a body that is suiciding.
return FALSE
if(clonemind.damnation_type) //Can't clone the damned.
INVOKE_ASYNC(src, .proc/horrifyingsound)
mess = TRUE
update_icon()
return FALSE
if(AmBloodsucker(clonemind.current)) //If the mind is a bloodsucker
return FALSE
if(clonemind.active) //somebody is using that mind
if( ckey(clonemind.key)!=ckey )
return FALSE
else
// get_ghost() will fail if they're unable to reenter their body
var/mob/dead/observer/G = clonemind.get_ghost()
if(!G)
return FALSE
if(G.suiciding) // The ghost came from a body that is suiciding.
return FALSE
if(clonemind.damnation_type) //Can't clone the damned.
INVOKE_ASYNC(src, .proc/horrifyingsound)
mess = TRUE
update_icon()
return FALSE
current_insurance = insurance
attempting = TRUE //One at a time!!
countdown.start()
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
H.hardset_dna(ui, mutation_index, H.real_name, null, mrace, features)
H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
H.easy_randmut(NEGATIVE+MINOR_NEGATIVE) //100% bad mutation. Can be cured with mutadone.
@@ -192,7 +169,14 @@
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, CLONING_POD_TRAIT)
H.Unconscious(80)
clonemind.transfer_to(H)
if(clonemind)
clonemind.transfer_to(H)
else if(get_clone_mind == CLONEPOD_POLL_MIND)
var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone? (Don't ERP without permission from the original)", null, null, null, 100, H, POLL_IGNORE_CLONE)
if(LAZYLEN(candidates))
var/mob/C = pick(candidates)
H.key = C.key
if(grab_ghost_when == CLONER_FRESH_CLONE)
H.grab_ghost()
@@ -209,6 +193,12 @@
var/datum/quirk/Q = new V(H)
Q.on_clone(quirks[V])
for(var/t in traumas)
var/datum/brain_trauma/BT = t
var/datum/brain_trauma/cloned_trauma = BT.on_clone()
if(cloned_trauma)
H.gain_trauma(cloned_trauma, BT.resilience)
H.set_cloned_appearance()
H.give_genitals(TRUE)
@@ -271,9 +261,6 @@
var/obj/item/bodypart/BP = I
BP.attach_limb(mob_occupant)
//Premature clones may have brain damage.
mob_occupant.adjustOrganLoss(ORGAN_SLOT_BRAIN, -((speed_coeff / 2) * dmg_mult))
use_power(7500) //This might need tweaking.
else if((mob_occupant && mob_occupant.cloneloss <= (100 - heal_level)))
@@ -399,6 +386,13 @@
to_chat(occupant, "<span class='notice'><b>There is a bright flash!</b><br><i>You feel like a new being.</i></span>")
mob_occupant.flash_act()
var/list/policies = CONFIG_GET(keyed_list/policyconfig)
var/policy = policies[POLICYCONFIG_ON_CLONE]
if(policy)
to_chat(occupant, policy)
occupant.log_message("revived using cloning.", LOG_GAME)
mob_occupant.adjustOrganLoss(ORGAN_SLOT_BRAIN, mob_occupant.getCloneLoss())
occupant.forceMove(T)
update_icon()
mob_occupant.domutcheck(1) //Waiting until they're out before possible monkeyizing. The 1 argument forces powers to manifest.
@@ -474,10 +468,9 @@
unattached_flesh.Cut()
H.setCloneLoss(CLONE_INITIAL_DAMAGE) //Yeah, clones start with very low health, not with random, because why would they start with random health
//H.setOrganLoss(ORGAN_SLOT_BRAIN, CLONE_INITIAL_DAMAGE)
// In addition to being cellularly damaged and having barely any
// brain function, they also have no limbs or internal organs.
// In addition to being cellularly damaged, they also have no limbs or internal organs.
// Applying brainloss is done when the clone leaves the pod, so application of traumas can happen.
// based on the level of damage sustained.
if(!HAS_TRAIT(H, TRAIT_NODISMEMBER))
var/static/list/zones = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG)
@@ -545,6 +538,17 @@
. += "cover-on"
. += "panel"
//Experimental cloner; clones a body regardless of the owner's status, letting a ghost control it instead
/obj/machinery/clonepod/experimental
name = "experimental cloning pod"
desc = "An ancient cloning pod. It seems to be an early prototype of the experimental cloners used in Nanotrasen Stations."
icon = 'icons/obj/machines/cloning.dmi'
icon_state = "pod_0"
req_access = null
circuit = /obj/item/circuitboard/machine/clonepod/experimental
internal_radio = FALSE
get_clone_mind = CLONEPOD_POLL_MIND
/*
* Manual -- A big ol' manual.
*/
+51 -3
View File
@@ -43,10 +43,13 @@
table.computer = src
break
/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/operating/ui_state(mob/user)
return GLOB.not_incapacitated_state
/obj/machinery/computer/operating/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "operating_computer", name, 350, 470, master_ui, state)
ui = new(user, src, "OperatingComputer", name)
ui.open()
/obj/machinery/computer/operating/ui_data(mob/user)
@@ -108,8 +111,53 @@
))
else
data["patient"] = null
return data
switch(patient.stat)
if(CONSCIOUS)
data["patient"]["stat"] = "Conscious"
data["patient"]["statstate"] = "good"
if(SOFT_CRIT)
data["patient"]["stat"] = "Conscious"
data["patient"]["statstate"] = "average"
if(UNCONSCIOUS)
data["patient"]["stat"] = "Unconscious"
data["patient"]["statstate"] = "average"
if(DEAD)
data["patient"]["stat"] = "Dead"
data["patient"]["statstate"] = "bad"
data["patient"]["health"] = patient.health
data["patient"]["blood_type"] = patient.dna.blood_type
data["patient"]["maxHealth"] = patient.maxHealth
data["patient"]["minHealth"] = HEALTH_THRESHOLD_DEAD
data["patient"]["bruteLoss"] = patient.getBruteLoss()
data["patient"]["fireLoss"] = patient.getFireLoss()
data["patient"]["toxLoss"] = patient.getToxLoss()
data["patient"]["oxyLoss"] = patient.getOxyLoss()
data["procedures"] = list()
if(patient.surgeries.len)
for(var/datum/surgery/procedure in patient.surgeries)
var/datum/surgery_step/surgery_step = procedure.get_surgery_step()
var/chems_needed = surgery_step.get_chem_list()
var/alternative_step
var/alt_chems_needed = ""
if(surgery_step.repeatable)
var/datum/surgery_step/next_step = procedure.get_surgery_next_step()
if(next_step)
alternative_step = capitalize(next_step.name)
alt_chems_needed = next_step.get_chem_list()
else
alternative_step = "Finish operation"
data["procedures"] += list(list(
"name" = capitalize("[parse_zone(procedure.location)] [procedure.name]"),
"next_step" = capitalize(surgery_step.name),
"chems_needed" = chems_needed,
"alternative_step" = alternative_step,
"alt_chems_needed" = alt_chems_needed
))
return data
/obj/machinery/computer/operating/ui_act(action, params)
if(..())
return
+37 -62
View File
@@ -2,12 +2,13 @@
name = "\improper AI system integrity restorer"
desc = "Used with intelliCards containing nonfunctional AIs to restore them to working order."
req_access = list(ACCESS_CAPTAIN, ACCESS_ROBOTICS, ACCESS_HEADS)
var/mob/living/silicon/ai/occupier = null
var/active = 0
circuit = /obj/item/circuitboard/computer/aifixer
icon_keyboard = "tech_key"
icon_screen = "ai-fixer"
light_color = LIGHT_COLOR_PINK
circuit = /obj/item/circuitboard/computer/aifixer
var/mob/living/silicon/ai/occupier = null
var/active = FALSE
/obj/machinery/computer/aifixer/attackby(obj/I, mob/user, params)
if(occupier && istype(I, /obj/item/screwdriver))
@@ -18,60 +19,45 @@
else
return ..()
/obj/machinery/computer/aifixer/ui_interact(mob/user)
. = ..()
var/dat = ""
/obj/machinery/computer/aifixer/ui_interact(mob/user, datum/tgui/ui) //artur didn't port this correctly
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "AiRestorer", name)
ui.open()
if (src.occupier)
var/laws
dat += "<h3>Stored AI: [src.occupier.name]</h3>"
dat += "<b>System integrity:</b> [(src.occupier.health+100)/2]%<br>"
/obj/machinery/computer/aifixer/ui_data(mob/user)
var/list/data = list()
if (src.occupier.laws.zeroth)
laws += "<b>0:</b> [src.occupier.laws.zeroth]<BR>"
data["ejectable"] = FALSE
data["AI_present"] = FALSE
data["error"] = null
if(!occupier)
data["error"] = "Please transfer an AI unit."
else
data["AI_present"] = TRUE
data["name"] = occupier.name
data["restoring"] = active
data["health"] = (occupier.health + 100) / 2
data["isDead"] = occupier.stat == DEAD
data["laws"] = occupier.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE)
for (var/index = 1, index <= src.occupier.laws.hacked.len, index++)
var/law = src.occupier.laws.hacked[index]
if (length(law) > 0)
var/num = ionnum()
laws += "<b>[num]:</b> [law]<BR>"
return data
for (var/index = 1, index <= src.occupier.laws.ion.len, index++)
var/law = src.occupier.laws.ion[index]
if (length(law) > 0)
var/num = ionnum()
laws += "<b>[num]:</b> [law]<BR>"
/obj/machinery/computer/aifixer/ui_act(action, params)
if(..())
return
if(!occupier)
active = FALSE
var/number = 1
for (var/index = 1, index <= src.occupier.laws.inherent.len, index++)
var/law = src.occupier.laws.inherent[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
for (var/index = 1, index <= src.occupier.laws.supplied.len, index++)
var/law = src.occupier.laws.supplied[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
dat += "<b>Laws:</b><br>[laws]<br>"
if (src.occupier.stat == DEAD)
dat += "<span class='bad'>AI non-functional</span>"
else
dat += "<span class='good'>AI functional</span>"
if (!src.active)
dat += {"<br><br><A href='byond://?src=[REF(src)];fix=1'>Begin Reconstruction</A>"}
else
dat += "<br><br>Reconstruction in process, please wait.<br>"
dat += {"<br><A href='?src=[REF(user)];mach_close=computer'>Close</A>"}
var/datum/browser/popup = new(user, "computer", "AI System Integrity Restorer", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
switch(action)
if("PRG_beginReconstruction")
if(occupier?.health < 100)
to_chat(usr, "<span class='notice'>Reconstruction in progress. This will take several minutes.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
active = TRUE
occupier.notify_ghost_cloning("Your core files are being restored!", source = src)
. = TRUE
/obj/machinery/computer/aifixer/proc/Fix()
use_power(1000)
@@ -91,17 +77,6 @@
active = Fix()
if(oldstat != occupier.stat)
update_icon()
updateDialog()
/obj/machinery/computer/aifixer/Topic(href, href_list)
if(..())
return
if(href_list["fix"])
to_chat(usr, "<span class='notice'>Reconstruction in progress. This will take several minutes.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0)
active = TRUE
add_fingerprint(usr)
updateUsrDialog()
/obj/machinery/computer/aifixer/update_overlays()
. = ..()
+153 -161
View File
@@ -3,19 +3,19 @@
desc = "Used to remotely control the flow of power to different parts of the station."
icon_screen = "solar"
icon_keyboard = "power_key"
req_access = list(ACCESS_ENGINE)
req_access = list(ACCESS_CE)
circuit = /obj/item/circuitboard/computer/apc_control
light_color = LIGHT_COLOR_YELLOW
var/mob/living/operator //Who's operating the computer right now
var/obj/machinery/power/apc/active_apc //The APC we're using right now
var/list/result_filters //For sorting the results
var/checking_logs = 0
var/should_log = TRUE
var/restoring = FALSE
var/list/logs
var/auth_id = "\[NULL\]"
var/auth_id = "\[NULL\]:"
/obj/machinery/computer/apc_control/Initialize()
/obj/machinery/computer/apc_control/Initialize(mapload, obj/item/circuitboard/C)
. = ..()
result_filters = list("Name" = null, "Charge Above" = null, "Charge Below" = null, "Responsive" = null)
logs = list()
/obj/machinery/computer/apc_control/process()
if(operator && (!operator.Adjacent(src) || stat))
@@ -23,8 +23,8 @@
if(active_apc)
if(!active_apc.locked)
active_apc.say("Remote access canceled. Interface locked.")
playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, 0)
playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, 0)
playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, FALSE)
playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, FALSE)
active_apc.locked = TRUE
active_apc.update_icon()
active_apc.remote_control = null
@@ -34,171 +34,163 @@
if(!IsAdminGhost(user))
to_chat(user,"<span class='warning'>[src] does not support AI control.</span>") //You already have APC access, cheater!
return
..(user)
..()
/obj/machinery/computer/apc_control/proc/check_apc(obj/machinery/power/apc/APC)
return APC.z == z && !APC.malfhack && !APC.aidisabled && !(APC.obj_flags & EMAGGED) && !APC.stat && !istype(APC.area, /area/ai_monitored) && !APC.area.outdoors
/obj/machinery/computer/apc_control/ui_interact(mob/living/user)
. = ..()
var/dat
if(authenticated)
if(!checking_logs)
dat += "Logged in as [auth_id].<br><br>"
dat += "<i>Filters</i><br>"
dat += "<b>Name:</b> <a href='?src=[REF(src)];name_filter=1'>[result_filters["Name"] ? result_filters["Name"] : "None set"]</a><br>"
dat += "<b>Charge:</b> <a href='?src=[REF(src)];above_filter=1'>\>[result_filters["Charge Above"] ? result_filters["Charge Above"] : "NaN"]%</a> and <a href='?src=[REF(src)];below_filter=1'>\<[result_filters["Charge Below"] ? result_filters["Charge Below"] : "NaN"]%</a><br>"
dat += "<b>Accessible:</b> <a href='?src=[REF(src)];access_filter=1'>[result_filters["Responsive"] ? "Non-Responsive Only" : "All"]</a><br><br>"
for(var/A in GLOB.apcs_list)
if(check_apc(A))
var/obj/machinery/power/apc/APC = A
if(result_filters["Name"] && !findtext(APC.name, result_filters["Name"]) && !findtext(APC.area.name, result_filters["Name"]))
continue
if(result_filters["Charge Above"] && (!APC.cell || (APC.cell && (APC.cell.charge / APC.cell.maxcharge) < result_filters["Charge Above"] / 100)))
continue
if(result_filters["Charge Below"] && APC.cell && (APC.cell.charge / APC.cell.maxcharge) > result_filters["Charge Below"] / 100)
continue
if(result_filters["Responsive"] && !APC.aidisabled)
continue
dat += "<a href='?src=[REF(src)];access_apc=[REF(APC)]'>[A]</a><br>\
<b>Charge:</b> [APC.cell ? "[DisplayEnergy(APC.cell.charge)] / [DisplayEnergy(APC.cell.maxcharge)] ([round((APC.cell.charge / APC.cell.maxcharge) * 100)]%)" : "No Powercell Installed"]<br>\
<b>Area:</b> [APC.area]<br>\
[APC.aidisabled || APC.panel_open ? "<font color='#FF0000'>APC does not respond to interface query.</font>" : "<font color='#00FF00'>APC responds to interface query.</font>"]<br><br>"
dat += "<a href='?src=[REF(src)];check_logs=1'>Check Logs</a><br>"
dat += "<a href='?src=[REF(src)];log_out=1'>Log Out</a><br>"
if(obj_flags & EMAGGED)
dat += "<font color='#FF0000'>WARNING: Logging functionality partially disabled from outside source.</font><br>"
dat += "<a href='?src=[REF(src)];restore_logging=1'>Restore logging functionality?</a><br>"
else
if(logs.len)
for(var/entry in logs)
dat += "[entry]<br>"
else
dat += "<i>No activity has been recorded at this time.</i><br>"
if(obj_flags & EMAGGED)
dat += "<a href='?src=[REF(src)];clear_logs=1'><font color='#FF0000'>@#%! CLEAR LOGS</a>"
dat += "<a href='?src=[REF(src)];check_apcs=1'>Return</a>"
operator = user
else
dat = "<a href='?src=[REF(src)];authenticate=1'>Please swipe a valid ID to log in...</a>"
var/datum/browser/popup = new(user, "apc_control", name, 600, 400)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/apc_control/ui_interact(mob/user, datum/tgui/ui)
operator = user
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ApcControl")
ui.open()
/obj/machinery/computer/apc_control/Topic(href, href_list)
/obj/machinery/computer/apc_control/ui_data(mob/user)
var/list/data = list()
data["auth_id"] = auth_id
data["authenticated"] = authenticated
data["emagged"] = obj_flags & EMAGGED
data["logging"] = should_log
data["restoring"] = restoring
data["logs"] = list()
data["apcs"] = list()
for(var/entry in logs)
data["logs"] += list(list("entry" = entry))
for(var/apc in GLOB.apcs_list)
if(check_apc(apc))
var/obj/machinery/power/apc/A = apc
var/has_cell = (A.cell) ? TRUE : FALSE
data["apcs"] += list(list(
"name" = A.area.name,
"operating" = A.operating,
"charge" = (has_cell) ? A.cell.percent() : "NOCELL",
"load" = DisplayPower(A.lastused_total),
"charging" = A.charging,
"chargeMode" = A.chargemode,
"eqp" = A.equipment,
"lgt" = A.lighting,
"env" = A.environ,
"responds" = A.aidisabled || A.panel_open,
"ref" = REF(A)
)
)
return data
/obj/machinery/computer/apc_control/ui_act(action, params)
if(..())
return
if(!usr || !usr.canUseTopic(src) || stat || QDELETED(src))
return
if(href_list["authenticate"])
var/obj/item/card/id/ID = usr.get_idcard(TRUE)
if(ID && istype(ID))
if(check_access(ID))
switch(action)
if("log-in")
if(obj_flags & EMAGGED)
authenticated = TRUE
auth_id = "[ID.registered_name] ([ID.assignment])"
log_activity("logged in")
if(href_list["log_out"])
log_activity("logged out")
authenticated = FALSE
auth_id = "\[NULL\]"
if(href_list["restore_logging"])
to_chat(usr, "<span class='robot notice'>[icon2html(src, usr)] Logging functionality restored from backup data.</span>")
obj_flags &= ~EMAGGED
LAZYADD(logs, "<b>-=- Logging restored to full functionality at this point -=-</b>")
if(href_list["access_apc"])
playsound(src, "terminal_type", 50, 0)
var/obj/machinery/power/apc/APC = locate(href_list["access_apc"]) in GLOB.apcs_list
if(!APC || APC.aidisabled || APC.panel_open || QDELETED(APC))
to_chat(usr, "<span class='robot danger'>[icon2html(src, usr)] APC does not return interface request. Remote access may be disabled.</span>")
return
if(active_apc)
to_chat(usr, "<span class='robot danger'>[icon2html(src, usr)] Disconnected from [active_apc].</span>")
active_apc.say("Remote access canceled. Interface locked.")
playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, 0)
playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, 0)
active_apc.locked = TRUE
active_apc.update_icon()
active_apc.remote_control = null
active_apc = null
to_chat(usr, "<span class='robot notice'>[icon2html(src, usr)] Connected to APC in [get_area_name(APC.area, TRUE)]. Interface request sent.</span>")
log_activity("remotely accessed APC in [get_area_name(APC.area, TRUE)]")
APC.remote_control = src
APC.ui_interact(usr)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
message_admins("[ADMIN_LOOKUPFLW(usr)] remotely accessed [APC] from [src] at [AREACOORD(src)].")
log_game("[key_name(usr)] remotely accessed [APC] from [src] at [AREACOORD(src)].")
if(APC.locked)
APC.say("Remote access detected. Interface unlocked.")
playsound(APC, 'sound/machines/boltsup.ogg', 25, 0)
playsound(APC, 'sound/machines/terminal_alert.ogg', 50, 0)
APC.locked = FALSE
APC.update_icon()
active_apc = APC
if(href_list["name_filter"])
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
var/new_filter = stripped_input(usr, "What name are you looking for?", name)
if(!src || !usr || !usr.canUseTopic(src) || stat || QDELETED(src))
return
log_activity("changed name filter to \"[new_filter]\"")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Name"] = new_filter
if(href_list["above_filter"])
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
var/new_filter = input(usr, "Enter a percentage from 1-100 to sort by (greater than).", name) as null|num
if(!src || !usr || !usr.canUseTopic(src) || stat || QDELETED(src))
return
log_activity("changed greater than charge filter to \"[new_filter]\"")
if(new_filter)
new_filter = clamp(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Above"] = new_filter
if(href_list["below_filter"])
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
var/new_filter = input(usr, "Enter a percentage from 1-100 to sort by (lesser than).", name) as null|num
if(!src || !usr || !usr.canUseTopic(src) || stat || QDELETED(src))
return
log_activity("changed lesser than charge filter to \"[new_filter]\"")
if(new_filter)
new_filter = clamp(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Below"] = new_filter
if(href_list["access_filter"])
if(isnull(result_filters["Responsive"]))
result_filters["Responsive"] = 1
log_activity("sorted by non-responsive APCs only")
else
result_filters["Responsive"] = !result_filters["Responsive"]
log_activity("sorted by all APCs")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if(href_list["check_logs"])
checking_logs = TRUE
log_activity("checked logs")
if(href_list["check_apcs"])
checking_logs = FALSE
log_activity("checked APCs")
if(href_list["clear_logs"])
logs = list()
ui_interact(usr) //Refresh the UI after a filter changes
auth_id = "Unknown (Unknown):"
log_activity("[auth_id] logged in to the terminal")
return
var/obj/item/card/id/ID = operator.get_idcard(TRUE)
if(ID && istype(ID))
if(check_access(ID))
authenticated = TRUE
auth_id = "[ID.registered_name] ([ID.assignment]):"
log_activity("[auth_id] logged in to the terminal")
playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE)
else
auth_id = "[ID.registered_name] ([ID.assignment]):"
log_activity("[auth_id] attempted to log into the terminal")
return
auth_id = "Unknown (Unknown):"
log_activity("[auth_id] attempted to log into the terminal")
if("log-out")
log_activity("[auth_id] logged out of the terminal")
playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE)
authenticated = FALSE
auth_id = "\[NULL\]"
if("toggle-logs")
should_log = !should_log
log_game("[key_name(operator)] set the logs of [src] in [AREACOORD(src)] [should_log ? "On" : "Off"]")
if("restore-console")
restoring = TRUE
addtimer(CALLBACK(src, .proc/restore_comp), rand(3,5) * 9)
if("access-apc")
var/ref = params["ref"]
playsound(src, "terminal_type", 50, FALSE)
var/obj/machinery/power/apc/APC = locate(ref) in GLOB.apcs_list
if(!APC)
return
if(active_apc)
to_chat(operator, "<span class='robot danger'>[icon2html(src, auth_id)] Disconnected from [active_apc].</span>")
active_apc.say("Remote access canceled. Interface locked.")
playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, FALSE)
playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, FALSE)
active_apc.locked = TRUE
active_apc.update_icon()
active_apc.remote_control = null
active_apc = null
APC.remote_control = src
APC.ui_interact(operator)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
log_game("[key_name(operator)] remotely accessed [APC] from [src] at [AREACOORD(src)].")
log_activity("[auth_id] remotely accessed APC in [get_area_name(APC.area, TRUE)]")
if(APC.locked)
APC.say("Remote access detected. Interface unlocked.")
playsound(APC, 'sound/machines/boltsup.ogg', 25, FALSE)
playsound(APC, 'sound/machines/terminal_alert.ogg', 50, FALSE)
APC.locked = FALSE
APC.update_icon()
active_apc = APC
if("check-logs")
log_activity("Checked Logs")
if("check-apcs")
log_activity("Checked APCs")
if("toggle-minor")
var/ref = params["ref"]
var/type = params["type"]
var/value = params["value"]
var/obj/machinery/power/apc/target = locate(ref) in GLOB.apcs_list
if(!target)
return
target.vars[type] = target.setsubsystem(text2num(value))
target.update_icon()
target.update()
var/setTo = ""
switch(target.vars[type])
if(0)
setTo = "Off"
if(1)
setTo = "Auto Off"
if(2)
setTo = "On"
if(3)
setTo = "Auto On"
log_activity("Set APC [target.area.name] [type] to [setTo]")
log_game("[key_name(operator)] Set APC [target.area.name] [type] to [setTo]]")
if("breaker")
var/ref = params["ref"]
var/obj/machinery/power/apc/target = locate(ref) in GLOB.apcs_list
target.toggle_breaker()
var/setTo = target.operating ? "On" : "Off"
log_activity("Turned APC [target.area.name]'s breaker [setTo]")
/obj/machinery/computer/apc_control/emag_act(mob/user)
. = ..()
if(!authenticated)
to_chat(user, "<span class='warning'>You bypass [src]'s access requirements using your emag.</span>")
authenticated = TRUE
log_activity("logged in")
else
if(obj_flags & EMAGGED)
return
user.visible_message("<span class='warning'>You emag [src], disabling precise logging and allowing you to clear logs.</span>")
log_game("[key_name(user)] emagged [src] at [AREACOORD(src)], disabling operator tracking.")
obj_flags |= EMAGGED
playsound(src, "sparks", 50, 1)
return TRUE
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
log_game("[key_name(user)] emagged [src] at [AREACOORD(src)]")
playsound(src, "sparks", 50, TRUE)
/obj/machinery/computer/apc_control/proc/log_activity(log_text)
var/op_string = operator && !(obj_flags & EMAGGED) ? operator : "\[NULL OPERATOR\]"
LAZYADD(logs, "<b>([STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)])</b> [op_string] [log_text]")
if(!should_log)
return
LAZYADD(logs, "([STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]): [auth_id] [log_text]")
/obj/machinery/computer/apc_control/proc/restore_comp()
obj_flags &= ~EMAGGED
should_log = TRUE
log_game("[key_name(operator)] restored the logs of [src] in [AREACOORD(src)]")
log_activity("-=- Logging restored to full functionality at this point -=-")
restoring = FALSE
/mob/proc/using_power_flow_console()
for(var/obj/machinery/computer/apc_control/A in range(1, src))
+17 -3
View File
@@ -42,9 +42,9 @@
/obj/item/clothing/mask/facehugger/toy = ARCADE_WEIGHT_RARE,
/obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = ARCADE_WEIGHT_TRICK,
/obj/item/hot_potato/harmless/toy = ARCADE_WEIGHT_RARE,
/obj/item/twohanded/dualsaber/toy = ARCADE_WEIGHT_RARE,
/obj/item/twohanded/dualsaber/hypereutactic/toy = ARCADE_WEIGHT_RARE,
/obj/item/twohanded/dualsaber/hypereutactic/toy/rainbow = ARCADE_WEIGHT_RARE,
/obj/item/dualsaber/toy = ARCADE_WEIGHT_RARE,
/obj/item/dualsaber/hypereutactic/toy = ARCADE_WEIGHT_RARE,
/obj/item/dualsaber/hypereutactic/toy/rainbow = ARCADE_WEIGHT_RARE,
/obj/item/storage/box/snappops = ARCADE_WEIGHT_TRICK,
/obj/item/clothing/under/syndicate/tacticool = ARCADE_WEIGHT_TRICK,
@@ -136,3 +136,17 @@
empprize = pickweight(prizes)
new empprize(loc)
explosion(loc, -1, 0, 1+num_of_prizes, flame_range = 1+num_of_prizes)
/obj/machinery/computer/arcade/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/stack/arcadeticket))
var/obj/item/stack/arcadeticket/T = O
var/amount = T.get_amount()
if(amount <2)
to_chat(user, "<span class='warning'>You need 2 tickets to claim a prize!</span>")
return
prizevend(user)
T.pay_tickets()
T.update_icon()
O = T
to_chat(user, "<span class='notice'>You turn in 2 tickets to the [src] and claim a prize!</span>")
return
@@ -184,6 +184,15 @@
blocked = FALSE
return
/obj/machinery/computer/arcade/battle/examine_more(mob/user)
to_chat(user, "<span class='notice'>Scribbled on the side of the Arcade Machine you notice some writing...\
\nmagical -> >=50 power\
\nsmart -> defend, defend, light attack\
\nshotgun -> defend, defend, power attack\
\nshort temper -> counter, counter, counter\
\npoisonous -> light attack, light attack, light attack\
\nchonker -> power attack, power attack, power attack</span>")
return ..()
/obj/machinery/computer/arcade/battle/emag_act(mob/user)
. = ..()
@@ -8,7 +8,7 @@
icon_state = "arcade"
circuit = /obj/item/circuitboard/computer/arcade/amputation
/obj/machinery/computer/arcade/amputation/attack_hand(mob/user)
/obj/machinery/computer/arcade/amputation/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!iscarbon(user))
return
var/mob/living/carbon/c_user = user
@@ -28,4 +28,4 @@
for(var/i=1; i<=rand(3,5); i++)
prizevend(user)
else
to_chat(c_user, "<span class='notice'>You (wisely) decide against putting your hand in the machine.</span>")
to_chat(c_user, "<span class='notice'>You (wisely) decide against putting your hand in the machine.</span>")
+5 -6
View File
@@ -19,11 +19,10 @@
SSradio.remove_object(src, receive_frequency)
return ..()
/obj/machinery/computer/atmos_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/atmos_alert/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "atmos_alert", name, 350, 300, master_ui, state)
ui = new(user, src, "AtmosAlertConsole", name)
ui.open()
/obj/machinery/computer/atmos_alert/ui_data(mob/user)
@@ -45,11 +44,11 @@
if("clear")
var/zone = params["zone"]
if(zone in priority_alarms)
to_chat(usr, "Priority alarm for [zone] cleared.")
to_chat(usr, "<span class='notice'>Priority alarm for [zone] cleared.</span>")
priority_alarms -= zone
. = TRUE
if(zone in minor_alarms)
to_chat(usr, "Minor alarm for [zone] cleared.")
to_chat(usr, "<span class='notice'>Minor alarm for [zone] cleared.</span>")
minor_alarms -= zone
. = TRUE
update_icon()
+6 -16
View File
@@ -53,14 +53,14 @@
"id_tag" = id_tag,
"timestamp" = world.time,
"pressure" = air_sample.return_pressure(),
"temperature" = air_sample.temperature,
"temperature" = air_sample.return_temperature(),
"gases" = list()
))
var/total_moles = air_sample.total_moles()
if(total_moles)
for(var/gas_id in air_sample.gases)
for(var/gas_id in air_sample.get_gases())
var/gas_name = GLOB.meta_gas_names[gas_id]
signal.data["gases"][gas_name] = air_sample.gases[gas_id] / total_moles * 100
signal.data["gases"][gas_name] = air_sample.get_moles(gas_id) / total_moles * 100
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
@@ -91,8 +91,6 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers)
icon_screen = "tank"
icon_keyboard = "atmos_key"
circuit = /obj/item/circuitboard/computer/atmos_control
ui_x = 400
ui_y = 925
var/frequency = FREQ_ATMOS_STORAGE
var/list/sensors = list(
@@ -123,11 +121,10 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers)
SSradio.remove_object(src, frequency)
return ..()
/obj/machinery/computer/atmos_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/atmos_control/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "atmos_control", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "AtmosControlConsole", name)
ui.open()
/obj/machinery/computer/atmos_control/ui_data(mob/user)
@@ -265,13 +262,6 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers)
for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in devices)
U.broadcast_status()
/obj/machinery/computer/atmos_control/tank/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_control", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/computer/atmos_control/tank/ui_data(mob/user)
var/list/data = ..()
data["tank"] = TRUE
+169 -93
View File
@@ -4,109 +4,163 @@
icon_screen = "cameras"
icon_keyboard = "security_key"
circuit = /obj/item/circuitboard/computer/security
var/last_pic = 1
var/list/network = list("ss13")
var/list/watchers = list() //who's using the console, associated with the camera they're on.
light_color = LIGHT_COLOR_RED
var/list/network = list("ss13")
var/obj/machinery/camera/active_camera
var/list/concurrent_users = list()
// Stuff needed to render the map
var/map_name
var/const/default_map_size = 15
var/obj/screen/cam_screen
var/obj/screen/plane_master/lighting/cam_plane_master
var/obj/screen/background/cam_background
/obj/machinery/computer/security/Initialize()
. = ..()
// Map name has to start and end with an A-Z character,
// and definitely NOT with a square bracket or even a number.
// I wasted 6 hours on this. :agony:
map_name = "camera_console_[REF(src)]_map"
// Convert networks to lowercase
for(var/i in network)
network -= i
network += lowertext(i)
/obj/machinery/computer/security/check_eye(mob/user)
if(!can_interact(user) || !(user in watchers) || !watchers[user])
user.unset_machine()
return
var/obj/machinery/camera/C = watchers[user]
if(!C.can_use())
user.unset_machine()
return
/obj/machinery/computer/security/on_unset_machine(mob/user)
watchers.Remove(user)
user.reset_perspective(null)
// Initialize map objects
cam_screen = new
cam_screen.name = "screen"
cam_screen.assigned_map = map_name
cam_screen.del_on_map_removal = FALSE
cam_screen.screen_loc = "[map_name]:1,1"
cam_plane_master = new
cam_plane_master.name = "plane_master"
cam_plane_master.assigned_map = map_name
cam_plane_master.del_on_map_removal = FALSE
cam_plane_master.screen_loc = "[map_name]:CENTER"
cam_background = new
cam_background.assigned_map = map_name
cam_background.del_on_map_removal = FALSE
/obj/machinery/computer/security/Destroy()
if(watchers.len)
for(var/mob/M in watchers)
M.unset_machine() //to properly reset the view of the users if the console is deleted.
qdel(cam_screen)
qdel(cam_plane_master)
qdel(cam_background)
return ..()
/obj/machinery/computer/security/can_interact(mob/user)
if((!hasSiliconAccessInArea(user) && !Adjacent(user)) || is_blind(user) || !in_view_range(user, src))
return FALSE
return ..()
/obj/machinery/computer/security/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
for(var/i in network)
network -= i
network += "[idnum][i]"
/obj/machinery/computer/security/interact(mob/user, special_state)
/obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui)
// Update UI
ui = SStgui.try_update_ui(user, src, ui)
// Show static if can't use the camera
if(!active_camera?.can_use())
show_camera_static()
if(!ui)
var/user_ref = REF(user)
var/is_living = isliving(user)
// Ghosts shouldn't count towards concurrent users, which produces
// an audible terminal_on click.
if(is_living)
concurrent_users += user_ref
// Turn on the console
if(length(concurrent_users) == 1 && is_living)
playsound(src, 'sound/machines/terminal_on.ogg', 25, FALSE)
use_power(active_power_usage)
// Register map objects
user.client.register_map_obj(cam_screen)
for(var/plane in cam_plane_master)
user.client.register_map_obj(plane)
user.client.register_map_obj(cam_background)
// Open UI
ui = new(user, src, "CameraConsole", name)
ui.open()
/obj/machinery/computer/security/ui_data()
var/list/data = list()
data["network"] = network
data["activeCamera"] = null
if(active_camera)
data["activeCamera"] = list(
name = active_camera.c_tag,
status = active_camera.status,
)
return data
/obj/machinery/computer/security/ui_static_data()
var/list/data = list()
data["mapRef"] = map_name
var/list/cameras = get_available_cameras()
data["cameras"] = list()
for(var/i in cameras)
var/obj/machinery/camera/C = cameras[i]
data["cameras"] += list(list(
name = C.c_tag,
))
return data
/obj/machinery/computer/security/ui_act(action, params)
. = ..()
if (ismob(user) && !isliving(user)) // ghosts don't need cameras
return
if (!network)
stack_trace("No camera network")
user.unset_machine()
return FALSE
if (!(islist(network)))
stack_trace("Camera network is not a list")
user.unset_machine()
return FALSE
var/list/camera_list = get_available_cameras()
if(!(user in watchers))
for(var/Num in camera_list)
var/obj/machinery/camera/CAM = camera_list[Num]
if(istype(CAM) && CAM.can_use())
watchers[user] = CAM //let's give the user the first usable camera, and then let him change to the camera he wants.
break
if(!(user in watchers))
user.unset_machine() // no usable camera on the network, we disconnect the user from the computer.
return FALSE
playsound(src, 'sound/machines/terminal_prompt.ogg', 25, 0)
use_camera_console(user)
/obj/machinery/computer/security/proc/use_camera_console(mob/user)
var/list/camera_list = get_available_cameras()
var/t = input(user, "Which camera should you change to?") as null|anything in camera_list
if(!src || user.machine != src) //while we were choosing we got disconnected from our computer or are using another machine.
return
if(!t || t == "Cancel")
user.unset_machine()
playsound(src, 'sound/machines/terminal_off.ogg', 25, 0)
if(.)
return
var/obj/machinery/camera/C = camera_list[t]
if(action == "switch_camera")
var/c_tag = params["name"]
var/list/cameras = get_available_cameras()
var/obj/machinery/camera/C = cameras[c_tag]
active_camera = C
playsound(src, get_sfx("terminal_type"), 25, FALSE)
if(!C || !C.can_use() || !can_interact(user))
user.unset_machine()
return FALSE
// Show static if can't use the camera
if(!active_camera?.can_use())
show_camera_static()
return TRUE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0)
if(isAI(user))
var/mob/living/silicon/ai/A = user
A.eyeobj.setLoc(get_turf(C))
A.client.eye = A.eyeobj
else
user.reset_perspective(C)
user.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static)
user.clear_fullscreen("flash", 5)
watchers[user] = C
use_power(50)
addtimer(CALLBACK(src, .proc/use_camera_console, user), 5)
var/list/visible_turfs = list()
for(var/turf/T in (C.isXRay() \
? range(C.view_range, C) \
: view(C.view_range, C)))
visible_turfs += T
//returns the list of cameras accessible from this computer
var/list/bbox = get_bbox_of_atoms(visible_turfs)
var/size_x = bbox[3] - bbox[1] + 1
var/size_y = bbox[4] - bbox[2] + 1
cam_screen.vis_contents = visible_turfs
cam_background.icon_state = "clear"
cam_background.fill_rect(1, 1, size_x, size_y)
return TRUE
/obj/machinery/computer/security/ui_close(mob/user)
var/user_ref = REF(user)
var/is_living = isliving(user)
// Living creature or not, we remove you anyway.
concurrent_users -= user_ref
// Unregister map objects
user.client.clear_map(map_name)
// Turn off the console
if(length(concurrent_users) == 0 && is_living)
active_camera = null
playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE)
use_power(0)
/obj/machinery/computer/security/proc/show_camera_static()
cam_screen.vis_contents.Cut()
cam_background.icon_state = "scanline2"
cam_background.fill_rect(1, 1, default_map_size, default_map_size)
// Returns the list of cameras accessible from this computer
/obj/machinery/computer/security/proc/get_available_cameras()
var/list/L = list()
for (var/obj/machinery/camera/C in GLOB.cameranet.cameras)
if((is_away_level(z) || is_away_level(C.z)) && (C.z != z))//if on away mission, can only receive feed from same z_level cameras
continue
L.Add(C)
camera_sort(L)
var/list/D = list()
D["Cancel"] = "Cancel"
for(var/obj/machinery/camera/C in L)
if(!C.network)
stack_trace("Camera in a cameranet has no camera network")
@@ -114,9 +168,9 @@
if(!(islist(C.network)))
stack_trace("Camera in a cameranet has a non-list camera network")
continue
var/list/tempnetwork = C.network&network
var/list/tempnetwork = C.network & network
if(tempnetwork.len)
D["[C.c_tag][(C.status ? null : " (Deactivated)")]"] = C
D["[C.c_tag]"] = C
return D
// SECURITY MONITORS
@@ -127,7 +181,6 @@
icon_state = "television"
icon_keyboard = null
icon_screen = "detective_tv"
clockwork = TRUE //it'd look weird
pass_flags = PASSTABLE
/obj/machinery/computer/security/mining
@@ -145,7 +198,7 @@
circuit = /obj/item/circuitboard/computer/research
/obj/machinery/computer/security/hos
name = "Head of Security's camera console"
name = "\improper Head of Security's camera console"
desc = "A custom security console with added access to the labor camp network."
network = list("ss13", "labor")
circuit = null
@@ -157,7 +210,7 @@
circuit = null
/obj/machinery/computer/security/qm
name = "Quartermaster's camera console"
name = "\improper Quartermaster's camera console"
desc = "A console with access to the mining, auxillary base and vault camera networks."
network = list("mine", "auxbase", "vault")
circuit = null
@@ -172,7 +225,6 @@
network = list("thunder")
density = FALSE
circuit = null
clockwork = TRUE //it'd look very weird
light_power = 0
/obj/machinery/computer/security/telescreen/Initialize()
@@ -190,11 +242,35 @@
name = "entertainment monitor"
desc = "Damn, they better have the /tg/ channel on these things."
icon = 'icons/obj/status_display.dmi'
icon_state = "entertainment"
icon_state = "entertainment_blank"
network = list("thunder")
density = FALSE
circuit = null
interaction_flags_atom = NONE // interact() is called by BigClick()
var/icon_state_off = "entertainment_blank"
var/icon_state_on = "entertainment"
/obj/machinery/computer/security/telescreen/entertainment/Initialize()
. = ..()
RegisterSignal(src, COMSIG_CLICK, .proc/BigClick)
// Bypass clickchain to allow humans to use the telescreen from a distance
/obj/machinery/computer/security/telescreen/entertainment/proc/BigClick()
interact(usr)
/obj/machinery/computer/security/telescreen/entertainment/proc/notify(on)
if(on && icon_state == icon_state_off)
say(pick(
"Feats of bravery live now at the thunderdome!",
"Two enter, one leaves! Tune in now!",
"Violence like you've never seen it before!",
"Spears! Camera! Action! LIVE NOW!"))
icon_state = icon_state_on
else
icon_state = icon_state_off
/obj/machinery/computer/security/telescreen/rd
name = "Research Director's telescreen"
name = "\improper Research Director's telescreen"
desc = "Used for watching the AI and the RD's goons from the safety of his office."
network = list("rd", "aicore", "aiupload", "minisat", "xeno", "test")
@@ -202,26 +278,26 @@
name = "circuitry telescreen"
desc = "Used for watching the other eggheads from the safety of the circuitry lab."
network = list("rd")
/obj/machinery/computer/security/telescreen/ce
name = "Chief Engineer's telescreen"
name = "\improper Chief Engineer's telescreen"
desc = "Used for watching the engine, telecommunications and the minisat."
network = list("engine", "singularity", "tcomms", "minisat")
/obj/machinery/computer/security/telescreen/cmo
name = "Chief Medical Officer's telescreen"
name = "\improper Chief Medical Officer's telescreen"
desc = "A telescreen with access to the medbay's camera network."
network = list("medbay")
/obj/machinery/computer/security/telescreen/vault
name = "Vault monitor"
name = "vault monitor"
desc = "A telescreen that connects to the vault's camera network."
network = list("vault")
/obj/machinery/computer/security/telescreen/toxins
name = "Bomb test site monitor"
name = "bomb test site monitor"
desc = "A telescreen that connects to the bomb test site's camera."
network = list("toxin")
network = list("toxins")
/obj/machinery/computer/security/telescreen/engine
name = "engine monitor"
@@ -254,7 +330,7 @@
network = list("minisat")
/obj/machinery/computer/security/telescreen/aiupload
name = "AI upload monitor"
name = "\improper AI upload monitor"
desc = "A telescreen that connects to the AI upload's camera network."
network = list("aiupload")
+10 -113
View File
@@ -29,9 +29,17 @@
if(lock_override & CAMERA_LOCK_REEBE)
z_lock |= SSmapping.levels_by_trait(ZTRAIT_REEBE)
/obj/machinery/computer/camera_advanced/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
for(var/i in networks)
networks -= i
networks += "[idnum][i]"
/obj/machinery/computer/camera_advanced/syndie
icon_keyboard = "syndie_key"
/obj/machinery/computer/camera_advanced/syndie/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
return //For syndie nuke shuttle, to spy for station.
/obj/machinery/computer/camera_advanced/proc/CreateEye()
eyeobj = new()
eyeobj.origin = src
@@ -95,10 +103,7 @@
return FALSE
return ..()
/obj/machinery/computer/camera_advanced/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/computer/camera_advanced/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(current_user)
to_chat(user, "The console is already in use!")
return
@@ -268,112 +273,4 @@
C.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/static)
C.clear_fullscreen("flash", 3) //Shorter flash than normal since it's an ~~advanced~~ console!
else
playsound(origin, 'sound/machines/terminal_prompt_deny.ogg', 25, 0)
//Used by servants of Ratvar! They let you beam to the station.
/obj/machinery/computer/camera_advanced/ratvar
name = "ratvarian camera observer"
desc = "A console used to snoop on the station's goings-on. A jet of steam occasionally whooshes out from slats on its sides."
use_power = FALSE
networks = list("ss13", "minisat") //:eye:
var/datum/action/innate/servant_warp/warp_action = new
/obj/machinery/computer/camera_advanced/ratvar/Initialize()
. = ..()
ratvar_act()
/obj/machinery/computer/camera_advanced/ratvar/process()
if(prob(1))
playsound(src, 'sound/machines/clockcult/steam_whoosh.ogg', 25, TRUE)
new/obj/effect/temp_visual/steam_release(get_turf(src))
/obj/machinery/computer/camera_advanced/ratvar/CreateEye()
..()
eyeobj.visible_icon = TRUE
eyeobj.icon = 'icons/mob/cameramob.dmi' //in case you still had any doubts
eyeobj.icon_state = "generic_camera"
/obj/machinery/computer/camera_advanced/ratvar/GrantActions(mob/living/carbon/user)
..()
if(warp_action)
warp_action.Grant(user)
warp_action.target = src
actions += warp_action
/obj/machinery/computer/camera_advanced/ratvar/can_use(mob/living/user)
if(!is_servant_of_ratvar(user))
to_chat(user, "<span class='warning'>[src]'s keys are in a language foreign to you, and you don't understand anything on its screen.</span>")
return
if(clockwork_ark_active())
to_chat(user, "<span class='warning'>The Ark is active, and [src] has shut down.</span>")
return
. = ..()
/datum/action/innate/servant_warp
name = "Warp"
desc = "Warps to the tile you're viewing. You can use the Abscond scripture to return. Clicking this button again cancels the warp."
icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
button_icon_state = "warp_down"
background_icon_state = "bg_clock"
buttontooltipstyle = "clockcult"
var/cancel = FALSE //if TRUE, an active warp will be canceled
var/obj/effect/temp_visual/ratvar/warp_marker/warping
/datum/action/innate/servant_warp/Activate()
if(QDELETED(target) || !(ishuman(owner) || iscyborg(owner)) || !owner.canUseTopic(target))
return
if(!GLOB.servants_active) //No leaving unless there's servants from the get-go
return
if(warping)
cancel = TRUE
return
var/mob/living/carbon/human/user = owner
var/mob/camera/aiEye/remote/remote_eye = user.remote_control
var/obj/machinery/computer/camera_advanced/ratvar/R = target
var/turf/T = get_turf(remote_eye)
if(!is_reebe(user.z) || !is_station_level(T.z))
return
if(isclosedturf(T))
to_chat(user, "<span class='sevtug_small'>You can't teleport into a wall.</span>")
return
else if(isspaceturf(T))
to_chat(user, "<span class='sevtug_small'>[prob(1) ? "Servant cannot into space." : "You can't teleport into space."]</span>")
return
else if(T.flags_1 & NOJAUNT_1)
to_chat(user, "<span class='sevtug_small'>This tile is blessed by holy water and deflects the warp.</span>")
return
var/area/AR = get_area(T)
if(!AR.clockwork_warp_allowed)
to_chat(user, "<span class='sevtug_small'>[AR.clockwork_warp_fail]</span>")
return
if(alert(user, "Are you sure you want to warp to [AR]?", target.name, "Warp", "Cancel") == "Cancel" || QDELETED(R) || !user.canUseTopic(R))
return
do_sparks(5, TRUE, user)
do_sparks(5, TRUE, T)
warping = new(T)
user.visible_message("<span class='warning'>[user]'s [target.name] flares!</span>", "<span class='bold sevtug_small'>You begin warping to [AR]...</span>")
button_icon_state = "warp_cancel"
owner.update_action_buttons()
if(!do_after(user, 50, target = warping, extra_checks = CALLBACK(src, .proc/is_canceled)))
to_chat(user, "<span class='bold sevtug_small'>Warp interrupted.</span>")
QDEL_NULL(warping)
button_icon_state = "warp_down"
owner.update_action_buttons()
cancel = FALSE
return
button_icon_state = "warp_down"
owner.update_action_buttons()
QDEL_NULL(warping)
if(!do_teleport(user, T, channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
to_chat(user, "<span class='bold sevtug_small'>Warp Failed. Something deflected our attempt to warp to [AR].</span>")
return
T.visible_message("<span class='warning'>[user] warps in!</span>")
playsound(user, 'sound/magic/magic_missile.ogg', 50, TRUE)
playsound(T, 'sound/magic/magic_missile.ogg', 50, TRUE)
user.setDir(SOUTH)
flash_color(user, flash_color = "#AF0AAF", flash_time = 5)
R.remove_eye_control(user)
/datum/action/innate/servant_warp/proc/is_canceled()
return !cancel
playsound(origin, 'sound/machines/terminal_prompt_deny.ogg', 25, 0)
+179 -92
View File
@@ -8,6 +8,7 @@
circuit = /obj/item/circuitboard/computer/cloning
req_access = list(ACCESS_HEADS) //ONLY USED FOR RECORD DELETION RIGHT NOW.
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/clonepod_type = /obj/machinery/clonepod
var/list/pods //Linked cloning pods
var/temp = "Inactive"
var/scantemp_ckey
@@ -17,6 +18,7 @@
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
var/loading = 0 // Nice loading text
var/autoprocess = 0
var/use_records = TRUE // Old experimental cloner.
var/list/records = list()
light_color = LIGHT_COLOR_BLUE
@@ -36,29 +38,32 @@
return ..()
/obj/machinery/computer/cloning/proc/GetAvailablePod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
if(!pods)
return
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.get_clone_mind == CLONEPOD_GET_MIND && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
/obj/machinery/computer/cloning/proc/HasEfficientPod()
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.is_operational() && pod.efficiency > 5)
return TRUE
if(!pods)
return
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.is_operational() && pod.efficiency > 5)
return TRUE
/obj/machinery/computer/cloning/proc/GetAvailableEfficientPod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return pod
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
if(!pods)
return
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return pod
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
/obj/machinery/computer/cloning/process()
if(!(scanner && LAZYLEN(pods) && autoprocess))
@@ -73,7 +78,7 @@
if(pod.occupant)
continue //how though?
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], R.fields["bank_account"]))
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["blood_type"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], R.fields["bank_account"], R.fields["traumas"]))
temp = "[R.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
records -= R
@@ -103,12 +108,10 @@
return null
/obj/machinery/computer/cloning/proc/findcloner()
var/obj/machinery/clonepod/podf = null
var/obj/machinery/clonepod/podf
for(var/direction in GLOB.cardinals)
podf = locate(/obj/machinery/clonepod, get_step(src, direction))
if (!isnull(podf) && podf.is_operational())
podf = locate(clonepod_type, get_step(src, direction))
if(podf?.is_operational())
AttachCloner(podf)
/obj/machinery/computer/cloning/proc/AttachCloner(obj/machinery/clonepod/pod)
@@ -132,7 +135,7 @@
else if(istype(W, /obj/item/multitool))
var/obj/item/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod))
if(istype(P.buffer, clonepod_type))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
@@ -157,13 +160,14 @@
var/dat = ""
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
if(!autoprocess)
dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>"
if(use_records)
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
if(!autoprocess)
dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>"
else
dat += "<a href='byond://?src=[REF(src)];task=stopautoprocess'>Stop autoclone</a>"
else
dat += "<a href='byond://?src=[REF(src)];task=stopautoprocess'>Stop autoclone</a>"
else
dat += "<span class='linkOff'>Autoclone</span>"
dat += "<span class='linkOff'>Autoclone</span>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
@@ -190,26 +194,29 @@
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
if(use_records)
if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
else
scantemp = "Ready to Clone"
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=[REF(src)];scan=1'>Start Scan</a>"
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
dat += "<a href='byond://?src=[REF(src)];scan=1'>[use_records ? "Start Scan" : "Clone"]</a>"
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>Start Scan</span>"
// Database
dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0)
dat += "<a href='byond://?src=[REF(src)];menu=2'>View Records ([src.records.len])</a><br>"
else
dat += "<span class='linkOff'>View Records (0)</span><br>"
if (src.diskette)
dat += "<a href='byond://?src=[REF(src)];disk=eject'>Eject Disk</a><br>"
dat += "<span class='linkOff'>[use_records ? "Start Scan" : "Clone"]</span>"
if(use_records)
// Database
dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0)
dat += "<a href='byond://?src=[REF(src)];menu=2'>View Records ([src.records.len])</a><br>"
else
dat += "<span class='linkOff'>View Records (0)</span><br>"
if (src.diskette)
dat += "<a href='byond://?src=[REF(src)];disk=eject'>Eject Disk</a><br>"
@@ -290,24 +297,19 @@
autoprocess = FALSE
STOP_PROCESSING(SSmachines, src)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = 1
loading = TRUE
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
var/prev_locked = scanner.locked
scanner.locked = TRUE
spawn(20)
src.scan_occupant(scanner.occupant)
loading = 0
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
scanner.locked = prev_locked
addtimer(CALLBACK(src, .proc/finish_scan, scanner.occupant, prev_locked), 2 SECONDS)
. = TRUE
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
@@ -317,8 +319,17 @@
else
scanner.locked = FALSE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
. = TRUE
else if(href_list["view_rec"])
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
. = TRUE
if(. || !use_records)
return
if(href_list["view_rec"])
playsound(src, "terminal_type", 25, 0)
src.active_record = find_record("id", href_list["view_rec"], records)
if(active_record)
@@ -330,6 +341,7 @@
src.menu = 3
else
src.temp = "Record missing."
. = TRUE
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
@@ -353,8 +365,9 @@
else
src.temp = "<font class='bad'>Access Denied.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if (href_list["disk"]) //Load or eject.
else if (href_list["disk"] && use_records) //Load or eject.
switch(href_list["disk"])
if("load")
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
@@ -392,10 +405,7 @@
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
src.temp = "Save successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
. = TRUE
else if (href_list["clone"])
var/datum/data/record/C = find_record("id", href_list["clone"], records)
@@ -415,7 +425,7 @@
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"]))
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["blood_type"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"], C.fields["traumas"]))
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
@@ -429,53 +439,49 @@
else
temp = "<font class='bad'>Data corruption.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if (href_list["menu"])
src.menu = text2num(href_list["menu"])
else if (href_list["menu"] && use_records)
menu = text2num(href_list["menu"])
playsound(src, "terminal_type", 25, 0)
. = TRUE
/obj/machinery/computer/cloning/proc/finish_scan(mob/living/L, prev_locked)
if(!scanner || !L)
return
src.add_fingerprint(usr)
src.updateUsrDialog()
return
if(use_records)
scan_occupant(L)
else
clone_occupant(L)
loading = FALSE
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
scanner.locked = prev_locked
/obj/machinery/computer/cloning/proc/scan_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
var/datum/bank_account/has_bank_account
// Do not use unless you know what they are.
var/mob/living/carbon/C = mob_occupant
var/mob/living/brain/B = mob_occupant
if(ishuman(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
var/obj/item/card/id/I = C.get_idcard()
if(I)
has_bank_account = I.registered_account
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if ((!mob_occupant.ckey) || (!mob_occupant.client))
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(SSeconomy.full_ancap && !has_bank_account)
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
if(!can_scan(dna, mob_occupant, FALSE, has_bank_account))
return
var/datum/data/record/R = new()
if(dna.species)
// We store the instance rather than the path, because some
@@ -497,11 +503,17 @@
R.fields["features"] = dna.features
R.fields["factions"] = mob_occupant.faction
R.fields["quirks"] = list()
R.fields["bank_account"] = has_bank_account
for(var/V in mob_occupant.roundstart_quirks)
var/datum/quirk/T = V
R.fields["quirks"][T.type] = T.clone_data()
R.fields["traumas"] = list()
if(ishuman(mob_occupant))
R.fields["traumas"] = C.get_traumas()
if(isbrain(mob_occupant))
R.fields["traumas"] = B.get_traumas()
R.fields["bank_account"] = has_bank_account
if (!isnull(mob_occupant.mind)) //Save that mind so traitors can continue traitoring after cloning.
R.fields["mind"] = "[REF(mob_occupant.mind)]"
@@ -520,3 +532,78 @@
board.records = records
scantemp = "Subject successfully scanned."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//Used by the experimental cloning computer.
/obj/machinery/computer/cloning/proc/clone_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(ishuman(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!can_scan(dna, mob_occupant, TRUE))
return
var/clone_species
if(dna.species)
clone_species = dna.species
else
var/datum/species/rando_race = pick(GLOB.roundstart_races)
clone_species = rando_race.type
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
/obj/machinery/computer/cloning/proc/can_scan(datum/dna/dna, mob/living/mob_occupant, experimental = FALSE, datum/bank_account/account)
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(!experimental)
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if (!experimental)
if(!mob_occupant.ckey || !mob_occupant.client)
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(SSeconomy.full_ancap && !account)
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
return TRUE
//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks.
/obj/machinery/computer/cloning/prototype
name = "prototype cloning console"
desc = "Used to operate an experimental cloner."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/cloning/prototype
clonepod_type = /obj/machinery/clonepod/experimental
+36 -40
View File
@@ -61,7 +61,7 @@
// main interface
if("main")
state = STATE_DEFAULT
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
if("login")
var/mob/M = usr
@@ -73,19 +73,19 @@
auth_id = "[I.registered_name] ([I.assignment])"
if((ACCESS_CAPTAIN in I.access))
authenticated = 2
playsound(src, 'sound/machines/terminal_on.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE)
if(obj_flags & EMAGGED)
authenticated = 2
auth_id = "Unknown"
to_chat(M, "<span class='warning'>[src] lets out a quiet alarm as its login is overridden.</span>")
playsound(src, 'sound/machines/terminal_on.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_alert.ogg', 25, 0)
playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE)
playsound(src, 'sound/machines/terminal_alert.ogg', 25, FALSE)
if(prob(25))
for(var/mob/living/silicon/ai/AI in active_ais())
SEND_SOUND(AI, sound('sound/machines/terminal_alert.ogg', volume = 10)) //Very quiet for balance reasons
if("logout")
authenticated = 0
playsound(src, 'sound/machines/terminal_off.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE)
if("swipeidseclevel")
var/mob/M = usr
@@ -109,7 +109,7 @@
security_level_cd = world.time + 15 SECONDS
if(GLOB.security_level != old_level)
to_chat(usr, "<span class='notice'>Authorization confirmed. Modifying security level.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
//Only notify people if an actual change happened
var/security_level = NUM2SECLEVEL(GLOB.security_level)
log_game("[key_name(usr)] has changed the security level to [security_level] with [src] at [AREACOORD(usr)].")
@@ -118,28 +118,28 @@
tmp_alertlevel = 0
else
to_chat(usr, "<span class='warning'>You are not authorized to do this!</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
tmp_alertlevel = 0
state = STATE_DEFAULT
else
to_chat(usr, "<span class='warning'>You need to swipe your ID!</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
if("announce")
if(authenticated==2)
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
make_announcement(usr)
if("crossserver")
if(authenticated==2)
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return
var/input = stripped_multiline_input(usr, "Please choose a message to transmit to allied stations. Please be aware that this process is very expensive, and abuse will lead to... termination.", "Send a message to an allied station.", "")
if(!input || !(usr in view(1,src)) || !checkCCcooldown())
return
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
send2otherserver("[station_name()]", input,"Comms_Console")
minor_announce(input, title = "Outgoing message to allied station")
usr.log_talk(input, LOG_SAY, tag="message to the other server")
@@ -168,22 +168,18 @@
if(D)
points_to_check = D.account_balance
if(points_to_check >= S.credit_cost)
var/obj/machinery/shuttle_manipulator/M = locate() in GLOB.machines
if(M)
SSshuttle.shuttle_purchased = TRUE
D.adjust_money(-S.credit_cost)
minor_announce("[usr.real_name] has purchased [S.name] for [S.credit_cost] credits." , "Shuttle Purchase")
message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [S.name].")
SSblackbox.record_feedback("text", "shuttle_purchase", 1, "[S.name]")
M.unload_preview()
M.load_template(S)
M.existing_shuttle = SSshuttle.emergency
M.action_load(S)
message_admins("[S.name] loaded, purchased by [usr]")
else
to_chat(usr, "Something went wrong! The shuttle exchange system seems to be down.")
SSshuttle.shuttle_purchased = TRUE
SSshuttle.unload_preview()
SSshuttle.load_template(S)
SSshuttle.existing_shuttle = SSshuttle.emergency
SSshuttle.action_load(S)
D.adjust_money(-S.credit_cost)
minor_announce("[usr.real_name] has purchased [S.name] for [S.credit_cost] credits." , "Shuttle Purchase")
message_admins("[ADMIN_LOOKUPFLW(usr)] purchased [S.name].")
log_shuttle("[key_name(usr)] has purchased [S.name].")
SSblackbox.record_feedback("text", "shuttle_purchase", 1, "[S.name]")
else
to_chat(usr, "Not enough credits.")
to_chat(usr, "<span class='alert'>Insufficient credits.</span>")
if("callshuttle")
state = STATE_DEFAULT
@@ -268,7 +264,7 @@
// Status display stuff
if("setstat")
playsound(src, "terminal_type", 50, 0)
playsound(src, "terminal_type", 50, FALSE)
switch(href_list["statdisp"])
if("message")
post_status("message", stat_msg1, stat_msg2)
@@ -308,13 +304,13 @@
if("MessageSyndicate")
if((authenticated==2) && (obj_flags & EMAGGED))
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return
var/input = stripped_input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING COORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "Send a message to /??????/.", "")
if(!input || !(usr in view(1,src)) || !checkCCcooldown())
return
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
Syndicate_announce(input, usr)
to_chat(usr, "<span class='danger'>SYSERR @l(19833)of(transmit.dm): !@$ MESSAGE TRANSMITTED TO SYNDICATE COMMAND.</span>")
for(var/client/X in GLOB.admins)
@@ -327,7 +323,7 @@
if("RestoreBackup")
to_chat(usr, "<span class='notice'>Backup routing data restored!</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
obj_flags &= ~EMAGGED
updateDialog()
@@ -341,7 +337,7 @@
return
Nuke_request(input, usr)
to_chat(usr, "<span class='notice'>Request sent.</span>")
usr.log_message("has requested the nuclear codes from CentCom", LOG_SAY)
usr.log_message("has requested the nuclear codes from CentCom with reason \"[input]\"", LOG_SAY)
priority_announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self Destruct Codes Requested","commandreport")
CM.lastTimeUsed = world.time
@@ -448,7 +444,7 @@
if(authenticated == 1)
authenticated = 2
to_chat(user, "<span class='danger'>You scramble the communication routing circuits!</span>")
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_alert.ogg', 50, FALSE)
return TRUE
/obj/machinery/computer/communications/ui_interact(mob/user)
@@ -514,16 +510,16 @@
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=login'>Log In</A> \]"
if(STATE_CALLSHUTTLE)
dat += get_call_shuttle_form()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
if(STATE_CANCELSHUTTLE)
dat += get_cancel_shuttle_form()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
if(STATE_MESSAGELIST)
dat += "Messages:"
for(var/i in 1 to messages.len)
var/datum/comm_message/M = messages[i]
dat += "<BR><A HREF='?src=[REF(src)];operation=viewmessage;message-num=[i]'>[M.title]</A>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
if(STATE_VIEWMESSAGE)
if (currmsg)
dat += "<B>[currmsg.title]</B><BR><BR>[currmsg.content]"
@@ -557,7 +553,7 @@
dat += " <A HREF='?src=[REF(src)];operation=setstat;statdisp=alert;alert=redalert'>Red Alert</A> |"
dat += " <A HREF='?src=[REF(src)];operation=setstat;statdisp=alert;alert=lockdown'>Lockdown</A> |"
dat += " <A HREF='?src=[REF(src)];operation=setstat;statdisp=alert;alert=biohazard'>Biohazard</A> \]<BR><HR>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
if(STATE_ALERT_LEVEL)
dat += "Current alert level: [NUM2SECLEVEL(GLOB.security_level)]<BR>"
if(GLOB.security_level == SEC_LEVEL_DELTA)
@@ -571,7 +567,7 @@
dat += "Confirm the change to: [NUM2SECLEVEL(tmp_alertlevel)]<BR>"
dat += "<A HREF='?src=[REF(src)];operation=swipeidseclevel'>Swipe ID</A> to confirm change.<BR>"
if(STATE_TOGGLE_EMERGENCY)
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, FALSE)
if(GLOB.emergency_access == 1)
dat += "<b>Emergency Maintenance Access is currently <font color='red'>ENABLED</font></b>"
dat += "<BR>Restore maintenance access restrictions? <BR>\[ <A HREF='?src=[REF(src)];operation=disableemergency'>OK</A> | <A HREF='?src=[REF(src)];operation=viewmessage'>Cancel</A> \]"
@@ -722,7 +718,7 @@
/obj/machinery/computer/communications/proc/make_announcement(mob/living/user, is_silicon)
if(!SScommunications.can_announce(user, is_silicon))
to_chat(user, "Intercomms recharging. Please stand by.")
to_chat(user, "<span class='alert'>Intercomms recharging. Please stand by.</span>")
return
var/input = stripped_input(user, "Please choose a message to announce to the station crew.", "What?")
if(!input || !user.canUseTopic(src))
+3 -4
View File
@@ -76,11 +76,10 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
/datum/crewmonitor/Destroy()
return ..()
/datum/crewmonitor/ui_interact(mob/user, ui_key = "crew", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/datum/crewmonitor/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, ui_key, "crew", "crew monitor", 800, 600 , master_ui, state)
ui = new(user, src, "CrewConsole")
ui.open()
/datum/crewmonitor/proc/show(mob/M, source)
File diff suppressed because it is too large Load Diff
@@ -53,10 +53,10 @@
var/obj/machinery/launchpad/pad = launchpads[number]
return pad
/obj/machinery/computer/launchpad/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/launchpad/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "launchpad_console", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "LaunchpadConsole", name)
ui.open()
/obj/machinery/computer/launchpad/ui_data(mob/user)
@@ -128,4 +128,4 @@
if("pull")
teleport(usr, current_pad, FALSE)
. = TRUE
. = TRUE
. = TRUE
@@ -6,8 +6,6 @@
icon_keyboard = "security_key"
req_access = list(ACCESS_ARMORY)
circuit = /obj/item/circuitboard/computer/gulag_teleporter_console
ui_x = 350
ui_y = 295
var/default_goal = 200
var/obj/machinery/gulag_teleporter/teleporter = null
@@ -21,11 +19,10 @@
. = ..()
scan_machinery()
/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "gulag_console", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "GulagTeleporterConsole", name)
ui.open()
/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_data(mob/user)
+86 -127
View File
@@ -5,163 +5,122 @@
icon_keyboard = "rd_key"
req_access = list(ACCESS_ROBOTICS)
circuit = /obj/item/circuitboard/computer/robotics
var/temp = null
light_color = LIGHT_COLOR_PINK
ui_x = 500
ui_y = 460
/obj/machinery/computer/robotics/proc/can_control(mob/user, mob/living/silicon/robot/R)
. = FALSE
if(!istype(R))
return FALSE
return
if(isAI(user))
if (R.connected_ai != user)
return FALSE
if(R.connected_ai != user)
return
if(iscyborg(user))
if (R != user)
return FALSE
if(R != user)
return
if(R.scrambledcodes)
return FALSE
if (hasSiliconAccessInArea(user) && !issilicon(user))
if (!Adjacent(user))
return FALSE
return
return TRUE
/obj/machinery/computer/robotics/ui_interact(mob/user)
. = ..()
if (src.z > 6)
to_chat(user, "<span class='boldannounce'>Unable to establish a connection</span>: \black You're too far away from the station!")
return
user.set_machine(src)
var/dat
var/robots = 0
/obj/machinery/computer/robotics/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "RoboticsControlConsole", name)
ui.open()
/obj/machinery/computer/robotics/ui_data(mob/user)
var/list/data = list()
data["can_hack"] = FALSE
if(issilicon(user))
var/mob/living/silicon/S = user
if(S.hack_software)
data["can_hack"] = TRUE
else if(IsAdminGhost(user))
data["can_hack"] = TRUE
data["cyborgs"] = list()
for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs)
if(!can_control(user, R))
continue
robots++
dat += "[R.name] |"
if(R.stat)
dat += " Not Responding |"
else if(R.locked_down)
dat += " Locked Down |"
else
dat += " Operating Normally |"
if(R.cell)
dat += " Battery Installed ([R.cell.charge]/[R.cell.maxcharge]) |"
else
dat += " No Cell Installed |"
if(R.module)
dat += " Module Installed ([R.module.name]) |"
else
dat += " No Module Installed |"
if(R.connected_ai)
dat += " Slaved to [R.connected_ai.name] |"
else
dat += " Independent from AI |"
if(issilicon(user) && user != R)
var/mob/living/silicon/S = user
if(is_servant_of_ratvar(S))
dat += "<A href='?src=[REF(src)];convert=[REF(R)]'>(<font color=#BE8700><i>Convert</i></font>)</A> "
else if(S.hack_software && !R.emagged)
dat += "<A href='?src=[REF(src)];magbot=[REF(R)]'>(<font color=blue><i>Hack</i></font>)</A> "
else if(IsAdminGhost(user) && !R.emagged)
dat += "<A href='?src=[REF(src)];magbot=[REF(R)]'>(<font color=blue><i>Hack</i></font>)</A> "
dat += "<A href='?src=[REF(src)];stopbot=[REF(R)]'>(<font color=green><i>[R.locked_down? "Lockdown" : "Release"]</i></font>)</A> "
dat += "<A href='?src=[REF(src)];killbot=[REF(R)]'>(<font color=red><i>Destroy</i></font>)</A>"
dat += "<BR>"
if(z != (get_turf(R)).z)
continue
var/list/cyborg_data = list(
name = R.name,
locked_down = R.locked_down,
status = R.stat,
charge = R.cell ? round(R.cell.percent()) : null,
module = R.module ? "[R.module.name] Module" : "No Module Detected",
synchronization = R.connected_ai,
emagged = R.emagged,
ref = REF(R)
)
data["cyborgs"] += list(cyborg_data)
if(!robots)
dat += "No Cyborg Units detected within access parameters."
dat += "<BR>"
var/drones = 0
data["drones"] = list()
for(var/mob/living/simple_animal/drone/D in GLOB.drones_list)
if(D.hacked)
continue
drones++
dat += "[D.name] |"
if(D.stat)
dat += " Not Responding |"
dat += "<A href='?src=[REF(src)];killdrone=[REF(D)]'>(<font color=red><i>Destroy</i></font>)</A>"
dat += "<BR>"
if(z != (get_turf(D)).z)
continue
var/list/drone_data = list(
name = D.name,
status = D.stat,
ref = REF(D)
)
data["drones"] += list(drone_data)
if(!drones)
dat += "No Drone Units detected within access parameters."
return data
var/datum/browser/popup = new(user, "computer", "Cyborg Control Console", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
/obj/machinery/computer/robotics/Topic(href, href_list)
/obj/machinery/computer/robotics/ui_act(action, params)
if(..())
return
if (href_list["temp"])
src.temp = null
else if (href_list["killbot"])
if(src.allowed(usr))
var/mob/living/silicon/robot/R = locate(href_list["killbot"]) in GLOB.silicon_mobs
if(can_control(usr, R))
var/choice = input("Are you certain you wish to detonate [R.name]?") in list("Confirm", "Abort")
if(choice == "Confirm" && can_control(usr, R) && !..())
switch(action)
if("killbot")
if(allowed(usr))
var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs
if(can_control(usr, R) && !..())
var/turf/T = get_turf(R)
message_admins("<span class='notice'>[ADMIN_LOOKUPFLW(usr)] detonated [key_name_admin(R, R.client)] at [ADMIN_VERBOSEJMP(T)]!</span>")
log_game("\<span class='notice'>[key_name(usr)] detonated [key_name(R)]!</span>")
if(R.connected_ai)
to_chat(R.connected_ai, "<br><br><span class='alert'>ALERT - Cyborg detonation detected: [R.name]</span><br>")
R.self_destruct()
else
to_chat(usr, "<span class='danger'>Access Denied.</span>")
else if (href_list["stopbot"])
if(src.allowed(usr))
var/mob/living/silicon/robot/R = locate(href_list["stopbot"]) in GLOB.silicon_mobs
if(can_control(usr, R))
var/choice = input("Are you certain you wish to [!R.locked_down ? "lock down" : "release"] [R.name]?") in list("Confirm", "Abort")
if(choice == "Confirm" && can_control(usr, R) && !..())
message_admins("<span class='notice'>[ADMIN_LOOKUPFLW(usr)] [!R.locked_down ? "locked down" : "released"] [key_name(R, R.client)][ADMIN_LOOKUPFLW(R)]!</span>")
else
to_chat(usr, "<span class='danger'>Access Denied.</span>")
if("stopbot")
if(allowed(usr))
var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs
if(can_control(usr, R) && !..())
message_admins("<span class='notice'>[ADMIN_LOOKUPFLW(usr)] [!R.locked_down ? "locked down" : "released"] [ADMIN_LOOKUPFLW(R)]!</span>")
log_game("[key_name(usr)] [!R.locked_down ? "locked down" : "released"] [key_name(R)]!")
R.SetLockdown(!R.locked_down)
to_chat(R, "[!R.locked_down ? "<span class='notice'>Your lockdown has been lifted!" : "<span class='alert'>You have been locked down!"]</span>")
if(R.connected_ai)
to_chat(R.connected_ai, "[!R.locked_down ? "<span class='notice'>NOTICE - Cyborg lockdown lifted" : "<span class='alert'>ALERT - Cyborg lockdown detected"]: <a href='?src=[REF(R.connected_ai)];track=[html_encode(R.name)]'>[R.name]</a></span><br>")
else
to_chat(usr, "<span class='danger'>Access Denied.</span>")
else if (href_list["magbot"])
var/mob/living/silicon/S = usr
if((istype(S) && S.hack_software) || IsAdminGhost(usr))
var/mob/living/silicon/robot/R = locate(href_list["magbot"]) in GLOB.silicon_mobs
if(istype(R) && !R.emagged && (R.connected_ai == usr || IsAdminGhost(usr)) && !R.scrambledcodes && can_control(usr, R))
log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!")
message_admins("[ADMIN_LOOKUPFLW(usr)] emagged cyborg [key_name_admin(R)] using robotic console!")
R.SetEmagged(1)
else if(href_list["convert"])
if(isAI(usr) && is_servant_of_ratvar(usr))
var/mob/living/silicon/robot/R = locate(href_list["convert"]) in GLOB.silicon_mobs
if(istype(R) && !is_servant_of_ratvar(R) && R.connected_ai == usr)
log_game("[key_name(usr)] converted [key_name(R)] using robotic console!")
message_admins("[ADMIN_LOOKUPFLW(usr)] converted cyborg [key_name_admin(R)] using robotic console!")
add_servant_of_ratvar(R)
else if (href_list["killdrone"])
if(src.allowed(usr))
var/mob/living/simple_animal/drone/D = locate(href_list["killdrone"]) in GLOB.mob_list
if(D.hacked)
to_chat(usr, "<span class='danger'>ERROR: [D] is not responding to external commands.</span>")
else
var/turf/T = get_turf(D)
message_admins("[ADMIN_LOOKUPFLW(usr)] detonated [key_name_admin(D)] at [ADMIN_VERBOSEJMP(T)]!")
log_game("[key_name(usr)] detonated [key_name(D)]!")
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, D)
s.start()
D.visible_message("<span class='danger'>\the [D] self destructs!</span>")
D.gib()
src.updateUsrDialog()
return
to_chat(usr, "<span class='danger'>Access Denied.</span>")
if("magbot")
var/mob/living/silicon/S = usr
if((istype(S) && S.hack_software) || IsAdminGhost(usr))
var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs
if(istype(R) && !R.emagged && (R.connected_ai == usr || IsAdminGhost(usr)) && !R.scrambledcodes && can_control(usr, R))
log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!")
message_admins("[ADMIN_LOOKUPFLW(usr)] emagged cyborg [key_name_admin(R)] using robotic console!")
R.SetEmagged(TRUE)
if("killdrone")
if(allowed(usr))
var/mob/living/simple_animal/drone/D = locate(params["ref"]) in GLOB.mob_list
if(D.hacked)
to_chat(usr, "<span class='danger'>ERROR: [D] is not responding to external commands.</span>")
else
var/turf/T = get_turf(D)
message_admins("[ADMIN_LOOKUPFLW(usr)] detonated [key_name_admin(D)] at [ADMIN_VERBOSEJMP(T)]!")
log_game("[key_name(usr)] detonated [key_name(D)]!")
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, TRUE, D)
s.start()
D.visible_message("<span class='danger'>\the [D] self-destructs!</span>")
D.gib()
+1 -1
View File
@@ -662,7 +662,7 @@ What a mess.*/
GLOB.data_core.removeMajorCrime(active1.fields["id"], href_list["cdataid"])
if("notes")
if(istype(active2, /datum/data/record))
var/t1 = stripped_input(usr, "Please summarize notes:", "Secure. records", active2.fields["notes"], null)
var/t1 = stripped_multiline_input(usr, "Please summarize notes:", "Secure records", active2.fields["notes"], 8192)
if(!canUseSecurityRecordsConsole(usr, t1, null, a2))
return
active2.fields["notes"] = t1
@@ -16,11 +16,10 @@
GLOB.alert_consoles -= src
return ..()
/obj/machinery/computer/station_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/station_alert/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "station_alert", name, 325, 500, master_ui, state)
ui = new(user, src, "StationAlertConsole", name)
ui.open()
/obj/machinery/computer/station_alert/ui_data(mob/user)
@@ -31,6 +30,7 @@
data["alarms"][class] = list()
for(var/area in alarms[class])
data["alarms"][class] += area
return data
/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source)
+13 -13
View File
@@ -34,11 +34,10 @@
break
return power_station
obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/teleporter/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "teleporter", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "Teleporter", name)
ui.open()
/obj/machinery/computer/teleporter/ui_data(mob/user)
@@ -56,7 +55,6 @@ obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/t
return data
/obj/machinery/computer/teleporter/ui_act(action, params)
if(..())
return
@@ -92,16 +90,18 @@ obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/t
say("Processing hub calibration to target...")
calibrating = TRUE
power_station.update_icon()
spawn(50 * (3 - power_station.teleporter_hub.accuracy)) //Better parts mean faster calibration
calibrating = FALSE
if(check_hub_connection())
power_station.teleporter_hub.calibrated = TRUE
say("Calibration complete.")
else
say("Error: Unable to detect hub.")
power_station.update_icon()
addtimer(CALLBACK(src, .proc/finish_calibration), 50 * (3 - power_station.teleporter_hub.accuracy)) //Better parts mean faster calibration
. = TRUE
/obj/machinery/computer/teleporter/proc/finish_calibration()
calibrating = FALSE
if(check_hub_connection())
power_station.teleporter_hub.calibrated = TRUE
say("Calibration complete.")
else
say("Error: Unable to detect hub.")
power_station.update_icon()
/obj/machinery/computer/teleporter/proc/check_hub_connection()
if(!power_station)
return FALSE
+64 -46
View File
@@ -9,6 +9,7 @@
var/active = FALSE
var/list/rangers = list()
var/stop = 0
var/volume = 70
var/datum/track/selection = null
/obj/machinery/jukebox/disco
@@ -51,74 +52,91 @@
else
icon_state = "[initial(icon_state)]"
/obj/machinery/jukebox/ui_interact(mob/user)
. = ..()
if(!user.canUseTopic(src, !hasSiliconAccessInArea(user)))
return
if (!anchored)
/obj/machinery/jukebox/ui_status(mob/user)
if(!anchored)
to_chat(user,"<span class='warning'>This device must be anchored by a wrench!</span>")
return
if(!allowed(user))
return UI_CLOSE
if(!allowed(user) && !isobserver(user))
to_chat(user,"<span class='warning'>Error: Access Denied.</span>")
user.playsound_local(src,'sound/misc/compiler-failure.ogg', 25, 1)
return
if(!SSjukeboxes.songs.len)
user.playsound_local(src, 'sound/misc/compiler-failure.ogg', 25, TRUE)
return UI_CLOSE
if(!SSjukeboxes.songs.len && !isobserver(user))
to_chat(user,"<span class='warning'>Error: No music tracks have been authorized for your station. Petition Central Command to resolve this issue.</span>")
playsound(src,'sound/misc/compiler-failure.ogg', 25, 1)
return
var/list/dat = list()
dat +="<div class='statusDisplay' style='text-align:center'>"
dat += "<b><A href='?src=[REF(src)];action=toggle'>[!active ? "BREAK IT DOWN" : "SHUT IT DOWN"]<b></A><br>"
dat += "</div><br>"
dat += "<A href='?src=[REF(src)];action=select'> Select Track</A><br>"
if(istype(selection))
dat += "Track Selected: [selection.song_name]<br>"
dat += "Track Length: [DisplayTimeText(selection.song_length)]<br><br>"
else
dat += "Track Selected: None!<br><br>"
var/datum/browser/popup = new(user, "vending", "[name]", 400, 350)
popup.set_content(dat.Join())
popup.open()
playsound(src, 'sound/misc/compiler-failure.ogg', 25, TRUE)
return UI_CLOSE
return ..()
/obj/machinery/jukebox/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Jukebox", name)
ui.open()
/obj/machinery/jukebox/Topic(href, href_list)
if(..())
/obj/machinery/jukebox/ui_data(mob/user)
var/list/data = list()
data["active"] = active
data["songs"] = list()
for(var/datum/track/S in SSjukeboxes.songs)
var/list/track_data = list(
name = S.song_name
)
data["songs"] += 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
data["volume"] = volume
return data
/obj/machinery/jukebox/ui_act(action, list/params)
. = ..()
if(.)
return
add_fingerprint(usr)
switch(href_list["action"])
switch(action)
if("toggle")
if (QDELETED(src))
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, 1)
playsound(src, 'sound/misc/compiler-failure.ogg', 50, TRUE)
return
if(!istype(selection))
to_chat(usr, "<span class='warning'>Error: Severe user incompetence detected.</span>")
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
return
if(!activate_music())
to_chat(usr, "<span class='warning'>Error: Generic hardware failure.</span>")
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
return
updateUsrDialog()
else if(active)
activate_music()
START_PROCESSING(SSobj, src)
return TRUE
else
stop = 0
updateUsrDialog()
if("select")
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
var/list/available = list()
for(var/datum/track/S in SSjukeboxes.songs)
available[S.song_name] = S
var/selected = input(usr, "Choose your song", "Track:") as null|anything in available
var/selected = params["track"]
if(QDELETED(src) || !selected || !istype(available[selected], /datum/track))
return
selection = available[selected]
updateUsrDialog()
return TRUE
if("set_volume")
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
else if(text2num(new_volume) != null)
volume = text2num(new_volume)
return TRUE
/obj/machinery/jukebox/proc/activate_music()
var/jukeboxslottotake = SSjukeboxes.addjukebox(src, selection, 2)
+1 -1
View File
@@ -59,7 +59,7 @@
return defib.get_cell()
//defib interaction
/obj/machinery/defibrillator_mount/attack_hand(mob/living/user)
/obj/machinery/defibrillator_mount/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!defib)
to_chat(user, "<span class='warning'>There's no defibrillator unit loaded!</span>")
return
+1 -1
View File
@@ -31,7 +31,7 @@
if(user.Adjacent(src))
. += "<span class='notice'>Alt-click it to beam its contents to any nearby disposal bins.</span>"
/obj/machinery/dish_drive/attack_hand(mob/living/user)
/obj/machinery/dish_drive/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!contents.len)
to_chat(user, "<span class='warning'>There's nothing in [src]!</span>")
return
+48 -63
View File
@@ -15,6 +15,7 @@
var/precision_coeff
var/message_cooldown
var/breakout_time = 1200
var/obj/machinery/computer/scan_consolenew/linked_console = null
/obj/machinery/dna_scannernew/RefreshParts()
scan_level = 0
@@ -22,8 +23,8 @@
precision_coeff = 0
for(var/obj/item/stock_parts/scanning_module/P in component_parts)
scan_level += P.rating
for(var/obj/item/stock_parts/matter_bin/P in component_parts)
precision_coeff = P.rating
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
precision_coeff = M.rating
for(var/obj/item/stock_parts/micro_laser/P in component_parts)
damage_coeff = P.rating
@@ -31,11 +32,8 @@
. = ..()
if(in_range(user, src) || isobserver(user))
. += "<span class='notice'>The status display reads: Radiation pulse accuracy increased by factor <b>[precision_coeff**2]</b>.<br>Radiation pulse damage decreased by factor <b>[damage_coeff**2]</b>.</span>"
if(scan_level >= 3)
. += "<span class='notice'>Scanner has been upgraded to support autoprocessing.<span>"
/obj/machinery/dna_scannernew/update_icon_state()
//no power or maintenance
if(stat & (NOPOWER|BROKEN))
icon_state = initial(icon_state)+ (state_open ? "_open" : "") + "_unpowered"
@@ -53,10 +51,6 @@
//running
icon_state = initial(icon_state)+ (state_open ? "_open" : "")
/obj/machinery/dna_scannernew/power_change()
..()
update_icon()
/obj/machinery/dna_scannernew/proc/toggle_open(mob/user)
if(panel_open)
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
@@ -76,11 +70,9 @@
if(!locked)
open_machine()
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
"<span class='italics'>You hear a metallic creaking from [src].</span>")
"<span class='hear'>You hear a metallic creaking from [src].</span>")
if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked)
return
@@ -96,33 +88,28 @@
return C
return null
/obj/machinery/dna_scannernew/close_machine(atom/movable/target)
/obj/machinery/dna_scannernew/close_machine(mob/living/carbon/user)
if(!state_open)
return FALSE
..(target)
// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
if(istype(mob_occupant))
if(locate_computer(/obj/machinery/computer/cloning))
if(!mob_occupant.suiciding && !(HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && !mob_occupant.hellbound)
mob_occupant.notify_ghost_cloning("Your corpse has been placed into a cloning scanner. Re-enter your corpse if you want to be cloned!", source = src)
..(user)
// DNA manipulators cannot operate on severed heads or brains
if(isliving(occupant))
var/obj/machinery/computer/scan_consolenew/console = locate_computer(/obj/machinery/computer/scan_consolenew)
if(console)
console.on_scanner_close()
if(iscarbon(occupant))
if(linked_console)
linked_console.on_scanner_close()
return TRUE
/obj/machinery/dna_scannernew/open_machine()
if(state_open || panel_open)
if(state_open)
return FALSE
..()
if(linked_console)
linked_console.on_scanner_open()
return TRUE
/obj/machinery/dna_scannernew/relaymove(mob/user as mob)
@@ -133,51 +120,49 @@
return
open_machine()
/obj/machinery/dna_scannernew/screwdriver_act(mob/living/user, obj/item/I)
. = TRUE
if(..())
return
if(occupant)
to_chat(user, "<span class='warning'>[src] is currently occupied!</span>")
return
if(state_open)
to_chat(user, "<span class='warning'>[src] must be closed to [panel_open ? "close" : "open"] its maintenance hatch!</span>")
return
if(default_deconstruction_screwdriver(user, icon_state, icon_state, I)) //sent icon_state is irrelevant...
update_icon() //..since we're updating the icon here, since the scanner can be unpowered when opened/closed
return
return FALSE
/obj/machinery/dna_scannernew/attackby(obj/item/I, mob/user, params)
/obj/machinery/dna_scannernew/wrench_act(mob/living/user, obj/item/I)
. = ..()
if(default_change_direction_wrench(user, I))
return TRUE
if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I))//sent icon_state is irrelevant...
update_icon()//..since we're updating the icon here, since the scanner can be unpowered when opened/closed
return
/obj/machinery/dna_scannernew/crowbar_act(mob/living/user, obj/item/I)
. = ..()
if(default_pry_open(I))
return TRUE
if(default_deconstruction_crowbar(I))
return TRUE
return
/obj/machinery/dna_scannernew/default_pry_open(obj/item/I) //wew
. = !(state_open || panel_open || (flags_1 & NODECONSTRUCT_1)) && I.tool_behaviour == TOOL_CROWBAR
if(.)
I.play_tool_sound(src, 50)
visible_message("<span class='notice'>[usr] pries open [src].</span>", "<span class='notice'>You pry open [src].</span>")
open_machine()
if(default_deconstruction_crowbar(I))
return
return ..()
/obj/machinery/dna_scannernew/interact(mob/user)
toggle_open(user)
/obj/machinery/dna_scannernew/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, !hasSiliconAccessInArea(user)))
return
interact(user)
return TRUE
/obj/machinery/dna_scannernew/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
var/mob/living/L = user
if(user.stat || (isliving(user) && (!(L.mobility_flags & MOBILITY_STAND) || !(L.mobility_flags & MOBILITY_UI))) || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
return
close_machine(target)
//Just for transferring between genetics machines.
/obj/item/disk/data
name = "DNA data disk"
icon_state = "datadisk0" //Gosh I hope syndies don't mistake them for the nuke disk.
var/list/genetic_makeup_buffer = list()
var/list/fields = list()
var/list/mutations = list()
var/max_mutations = 6
var/read_only = FALSE //Well,it's still a floppy disk
/obj/item/disk/data/Initialize()
. = ..()
icon_state = "datadisk[rand(0,6)]"
add_overlay("datadisk_gene")
/obj/item/disk/data/attack_self(mob/user)
read_only = !read_only
to_chat(user, "<span class='notice'>You flip the write-protect tab to [read_only ? "protected" : "unprotected"].</span>")
/obj/item/disk/data/examine(mob/user)
. = ..()
. += "The write-protect tab is set to [read_only ? "protected" : "unprotected"]."
+55 -43
View File
@@ -50,7 +50,7 @@
integrity_failure = 0.25
damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_N
autoclose = TRUE
secondsElectrified = 0 //How many seconds remain until the door is no longer electrified. -1 if it is permanently electrified until someone fixes it.
secondsElectrified = NOT_ELECTRIFIED //How many seconds remain until the door is no longer electrified. -1 if it is permanently electrified until someone fixes it.
assemblytype = /obj/structure/door_assembly
normalspeed = 1
explosion_block = 1
@@ -93,7 +93,7 @@
var/shuttledocked = 0
var/delayed_close_requested = FALSE // TRUE means the door will automatically close the next time it's opened.
var/air_tight = FALSE //TRUE means density will be set as soon as the door begins to close
air_tight = FALSE
var/prying_so_hard = FALSE
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
@@ -157,6 +157,10 @@
. = ..()
AddComponent(/datum/component/ntnet_interface)
/obj/machinery/door/airlock/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
if(id_tag)
id_tag = "[idnum][id_tag]"
/obj/machinery/door/airlock/proc/update_other_id()
for(var/obj/machinery/door/airlock/A in GLOB.airlocks)
if(A.closeOtherId == closeOtherId && A != src)
@@ -188,7 +192,7 @@
/obj/machinery/door/airlock/vv_edit_var(var_name)
. = ..()
switch (var_name)
if ("cyclelinkeddir")
if (NAMEOF(src, cyclelinkeddir))
cyclelinkairlock()
/obj/machinery/door/airlock/check_access_ntnet(datum/netdata/data)
@@ -294,10 +298,10 @@
/obj/machinery/door/airlock/Destroy()
QDEL_NULL(wires)
QDEL_NULL(electronics)
if(charge)
qdel(charge)
charge = null
QDEL_NULL(electronics)
if (cyclelinkedairlock)
if (cyclelinkedairlock.cyclelinkedairlock == src)
cyclelinkedairlock.cyclelinkedairlock = null
@@ -305,7 +309,7 @@
if(id_tag)
for(var/obj/machinery/doorButtons/D in GLOB.machines)
D.removeMe(src)
qdel(note)
QDEL_NULL(note)
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.remove_from_hud(src)
return ..()
@@ -413,8 +417,8 @@
// shock user with probability prb (if all connections & power are working)
// returns TRUE if shocked, FALSE otherwise
// The preceding comment was borrowed from the grille's shock script
/obj/machinery/door/airlock/proc/shock(mob/user, prb)
if(!hasPower()) // unpowered, no shock
/obj/machinery/door/airlock/proc/shock(mob/living/user, prb)
if(!istype(user) || !hasPower()) // unpowered, no shock
return FALSE
if(shockCooldown > world.time)
return FALSE //Already shocked someone recently?
@@ -759,13 +763,10 @@
/obj/machinery/door/airlock/attack_paw(mob/user)
return attack_hand(user)
/obj/machinery/door/airlock/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/door/airlock/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!(issilicon(user) || IsAdminGhost(user)))
if(src.isElectrified())
if(src.shock(user, 100))
if(isElectrified())
if(shock(user, 100))
return
if(ishuman(user) && prob(40) && src.density)
@@ -779,6 +780,8 @@
H.apply_damage(10, BRUTE, BODY_ZONE_HEAD)
else
visible_message("<span class='danger'>[user] headbutts the airlock. Good thing [user.p_theyre()] wearing a helmet.</span>")
else
return ..()
/obj/machinery/door/airlock/attempt_wire_interaction(mob/user)
if(security_level)
@@ -787,15 +790,15 @@
return ..()
/obj/machinery/door/airlock/proc/electrified_loop()
while (secondsElectrified > 0)
while (secondsElectrified > NOT_ELECTRIFIED)
sleep(10)
if(QDELETED(src))
return
secondsElectrified -= 1
secondsElectrified--
updateDialog()
// This is to protect against changing to permanent, mid loop.
if(secondsElectrified==0)
if(secondsElectrified == NOT_ELECTRIFIED)
set_electrified(NOT_ELECTRIFIED)
else
set_electrified(ELECTRIFIED_PERMANENT)
@@ -822,8 +825,8 @@
/obj/machinery/door/airlock/attackby(obj/item/C, mob/user, params)
if(!issilicon(user) && !IsAdminGhost(user))
if(src.isElectrified())
if(src.shock(user, 75))
if(isElectrified())
if(shock(user, 75))
return
add_fingerprint(user)
@@ -836,7 +839,7 @@
to_chat(user, "<span class='warning'>You need at least 2 metal sheets to reinforce [src].</span>")
return
to_chat(user, "<span class='notice'>You start reinforcing [src].</span>")
if(do_after(user, 20, 1, target = src))
if(do_after(user, 20, TRUE, target = src))
if(!panel_open || !S.use(2))
return
user.visible_message("<span class='notice'>[user] reinforces \the [src] with metal.</span>",
@@ -1058,16 +1061,16 @@
to_chat(user, "<span class='warning'>The airlock's bolts prevent it from being forced!</span>")
else if( !welded && !operating)
if(!beingcrowbarred) //being fireaxe'd
var/obj/item/twohanded/fireaxe/F = I
if(F.wielded)
INVOKE_ASYNC(src, (density ? .proc/open : .proc/close), 2)
else
to_chat(user, "<span class='warning'>You need to be wielding the fire axe to do that!</span>")
var/obj/item/fireaxe/axe = I
if(!axe.wielded)
to_chat(user, "<span class='warning'>You need to be wielding \the [axe] to do that!</span>")
return
INVOKE_ASYNC(src, (density ? .proc/open : .proc/close), 2)
else
INVOKE_ASYNC(src, (density ? .proc/open : .proc/close), 2)
if(istype(I, /obj/item/crowbar/power))
if(isElectrified())
if(hasPower() && isElectrified())
shock(user,100)//it's like sticking a forck in a power socket
return
@@ -1087,12 +1090,11 @@
time_to_open = 50
playsound(src, 'sound/machines/airlock_alien_prying.ogg',100,1) //is it aliens or just the CE being a dick?
prying_so_hard = TRUE
var/result = do_after(user, time_to_open,target = src)
prying_so_hard = FALSE
if(result)
if(do_after(user, time_to_open,target = src))
open(2)
if(density && !open(2))
to_chat(user, "<span class='warning'>Despite your attempts, [src] refuses to open.</span>")
prying_so_hard = FALSE
/obj/machinery/door/airlock/open(forced=0)
if( operating || welded || locked )
@@ -1109,7 +1111,6 @@
detonated = 1
charge = null
for(var/mob/living/carbon/human/H in orange(2,src))
H.Unconscious(160)
H.adjust_fire_stacks(20)
H.IgniteMob() //Guaranteed knockout and ignition for nearby people
H.apply_damage(40, BRUTE, BODY_ZONE_CHEST)
@@ -1357,12 +1358,25 @@
wires.cut_all()
update_icon()
/obj/machinery/door/airlock/proc/set_electrified(seconds)
/obj/machinery/door/airlock/proc/set_electrified(seconds, mob/user)
secondsElectrified = seconds
diag_hud_set_electrified()
if(secondsElectrified > 0)
if(secondsElectrified > NOT_ELECTRIFIED)
INVOKE_ASYNC(src, .proc/electrified_loop)
if(user)
var/message
switch(secondsElectrified)
if(ELECTRIFIED_PERMANENT)
message = "permanently shocked"
if(NOT_ELECTRIFIED)
message = "unshocked"
else
message = "temp shocked for [secondsElectrified] seconds"
LAZYADD(shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(user)] - ([uppertext(message)])"))
log_combat(user, src, message)
//add_hiddenprint(user)
/obj/machinery/door/airlock/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(obj_integrity < (0.75 * max_integrity))
@@ -1436,11 +1450,10 @@
else if(istype(note, /obj/item/photo))
return "photo"
/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/door/airlock/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "ai_airlock", name, 500, 390, master_ui, state)
ui = new(user, src, "AiAirlock", name)
ui.open()
return TRUE
@@ -1448,13 +1461,13 @@
var/list/data = list()
var/list/power = list()
power["main"] = src.secondsMainPowerLost ? 0 : 2 // boolean
power["main_timeleft"] = src.secondsMainPowerLost
power["backup"] = src.secondsBackupPowerLost ? 0 : 2 // boolean
power["backup_timeleft"] = src.secondsBackupPowerLost
power["main"] = secondsMainPowerLost ? 0 : 2 // boolean
power["main_timeleft"] = secondsMainPowerLost
power["backup"] = secondsBackupPowerLost ? 0 : 2 // boolean
power["backup_timeleft"] = secondsBackupPowerLost
data["power"] = power
data["shock"] = secondsElectrified == 0 ? 2 : 0
data["shock"] = secondsElectrified == NOT_ELECTRIFIED ? 2 : 0
data["shock_timeleft"] = secondsElectrified
data["id_scanner"] = !aiDisabledIdScanner
data["emergency"] = emergency // access
@@ -1491,14 +1504,14 @@
loseMainPower()
update_icon()
else
to_chat(usr, "Main power is already offline.")
to_chat(usr, "<span class='warning'>Main power is already offline.</span>")
. = TRUE
if("disrupt-backup")
if(!secondsBackupPowerLost)
loseBackupPower()
update_icon()
else
to_chat(usr, "Backup power is already offline.")
to_chat(usr, "<span class='warning'>Backup power is already offline.</span>")
. = TRUE
if("shock-restore")
shock_restore(usr)
@@ -1527,7 +1540,6 @@
. = TRUE
if("speed-toggle")
normalspeed = !normalspeed
. = TRUE
if("open-close")
user_toggle_open(usr)
@@ -2,42 +2,54 @@
name = "airlock electronics"
req_access = list(ACCESS_MAINT_TUNNELS)
custom_price = PRICE_CHEAP
/// A list of all granted accesses
var/list/accesses = list()
/// If the airlock should require ALL or only ONE of the listed accesses
var/one_access = 0
var/unres_sides = 0 //unrestricted sides, or sides of the airlock that will open regardless of access
/// Unrestricted sides, or sides of the airlock that will open regardless of access
var/unres_sides = 0
/// A holder of the electronics, in case of them working as an integrated part
var/holder
/obj/item/electronics/airlock/examine(mob/user)
. = ..()
. += "<span class='notice'>Has a neat <i>selection menu</i> for modifying airlock access levels.</span>"
/obj/item/electronics/airlock/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/electronics/airlock/ui_state(mob/user)
return GLOB.hands_state
/obj/item/electronics/airlock/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "airlock_electronics", name, 420, 485, master_ui, state)
ui = new(user, src, "AirlockElectronics", name)
ui.open()
/obj/item/electronics/airlock/ui_static_data(mob/user)
var/list/data = list()
var/list/regions = list()
for(var/i in 1 to 7)
var/list/accesses = list()
for(var/access in get_region_accesses(i))
if (get_access_desc(access))
accesses += list(list(
"desc" = replacetext(get_access_desc(access), "&nbsp", " "),
"ref" = access,
))
regions += list(list(
"name" = get_region_accesses_name(i),
"regid" = i,
"accesses" = accesses
))
data["regions"] = regions
return data
/obj/item/electronics/airlock/ui_data()
var/list/data = list()
var/list/regions = list()
for(var/i in 1 to 7)
var/list/region = list()
var/list/accesses = list()
for(var/j in get_region_accesses(i))
var/list/access = list()
access["name"] = get_access_desc(j)
access["id"] = j
access["req"] = (j in src.accesses)
accesses[++accesses.len] = access
region["name"] = get_region_accesses_name(i)
region["accesses"] = accesses
regions[++regions.len] = region
data["regions"] = regions
data["accesses"] = accesses
data["oneAccess"] = one_access
data["unres_direction"] = unres_sides
return data
/obj/item/electronics/airlock/ui_act(action, params)
@@ -48,12 +60,12 @@
accesses = list()
one_access = 0
. = TRUE
if("one_access")
one_access = !one_access
. = TRUE
if("grant_all")
accesses = get_all_accesses()
. = TRUE
if("one_access")
one_access = !one_access
. = TRUE
if("set")
var/access = text2num(params["access"])
if (!(access in accesses))
@@ -65,3 +77,20 @@
var/unres_direction = text2num(params["unres_direction"])
unres_sides ^= unres_direction //XOR, toggles only the bit that was clicked
. = TRUE
if("grant_region")
var/region = text2num(params["region"])
if(isnull(region))
return
accesses |= get_region_accesses(region)
. = TRUE
if("deny_region")
var/region = text2num(params["region"])
if(isnull(region))
return
accesses -= get_region_accesses(region)
. = TRUE
/obj/item/electronics/airlock/ui_host()
if(holder)
return holder
return src
@@ -310,6 +310,17 @@
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/bronze
name = "bronze airlock"
icon = 'icons/obj/doors/airlocks/clockwork/pinion_airlock.dmi'
overlays_file = 'icons/obj/doors/airlocks/clockwork/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_bronze
/obj/machinery/door/airlock/bronze/seethru
assemblytype = /obj/structure/door_assembly/door_assembly_bronze/seethru
opacity = 0
glass = TRUE
//////////////////////////////////
/*
Station2 Airlocks
+4 -5
View File
@@ -140,11 +140,10 @@
. = new_time == timer_duration //return 1 on no change
timer_duration = new_time
/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/door_timer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "brig_timer", name, 300, 138, master_ui, state)
ui = new(user, src, "BrigTimer", name)
ui.open()
//icon update function
@@ -235,7 +234,7 @@
preset_time = PRESET_LONG
. = set_timer(preset_time)
if(timing)
activation_time = REALTIMEOFDAY
activation_time = world.time
else
. = FALSE
+44 -13
View File
@@ -11,14 +11,15 @@
max_integrity = 350
armor = list("melee" = 30, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 70)
CanAtmosPass = ATMOS_PASS_DENSITY
flags_1 = PREVENT_CLICK_UNDER_1
flags_1 = PREVENT_CLICK_UNDER_1|DEFAULT_RICOCHET_1
ricochet_chance_mod = 0.8
interaction_flags_atom = INTERACT_ATOM_UI_INTERACT
var/secondsElectrified = 0
var/air_tight = FALSE //TRUE means density will be set as soon as the door begins to close
var/shockedby
var/visible = TRUE
var/visible = TRUE // To explain: Whether the door can block line of sight when closed or not.
var/operating = FALSE
var/glass = FALSE
var/welded = FALSE
@@ -139,10 +140,7 @@
do_animate("deny")
return
/obj/machinery/door/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/door/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
return try_to_activate_door(user)
/obj/machinery/door/attack_tk(mob/user)
@@ -161,7 +159,7 @@
open()
else
close()
return
return TRUE
if(density)
do_animate("deny")
@@ -181,11 +179,36 @@
/obj/machinery/door/proc/try_to_crowbar(obj/item/I, mob/user)
return
/obj/machinery/door/proc/is_holding_pressure()
var/turf/open/T = loc
if(!T)
return FALSE
if(!density)
return FALSE
// alrighty now we check for how much pressure we're holding back
var/min_moles = T.air.total_moles()
var/max_moles = min_moles
// okay this is a bit hacky. First, we set density to 0 and recalculate our adjacent turfs
density = FALSE
T.ImmediateCalculateAdjacentTurfs()
// then we use those adjacent turfs to figure out what the difference between the lowest and highest pressures we'd be holding is
for(var/turf/open/T2 in T.atmos_adjacent_turfs)
if((flags_1 & ON_BORDER_1) && get_dir(src, T2) != dir)
continue
var/moles = T2.air.total_moles()
if(moles < min_moles)
min_moles = moles
if(moles > max_moles)
max_moles = moles
density = TRUE
T.ImmediateCalculateAdjacentTurfs() // alright lets put it back
return max_moles - min_moles > 20
/obj/machinery/door/attackby(obj/item/I, mob/user, params)
if(user.a_intent != INTENT_HARM && (istype(I, /obj/item/crowbar) || istype(I, /obj/item/twohanded/fireaxe)))
if(user.a_intent != INTENT_HARM && (I.tool_behaviour == TOOL_CROWBAR || istype(I, /obj/item/fireaxe)))
try_to_crowbar(I, user)
return 1
else if(istype(I, /obj/item/weldingtool))
else if(I.tool_behaviour == TOOL_WELDER)
try_to_weld(I, user)
return 1
else if(!(I.item_flags & NOBLUDGEON) && user.a_intent != INTENT_HARM)
@@ -223,13 +246,13 @@
if(prob(20/severity) && (istype(src, /obj/machinery/door/airlock) || istype(src, /obj/machinery/door/window)) )
INVOKE_ASYNC(src, .proc/open)
if(prob(severity*10 - 20))
if(secondsElectrified == 0)
secondsElectrified = -1
if(secondsElectrified == MACHINE_NOT_ELECTRIFIED)
secondsElectrified = MACHINE_ELECTRIFIED_PERMANENT
LAZYADD(shockedby, "\[[TIME_STAMP("hh:mm:ss", FALSE)]\]EM Pulse")
addtimer(CALLBACK(src, .proc/unelectrify), 300)
/obj/machinery/door/proc/unelectrify()
secondsElectrified = 0
secondsElectrified = MACHINE_NOT_ELECTRIFIED
/obj/machinery/door/update_icon_state()
if(density)
@@ -289,8 +312,11 @@
return
operating = TRUE
do_animate("closing")
layer = closingLayer
if(air_tight)
density = TRUE
sleep(5)
density = TRUE
sleep(5)
@@ -302,7 +328,7 @@
update_freelook_sight()
if(safe)
CheckForMobs()
else
else if(!(flags_1 & ON_BORDER_1))
crush()
return 1
@@ -314,6 +340,11 @@
/obj/machinery/door/proc/crush()
for(var/mob/living/L in get_turf(src))
L.visible_message("<span class='warning'>[src] closes on [L], crushing [L.p_them()]!</span>", "<span class='userdanger'>[src] closes on you and crushes you!</span>")
if(iscarbon(L))
var/mob/living/carbon/C = L
for(var/i in C.all_wounds) // should probably replace with signal
var/datum/wound/W = i
W.crush(DOOR_CRUSH_DAMAGE)
if(isalien(L)) //For xenos
L.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 1.5) //Xenos go into crit after aproximately the same amount of crushes as humans.
L.emote("roar")
+173 -29
View File
@@ -23,6 +23,10 @@
assemblytype = /obj/structure/firelock_frame
armor = list("melee" = 30, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 95, "acid" = 70)
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN
air_tight = TRUE
attack_hand_is_action = TRUE
attack_hand_speed = CLICK_CD_MELEE
var/emergency_close_timer = 0
var/nextstate = null
var/boltslocked = TRUE
var/list/affecting_areas
@@ -68,13 +72,16 @@
return ..()
/obj/machinery/door/firedoor/Bumped(atom/movable/AM)
if(panel_open || operating)
if(panel_open || operating || welded)
return
if(!density)
return ..()
if(ismob(AM))
var/mob/user = AM
if(density && !welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user)))
add_fingerprint(user)
open()
return TRUE
return FALSE
/obj/machinery/door/firedoor/power_change()
if(powered(power_channel))
stat &= ~NOPOWER
@@ -82,13 +89,17 @@
else
stat |= NOPOWER
/obj/machinery/door/firedoor/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/door/firedoor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user)))
add_fingerprint(user)
if(density)
emergency_close_timer = world.time + 30 // prevent it from instaclosing again if in space
open()
else
close()
return TRUE
if(operating || !density)
return
user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("[user] bangs on \the [src].",
"You bang on \the [src].")
@@ -100,7 +111,7 @@
return
if(welded)
if(istype(C, /obj/item/wrench))
if(C.tool_behaviour == TOOL_WRENCH)
if(boltslocked)
to_chat(user, "<span class='notice'>There are screws locking the bolts in place!</span>")
return
@@ -114,7 +125,7 @@
"<span class='notice'>You undo [src]'s floor bolts.</span>")
deconstruct(TRUE)
return
if(istype(C, /obj/item/screwdriver))
if(C.tool_behaviour == TOOL_SCREWDRIVER)
user.visible_message("<span class='notice'>[user] [boltslocked ? "unlocks" : "locks"] [src]'s bolts.</span>", \
"<span class='notice'>You [boltslocked ? "unlock" : "lock"] [src]'s floor bolts.</span>")
C.play_tool_sound(src)
@@ -140,10 +151,27 @@
return
if(density)
if(is_holding_pressure())
// tell the user that this is a bad idea, and have a do_after as well
to_chat(user, "<span class='warning'>As you begin crowbarring \the [src] a gush of air blows in your face... maybe you should reconsider?</span>")
if(!do_after(user, 15, TRUE, src)) // give them a few seconds to reconsider their decision.
return
log_game("[key_name_admin(user)] has opened a firelock with a pressure difference at [AREACOORD(loc)]") // there bibby I made it logged just for you. Enjoy.
// since we have high-pressure-ness, close all other firedoors on the tile
whack_a_mole()
if(welded || operating || !density)
return // in case things changed during our do_after
emergency_close_timer = world.time + 60 // prevent it from instaclosing again if in space
open()
else
close()
/obj/machinery/door/firedoor/proc/allow_hand_open(mob/user)
var/area/A = get_area(src)
if(A && A.fire)
return FALSE
return !is_holding_pressure()
/obj/machinery/door/firedoor/attack_ai(mob/user)
add_fingerprint(user)
if(welded || operating || stat & NOPOWER)
@@ -171,20 +199,16 @@
if("closing")
flick("door_closing", src)
/obj/machinery/door/firedoor/update_icon_state()
/obj/machinery/door/firedoor/update_icon()
cut_overlays()
if(density)
icon_state = "door_closed"
if(welded)
add_overlay("welded")
else
icon_state = "door_open"
/obj/machinery/door/firedoor/update_overlays()
. = ..()
if(!welded)
return
if(density)
. += "welded"
else
. += "welded_open"
if(welded)
add_overlay("welded_open")
/obj/machinery/door/firedoor/open()
. = ..()
@@ -194,6 +218,61 @@
. = ..()
latetoggle()
/obj/machinery/door/firedoor/proc/whack_a_mole(reconsider_immediately = FALSE)
set waitfor = 0
for(var/cdir in GLOB.cardinals)
if((flags_1 & ON_BORDER_1) && cdir != dir)
continue
whack_a_mole_part(get_step(src, cdir), reconsider_immediately)
if(flags_1 & ON_BORDER_1)
whack_a_mole_part(get_turf(src), reconsider_immediately)
/obj/machinery/door/firedoor/proc/whack_a_mole_part(turf/start_point, reconsider_immediately)
set waitfor = 0
var/list/doors_to_close = list()
var/list/turfs = list()
turfs[start_point] = 1
for(var/i = 1; (i <= turfs.len && i <= 11); i++) // check up to 11 turfs.
var/turf/open/T = turfs[i]
if(istype(T, /turf/open/space))
return -1
for(var/T2 in T.atmos_adjacent_turfs)
if(turfs[T2])
continue
var/is_cut_by_unopen_door = FALSE
for(var/obj/machinery/door/firedoor/FD in T2)
if((FD.flags_1 & ON_BORDER_1) && get_dir(T2, T) != FD.dir)
continue
if(FD.operating || FD == src || FD.welded || FD.density)
continue
doors_to_close += FD
is_cut_by_unopen_door = TRUE
for(var/obj/machinery/door/firedoor/FD in T)
if((FD.flags_1 & ON_BORDER_1) && get_dir(T, T2) != FD.dir)
continue
if(FD.operating || FD == src || FD.welded || FD.density)
continue
doors_to_close += FD
is_cut_by_unopen_door= TRUE
if(!is_cut_by_unopen_door)
turfs[T2] = 1
if(turfs.len > 10)
return // too big, don't bother
for(var/obj/machinery/door/firedoor/FD in doors_to_close)
FD.emergency_pressure_stop(FALSE)
if(reconsider_immediately)
var/turf/open/T = FD.loc
if(istype(T))
T.ImmediateCalculateAdjacentTurfs()
/obj/machinery/door/firedoor/proc/emergency_pressure_stop(consider_timer = TRUE)
set waitfor = 0
if(density || operating || welded)
return
if(world.time >= emergency_close_timer || !consider_timer)
close()
/obj/machinery/door/firedoor/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
var/obj/structure/firelock_frame/F = new assemblytype(get_turf(src))
@@ -219,7 +298,7 @@
/obj/machinery/door/firedoor/border_only
icon = 'icons/obj/doors/edge_Doorfire.dmi'
flags_1 = ON_BORDER_1
flags_1 = ON_BORDER_1|DEFAULT_RICOCHET_1
CanAtmosPass = ATMOS_PASS_PROC
/obj/machinery/door/firedoor/border_only/closed
@@ -227,6 +306,59 @@
opacity = TRUE
density = TRUE
/obj/machinery/door/firedoor/border_only/close()
if(density)
return TRUE
if(operating || welded)
return
var/turf/T1 = get_turf(src)
var/turf/T2 = get_step(T1, dir)
for(var/mob/living/M in T1)
if(M.stat == CONSCIOUS && M.pulling && M.pulling.loc == T2 && !M.pulling.anchored && M.pulling.move_resist <= M.move_force)
var/mob/living/M2 = M.pulling
if(!istype(M2) || !M2.buckled || !M2.buckled.buckle_prevents_pull)
to_chat(M, "<span class='notice'>You pull [M.pulling] through [src] right as it closes</span>")
M.pulling.forceMove(T1)
M.start_pulling(M2)
for(var/mob/living/M in T2)
if(M.stat == CONSCIOUS && M.pulling && M.pulling.loc == T1 && !M.pulling.anchored && M.pulling.move_resist <= M.move_force)
var/mob/living/M2 = M.pulling
if(!istype(M2) || !M2.buckled || !M2.buckled.buckle_prevents_pull)
to_chat(M, "<span class='notice'>You pull [M.pulling] through [src] right as it closes</span>")
M.pulling.forceMove(T2)
M.start_pulling(M2)
. = ..()
/obj/machinery/door/firedoor/border_only/allow_hand_open(mob/user)
var/area/A = get_area(src)
if((!A || !A.fire) && !is_holding_pressure())
return TRUE
whack_a_mole(TRUE) // WOOP WOOP SIDE EFFECTS
var/turf/T = loc
var/turf/T2 = get_step(T, dir)
if(!T || !T2)
return
var/status1 = check_door_side(T)
var/status2 = check_door_side(T2)
if((status1 == 1 && status2 == -1) || (status1 == -1 && status2 == 1))
to_chat(user, "<span class='warning'>Access denied. Try closing another firedoor to minimize decompression, or using a crowbar.</span>")
return FALSE
return TRUE
/obj/machinery/door/firedoor/border_only/proc/check_door_side(turf/open/start_point)
var/list/turfs = list()
turfs[start_point] = 1
for(var/i = 1; (i <= turfs.len && i <= 11); i++) // check up to 11 turfs.
var/turf/open/T = turfs[i]
if(istype(T, /turf/open/space))
return -1
for(var/T2 in T.atmos_adjacent_turfs)
turfs[T2] = 1
if(turfs.len <= 10)
return 0 // not big enough to matter
return start_point.air.return_pressure() < 20 ? -1 : 1
/obj/machinery/door/firedoor/border_only/CanPass(atom/movable/mover, turf/target)
if(istype(mover) && (mover.pass_flags & PASSGLASS))
return TRUE
@@ -257,6 +389,18 @@
assemblytype = /obj/structure/firelock_frame/heavy
max_integrity = 550
/obj/machinery/door/firedoor/window
name = "window shutter"
icon = 'icons/obj/doors/doorfirewindow.dmi'
desc = "A second window that slides in when the original window is broken, designed to protect against hull breaches. Truly a work of genius by NT engineers."
glass = TRUE
explosion_block = 0
max_integrity = 50
resistance_flags = 0 // not fireproof
heat_proof = FALSE
/obj/machinery/door/firedoor/window/allow_hand_open()
return TRUE
/obj/item/electronics/firelock
name = "firelock circuitry"
@@ -294,7 +438,7 @@
/obj/structure/firelock_frame/attackby(obj/item/C, mob/user)
switch(constructionStep)
if(CONSTRUCTION_PANEL_OPEN)
if(istype(C, /obj/item/crowbar))
if(C.tool_behaviour == TOOL_CROWBAR)
C.play_tool_sound(src)
user.visible_message("<span class='notice'>[user] starts prying something out from [src]...</span>", \
"<span class='notice'>You begin prying out the wire cover...</span>")
@@ -308,7 +452,7 @@
constructionStep = CONSTRUCTION_WIRES_EXPOSED
update_icon()
return
if(istype(C, /obj/item/wrench))
if(C.tool_behaviour == TOOL_WRENCH)
if(locate(/obj/machinery/door/firedoor) in get_turf(src))
to_chat(user, "<span class='warning'>There's already a firelock there.</span>")
return
@@ -350,7 +494,7 @@
return
if(CONSTRUCTION_WIRES_EXPOSED)
if(istype(C, /obj/item/wirecutters))
if(C.tool_behaviour == TOOL_WIRECUTTER)
C.play_tool_sound(src)
user.visible_message("<span class='notice'>[user] starts cutting the wires from [src]...</span>", \
"<span class='notice'>You begin removing [src]'s wires...</span>")
@@ -364,7 +508,7 @@
constructionStep = CONSTRUCTION_GUTTED
update_icon()
return
if(istype(C, /obj/item/crowbar))
if(C.tool_behaviour == TOOL_CROWBAR)
C.play_tool_sound(src)
user.visible_message("<span class='notice'>[user] starts prying a metal plate into [src]...</span>", \
"<span class='notice'>You begin prying the cover plate back onto [src]...</span>")
@@ -379,7 +523,7 @@
update_icon()
return
if(CONSTRUCTION_GUTTED)
if(istype(C, /obj/item/crowbar))
if(C.tool_behaviour == TOOL_CROWBAR)
user.visible_message("<span class='notice'>[user] begins removing the circuit board from [src]...</span>", \
"<span class='notice'>You begin prying out the circuit board from [src]...</span>")
if(!C.use_tool(src, user, 50, volume=50))
@@ -401,7 +545,7 @@
"<span class='notice'>You begin adding wires to [src]...</span>")
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
if(do_after(user, 60, target = src))
if(constructionStep != CONSTRUCTION_GUTTED || !B.use_tool(src, user, 0, 5))
if(constructionStep != CONSTRUCTION_GUTTED || B.get_amount() < 5 || !B)
return
user.visible_message("<span class='notice'>[user] adds wires to [src].</span>", \
"<span class='notice'>You wire [src].</span>")
@@ -410,7 +554,7 @@
update_icon()
return
if(CONSTRUCTION_NOCIRCUIT)
if(istype(C, /obj/item/weldingtool))
if(C.tool_behaviour == TOOL_WELDER)
if(!C.tool_start_check(user, amount=1))
return
user.visible_message("<span class='notice'>[user] begins cutting apart [src]'s frame...</span>", \
+3
View File
@@ -16,6 +16,9 @@
damage_deflection = 70
poddoor = TRUE
/obj/machinery/door/poddoor/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
id = "[idnum][id]"
/obj/machinery/door/poddoor/preopen
icon_state = "open"
density = FALSE
+21 -7
View File
@@ -11,7 +11,7 @@
integrity_failure = 0
armor = list("melee" = 20, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 70, "acid" = 100)
visible = FALSE
flags_1 = ON_BORDER_1
flags_1 = ON_BORDER_1|DEFAULT_RICOCHET_1
opacity = 0
CanAtmosPass = ATMOS_PASS_PROC
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN
@@ -54,6 +54,15 @@
else
icon_state = "[src.base_state]open"
/obj/machinery/door/window/update_atom_colour()
if((color && (color_hex2num(color) < 255)))
visible = TRUE
if(density)
set_opacity(TRUE)
else
visible = FALSE
set_opacity(density && visible)
/obj/machinery/door/window/proc/open_and_close()
open()
if(src.check_access(null))
@@ -143,16 +152,18 @@
do_animate("opening")
playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1)
src.icon_state ="[src.base_state]open"
sleep(10)
addtimer(CALLBACK(src, .proc/finish_opening), 10)
return TRUE
/obj/machinery/door/window/proc/finish_opening()
operating = FALSE
density = FALSE
// src.sd_set_opacity(0) //TODO: why is this here? Opaque windoors? ~Carn
if(visible)
set_opacity(FALSE)
air_update_turf(1)
update_freelook_sight()
if(operating == 1) //emag again
operating = FALSE
return 1
/obj/machinery/door/window/close(forced=0)
if (src.operating)
@@ -171,10 +182,13 @@
density = TRUE
air_update_turf(1)
update_freelook_sight()
sleep(10)
addtimer(CALLBACK(src, .proc/finish_closing), 10)
return TRUE
/obj/machinery/door/window/proc/finish_closing()
if(visible)
set_opacity(TRUE)
operating = FALSE
return 1
/obj/machinery/door/window/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
switch(damage_type)
-298
View File
@@ -1,298 +0,0 @@
//Experimental cloner; clones a body regardless of the owner's status, letting a ghost control it instead
/obj/machinery/clonepod/experimental
name = "experimental cloning pod"
desc = "An ancient cloning pod. It seems to be an early prototype of the experimental cloners used in Nanotrasen Stations."
icon = 'icons/obj/machines/cloning.dmi'
icon_state = "pod_0"
req_access = null
circuit = /obj/item/circuitboard/machine/clonepod/experimental
internal_radio = FALSE
//Start growing a human clone in the pod!
/obj/machinery/clonepod/experimental/growclone(clonename, ui, mutation_index, mindref, last_death, blood_type, datum/species/mrace, list/features, factions, list/quirks)
if(panel_open)
return FALSE
if(mess || attempting)
return FALSE
attempting = TRUE //One at a time!!
countdown.start()
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
if(efficiency > 2)
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
H.dna.remove_mutation_group(unclean_mutations)
if(efficiency > 5 && prob(20))
H.easy_randmut(POSITIVE)
if(efficiency < 3 && prob(50))
var/mob/M = H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
if(ismob(M))
H = M
H.silent = 20 //Prevents an extreme edge case where clones could speak if they said something at exactly the right moment.
occupant = H
if(!clonename) //to prevent null names
clonename = "clone ([rand(1,999)])"
H.real_name = clonename
icon_state = "pod_1"
//Get the clone body ready
maim_clone(H)
ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning")
ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning")
ADD_TRAIT(H, TRAIT_MUTE, "cloning")
ADD_TRAIT(H, TRAIT_NOBREATH, "cloning")
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H)
if(LAZYLEN(candidates))
var/mob/C = pick(candidates)
H.key = C.key
if(grab_ghost_when == CLONER_FRESH_CLONE)
H.grab_ghost()
to_chat(H, "<span class='notice'><b>Consciousness slowly creeps over you as your body regenerates.</b><br><i>So this is what cloning feels like?</i></span>")
if(grab_ghost_when == CLONER_MATURE_CLONE)
H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
to_chat(H.get_ghost(TRUE), "<span class='notice'>Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.</span>")
if(H)
H.faction |= factions
H.set_cloned_appearance()
H.suiciding = FALSE
attempting = FALSE
return TRUE
//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks.
/obj/machinery/computer/prototype_cloning
name = "prototype cloning console"
desc = "Used to operate an experimental cloner."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/prototype_cloning
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/list/pods //Linked experimental cloning pods
var/temp = "Inactive"
var/scantemp = "Ready to Scan"
var/loading = FALSE // Nice loading text
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/prototype_cloning/Initialize()
. = ..()
updatemodules(TRUE)
/obj/machinery/computer/prototype_cloning/Destroy()
if(pods)
for(var/P in pods)
DetachCloner(P)
pods = null
return ..()
/obj/machinery/computer/prototype_cloning/proc/GetAvailablePod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/experimental/pod = P
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
/obj/machinery/computer/prototype_cloning/proc/updatemodules(findfirstcloner)
scanner = findscanner()
if(findfirstcloner && !LAZYLEN(pods))
findcloner()
/obj/machinery/computer/prototype_cloning/proc/findscanner()
var/obj/machinery/dna_scannernew/scannerf = null
// Loop through every direction
for(var/direction in GLOB.cardinals)
// Try to find a scanner in that direction
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, direction))
// If found and operational, return the scanner
if (!isnull(scannerf) && scannerf.is_operational())
return scannerf
// If no scanner was found, it will return null
return null
/obj/machinery/computer/prototype_cloning/proc/findcloner()
var/obj/machinery/clonepod/experimental/podf = null
for(var/direction in GLOB.cardinals)
podf = locate(/obj/machinery/clonepod/experimental, get_step(src, direction))
if (!isnull(podf) && podf.is_operational())
AttachCloner(podf)
/obj/machinery/computer/prototype_cloning/proc/AttachCloner(obj/machinery/clonepod/experimental/pod)
if(!pod.connected)
pod.connected = src
LAZYADD(pods, pod)
/obj/machinery/computer/prototype_cloning/proc/DetachCloner(obj/machinery/clonepod/experimental/pod)
pod.connected = null
LAZYREMOVE(pods, pod)
/obj/machinery/computer/prototype_cloning/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/multitool))
var/obj/item/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod/experimental))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
return
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
var/obj/machinery/clonepod/experimental/pod = P.buffer
if(pod.connected)
pod.connected.DetachCloner(pod)
AttachCloner(pod)
else
P.buffer = src
to_chat(user, "<font color = #666633>-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-</font color>")
return
else
return ..()
/obj/machinery/computer/prototype_cloning/attack_hand(mob/user)
if(..())
return
interact(user)
/obj/machinery/computer/prototype_cloning/interact(mob/user)
user.set_machine(src)
add_fingerprint(user)
if(..())
return
updatemodules(TRUE)
var/dat = ""
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
if (isnull(src.scanner) || !LAZYLEN(pods))
dat += "<h3>Modules</h3>"
//dat += "<a href='byond://?src=[REF(src)];relmodules=1'>Reload Modules</a>"
if (isnull(src.scanner))
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
if (!LAZYLEN(pods))
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
// Scan-n-Clone
if (!isnull(src.scanner))
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
dat += "<h3>Cloning</h3>"
dat += "<div class='statusDisplay'>"
if(!scanner_occupant)
dat += "Scanner Unoccupied"
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
scantemp = "Ready to Clone"
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=[REF(src)];clone=1'>Clone</a>"
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>Clone</span>"
var/datum/browser/popup = new(user, "cloning", "Prototype Cloning System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/prototype_cloning/Topic(href, href_list)
if(..())
return
if(loading)
return
else if ((href_list["clone"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = TRUE
updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
spawn(20)
clone_occupant(scanner.occupant)
loading = FALSE
updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
if ((!scanner.locked) && (scanner.occupant))
scanner.locked = TRUE
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
scanner.locked = FALSE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if (href_list["refresh"])
updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
add_fingerprint(usr)
updateUsrDialog()
return
/obj/machinery/computer/prototype_cloning/proc/clone_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(ishuman(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
var/clone_species
if(dna.species)
clone_species = dna.species
else
var/datum/species/rando_race = pick(GLOB.roundstart_races)
clone_species = rando_race.type
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
pod.growclone(mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
+1 -1
View File
@@ -141,7 +141,7 @@
if(user)
log_game("[user] reset a fire alarm at [COORD(src)]")
/obj/machinery/firealarm/attack_hand(mob/user)
/obj/machinery/firealarm/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(buildstage != 2)
return ..()
add_fingerprint(user)
+3
View File
@@ -36,6 +36,9 @@
else
bulb = new(src)
/obj/machinery/flasher/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
id = "[idnum][id]"
/obj/machinery/flasher/Destroy()
QDEL_NULL(bulb)
return ..()
+13 -14
View File
@@ -20,18 +20,15 @@
return ..()
/obj/machinery/gulag_item_reclaimer/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED) // emagging lets anyone reclaim all the items
return
req_access = list()
obj_flags |= EMAGGED
return TRUE
/obj/machinery/gulag_item_reclaimer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/gulag_item_reclaimer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "gulag_item_reclaimer", name, 300, 400, master_ui, state)
ui = new(user, src, "GulagItemReclaimer", name)
ui.open()
/obj/machinery/gulag_item_reclaimer/ui_data(mob/user)
@@ -60,20 +57,22 @@
mobs += list(mob_info)
data["mobs"] = mobs
data["can_reclaim"] = can_reclaim
return data
/obj/machinery/gulag_item_reclaimer/ui_act(action, list/params)
/obj/machinery/gulag_item_reclaimer/ui_act(action, params)
if(..())
return
switch(action)
if("release_items")
var/mob/M = locate(params["mobref"])
if(M == usr || allowed(usr))
drop_items(M)
else
to_chat(usr, "Access denied.")
var/mob/living/carbon/human/H = locate(params["mobref"]) in stored_items
if(H != usr && !allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return
drop_items(H)
. = TRUE
/obj/machinery/gulag_item_reclaimer/proc/drop_items(mob/user)
if(!stored_items[user])
-2
View File
@@ -101,8 +101,6 @@ The console is located at computer/gulag_teleporter.dm
if(!locked)
open_machine()
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
"<span class='italics'>You hear a metallic creaking from [src].</span>")
+1 -1
View File
@@ -50,7 +50,7 @@
harvesting = FALSE
warming_up = FALSE
/obj/machinery/harvester/attack_hand(mob/user)
/obj/machinery/harvester/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(state_open)
close_machine()
else if(!harvesting)
+183 -188
View File
@@ -25,7 +25,6 @@ Possible to do for anyone motivated enough:
*/
GLOBAL_LIST_EMPTY(network_holopads)
#define HOLOPAD_PASSIVE_POWER_USAGE 1
#define HOLOGRAM_POWER_USAGE 2
@@ -34,34 +33,64 @@ GLOBAL_LIST_EMPTY(network_holopads)
desc = "It's a floor-mounted device for projecting holographic images."
icon_state = "holopad0"
layer = LOW_OBJ_LAYER
plane = ABOVE_WALL_PLANE
plane = FLOOR_PLANE
flags_1 = HEAR_1
req_access = list(ACCESS_KEYCARD_AUTH) //Used to allow for forced connecting to other (not secure) holopads. Anyone can make a call, though.
use_power = IDLE_POWER_USE
idle_power_usage = 5
active_power_usage = 100
max_integrity = 300
armor = list("melee" = 50, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 0)
circuit = /obj/item/circuitboard/machine/holopad
var/list/masters //List of living mobs that use the holopad
var/list/holorays //Holoray-mob link.
var/last_request = 0 //to prevent request spam. ~Carn
var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating.
var/temp = ""
var/list/holo_calls //array of /datum/holocalls
var/datum/holocall/outgoing_call //do not modify the datums only check and call the public procs
var/obj/item/disk/holodisk/disk //Record disk
var/replay_mode = FALSE //currently replaying a recording
var/loop_mode = FALSE //currently looping a recording
var/record_mode = FALSE //currently recording
var/record_start = 0 //recording start time
var/record_user //user that inititiated the recording
var/obj/effect/overlay/holo_pad_hologram/replay_holo //replay hologram
var/static/force_answer_call = FALSE //Calls will be automatically answered after a couple rings, here for debugging
/// List of living mobs that use the holopad
var/list/masters
/// Holoray-mob link
var/list/holorays
/// To prevent request spam. ~Carn
var/last_request = 0
/// Change to change how far the AI can move away from the holopad before deactivating
var/holo_range = 5
/// Array of /datum/holocalls
var/list/holo_calls
/// Currently outgoing holocall, do not modify the datums only check and call the public procs
var/datum/holocall/outgoing_call
/// Record disk
var/obj/item/disk/holodisk/disk
/// Currently replaying a recording
var/replay_mode = FALSE
/// Currently looping a recording
var/loop_mode = FALSE
/// Currently recording
var/record_mode = FALSE
/// Recording start time
var/record_start = 0
/// User that inititiated the recording
var/record_user
/// Replay hologram
var/obj/effect/overlay/holo_pad_hologram/replay_holo
/// Calls will be automatically answered after a couple rings, here for debugging
var/static/force_answer_call = FALSE
// var/static/list/holopads = list()
var/obj/effect/overlay/holoray/ray
var/ringing = FALSE
var/offset = FALSE
var/on_network = TRUE
/// For pads in secure areas; do not allow forced connecting
var/secure = FALSE
/// If we are currently calling another holopad
var/calling = FALSE
/*
/obj/machinery/holopad/secure
name = "secure holopad"
desc = "It's a floor-mounted device for projecting holographic images. This one will refuse to auto-connect incoming calls."
secure = TRUE
/obj/machinery/holopad/secure/Initialize()
. = ..()
var/obj/item/circuitboard/machine/holopad/board = circuit
board.secure = TRUE
board.build_path = /obj/machinery/holopad/secure
*/
/obj/machinery/holopad/tutorial
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
flags_1 = NODECONSTRUCT_1
@@ -78,7 +107,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
new_disk.forceMove(src)
disk = new_disk
/obj/machinery/holopad/tutorial/attack_hand(mob/user)
/obj/machinery/holopad/tutorial/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!istype(user))
return
if(user.incapacitated() || !is_operational())
@@ -121,10 +150,8 @@ GLOBAL_LIST_EMPTY(network_holopads)
return ..()
/obj/machinery/holopad/power_change()
if (powered())
stat &= ~NOPOWER
else
stat |= NOPOWER
. = ..()
if (!powered())
if(replay_mode)
replay_stop()
if(record_mode)
@@ -163,171 +190,150 @@ GLOBAL_LIST_EMPTY(network_holopads)
if(istype(P,/obj/item/disk/holodisk))
if(disk)
to_chat(user,"<span class='notice'>There's already a disk inside [src]</span>")
to_chat(user,"<span class='warning'>There's already a disk inside [src]!</span>")
return
if (!user.transferItemToLoc(P,src))
return
to_chat(user,"<span class='notice'>You insert [P] into [src]</span>")
to_chat(user,"<span class='notice'>You insert [P] into [src].</span>")
disk = P
updateDialog()
return
return ..()
/obj/machinery/holopad/ui_status(mob/user)
if(!is_operational())
return UI_CLOSE
if(outgoing_call && !calling)
return UI_CLOSE
return ..()
/obj/machinery/holopad/ui_interact(mob/living/carbon/human/user) //Carn: Hologram requests.
/obj/machinery/holopad/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Holopad", name)
ui.open()
/obj/machinery/holopad/ui_data(mob/user)
var/list/data = list()
data["calling"] = calling
data["on_network"] = on_network
data["on_cooldown"] = last_request + 200 < world.time ? FALSE : TRUE
data["allowed"] = allowed(user)
data["disk"] = disk ? TRUE : FALSE
data["disk_record"] = disk?.record ? TRUE : FALSE
data["replay_mode"] = replay_mode
data["loop_mode"] = loop_mode
data["record_mode"] = record_mode
data["holo_calls"] = list()
for(var/I in holo_calls)
var/datum/holocall/HC = I
var/list/call_data = list(
caller = HC.user,
connected = HC.connected_holopad == src ? TRUE : FALSE,
ref = REF(HC)
)
data["holo_calls"] += list(call_data)
return data
/obj/machinery/holopad/ui_act(action, list/params)
. = ..()
if(!istype(user))
if(.)
return
if(outgoing_call || user.incapacitated() || !is_operational())
return
user.set_machine(src)
var/dat
if(temp)
dat = temp
else
if(on_network)
dat += "<a href='?src=[REF(src)];AIrequest=1'>Request an AI's presence</a><br>"
dat += "<a href='?src=[REF(src)];Holocall=1'>Call another holopad</a><br>"
if(disk)
if(disk.record)
//Replay
dat += "<a href='?src=[REF(src)];replay_start=1'>Replay disk recording</a><br>"
dat += "<a href='?src=[REF(src)];loop_start=1'>Loop disk recording</a><br>"
//Clear
dat += "<a href='?src=[REF(src)];record_clear=1'>Clear disk recording</a><br>"
switch(action)
if("AIrequest")
if(last_request + 200 < world.time)
last_request = world.time
to_chat(usr, "<span class='info'>You requested an AI's presence.</span>")
var/area/area = get_area(src)
for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs)
if(!AI.client)
continue
to_chat(AI, "<span class='info'>Your presence is requested at <a href='?src=[REF(AI)];jumptoholopad=[REF(src)]'>\the [area]</a>.</span>")
return TRUE
else
//Record
dat += "<a href='?src=[REF(src)];record_start=1'>Start new recording</a><br>"
//Eject
dat += "<a href='?src=[REF(src)];disk_eject=1'>Eject disk</a><br>"
to_chat(usr, "<span class='info'>A request for AI presence was already sent recently.</span>")
return
if("holocall")
if(outgoing_call)
return
if(usr.loc == loc)
var/list/callnames = list()
for(var/I in GLOB.network_holopads)
var/area/A = get_area(I)
if(A)
LAZYADD(callnames[A], I)
callnames -= get_area(src)
var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in sortNames(callnames)
if(QDELETED(usr) || !result || outgoing_call)
return
if(usr.loc == loc)
var/input = text2num(params["headcall"])
var/headcall = input == 1 ? TRUE : FALSE
new /datum/holocall(usr, src, callnames[result], headcall)
calling = TRUE
return TRUE
else
to_chat(usr, "<span class='warning'>You must stand on the holopad to make a call!</span>")
if("connectcall")
var/datum/holocall/call_to_connect = locate(params["holopad"]) in holo_calls
if(!QDELETED(call_to_connect))
call_to_connect.Answer(src)
return TRUE
if("disconnectcall")
var/datum/holocall/call_to_disconnect = locate(params["holopad"]) in holo_calls
if(!QDELETED(call_to_disconnect))
call_to_disconnect.Disconnect(src)
return TRUE
if("disk_eject")
if(disk && !replay_mode)
disk.forceMove(drop_location())
disk = null
return TRUE
if("replay_mode")
if(replay_mode)
replay_stop()
return TRUE
else
replay_start()
return TRUE
if("loop_mode")
loop_mode = !loop_mode
return TRUE
if("record_mode")
if(record_mode)
record_stop()
return TRUE
else
record_start(usr)
return TRUE
if("record_clear")
record_clear()
return TRUE
if("offset")
offset++
if(offset > 4)
offset = FALSE
var/turf/new_turf
if(!offset)
new_turf = get_turf(src)
else
new_turf = get_step(src, GLOB.cardinals[offset])
replay_holo.forceMove(new_turf)
return TRUE
if("hang_up")
if(outgoing_call)
outgoing_call.Disconnect(src)
return TRUE
if(LAZYLEN(holo_calls))
dat += "=====================================================<br>"
if(on_network)
var/one_answered_call = FALSE
var/one_unanswered_call = FALSE
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad != src)
dat += "<a href='?src=[REF(src)];connectcall=[REF(HC)]'>Answer call from [get_area(HC.calling_holopad)]</a><br>"
one_unanswered_call = TRUE
else
one_answered_call = TRUE
if(one_answered_call && one_unanswered_call)
dat += "=====================================================<br>"
//we loop twice for formatting
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad == src)
dat += "<a href='?src=[REF(src)];disconnectcall=[REF(HC)]'>Disconnect call from [HC.user]</a><br>"
var/datum/browser/popup = new(user, "holopad", name, 300, 175)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
//Stop ringing the AI!!
/**
* hangup_all_calls: Disconnects all current holocalls from the holopad
*/
/obj/machinery/holopad/proc/hangup_all_calls()
for(var/I in holo_calls)
var/datum/holocall/HC = I
HC.Disconnect(src)
/obj/machinery/holopad/Topic(href, href_list)
if(..() || isAI(usr))
return
add_fingerprint(usr)
if(!is_operational())
return
if (href_list["AIrequest"])
if(last_request + 200 < world.time)
last_request = world.time
temp = "You requested an AI's presence.<BR>"
temp += "<A href='?src=[REF(src)];mainmenu=1'>Main Menu</A>"
var/area/area = get_area(src)
for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs)
if(!AI.client)
continue
to_chat(AI, "<span class='info'>Your presence is requested at <a href='?src=[REF(AI)];jumptoholopad=[REF(src)]'>\the [area]</a>.</span>")
else
temp = "A request for AI presence was already sent recently.<BR>"
temp += "<A href='?src=[REF(src)];mainmenu=1'>Main Menu</A>"
else if(href_list["Holocall"])
if(outgoing_call)
return
temp = "You must stand on the holopad to make a call!<br>"
temp += "<A href='?src=[REF(src)];mainmenu=1'>Main Menu</A>"
if(usr.loc == loc)
var/list/callnames = list()
for(var/I in GLOB.network_holopads)
var/area/A = get_area(I)
if(A)
LAZYADD(callnames[A], I)
callnames -= get_area(src)
var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in callnames
if(QDELETED(usr) || !result || outgoing_call)
return
if(usr.loc == loc)
temp = "Dialing...<br>"
temp += "<A href='?src=[REF(src)];mainmenu=1'>Main Menu</A>"
new /datum/holocall(usr, src, callnames[result])
else if(href_list["connectcall"])
var/datum/holocall/call_to_connect = locate(href_list["connectcall"])
if(!QDELETED(call_to_connect))
call_to_connect.Answer(src)
temp = ""
else if(href_list["disconnectcall"])
var/datum/holocall/call_to_disconnect = locate(href_list["disconnectcall"])
if(!QDELETED(call_to_disconnect))
call_to_disconnect.Disconnect(src)
temp = ""
else if(href_list["mainmenu"])
temp = ""
if(outgoing_call)
outgoing_call.Disconnect()
else if(href_list["disk_eject"])
if(disk && !replay_mode)
disk.forceMove(drop_location())
disk = null
else if(href_list["replay_stop"])
replay_stop()
else if(href_list["replay_start"])
replay_start()
else if(href_list["loop_start"])
loop_mode = TRUE
replay_start()
else if(href_list["record_start"])
record_start(usr)
else if(href_list["record_stop"])
record_stop()
else if(href_list["record_clear"])
record_clear()
else if(href_list["offset"])
offset++
if (offset > 4)
offset = FALSE
var/turf/new_turf
if (!offset)
new_turf = get_turf(src)
else
new_turf = get_step(src, GLOB.cardinals[offset])
replay_holo.forceMove(new_turf)
updateDialog()
//do not allow AIs to answer calls or people will use it to meta the AI sattelite
/obj/machinery/holopad/attack_ai(mob/living/silicon/ai/user)
if (!istype(user))
@@ -366,6 +372,9 @@ GLOBAL_LIST_EMPTY(network_holopads)
if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2)))
HC.Answer(src)
break
if(!secure) //HC.head_call &&
HC.Answer(src)
break
if(outgoing_call)
HC.Disconnect(src)//can't answer calls while calling
else
@@ -412,17 +421,17 @@ GLOBAL_LIST_EMPTY(network_holopads)
/*This is the proc for special two-way communication between AI and holopad/people talking near holopad.
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(speaker && LAZYLEN(masters) && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
for(var/mob/living/silicon/ai/master in masters)
if(masters[master] && speaker != master)
master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad == src && speaker != HC.hologram)
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode, source)
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
if(outgoing_call && speaker == outgoing_call.user)
outgoing_call.hologram.say(raw_message)
@@ -449,7 +458,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
else
icon_state = "holopad0"
/obj/machinery/holopad/proc/set_holo(mob/living/user, var/obj/effect/overlay/holo_pad_hologram/h)
/obj/machinery/holopad/proc/set_holo(mob/living/user, obj/effect/overlay/holo_pad_hologram/h)
LAZYSET(masters, user, h)
LAZYSET(holorays, user, new /obj/effect/overlay/holoray(loc))
var/mob/living/silicon/ai/AI = user
@@ -504,7 +513,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
else
return FALSE
/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf, direction)
/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf)
if(LAZYLEN(masters) && masters[user])
var/obj/effect/overlay/holo_pad_hologram/holo = masters[user]
var/transfered = FALSE
@@ -516,8 +525,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
transfered = TRUE
//All is good.
holo.forceMove(new_turf)
if(direction)
holo.setDir(direction)
if(!transfered)
update_holoray(user,new_turf)
return TRUE
@@ -568,22 +575,15 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(!replay_mode)
replay_mode = TRUE
replay_holo = setup_replay_holo(disk.record)
temp = "Replaying...<br>"
temp += "<A href='?src=[REF(src)];offset=1'>Change offset</A><br>"
temp += "<A href='?src=[REF(src)];replay_stop=1'>End replay</A>"
SetLightsAndPower()
replay_entry(1)
return
/obj/machinery/holopad/proc/replay_stop()
if(replay_mode)
replay_mode = FALSE
loop_mode = FALSE
offset = FALSE
temp = null
QDEL_NULL(replay_holo)
SetLightsAndPower()
updateDialog()
/obj/machinery/holopad/proc/record_start(mob/living/user)
if(!user || !disk || disk.record)
@@ -593,8 +593,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
record_start = world.time
record_user = user
disk.record.set_caller_image(user)
temp = "Recording...<br>"
temp += "<A href='?src=[REF(src)];record_stop=1'>End recording.</A>"
/obj/machinery/holopad/proc/record_message(mob/living/speaker,message,language)
if(!record_mode)
@@ -641,7 +639,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(replay_holo)
replay_holo.say(message)
if(HOLORECORD_SOUND)
playsound(src,entry[2],50,1)
playsound(src,entry[2],50,TRUE)
if(HOLORECORD_DELAY)
addtimer(CALLBACK(src,.proc/replay_entry,entry_number+1),entry[2])
return
@@ -660,14 +658,11 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/holopad/proc/record_stop()
if(record_mode)
record_mode = FALSE
temp = null
record_user = null
updateDialog()
/obj/machinery/holopad/proc/record_clear()
if(disk && disk.record)
QDEL_NULL(disk.record)
updateDialog()
/obj/effect/overlay/holo_pad_hologram
initial_language_holder = /datum/language_holder/universal
+9 -12
View File
@@ -6,14 +6,12 @@
circuit = /obj/item/circuitboard/machine/hypnochair
density = TRUE
opacity = 0
ui_x = 375
ui_y = 480
var/mob/living/carbon/victim = null ///Keeps track of the victim to apply effects if it teleports away
var/interrogating = FALSE ///Is the device currently interrogating someone?
var/start_time = 0 ///Time when the interrogation was started, to calculate effect in case of interruption
var/trigger_phrase = "" ///Trigger phrase to implant
var/timerid = 0 ///Timer ID for interrogations
var/message_cooldown = 0 ///Cooldown for breakout message
/obj/machinery/hypnochair/Initialize()
@@ -25,24 +23,24 @@
if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I))
update_icon()
return
if(default_pry_open(I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
/obj/machinery/hypnochair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/hypnochair/ui_state(mob/user)
return GLOB.notcontained_state
/obj/machinery/hypnochair/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "hypnochair", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "HypnoChair", name)
ui.open()
/obj/machinery/hypnochair/ui_data()
var/list/data = list()
data["occupied"] = occupant ? TRUE : FALSE
data["occupied"] = occupant ? 1 : 0
data["open"] = state_open
data["interrogating"] = interrogating
@@ -178,8 +176,6 @@
icon_state += "_occupied"
/obj/machinery/hypnochair/container_resist(mob/living/user)
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(600)].)</span>", \
"<span class='hear'>You hear a metallic creaking from [src].</span>")
@@ -203,3 +199,4 @@
if(!(L.mobility_flags & MOBILITY_STAND))
return
close_machine(target)
+4 -4
View File
@@ -26,10 +26,7 @@
on = TRUE
icon_state = "igniter1"
/obj/machinery/igniter/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/igniter/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
add_fingerprint(user)
use_power(50)
@@ -53,6 +50,9 @@
else
icon_state = "igniter0"
/obj/machinery/igniter/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
id = "[idnum][id]"
// Wall mounted remote-control igniter.
/obj/machinery/sparker
+26 -11
View File
@@ -3,17 +3,19 @@
/obj/machinery/iv_drip
name = "\improper IV drip"
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate."
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. Alt-Click to change the transfer rate."
icon = 'icons/obj/iv_drip.dmi'
icon_state = "iv_drip"
anchored = FALSE
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
var/mob/living/carbon/attached
var/mode = IV_INJECTING
var/dripfeed = FALSE
var/obj/item/reagent_containers/beaker
var/static/list/drip_containers = typecacheof(list(/obj/item/reagent_containers/blood,
/obj/item/reagent_containers/food,
/obj/item/reagent_containers/glass))
/obj/item/reagent_containers/glass,
/obj/item/reagent_containers/chem_pack))
/obj/machinery/iv_drip/Initialize(mapload)
. = ..()
@@ -131,9 +133,11 @@
if(mode)
if(beaker.reagents.total_volume)
var/transfer_amount = 5
if (dripfeed)
transfer_amount = 1
if(istype(beaker, /obj/item/reagent_containers/blood))
// speed up transfer on blood packs
transfer_amount = 10
transfer_amount *= 2
var/fraction = min(transfer_amount/beaker.reagents.total_volume, 1) //the fraction that is transfered of the total volume
beaker.reagents.reaction(attached, INJECT, fraction, FALSE) //make reagents reacts, but don't spam messages
beaker.reagents.trans_to(attached, transfer_amount)
@@ -157,12 +161,7 @@
attached.transfer_blood_to(beaker, amount)
update_icon()
/obj/machinery/iv_drip/attack_hand(mob/user)
. = ..()
if(.)
return
if(!ishuman(user))
return
/obj/machinery/iv_drip/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(attached)
visible_message("[attached] is detached from [src]")
attached = null
@@ -173,7 +172,21 @@
else
toggle_mode()
/obj/machinery/iv_drip/verb/eject_beaker()
/obj/machinery/iv_drip/AltClick(mob/living/user)
if(!user.canUseTopic(src, be_close=TRUE))
return
if(dripfeed)
dripfeed = FALSE
to_chat(usr, "<span class='notice'>You loosen the valve to speed up the [src].</span>")
else
dripfeed = TRUE
to_chat(usr, "<span class='notice'>You tighten the valve to slowly drip-feed the contents of [src].</span>")
/obj/machinery/iv_drip/attack_robot(mob/user)
if(Adjacent(user))
attack_hand(user)
/obj/machinery/iv_drip/verb/eject_beaker(mob/user)
set category = "Object"
set name = "Remove IV Container"
set src in view(1)
@@ -188,6 +201,8 @@
if(usr && Adjacent(usr) && usr.can_hold_items())
if(!usr.put_in_hands(beaker))
beaker.forceMove(drop_location())
if(iscyborg(user))
beaker.forceMove(drop_location())
beaker = null
update_icon()
@@ -225,7 +240,7 @@
/obj/machinery/iv_drip/telescopic
name = "telescopic IV drip"
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down."
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down.Alt-Click with a beaker attached to change the transfer rate."
icon_state = "iv_drip"
/obj/machinery/iv_drip/telescopic/update_icon_state()
+7 -6
View File
@@ -282,13 +282,14 @@
ui_interact(user)
to_chat(user, "<span class='notice'>[src] projects a display onto your retina.</span>")
/obj/item/launchpad_remote/ui_interact(mob/user, ui_key = "launchpad_remote", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "launchpad_remote", "Briefcase Launchpad Remote", 300, 240, master_ui, state) //width, height
ui.set_style("syndicate")
ui.open()
/obj/item/launchpad_remote/ui_state(mob/user)
return GLOB.inventory_state
/obj/item/launchpad_remote/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "LaunchpadRemote")
ui.open()
ui.set_autoupdate(TRUE)
/obj/item/launchpad_remote/ui_data(mob/user)
+2
View File
@@ -11,6 +11,8 @@
var/id = 1
var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess.
/obj/machinery/mass_driver/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
id = "[idnum][id]"
/obj/machinery/mass_driver/proc/drive(amount)
if(stat & (BROKEN|NOPOWER))
@@ -4,6 +4,15 @@
#define POPUP_ANIM_TIME 5
#define POPDOWN_ANIM_TIME 5 //Be sure to change the icon animation at the same time or it'll look bad
#define TURRET_FLAG_SHOOT_ALL_REACT (1<<0) // The turret gets pissed off and shoots at people nearby (unless they have sec access!)
#define TURRET_FLAG_AUTH_WEAPONS (1<<1) // Checks if it can shoot people that have a weapon they aren't authorized to have
#define TURRET_FLAG_SHOOT_CRIMINALS (1<<2) // Checks if it can shoot people that are wanted
#define TURRET_FLAG_SHOOT_ALL (1<<3) // The turret gets pissed off and shoots at people nearby (unless they have sec access!)
#define TURRET_FLAG_SHOOT_ANOMALOUS (1<<4) // Checks if it can shoot at unidentified lifeforms (ie xenos)
#define TURRET_FLAG_SHOOT_UNSHIELDED (1<<5) // Checks if it can shoot people that aren't mindshielded and who arent heads
#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
/obj/machinery/porta_turret
name = "turret"
icon = 'icons/obj/turrets.dmi'
@@ -15,69 +24,79 @@
use_power = IDLE_POWER_USE //this turret uses and requires power
idle_power_usage = 50 //when inactive, this turret takes up constant 50 Equipment power
active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power
req_access = list(ACCESS_SEC_DOORS)
req_access = list(ACCESS_SECURITY) /// Only people with Security access
power_channel = EQUIP //drains power from the EQUIPMENT channel
var/base_icon_state = "standard"
var/scan_range = 7
var/atom/base = null //for turrets inside other objects
var/raised = 0 //if the turret cover is "open" and the turret is raised
var/raising= 0 //if the turret is currently opening or closing its cover
max_integrity = 160 //the turret's health
integrity_failure = 0.5
armor = list("melee" = 50, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
var/locked = TRUE //if the turret's behaviour control access is locked
var/controllock = FALSE //if the turret responds to control panels
var/installation = /obj/item/gun/energy/e_gun/turret //the type of weapon installed by default
/// Base turret icon state
var/base_icon_state = "standard"
/// Scan range of the turret for locating targets
var/scan_range = 7
/// For turrets inside other objects
var/atom/base = null
/// If the turret cover is "open" and the turret is raised
var/raised = FALSE
/// If the turret is currently opening or closing its cover
var/raising = FALSE
/// If the turret's behaviour control access is locked
var/locked = TRUE
/// If the turret responds to control panels
var/controllock = FALSE
/// The type of weapon installed by default
var/installation = /obj/item/gun/energy/e_gun/turret
/// What stored gun is in the turret
var/obj/item/gun/stored_gun = null
var/gun_charge = 0 //the charge of the gun when retrieved from wreckage
/// The charge of the gun when retrieved from wreckage
var/gun_charge = 0
/// In which mode is turret in, stun or lethal
var/mode = TURRET_STUN
var/stun_projectile = null //stun mode projectile type
/// Stun mode projectile type
var/stun_projectile = null
/// Sound of stun projectile
var/stun_projectile_sound
var/nonlethal_projectile //projectile to use in stun mode when the target is resting, if any
/// Projectile to use in stun mode when the target is resting, if any
var/nonlethal_projectile
/// Sound of stun projectile wen the target is resting, optional
var/nonlethal_projectile_sound
var/lethal_projectile = null //lethal mode projectile type
/// Lethal mode projectile type
var/lethal_projectile = null
/// Sound of lethal projectile
var/lethal_projectile_sound
var/reqpower = 500 //power needed per shot
var/always_up = 0 //Will stay active
var/has_cover = 1 //Hides the cover
var/obj/machinery/porta_turret_cover/cover = null //the cover that is covering this turret
var/last_fired = 0 //world.time the turret last fired
var/shot_delay = 15 //ticks until next shot (1.5 ?)
var/check_records = 1 //checks if it can use the security records
var/criminals = 1 //checks if it can shoot people on arrest
var/auth_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have
var/stun_all = 0 //if this is active, the turret shoots everything that isn't security or head of staff
var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos)
var/shoot_unloyal = 0 //checks if it can shoot people that aren't loyalty implantd
var/attacked = 0 //if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!)
var/on = TRUE //determines if the turret is on
var/list/faction = list("turret") // Same faction mobs will never be shot at, no matter the other settings
var/datum/effect_system/spark_spread/spark_system //the spark system, used for generating... sparks?
/// Power needed per shot
var/reqpower = 500
/// Will stay active
var/always_up = FALSE
/// Hides the cover
var/has_cover = TRUE
/// The cover that is covering this turret
var/obj/machinery/porta_turret_cover/cover = null
/// World.time the turret last fired
var/last_fired = 0
/// Ticks until next shot (1.5 ?)
var/shot_delay = 15
/// Turret flags about who is turret allowed to shoot
var/turret_flags = TURRET_FLAG_SHOOT_CRIMINALS | TURRET_FLAG_SHOOT_ANOMALOUS
/// Determines if the turret is on
var/on = TRUE
/// Same faction mobs will never be shot at, no matter the other settings
var/list/faction = list("turret")
/// The spark system, used for generating... sparks?
var/datum/effect_system/spark_spread/spark_system
/// Linked turret control panel of the turret
var/obj/machinery/turretid/cp = null
var/wall_turret_direction //The turret will try to shoot from a turf in that direction when in a wall
var/manual_control = FALSE //
/// The turret will try to shoot from a turf in that direction when in a wall
var/wall_turret_direction
/// If the turret is manually controlled
var/manual_control = FALSE
/// Action button holder for quitting manual control
var/datum/action/turret_quit/quit_action
/// Action button holder for switching between turret modes when manually controlling
var/datum/action/turret_toggle/toggle_action
/// Mob that is remotely controlling the turret
var/mob/remote_controller
/// MISSING:
var/shot_stagger = 0
/obj/machinery/porta_turret/Initialize()
. = ..()
@@ -99,6 +118,27 @@
if(!has_cover)
INVOKE_ASYNC(src, .proc/popUp)
/obj/machinery/porta_turret/proc/toggle_on(var/set_to)
var/current = on
if (!isnull(set_to))
on = set_to
else
on = !on
if (current != on)
check_should_process()
if (!on)
popDown()
/obj/machinery/porta_turret/proc/check_should_process()
if (datum_flags & DF_ISPROCESSING)
if (!on || !anchored || (stat & BROKEN) || !powered())
//end_processing()
STOP_PROCESSING(SSmachines, src)
else
if (on && anchored && !(stat & BROKEN) && powered())
START_PROCESSING(SSmachines, src)
//begin_processing()
/obj/machinery/porta_turret/update_icon_state()
if(!anchored)
icon_state = "turretCover"
@@ -118,7 +158,6 @@
else
icon_state = "[base_icon_state]_unpowered"
/obj/machinery/porta_turret/proc/setup(obj/item/gun/turret_gun)
if(stored_gun)
qdel(stored_gun)
@@ -159,83 +198,88 @@
remove_control()
return ..()
/obj/machinery/porta_turret/ui_interact(mob/user)
. = ..()
var/dat
dat += "Status: <a href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</a><br>"
dat += "Behaviour controls are [locked ? "locked" : "unlocked"]<br>"
/obj/machinery/porta_turret/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "PortableTurret", name)
ui.open()
if(!locked)
dat += "Check for Weapon Authorization: <A href='?src=[REF(src)];operation=authweapon'>[auth_weapons ? "Yes" : "No"]</A><BR>"
dat += "Check Security Records: <A href='?src=[REF(src)];operation=checkrecords'>[check_records ? "Yes" : "No"]</A><BR>"
dat += "Neutralize Identified Criminals: <A href='?src=[REF(src)];operation=shootcrooks'>[criminals ? "Yes" : "No"]</A><BR>"
dat += "Neutralize All Non-Security and Non-Command Personnel: <A href='?src=[REF(src)];operation=shootall'>[stun_all ? "Yes" : "No"]</A><BR>"
dat += "Neutralize All Unidentified Life Signs: <A href='?src=[REF(src)];operation=checkxenos'>[check_anomalies ? "Yes" : "No"]</A><BR>"
dat += "Neutralize All Non-Loyalty Implanted Personnel: <A href='?src=[REF(src)];operation=checkloyal'>[shoot_unloyal ? "Yes" : "No"]</A><BR>"
/obj/machinery/porta_turret/ui_data(mob/user)
var/list/data = list(
"locked" = locked,
"on" = on,
"check_weapons" = turret_flags & TURRET_FLAG_AUTH_WEAPONS,
"neutralize_criminals" = turret_flags & TURRET_FLAG_SHOOT_CRIMINALS,
"neutralize_all" = turret_flags & TURRET_FLAG_SHOOT_ALL,
"neutralize_unidentified" = turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS,
"neutralize_nonmindshielded" = turret_flags & TURRET_FLAG_SHOOT_UNSHIELDED,
"neutralize_cyborgs" = turret_flags & TURRET_FLAG_SHOOT_BORGS,
"ignore_heads" = turret_flags & TURRET_FLAG_SHOOT_HEADS,
"manual_control" = manual_control,
"silicon_user" = FALSE,
"allow_manual_control" = FALSE,
"lasertag_turret" = istype(src, /obj/machinery/porta_turret/lasertag),
)
if(issilicon(user))
data["silicon_user"] = TRUE
if(!manual_control)
var/mob/living/silicon/S = user
if(S.hack_software)
dat += "Assume direct control : <a href='?src=[REF(src)];operation=manual'>Manual Control</a><br>"
else
dat += "Warning! Remote control protocol enabled.<br>"
data["allow_manual_control"] = TRUE
return data
var/datum/browser/popup = new(user, "autosec", "Automatic Portable Turret Installation", 300, 300)
popup.set_content(dat)
popup.open()
/obj/machinery/porta_turret/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
add_fingerprint(usr)
if(href_list["power"] && !locked)
if(anchored) //you can't turn a turret on/off if it's not anchored/secured
on = !on //toggle on/off
else
to_chat(usr, "<span class='notice'>It has to be secured first!</span>")
interact(usr)
/obj/machinery/porta_turret/ui_act(action, list/params)
. = ..()
if(.)
return
if(href_list["operation"])
switch(href_list["operation"]) //toggles customizable behavioural protocols
if("authweapon")
auth_weapons = !auth_weapons
if("checkrecords")
check_records = !check_records
if("shootcrooks")
criminals = !criminals
if("shootall")
stun_all = !stun_all
if("checkxenos")
check_anomalies = !check_anomalies
if("checkloyal")
shoot_unloyal = !shoot_unloyal
if("manual")
if(issilicon(usr) && !manual_control)
give_control(usr)
interact(usr)
switch(action)
if("power")
if(anchored)
toggle_on()
return TRUE
else
to_chat(usr, "<span class='warning'>It has to be secured first!</span>")
if("authweapon")
turret_flags ^= TURRET_FLAG_AUTH_WEAPONS
return TRUE
if("shootcriminals")
turret_flags ^= TURRET_FLAG_SHOOT_CRIMINALS
return TRUE
if("shootall")
turret_flags ^= TURRET_FLAG_SHOOT_ALL
return TRUE
if("checkxenos")
turret_flags ^= TURRET_FLAG_SHOOT_ANOMALOUS
return TRUE
if("checkloyal")
turret_flags ^= TURRET_FLAG_SHOOT_UNSHIELDED
return TRUE
if("shootborgs")
turret_flags ^= TURRET_FLAG_SHOOT_BORGS
return TRUE
if("shootheads")
turret_flags ^= TURRET_FLAG_SHOOT_HEADS
return TRUE
if("manual")
if(!issilicon(usr))
return
give_control(usr)
return TRUE
/obj/machinery/porta_turret/ui_host(mob/user)
if(has_cover && cover)
return cover
if(base)
return base
return src
/obj/machinery/porta_turret/power_change()
if(!anchored)
. = ..()
if(!anchored || (stat & BROKEN) || !powered())
update_icon()
remove_control()
return
if(stat & BROKEN)
update_icon()
remove_control()
else
if( powered() )
stat &= ~NOPOWER
update_icon()
else
spawn(rand(0, 15))
stat |= NOPOWER
remove_control()
update_icon()
check_should_process()
/obj/machinery/porta_turret/attackby(obj/item/I, mob/user, params)
if(stat & BROKEN)
@@ -283,8 +327,10 @@
locked = !locked
to_chat(user, "<span class='notice'>Controls are now [locked ? "locked" : "unlocked"].</span>")
else
to_chat(user, "<span class='notice'>Access denied.</span>")
to_chat(user, "<span class='alert'>Access denied.</span>")
else if(istype(I, /obj/item/multitool) && !locked)
if(!multitool_check_buffer(user, I))
return
var/obj/item/multitool/M = I
M.buffer = src
to_chat(user, "<span class='notice'>You add [src] to multitool buffer.</span>")
@@ -292,19 +338,17 @@
return ..()
/obj/machinery/porta_turret/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "<span class='warning'>You short out [src]'s threat assessment circuits.</span>")
visible_message("[src] hums oddly...")
audible_message("<span class='hear'>[src] hums oddly...</span>")
obj_flags |= EMAGGED
controllock = TRUE
on = FALSE //turns off the turret temporarily
toggle_on(FALSE) //turns off the turret temporarily
update_icon()
sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
on = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
return TRUE
//6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
addtimer(CALLBACK(src, .proc/toggle_on, TRUE), 6 SECONDS)
//turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
/obj/machinery/porta_turret/emp_act(severity)
. = ..()
@@ -313,63 +357,41 @@
if(on)
//if the turret is on, the EMP no matter how severe disables the turret for a while
//and scrambles its settings, with a slight chance of having an emag effect
check_records = pick(0, 1)
criminals = pick(0, 1)
auth_weapons = pick(0, 1)
stun_all = pick(0, 0, 0, 0, 1) //stun_all is a pretty big deal, so it's least likely to get turned on
if(prob(50))
turret_flags |= TURRET_FLAG_SHOOT_CRIMINALS
if(prob(50))
turret_flags |= TURRET_FLAG_AUTH_WEAPONS
if(prob(20))
turret_flags |= TURRET_FLAG_SHOOT_ALL // Shooting everyone is a pretty big deal, so it's least likely to get turned on
on = FALSE
toggle_on(FALSE)
remove_control()
spawn(rand(60,600))
if(!on)
on = TRUE
addtimer(CALLBACK(src, .proc/toggle_on, TRUE), rand(60,600))
/obj/machinery/porta_turret/take_damage(damage, damage_type = BRUTE, damage_flag = 0, sound_effect = 1)
. = ..()
if(.) //damage received
if(. && obj_integrity > 0) //damage received
if(prob(30))
spark_system.start()
if(on && !attacked && !(obj_flags & EMAGGED))
attacked = TRUE
if(on && !(turret_flags & TURRET_FLAG_SHOOT_ALL_REACT) && !(obj_flags & EMAGGED))
turret_flags |= TURRET_FLAG_SHOOT_ALL_REACT
addtimer(CALLBACK(src, .proc/reset_attacked), 60)
/obj/machinery/porta_turret/proc/reset_attacked()
attacked = FALSE
turret_flags &= ~TURRET_FLAG_SHOOT_ALL_REACT
/obj/machinery/porta_turret/deconstruct(disassembled = TRUE)
qdel(src)
/obj/machinery/porta_turret/obj_break(damage_flag)
if(!(flags_1 & NODECONSTRUCT_1) && !(stat & BROKEN))
stat |= BROKEN //enables the BROKEN bit
. = ..()
if(.)
power_change()
invisibility = 0
spark_system.start() //creates some sparks because they look cool
qdel(cover) //deletes the cover - no need on keeping it there!
//turret healing
/obj/machinery/porta_turret/examine(mob/user)
. = ..()
if(obj_integrity < max_integrity)
. += "<span class='notice'>Use a welder to fix it.</span>"
/obj/machinery/porta_turret/welder_act(mob/living/user, obj/item/I)
. = TRUE
if(obj_integrity < max_integrity)
if(!I.tool_start_check(user, amount=0))
return
user.visible_message("[user] is welding the turret.", \
"<span class='notice'>You begin repairing the turret...</span>", \
"<span class='italics'>You hear welding.</span>")
if(I.use_tool(src, user, 40, volume=50))
obj_integrity = max_integrity
user.visible_message("[user.name] has repaired [src].", \
"<span class='notice'>You finish repairing the turret.</span>")
else
to_chat(user, "<span class='notice'>The turret doesn't need repairing.</span>")
/obj/machinery/porta_turret/process()
//the main machinery process
if(cover == null && anchored) //if it has no cover and is anchored
@@ -381,35 +403,43 @@
cover.parent_turret = src //assign the cover its parent_turret, which would be this (src)
if(!on || (stat & (NOPOWER|BROKEN)) || manual_control)
return
return PROCESS_KILL
var/list/targets = list()
for(var/mob/A in view(scan_range, base))
if(A.invisibility > SEE_INVISIBLE_LIVING)
continue
if(check_anomalies)//if it's set to check for simple animals
if(turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS)//if it's set to check for simple animals
if(isanimal(A))
var/mob/living/simple_animal/SA = A
if(SA.stat || in_faction(SA)) //don't target if dead or in faction
continue
targets += SA
if(issilicon(A))
var/mob/living/silicon/sillycone = A
if(sillycone.stat || in_faction(sillycone))
continue
if(issilicon(A))
var/mob/living/silicon/sillycone = A
if(ispAI(A))
continue
if((turret_flags & TURRET_FLAG_SHOOT_BORGS) && sillycone.stat != DEAD && iscyborg(sillycone))
targets += sillycone
continue
if(sillycone.stat || in_faction(sillycone))
continue
if(iscyborg(sillycone))
var/mob/living/silicon/robot/sillyconerobot = A
if(LAZYLEN(faction) && (ROLE_SYNDICATE in faction) && sillyconerobot.emagged == TRUE)
continue
if(iscyborg(sillycone))
var/mob/living/silicon/robot/sillyconerobot = A
if(LAZYLEN(faction) && (ROLE_SYNDICATE in faction) && sillyconerobot.emagged == TRUE)
continue
targets += sillycone
if(iscarbon(A))
else if(iscarbon(A))
var/mob/living/carbon/C = A
//If not emagged, only target non downed carbons
if(mode != TURRET_LETHAL && (C.stat || C.handcuffed || (C.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)))//CIT CHANGE - replaces check for lying with check for recoveringstam
//If not emagged, only target carbons that can use items
if(mode != TURRET_LETHAL && (C.stat || C.handcuffed || !(C.mobility_flags & MOBILITY_USE)))
continue
//If emagged, target all but dead carbons
@@ -418,12 +448,13 @@
//if the target is a human and not in our faction, analyze threat level
if(ishuman(C) && !in_faction(C))
if(assess_perp(C) >= 4)
targets += C
else if(check_anomalies) //non humans who are not simple animals (xenos etc)
else if(turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS) //non humans who are not simple animals (xenos etc)
if(!in_faction(C))
targets += C
for(var/A in GLOB.mechas_list)
if((get_dist(A, base) < scan_range) && can_see(base, A, scan_range))
var/obj/mecha/Mech = A
@@ -431,11 +462,18 @@
if(assess_perp(Mech.occupant) >= 4)
targets += Mech
if((turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS) && GLOB.blobs.len && (mode == TURRET_LETHAL))
for(var/obj/structure/blob/B in view(scan_range, base))
targets += B
if(targets.len)
tryToShootAt(targets)
else if(!always_up)
popDown() // no valid targets, close the cover
/obj/machinery/porta_turret/proc/randomize_shot_stagger()
shot_stagger = rand(0, min(2 SECONDS, round(shot_delay/3, world.tick_lag)))
/obj/machinery/porta_turret/proc/tryToShootAt(list/atom/movable/targets)
while(targets.len > 0)
var/atom/movable/M = pick(targets)
@@ -443,7 +481,6 @@
if(target(M))
return 1
/obj/machinery/porta_turret/proc/popUp() //pops the turret up
if(!anchored)
return
@@ -485,36 +522,37 @@
if(obj_flags & EMAGGED)
return 10 //if emagged, always return 10.
if((stun_all || attacked) && !allowed(perp))
if((turret_flags & (TURRET_FLAG_SHOOT_ALL | TURRET_FLAG_SHOOT_ALL_REACT)) && !allowed(perp))
//if the turret has been attacked or is angry, target all non-sec people
if(!allowed(perp))
return 10
if(auth_weapons) //check for weapon authorization
if(turret_flags & TURRET_FLAG_AUTH_WEAPONS) //check for weapon authorization
if(isnull(perp.wear_id) || istype(perp.wear_id.GetID(), /obj/item/card/id/syndicate))
if(allowed(perp)) //if the perp has security access, return 0
return 0
if(perp.is_holding_item_of_type(/obj/item/gun) || perp.is_holding_item_of_type(/obj/item/melee/baton))
threatcount += 4
if(istype(perp.belt, /obj/item/gun) || istype(perp.belt, /obj/item/melee/baton))
threatcount += 2
if(check_records) //if the turret can check the records, check if they are set to *Arrest* on records
if(turret_flags & TURRET_FLAG_SHOOT_CRIMINALS) //if the turret can check the records, check if they are set to *Arrest* on records
var/perpname = perp.get_face_name(perp.get_id_name())
var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security)
if(!R || (R.fields["criminal"] == "*Arrest*"))
threatcount += 4
if(shoot_unloyal)
if (!HAS_TRAIT(perp, TRAIT_MINDSHIELD))
threatcount += 4
if((turret_flags & TURRET_FLAG_SHOOT_UNSHIELDED) && (!HAS_TRAIT(perp, TRAIT_MINDSHIELD)))
threatcount += 4
// If we aren't shooting heads then return a threatcount of 0
if (!(turret_flags & TURRET_FLAG_SHOOT_HEADS) && (perp.get_assignment() in GLOB.command_positions))
return 0
return threatcount
/obj/machinery/porta_turret/proc/in_faction(mob/target)
for(var/faction1 in faction)
if(faction1 in target.faction)
@@ -525,18 +563,21 @@
if(target)
popUp() //pop the turret up if it's not already up.
setDir(get_dir(base, target))//even if you can't shoot, follow the target
shootAt(target)
INVOKE_ASYNC(src, .proc/shootAt, target)
return 1
return
/obj/machinery/porta_turret/proc/shootAt(atom/movable/target)
/obj/machinery/porta_turret/proc/shootAt(atom/movable/target, stagger_enabled = FALSE)
if(!raised) //the turret has to be raised in order to fire - makes sense, right?
return
if(!(obj_flags & EMAGGED)) //if it hasn't been emagged, cooldown before shooting again
if(last_fired + shot_delay > world.time)
return
last_fired = world.time
if(last_fired + shot_delay > world.time)
return
last_fired = world.time
if(stagger_enabled)
randomize_shot_stagger()
sleep(shot_stagger)
var/turf/T = get_turf(src)
var/turf/U = get_turf(target)
@@ -557,15 +598,14 @@
T = closer
break
var/mob/living/carbon/C
if(iscarbon(target))
C = target
update_icon()
var/obj/item/projectile/A
//any emagged turrets drains 2x power and uses a different projectile?
if(mode == TURRET_STUN)
if(nonlethal_projectile && C && C.resting)
var/mob/living/carbon/C = null
if(iscarbon(target))
C = target
if(nonlethal_projectile && C?.resting)
use_power(reqpower*0.5)
A = new nonlethal_projectile(T)
playsound(loc, nonlethal_projectile_sound, 75, 1)
@@ -576,7 +616,7 @@
else
use_power(reqpower * 2)
A = new lethal_projectile(T)
playsound(loc, lethal_projectile_sound, 75, 1)
playsound(loc, lethal_projectile_sound, 75, TRUE)
//Shooting Code:
@@ -586,16 +626,15 @@
A.fire()
return A
/obj/machinery/porta_turret/proc/setState(on, mode)
/obj/machinery/porta_turret/proc/setState(on, mode, shoot_cyborgs)
if(controllock)
return
src.on = on
if(!on)
popDown()
shoot_cyborgs ? (turret_flags |= TURRET_FLAG_SHOOT_BORGS) : (turret_flags &= ~TURRET_FLAG_SHOOT_BORGS)
toggle_on(on)
src.mode = mode
power_change()
/datum/action/turret_toggle
name = "Toggle Mode"
icon_icon = 'icons/mob/actions/actions_mecha.dmi'
@@ -679,7 +718,15 @@
/obj/machinery/porta_turret/syndicate/ComponentInitialize()
. = ..()
AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES)
// AddComponent(/datum/component/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES)
AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES) //this one or ^ one?
/obj/machinery/porta_turret/syndicate/setup()
return
/obj/machinery/porta_turret/syndicate/assess_perp(mob/living/carbon/human/perp)
return 10 //Syndicate turrets shoot everything not in their faction
/obj/machinery/porta_turret/syndicate/energy
icon_state = "standard_stun"
@@ -692,7 +739,6 @@
lethal_projectile_sound = 'sound/weapons/laser.ogg'
desc = "An energy blaster auto-turret."
/obj/machinery/porta_turret/syndicate/energy/heavy
icon_state = "standard_stun"
base_icon_state = "standard"
@@ -709,14 +755,13 @@
integrity_failure = 0.08
armor = list("melee" = 50, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
/obj/machinery/porta_turret/syndicate/setup()
return
/obj/machinery/porta_turret/syndicate/assess_perp(mob/living/carbon/human/perp)
return 10 //Syndicate turrets shoot everything not in their faction
/obj/machinery/porta_turret/syndicate/energy/raven
stun_projectile = /obj/item/projectile/beam/laser
stun_projectile_sound = 'sound/weapons/laser.ogg'
faction = list("neutral","silicon","turret")
/obj/machinery/porta_turret/syndicate/pod
integrity_failure = 0.5
max_integrity = 40
stun_projectile = /obj/item/projectile/bullet/syndicate_turret
lethal_projectile = /obj/item/projectile/bullet/syndicate_turret
@@ -743,6 +788,7 @@
faction = list("silicon")
nonlethal_projectile = /obj/item/projectile/beam/disabler
nonlethal_projectile_sound = 'sound/weapons/taser2.ogg'
turret_flags = TURRET_FLAG_SHOOT_CRIMINALS | TURRET_FLAG_SHOOT_ANOMALOUS | TURRET_FLAG_SHOOT_HEADS
/obj/machinery/porta_turret/ai/assess_perp(mob/living/carbon/human/perp)
return 10 //AI turrets shoot at everything not in their faction
@@ -798,6 +844,7 @@
/obj/machinery/porta_turret/centcom_shuttle/weak
max_integrity = 120
integrity_failure = 0.5
name = "Old Laser Turret"
desc = "A turret built with substandard parts and run down further with age. Still capable of delivering lethal lasers to the odd space carp, but not much else."
stun_projectile = /obj/item/projectile/beam/weak/penetrator
@@ -811,7 +858,6 @@
stun_projectile_sound = 'sound/weapons/gunshot.ogg'
desc = "A ballistic machine gun auto-turret."
////////////////////////
//Turret Control Panel//
////////////////////////
@@ -822,14 +868,22 @@
icon = 'icons/obj/machines/turret_control.dmi'
icon_state = "control_standby"
density = FALSE
var/enabled = 1
var/lethal = 0
var/locked = TRUE
var/control_area = null //can be area name, path or nothing.
var/ailock = 0 // AI cannot use this
req_access = list(ACCESS_AI_UPLOAD)
var/list/obj/machinery/porta_turret/turrets = list()
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/// Variable dictating if linked turrets are active and will shoot targets
var/enabled = TRUE
/// Variable dictating if linked turrets will shoot lethal projectiles
var/lethal = FALSE
/// Variable dictating if the panel is locked, preventing changes to turret settings
var/locked = TRUE
/// An area in which linked turrets are located, it can be an area name, path or nothing
var/control_area = null
/// AI is unable to use this machine if set to TRUE
var/ailock = FALSE
/// Variable dictating if linked turrets will shoot cyborgs
var/shoot_cyborgs = FALSE
/// List of all linked turrets
var/list/turrets = list()
/obj/machinery/turretid/Initialize(mapload, ndir = 0, built = 0)
. = ..()
@@ -862,112 +916,111 @@
T.cp = src
/obj/machinery/turretid/examine(mob/user)
. = ..()
if(hasSiliconAccessInArea(user) && (!stat & BROKEN))
. += "<span class='notice'>Ctrl-click [src] to [ enabled ? "disable" : "enable"] turrets.</span>"
. += "<span class='notice'>Alt-click [src] to set turrets to [ lethal ? "stun" : "kill"].</span>"
. += ..()
if(issilicon(user) && !(stat & BROKEN))
. += {"<span class='notice'>Ctrl-click [src] to [ enabled ? "disable" : "enable"] turrets.</span>
<span class='notice'>Alt-click [src] to set turrets to [ lethal ? "stun" : "kill"].</span>"}
/obj/machinery/turretid/attackby(obj/item/I, mob/user, params)
if(stat & BROKEN)
return
if (istype(I, /obj/item/multitool))
if(!multitool_check_buffer(user, I))
return
var/obj/item/multitool/M = I
if(M.buffer && istype(M.buffer, /obj/machinery/porta_turret))
turrets |= M.buffer
to_chat(user, "You link \the [M.buffer] with \the [src]")
to_chat(user, "<span class='notice'>You link \the [M.buffer] with \the [src].</span>")
return
if (hasSiliconAccessInArea(user))
if (issilicon(user))
return attack_hand(user)
if ( get_dist(src, user) == 0 ) // trying to unlock the interface
if (allowed(usr))
if(obj_flags & EMAGGED)
to_chat(user, "<span class='notice'>The turret control is unresponsive.</span>")
to_chat(user, "<span class='warning'>The turret control is unresponsive!</span>")
return
locked = !locked
to_chat(user, "<span class='notice'>You [ locked ? "lock" : "unlock"] the panel.</span>")
if (locked)
if (user.machine==src)
user.unset_machine()
user << browse(null, "window=turretid")
else
if (user.machine==src)
attack_hand(user)
else
to_chat(user, "<span class='warning'>Access denied.</span>")
to_chat(user, "<span class='alert'>Access denied.</span>")
/obj/machinery/turretid/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "<span class='danger'>You short out the turret controls' access analysis module.</span>")
to_chat(user, "<span class='notice'>You short out the turret controls' access analysis module.</span>")
obj_flags |= EMAGGED
locked = FALSE
if(user && user.machine == src)
attack_hand(user)
return TRUE
/obj/machinery/turretid/attack_ai(mob/user)
if(!ailock || IsAdminGhost(user))
return attack_hand(user)
else
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
to_chat(user, "<span class='warning'>There seems to be a firewall preventing you from accessing this device!</span>")
/obj/machinery/turretid/ui_interact(mob/user)
/obj/machinery/turretid/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "TurretControl", name)
ui.open()
/obj/machinery/turretid/ui_data(mob/user)
var/list/data = list()
data["locked"] = locked
data["siliconUser"] = hasSiliconAccessInArea(user) || IsAdminGhost(user)
data["enabled"] = enabled
data["lethal"] = lethal
data["shootCyborgs"] = shoot_cyborgs
return data
/obj/machinery/turretid/ui_act(action, list/params)
. = ..()
if ( get_dist(src, user) > 0 )
if ( !(hasSiliconAccessInArea(user) || IsAdminGhost(user)) )
to_chat(user, "<span class='notice'>You are too far away.</span>")
user.unset_machine()
user << browse(null, "window=turretid")
return
var/t = ""
if(locked && !(hasSiliconAccessInArea(user) || IsAdminGhost(user)))
t += "<div class='notice icon'>Swipe ID card to unlock interface</div>"
else
if(!hasSiliconAccessInArea(user) && !IsAdminGhost(user))
t += "<div class='notice icon'>Swipe ID card to lock interface</div>"
t += "Turrets [enabled?"activated":"deactivated"] - <A href='?src=[REF(src)];toggleOn=1'>[enabled?"Disable":"Enable"]?</a><br>"
t += "Currently set for [lethal?"lethal":"stun repeatedly"] - <A href='?src=[REF(src)];toggleLethal=1'>Change to [lethal?"Stun repeatedly":"Lethal"]?</a><br>"
var/datum/browser/popup = new(user, "turretid", "Turret Control Panel ([get_area_name(src, TRUE)])")
popup.set_content(t)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/turretid/Topic(href, href_list)
if(..())
if(.)
return
if (locked)
if(!(hasSiliconAccessInArea(usr) || IsAdminGhost(usr)))
to_chat(usr, "Control panel is locked!")
return
if (href_list["toggleOn"])
toggle_on()
else if (href_list["toggleLethal"])
toggle_lethal()
attack_hand(usr)
/obj/machinery/turretid/proc/toggle_lethal()
switch(action)
if("lock")
if(!hasSiliconAccessInArea(usr) || IsAdminGhost(usr))
return
if((obj_flags & EMAGGED) || (stat & BROKEN))
to_chat(usr, "<span class='warning'>The turret control is unresponsive!</span>")
return
locked = !locked
return TRUE
if("power")
toggle_on(usr)
return TRUE
if("mode")
toggle_lethal(usr)
return TRUE
if("shoot_silicons")
shoot_silicons(usr)
return TRUE
/obj/machinery/turretid/proc/toggle_lethal(mob/user)
lethal = !lethal
add_hiddenprint(user)
log_combat(user, src, "[lethal ? "enabled" : "disabled"] lethals on")
updateTurrets()
/obj/machinery/turretid/proc/toggle_on()
/obj/machinery/turretid/proc/toggle_on(mob/user)
enabled = !enabled
add_hiddenprint(user)
log_combat(user, src, "[enabled ? "enabled" : "disabled"]")
updateTurrets()
/obj/machinery/turretid/proc/shoot_silicons(mob/user)
shoot_cyborgs = !shoot_cyborgs
add_hiddenprint(user)
log_combat(user, src, "[shoot_cyborgs ? "Shooting Borgs" : "Not Shooting Borgs"]")
updateTurrets()
/obj/machinery/turretid/proc/updateTurrets()
for (var/obj/machinery/porta_turret/aTurret in turrets)
aTurret.setState(enabled, lethal)
update_icon()
/obj/machinery/turretid/power_change()
..()
aTurret.setState(enabled, lethal, shoot_cyborgs)
update_icon()
/obj/machinery/turretid/update_icon_state()
@@ -1045,11 +1098,7 @@
/obj/machinery/porta_turret/lasertag
req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE)
check_records = 0
criminals = 0
auth_weapons = 1
stun_all = 0
check_anomalies = 0
turret_flags = TURRET_FLAG_AUTH_WEAPONS
var/team_color
/obj/machinery/porta_turret/lasertag/assess_perp(mob/living/carbon/human/perp)
@@ -1077,20 +1126,14 @@
if(properties["team_color"])
team_color = properties["team_color"]
/obj/machinery/porta_turret/lasertag/ui_interact(mob/user)
. = ..()
/obj/machinery/porta_turret/lasertag/ui_status(mob/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(team_color == "blue" && istype(H.wear_suit, /obj/item/clothing/suit/redtag))
return
return UI_CLOSE
if(team_color == "red" && istype(H.wear_suit, /obj/item/clothing/suit/bluetag))
return
var/dat = "Status: <a href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</a>"
var/datum/browser/popup = new(user, "autosec", "Automatic Portable Turret Installation", 300, 300)
popup.set_content(dat)
popup.open()
return UI_CLOSE
return ..()
//lasertag presets
/obj/machinery/porta_turret/lasertag/red
@@ -1106,11 +1149,9 @@
if(on)
if(team_color == "blue")
if(istype(P, /obj/item/projectile/beam/lasertag/redtag))
on = FALSE
spawn(100)
on = TRUE
toggle_on(FALSE)
addtimer(CALLBACK(src, .proc/toggle_on, TRUE), 10 SECONDS)
else if(team_color == "red")
if(istype(P, /obj/item/projectile/beam/lasertag/bluetag))
on = FALSE
spawn(100)
on = TRUE
toggle_on(FALSE)
addtimer(CALLBACK(src, .proc/toggle_on, TRUE), 10 SECONDS)
@@ -79,6 +79,9 @@
if(PTURRET_INTERNAL_ARMOUR_ON)
if(istype(I, /obj/item/gun/energy)) //the gun installation part
var/obj/item/gun/energy/E = I
if(!E.can_turret)
to_chat(user, "<span class='warning'>[src] can't be fit into turrets.</span>")
return
if(!user.transferItemToLoc(E, src))
return
installed_gun = E
@@ -168,10 +171,7 @@
return ..()
/obj/machinery/porta_turret_construct/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/porta_turret_construct/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
switch(build_step)
if(PTURRET_GUN_EQUIPPED)
build_step = PTURRET_INTERNAL_ARMOUR_ON
@@ -31,10 +31,7 @@
return parent_turret.attack_ai(user)
/obj/machinery/porta_turret_cover/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/porta_turret_cover/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
return parent_turret.attack_hand(user)
Regular → Executable
+2 -5
View File
@@ -19,7 +19,7 @@
/obj/item/modular_computer,
/obj/item/ammo_casing/mws_batt,
/obj/item/ammo_box/magazine/mws_mag,
/obj/item/twohanded/electrostaff,
/obj/item/electrostaff,
/obj/item/gun/ballistic/automatic/magrifle))
/obj/machinery/recharger/RefreshParts()
@@ -108,10 +108,7 @@
return ..()
/obj/machinery/recharger/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/recharger/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
add_fingerprint(user)
if(charging)
+3 -14
View File
@@ -126,17 +126,6 @@
update_icon()
/obj/machinery/recharge_station/proc/process_occupant()
if(occupant && iscyborg(occupant))
var/mob/living/silicon/robot/R = occupant
restock_modules()
if(repairs)
R.heal_bodypart_damage(repairs, repairs - 1)
if(R.cell)
R.cell.charge = min(R.cell.charge + recharge_speed, R.cell.maxcharge)
/obj/machinery/recharge_station/proc/restock_modules()
if(occupant)
var/mob/living/silicon/robot/R = occupant
if(R && R.module)
var/coeff = recharge_speed * 0.005
R.module.respawn_consumable(R, coeff)
if(!occupant)
return
SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, recharge_speed, repairs)
+1 -1
View File
@@ -225,6 +225,6 @@
/obj/item/paper/guides/recycler
name = "paper - 'garbage duty instructions'"
info = "<h2>New Assignment</h2> You have been assigned to collect garbage from trash bins, located around the station. The crewmembers will put their trash into it and you will collect the said trash.<br><br>There is a recycling machine near your closet, inside maintenance; use it to recycle the trash for a small chance to get useful minerals. Then deliver these minerals to cargo or engineering. You are our last hope for a clean station, do not screw this up!"
info = "_New Assignment_\n\n You have been assigned to collect garbage from trash bins, located around the station. The crewmembers will put their trash into it and you will collect the said trash.<br><br>There is a recycling machine near your closet, inside maintenance; use it to recycle the trash for a small chance to get useful minerals. Then deliver these minerals to cargo or engineering. You are our last hope for a clean station, do not screw this up!"
#undef SAFETY_COOLDOWN
+44
View File
@@ -0,0 +1,44 @@
/obj/machinery/sheetifier
name = "Sheet-meister 2000"
desc = "A very sheety machine"
icon = 'icons/obj/machines/sheetifier.dmi'
icon_state = "base_machine"
density = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 100
circuit = /obj/item/circuitboard/machine/sheetifier
layer = BELOW_OBJ_LAYER
var/busy_processing = FALSE
/obj/machinery/sheetifier/Initialize()
. = ..()
AddComponent(/datum/component/material_container, list(/datum/material/meat), MINERAL_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, TRUE, /obj/item/reagent_containers/food/snacks/meat/slab, CALLBACK(src, .proc/CanInsertMaterials), CALLBACK(src, .proc/AfterInsertMaterials))
/obj/machinery/sheetifier/update_overlays()
. = ..()
if(stat & (BROKEN|NOPOWER))
return
var/mutable_appearance/on_overlay = mutable_appearance(icon, "buttons_on")
. += on_overlay
/obj/machinery/sheetifier/update_icon_state()
icon_state = "base_machine[busy_processing ? "_processing" : ""]"
/obj/machinery/sheetifier/proc/CanInsertMaterials()
return !busy_processing
/obj/machinery/sheetifier/proc/AfterInsertMaterials(item_inserted, id_inserted, amount_inserted)
busy_processing = TRUE
update_icon()
var/datum/material/last_inserted_material = id_inserted
var/mutable_appearance/processing_overlay = mutable_appearance(icon, "processing")
processing_overlay.color = last_inserted_material.color
flick_overlay_static(processing_overlay, src, 64)
addtimer(CALLBACK(src, .proc/finish_processing), 64)
/obj/machinery/sheetifier/proc/finish_processing()
busy_processing = FALSE
update_icon()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all() //Returns all as sheets
@@ -130,7 +130,7 @@
var/deltaTemperature = req_power / heat_cap
if(deltaTemperature < 0)
return
env.temperature += deltaTemperature
env.set_temperature(env.return_temperature(),deltaTemperature)
air_update_turf()
/obj/machinery/shuttle/engine/default_change_direction_wrench(mob/user, obj/item/I)
@@ -89,8 +89,8 @@
var/datum/gas_mixture/air_contents = airs[1]
if(!air_contents)
return
air_contents.volume = gas_capacity
air_contents.temperature = T20C
air_contents.set_volume(gas_capacity)
air_contents.set_temperature(T20C)
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/hasFuel(var/required)
var/datum/gas_mixture/air_contents = airs[1]
+11 -22
View File
@@ -83,9 +83,9 @@
var/datum/gas_mixture/env = L.return_air()
var/newMode = HEATER_MODE_STANDBY
if(setMode != HEATER_MODE_COOL && env.temperature < targetTemperature - temperatureTolerance)
if(setMode != HEATER_MODE_COOL && env.return_temperature() < targetTemperature - temperatureTolerance)
newMode = HEATER_MODE_HEAT
else if(setMode != HEATER_MODE_HEAT && env.temperature > targetTemperature + temperatureTolerance)
else if(setMode != HEATER_MODE_HEAT && env.return_temperature() > targetTemperature + temperatureTolerance)
newMode = HEATER_MODE_COOL
if(mode != newMode)
@@ -96,7 +96,7 @@
return
var/heat_capacity = env.heat_capacity()
var/requiredPower = abs(env.temperature - targetTemperature) * heat_capacity
var/requiredPower = abs(env.return_temperature() - targetTemperature) * heat_capacity
requiredPower = min(requiredPower, heatingPower)
if(requiredPower < 1)
@@ -106,7 +106,7 @@
if(mode == HEATER_MODE_COOL)
deltaTemperature *= -1
if(deltaTemperature)
env.temperature += deltaTemperature
env.set_temperature(env.return_temperature() + deltaTemperature)
air_update_turf()
cell.use(requiredPower / efficiency)
else
@@ -170,12 +170,10 @@
..()
default_unfasten_wrench(user, I, 5)
return TRUE
/obj/machinery/space_heater/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/space_heater/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "space_heater", name, 400, 305, master_ui, state)
ui = new(user, src, "SpaceHeater", name)
ui.open()
/obj/machinery/space_heater/ui_data()
@@ -194,9 +192,9 @@
var/curTemp
if(istype(L))
var/datum/gas_mixture/env = L.return_air()
curTemp = env.temperature
curTemp = env.return_temperature()
else if(isturf(L))
curTemp = L.temperature
curTemp = L.return_temperature()
if(isnull(curTemp))
data["currentTemp"] = "N/A"
else
@@ -210,7 +208,7 @@
if("power")
on = !on
mode = HEATER_MODE_STANDBY
usr.visible_message("[usr] switches [on ? "on" : "off"] \the [src].", "<span class='notice'>You switch [on ? "on" : "off"] \the [src].</span>")
usr.visible_message("<span class='notice'>[usr] switches [on ? "on" : "off"] \the [src].</span>", "<span class='notice'>You switch [on ? "on" : "off"] \the [src].</span>")
update_icon()
if (on)
START_PROCESSING(SSmachines, src)
@@ -222,16 +220,7 @@
if(!panel_open)
return
var/target = params["target"]
var/adjust = text2num(params["adjust"])
if(target == "input")
target = input("New target temperature:", name, round(targetTemperature - T0C, 1)) as num|null
if(!isnull(target) && !..())
target += T0C
. = TRUE
else if(adjust)
target = targetTemperature + adjust
. = TRUE
else if(text2num(target) != null)
if(text2num(target) != null)
target= text2num(target) + T0C
. = TRUE
if(.)
+1 -1
View File
@@ -287,7 +287,7 @@
if(!.)
return
switch(var_name)
if("shuttle_id")
if(NAMEOF(src, shuttle_id))
update()
/obj/machinery/status_display/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
+6 -6
View File
@@ -301,8 +301,6 @@
open_machine()
dump_contents()
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
user.visible_message("<span class='notice'>You see [user] kicking against the doors of [src]!</span>", \
"<span class='notice'>You start kicking against the doors... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
"<span class='italics'>You hear a thump from [src].</span>")
@@ -379,11 +377,13 @@
return ..()
/obj/machinery/suit_storage_unit/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/suit_storage_unit/ui_state(mob/user)
return GLOB.notcontained_state
/obj/machinery/suit_storage_unit/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "suit_storage_unit", name, 400, 305, master_ui, state)
ui = new(user, src, "SuitStorageUnit", name)
ui.open()
/obj/machinery/suit_storage_unit/ui_data()
+1 -4
View File
@@ -68,10 +68,7 @@ GLOBAL_VAR_INIT(singularity_counter, 0)
/obj/machinery/power/singularity_beacon/attack_ai(mob/user)
return
/obj/machinery/power/singularity_beacon/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/power/singularity_beacon/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(anchored)
return active ? Deactivate(user) : Activate(user)
else
@@ -17,11 +17,10 @@
var/notice = ""
var/universal_translate = FALSE // set to TRUE(1) if it can translate nonhuman speech
/obj/machinery/computer/telecomms/server/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/telecomms/server/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "tcommsserver", "Telecomms Server Monitor", 575, 400, master_ui, state)
ui = new(user, src, "TelecommsLogBrowser", "Telecomms Server Monitor")
ui.open()
/obj/machinery/computer/telecomms/server/ui_data(mob/user)
@@ -36,12 +36,11 @@
light_color = LIGHT_COLOR_GREEN
/obj/machinery/computer/message_monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/message_monitor/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "telepdalog", name, 727, 510, master_ui, state)
ui = new(user, src, "TelecommsPDALog", name)
ui.open()
/obj/machinery/computer/message_monitor/ui_static_data(mob/user)
@@ -389,7 +388,6 @@
/obj/item/paper/monitorkey/proc/print(obj/machinery/telecomms/message_server/server)
info = "<center><h2>Daily Key Reset</h2></center><br>The new message monitor key is '[server.decryptkey]'.<br>Please keep this a secret and away from the clown.<br>If necessary, change the password to a more secure one."
info_links = info
add_overlay("paper_words")
/obj/item/paper/monitorkey/LateInitialize()
@@ -17,12 +17,11 @@
circuit = /obj/item/circuitboard/computer/comm_monitor
/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "telemonitor", name, 575, 400, master_ui, state)
ui = new(user, src, "TelecommsMonitor", name)
ui.open()
/obj/machinery/computer/telecomms/monitor/ui_data(mob/user)
@@ -27,16 +27,15 @@
else
return ..()
/obj/machinery/telecomms/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
/obj/machinery/telecomms/ui_interact(mob/user, datum/tgui/ui)
if(!canInteract(user))
if(ui)
ui.close() //haha no.
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "teleinteract", "[name] Access", 520, 500, master_ui, state)
ui = new(user, src, "TelecommsInteraction", "[name] Access")
ui.open()
/obj/machinery/telecomms/ui_data(mob/user)
@@ -5,16 +5,73 @@
require the message server.
*/
// A decorational representation of SSblackbox, usually placed alongside the message server.
// A decorational representation of SSblackbox, usually placed alongside the message server. Also contains a traitor theft item.
/obj/machinery/blackbox_recorder
icon = 'icons/obj/stationobjs.dmi'
icon_state = "blackbox"
name = "Blackbox Recorder"
name = "blackbox recorder"
density = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 100
armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 70)
var/obj/item/stored
/obj/machinery/blackbox_recorder/Initialize()
. = ..()
stored = new /obj/item/blackbox(src)
/obj/machinery/blackbox_recorder/on_attack_hand(mob/living/user, act_intent, unarmed_attack_flags)
. = ..()
if(stored)
to_chat(user, "<span class='notice'>You start struggling to pry the [stored] from the [src]...</span>")
if(!do_after(user, 30 SECONDS, TRUE, src))
to_chat(user, "<span class='warning'>Your fingers slip as you fail to pry the [stored] from the [src], clicking it right back into the slot!</span>")
return
if(user.put_in_hands(stored))
stored.forceMove(user.drop_location())
stored = null
to_chat(user, "<span class='warning'>You successfully pry the [stored] from the [src], and send its overwhelming weight tumbling onto the ground! The tapes on the [src] stop spinning...</span>")
update_icon()
return
else
to_chat(user, "<span class='warning'>It seems that the blackbox is missing...</span>")
return
/obj/machinery/blackbox_recorder/attackby(obj/item/I, mob/living/user, params)
. = ..()
if(istype(I, /obj/item/blackbox))
if(HAS_TRAIT(I, TRAIT_NODROP) || !user.transferItemToLoc(I, src))
to_chat(user, "<span class='warning'>[I] is stuck to your hand!</span>")
return
user.visible_message("<span class='notice'>[user] clicks the [I] into the [src]!</span>", \
"<span class='notice'>You press [I] into [src], and it clicks into place. The tapes on the [src] begin spinning again...</span>")
playsound(src, 'sound/machines/click.ogg', 50, TRUE)
stored = I
update_icon()
return ..()
return ..()
/obj/machinery/blackbox_recorder/Destroy()
if(stored)
stored.forceMove(loc)
new /obj/effect/decal/cleanable/oil(loc)
return ..()
/obj/machinery/blackbox_recorder/update_icon()
. = ..()
if(!stored)
icon_state = "blackbox_b"
else
icon_state = "blackbox"
/obj/item/blackbox
name = "the blackbox"
desc = "A strange relic, capable of recording data on extradimensional vertices. It lives inside the blackbox recorder for safe keeping."
icon = 'icons/obj/stationobjs.dmi'
icon_state = "blackcube"
w_class = WEIGHT_CLASS_BULKY
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
// The message server itself.
@@ -140,9 +197,9 @@
..()
if(href_list["photo"])
var/mob/M = usr
M << browse_rsc(picture.picture_image, "pda_photo.png")
M << browse_rsc(picture.picture_image, "pda_photo.png")
var/dat = "<div style='overflow: hidden; margin :0; text-align: center'>"
dat += "<img src='pda_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />"
dat += "</div>"
+5 -4
View File
@@ -18,9 +18,6 @@
/obj/machinery/turnstile/CanAtmosPass(turf/T)
return TRUE
/obj/machinery/turnstile/bullet_act(obj/item/projectile/P, def_zone)
return BULLET_ACT_FORCE_PIERCE //Pass through!
/obj/machinery/turnstile/proc/allowed_access(var/mob/B)
if(B.pulledby && ismob(B.pulledby))
return allowed(B.pulledby) | allowed(B)
@@ -28,6 +25,8 @@
return allowed(B)
/obj/machinery/turnstile/CanPass(atom/movable/AM, turf/T)
if(istype(AM, /obj/item/projectile))
return TRUE
if(ismob(AM))
var/mob/B = AM
if(isliving(AM))
@@ -60,6 +59,8 @@
return FALSE
/obj/machinery/turnstile/CheckExit(atom/movable/AM as mob|obj, target)
if(istype(AM, /obj/item/projectile))
return TRUE
if(isliving(AM))
var/mob/living/M = AM
var/outdir = dir
@@ -81,4 +82,4 @@
M.last_bumped = world.time
return canexit
else
return TRUE
return TRUE
+1 -4
View File
@@ -297,10 +297,7 @@ GLOBAL_LIST_INIT(dye_registry, list(
else
return ..()
/obj/machinery/washing_machine/attack_hand(mob/user)
. = ..()
if(.)
return
/obj/machinery/washing_machine/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(busy)
to_chat(user, "<span class='warning'>[src] is busy.</span>")
return
+4 -4
View File
@@ -10,7 +10,7 @@
var/charges = 1
var/insisting = 0
/obj/machinery/wish_granter/attack_hand(mob/living/carbon/user)
/obj/machinery/wish_granter/on_attack_hand(mob/living/carbon/user)
if(charges <= 0)
to_chat(user, "The Wish Granter lies silent.")
return
@@ -31,7 +31,7 @@
user.dna.add_mutation(XRAY)
user.dna.add_mutation(SPACEMUT)
user.dna.add_mutation(TK)
user.next_move_modifier *= 0.5 //half the delay between attacks!
user.action_cooldown_mod *= 0.5
to_chat(user, "Things around you feel slower!")
charges--
insisting = FALSE
@@ -101,14 +101,14 @@
to_chat(user, "[killreward] materializes into your hands!")
else
to_chat(user, "[killreward] materializes onto the floor.")
user.next_move_modifier *= 0.8 //20% less delay between attacks!
user.action_cooldown_mod *= 0.8
to_chat(user, "Things around you feel slightly slower!")
var/mob/living/simple_animal/hostile/venus_human_trap/killwish = new /mob/living/simple_animal/hostile/venus_human_trap(loc)
killwish.maxHealth = 1500
killwish.health = killwish.maxHealth
killwish.vine_grab_distance = 6
killwish.melee_damage_upper = 30
killwish.loot = list(/obj/item/twohanded/dualsaber/hypereutactic)
killwish.loot = list(/obj/item/dualsaber/hypereutactic)
charges--
insisting = FALSE
if(!charges)
+2 -2
View File
@@ -21,7 +21,7 @@
var/cell_charge = get_charge()
var/datum/gas_mixture/int_tank_air = internal_tank.return_air()
var/tank_pressure = internal_tank ? round(int_tank_air.return_pressure(),0.01) : "None"
var/tank_temperature = internal_tank ? int_tank_air.temperature : "Unknown"
var/tank_temperature = internal_tank ? int_tank_air.return_temperature() : "Unknown"
var/cabin_pressure = round(return_pressure(),0.01)
var/output = {"[report_internal_damage()]
[integrity<30?"<font color='red'><b>DAMAGE LEVEL CRITICAL</b></font><br>":null]
@@ -155,4 +155,4 @@
var/color=""
for (var/i=0;i<6;i++)
color = color+pick(colors)
return color
return color
+4 -2
View File
@@ -15,6 +15,8 @@
internals_req_access = list()
add_req_access = 0
wreckage = /obj/structure/mecha_wreckage/durand/neovgre
stepsound = 'sound/mecha/neostep2.ogg'
turnsound = 'sound/mecha/powerloader_step.ogg'
/obj/mecha/combat/neovgre/GrantActions(mob/living/user, human_occupant = 0) //No Eject action for you sonny jim, your life for Ratvar!
internals_action.Grant(user, src)
@@ -32,7 +34,7 @@
/obj/mecha/combat/neovgre/MouseDrop_T(mob/M, mob/user)
if(!is_servant_of_ratvar(user))
to_chat(user, "<span class='brass'>BEGONE HERETIC!</span>")
to_chat(user, "<span class='neovgre'>BEGONE HEATHEN!</span>")
return
else
..()
@@ -91,7 +93,7 @@
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre
equip_cooldown = 8 //Rapid fire heavy laser cannon, simple yet elegant
energy_drain = 30
name = "Aribter Laser Cannon"
name = "Arbiter Laser Cannon"
desc = "Please re-attach this to neovgre and stop asking questions about why it looks like a normal Nanotrasen issue Solaris laser cannon - Nezbere"
fire_sound = 'sound/weapons/neovgre_laser.ogg'
+17 -9
View File
@@ -11,10 +11,15 @@
var/equip_ready = 1 //whether the equipment is ready for use. (or deactivated/activated for static stuff)
var/energy_drain = 0
var/obj/mecha/chassis = null
var/range = MELEE //bitFflags
/// Bitflag. Determines the range of the equipment.
var/range = MELEE
/// Bitflag. Used by exosuit fabricator to assign sub-categories based on which exosuits can equip this.
var/mech_flags = NONE
var/salvageable = 1
//var/detachable = TRUE // Set to FALSE for built-in equipment that cannot be removed
var/selectable = 1 // Set to 0 for passive equipment such as mining scanner or armor plates
var/harmful = FALSE //Controls if equipment can be used to attack by a pacifist.
//var/destroy_sound = 'sound/mecha/critdestr.ogg'
/obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page()
if(chassis)
@@ -35,9 +40,14 @@
if(chassis.selected == src)
chassis.selected = null
src.update_chassis_page()
chassis.occupant_message("<span class='danger'>[src] is destroyed!</span>")
//log_message("[src] is destroyed.", LOG_MECHA)
chassis.log_append_to_last("[src] is destroyed.",1)
SEND_SOUND(chassis.occupant, sound(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon) ? 'sound/mecha/weapdestr.ogg' : 'sound/mecha/critdestr.ogg', volume=50))
if(chassis.occupant)
chassis.occupant_message("<span class='danger'>[src] is destroyed!</span>")
SEND_SOUND(chassis.occupant, sound(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon) ? 'sound/mecha/weapdestr.ogg' : 'sound/mecha/critdestr.ogg', volume=50))
//chassis.occupant.playsound_local(chassis, destroy_sound, 50)
//if(!detachable) //If we're a built-in nondetachable equipment, let's lock up the slot that we were in.
// chassis.max_equip--
chassis = null
return ..()
@@ -59,7 +69,7 @@
return txt
/obj/item/mecha_parts/mecha_equipment/proc/is_ranged()//add a distance restricted equipment. Why not?
return range&RANGED
return range&RANGED //rename to MECHA_RANGE and MECHA_MELEE
/obj/item/mecha_parts/mecha_equipment/proc/is_melee()
return range&MELEE
@@ -72,10 +82,10 @@
return 0
if(!equip_ready)
return 0
if(crit_fail)
return 0
if(energy_drain && !chassis.has_charge(energy_drain))
return 0
if(crit_fail)
return 0
if(chassis.equipment_disabled)
to_chat(chassis.occupant, "<span=warn>Error -- Equipment control unit is unresponsive.</span>")
return 0
@@ -117,8 +127,6 @@
chassis = M
forceMove(M)
M.mecha_log_message("[src] initialized.")
if(!M.selected && selectable)
M.selected = src
src.update_chassis_page()
return
@@ -150,7 +158,7 @@
chassis.occupant_message("[icon2html(src, chassis.occupant)] [message]")
return
/obj/item/mecha_parts/mecha_equipment/proc/mecha_log_message(message, color)
/obj/item/mecha_parts/mecha_equipment/proc/mecha_log_message(message, color) //on tg this just overrides log_message
log_message(message, LOG_GAME, color) //pass to default admin logging too
if(chassis)
chassis.mecha_log_message(message, color) //and pass to our chassis
@@ -1,6 +1,7 @@
// Sleeper, Medical Beam, and Syringe gun
/obj/item/mecha_parts/mecha_equipment/medical
mech_flags = EXOSUIT_MODULE_MEDICAL
/obj/item/mecha_parts/mecha_equipment/medical/Initialize()
. = ..()
@@ -17,6 +17,7 @@
toolspeed = 0.9
var/drill_delay = 7
var/drill_level = DRILL_BASIC
mech_flags = EXOSUIT_MODULE_WORKING | EXOSUIT_MODULE_COMBAT
/obj/item/mecha_parts/mecha_equipment/drill/Initialize()
. = ..()
@@ -153,6 +154,7 @@
selectable = 0
equip_cooldown = 15
var/scanning_time = 0
mech_flags = EXOSUIT_MODULE_WORKING
/obj/item/mecha_parts/mecha_equipment/mining_scanner/Initialize()
. = ..()

Some files were not shown because too many files have changed in this diff Show More