Merge branch 'master' into cool-ipcs
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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!"
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
. = ..()
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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] </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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]."
|
||||
|
||||
@@ -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), " ", " "),
|
||||
"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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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>", \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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] </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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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(.)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user