Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into putnamos-for-real

This commit is contained in:
Putnam
2020-07-08 22:02:03 -07:00
1515 changed files with 270775 additions and 326499 deletions
+16 -1
View File
@@ -38,6 +38,10 @@
var/poweralm = TRUE
var/lightswitch = TRUE
var/totalbeauty = 0 //All beauty in this area combined, only includes indoor area.
var/beauty = 0 // Beauty average per open turf in the area
var/beauty_threshold = 150 //If a room is too big it doesn't have beauty.
var/requires_power = TRUE
/// This gets overridden to 1 for space in area/Initialize().
var/always_unpowered = FALSE
@@ -65,7 +69,7 @@
/// Hides area from player Teleport function.
var/hidden = FALSE
/// Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
var/safe = FALSE
var/safe = FALSE
/// If false, loading multiple maps with this area type will create multiple instances.
var/unique = TRUE
@@ -192,6 +196,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
/area/LateInitialize()
if(!base_area) //we don't want to run it twice.
power_change() // all machines set to current power level, also updates icon
update_beauty()
/area/proc/reg_in_areas_in_z()
if(contents.len)
@@ -538,6 +543,16 @@ GLOBAL_LIST_EMPTY(teleportlocs)
L.client.played = TRUE
addtimer(CALLBACK(L.client, /client/proc/ResetAmbiencePlayed), 600)
///Divides total beauty in the room by roomsize to allow us to get an average beauty per tile.
/area/proc/update_beauty()
if(!areasize)
beauty = 0
return FALSE
if(areasize >= beauty_threshold)
beauty = 0
return FALSE //Too big
beauty = totalbeauty / areasize
/area/Exited(atom/movable/M)
SEND_SIGNAL(src, COMSIG_AREA_EXITED, M)
SEND_SIGNAL(M, COMSIG_EXIT_AREA, src) //The atom that exits the area
+2 -1
View File
@@ -32,7 +32,8 @@
/area/centcom/vip
name = "VIP Zone"
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
/area/centcom/winterball
/area/centcom/winterball
name = "winterball Zone"
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
+8
View File
@@ -32,6 +32,14 @@
/area/ruin/powered/seedvault
icon_state = "dk_yellow"
/area/ruin/unpowered/elephant_graveyard
name = "Elephant Graveyard"
icon_state = "dk_yellow"
/area/ruin/powered/graveyard_shuttle
name = "Elephant Graveyard"
icon_state = "green"
/area/ruin/unpowered/syndicate_lava_base
name = "Secret Base"
icon_state = "dk_yellow"
+19
View File
@@ -129,7 +129,26 @@
icon_state = "crew_quarters"
//Ruin of Space Diner
/area/ruin/space/diner
name = "Space Diner"
/area/ruin/space/diner/interior
name = "Space Diner"
icon_state = "maintbar"
has_gravity = STANDARD_GRAVITY
blob_allowed = FALSE //Nope, no winning in the diner as a blob. Gotta eat the main station.
/area/ruin/space/diner/solars
requires_power = FALSE
dynamic_lighting = DYNAMIC_LIGHTING_IFSTARLIGHT
valid_territory = FALSE
blob_allowed = FALSE
flags_1 = NONE
ambientsounds = ENGINEERING
name = "Space Diner Solar Array"
icon_state = "yellow"
//Ruin of Derelict Oupost
+15 -1
View File
@@ -93,6 +93,13 @@
/area/shuttle/abandoned/pod
name = "Abandoned Ship Pod"
////////////////////////////Bounty Hunter Shuttles////////////////////////////
/area/shuttle/hunter
name = "Hunter Shuttle"
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
blob_allowed = FALSE
canSmoothWithAreas = /area/shuttle/hunter
////////////////////////////Single-area shuttles////////////////////////////
/area/shuttle/transit
@@ -103,6 +110,10 @@
/area/shuttle/custom
name = "Custom player shuttle"
/area/shuttle/custom/powered
name = "Custom Powered player shuttle"
requires_power = FALSE
/area/shuttle/arrival
name = "Arrival Shuttle"
unique = TRUE // SSjob refers to this area for latejoiners
@@ -200,4 +211,7 @@
name = "Tiny Freighter"
/area/shuttle/caravan/freighter3
name = "Tiny Freighter"
name = "Tiny Freighter"
/area/shuttle/snowtaxi
name = "Snow Taxi"
+86 -49
View File
@@ -8,6 +8,13 @@
var/interaction_flags_atom = NONE
var/datum/reagents/reagents = null
var/flags_ricochet = NONE
///When a projectile tries to ricochet off this atom, the projectile ricochet chance is multiplied by this
var/ricochet_chance_mod = 1
///When a projectile ricochets off this atom, it deals the normal damage * this modifier to this atom
var/ricochet_damage_mod = 0.33
//This atom's HUD (med/sec, etc) images. Associative list.
var/list/image/hud_list = null
//HUD images that this atom can provide.
@@ -41,12 +48,15 @@
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
///Modifier that raises/lowers the effect of the amount of a material, prevents small and easy to get items from being death machines.
var/material_modifier = 1
var/datum/wires/wires = null
var/icon/blood_splatter_icon
var/list/fingerprints
var/list/fingerprintshidden
@@ -105,11 +115,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()
@@ -139,8 +146,27 @@
return ..()
/**
* Checks if a projectile should ricochet off of us. Projectiles get final say.
* [__DEFINES/projectiles.dm] for return values.
*/
/atom/proc/check_projectile_ricochet(obj/item/projectile/P)
return (flags_1 & DEFAULT_RICOCHET_1)? PROJECTILE_RICOCHET_YES : PROJECTILE_RICOCHET_NO
/atom/proc/handle_ricochet(obj/item/projectile/P)
return
var/turf/p_turf = get_turf(P)
var/face_direction = get_dir(src, p_turf)
var/face_angle = dir2angle(face_direction)
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (P.Angle + 180))
var/a_incidence_s = abs(incidence_s)
if(a_incidence_s > 90 && a_incidence_s < 270)
return FALSE
if((P.flag in list("bullet", "bomb")) && P.ricochet_incidence_leeway)
if((a_incidence_s < 90 && a_incidence_s < 90 - P.ricochet_incidence_leeway) || (a_incidence_s > 270 && a_incidence_s -270 > P.ricochet_incidence_leeway))
return
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
P.setAngle(new_angle_s)
return TRUE
/atom/proc/CanPass(atom/movable/mover, turf/target)
return !density
@@ -313,10 +339,11 @@
. += desc
if(custom_materials)
var/list/materials_list = list()
for(var/i in custom_materials)
var/datum/material/M = i
. += "<u>It is made out of [M.name]</u>."
materials_list += "[M.name]"
. += "<u>It is made out of [english_list(materials_list)]</u>."
if(reagents)
if(reagents.reagents_holder_flags & TRANSPARENT)
. += "It contains:"
@@ -409,7 +436,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()
@@ -417,13 +444,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)
@@ -434,18 +463,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)
@@ -514,28 +558,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
@@ -581,6 +604,14 @@
SEND_SIGNAL(src, COMSIG_ATOM_RCD_ACT, user, the_rcd, passed_mode)
return FALSE
/**
* Respond to a electric bolt action on our item
*
* Default behaviour is to return, we define here to allow for cleaner code later on
*/
/atom/proc/zap_act(power, zap_flags, shocked_targets)
return
/atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user)
if(GetComponent(/datum/component/storage))
return component_storage_contents_dump_act(src_object, user)
@@ -835,6 +866,17 @@
/atom/proc/GenerateTag()
return
/**
* Called after a shuttle is loaded **from map template initially**.
*
* @params
* * port - Mobile port/shuttle
* * dock - Stationary dock the shuttle's at
* * idnum - ID number of the shuttle
*/
/atom/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
return
// Generic logging helper
/atom/proc/log_message(message, message_type, color=null, log_globally=TRUE)
if(!log_globally)
@@ -927,14 +969,14 @@ Proc for attack log creation, because really why not
target.log_message(reverse_message, LOG_ATTACK, color="orange", log_globally=FALSE)
// Filter stuff
/atom/movable/proc/add_filter(name,priority,list/params)
/atom/proc/add_filter(name,priority,list/params)
LAZYINITLIST(filter_data)
var/list/p = params.Copy()
p["priority"] = priority
filter_data[name] = p
update_filters()
/atom/movable/proc/update_filters()
/atom/proc/update_filters()
filters = null
filter_data = sortTim(filter_data, /proc/cmp_filter_data_priority, TRUE)
for(var/f in filter_data)
@@ -943,11 +985,11 @@ Proc for attack log creation, because really why not
arguments -= "priority"
filters += filter(arglist(arguments))
/atom/movable/proc/get_filter(name)
/atom/proc/get_filter(name)
if(filter_data && filter_data[name])
return filters[filter_data.Find(name)]
/atom/movable/proc/remove_filter(name)
/atom/proc/remove_filter(name)
if(filter_data && filter_data[name])
filter_data -= name
update_filters()
@@ -958,26 +1000,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
+18 -16
View File
@@ -37,6 +37,8 @@
var/throwforce = 0
var/datum/component/orbiter/orbiting
var/can_be_z_moved = TRUE
///If we were without gravity and another animation happened, the bouncing will stop, and we need to restart it in next life().
var/floating_need_update = FALSE
var/zfalling = FALSE
@@ -56,10 +58,6 @@
em_block = new(src, render_target)
vis_contents += em_block
/atom/movable/Destroy()
QDEL_NULL(em_block)
return ..()
/atom/movable/proc/update_emissive_block()
if(blocks_emissive != EMISSIVE_BLOCK_GENERIC)
return
@@ -183,14 +181,15 @@
return TRUE
/atom/movable/proc/stop_pulling()
if(pulling)
pulling.pulledby = null
var/mob/living/ex_pulled = pulling
pulling = null
setGrabState(0)
if(isliving(ex_pulled))
var/mob/living/L = ex_pulled
L.update_mobility()// mob gets up if it was lyng down in a chokehold
if(!pulling)
return
pulling.pulledby = null
var/mob/living/ex_pulled = pulling
pulling = null
setGrabState(0)
if(isliving(ex_pulled))
var/mob/living/L = ex_pulled
L.update_mobility()// mob gets up if it was lyng down in a chokehold
/atom/movable/proc/Move_Pulled(atom/A)
if(!pulling)
@@ -232,10 +231,12 @@
/atom/movable/Destroy(force)
QDEL_NULL(proximity_monitor)
QDEL_NULL(language_holder)
QDEL_NULL(em_block)
unbuckle_all_mobs(force=1)
. = ..()
if(loc)
//Restore air flow if we were blocking it (movables with ATMOS_PASS_PROC will need to do this manually if necessary)
if(((CanAtmosPass == ATMOS_PASS_DENSITY && density) || CanAtmosPass == ATMOS_PASS_NO) && isturf(loc))
@@ -493,15 +494,16 @@
/atom/movable/proc/float(on)
if(throwing)
return
if(on && !(movement_type & FLOATING))
if(on && (!(movement_type & FLOATING) || floating_need_update))
animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1)
sleep(10)
animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1)
setMovetype(movement_type | FLOATING)
else if (!on && (movement_type & FLOATING))
if(!(movement_type & FLOATING))
setMovetype(movement_type | FLOATING)
else if (!on && movement_type & FLOATING)
animate(src, pixel_y = initial(pixel_y), time = 10)
setMovetype(movement_type & ~FLOATING)
floating_need_update = FALSE
/* Language procs
* Unless you are doing something very specific, these are the ones you want to use.
@@ -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
@@ -202,7 +202,7 @@
icon_state = "moustacheg"
clumsy_check = GRENADE_NONCLUMSY_FUMBLE
/obj/item/grenade/chem_grenade/teargas/moustache/prime()
/obj/item/grenade/chem_grenade/teargas/moustache/prime(mob/living/lanced_by)
var/list/check_later = list()
for(var/mob/living/carbon/C in get_turf(src))
check_later += C
+3 -6
View File
@@ -48,9 +48,6 @@
/obj/machinery/dominator/hulk_damage()
return (max_integrity - integrity_failure) / DOM_HULK_HITS_REQUIRED
/obj/machinery/dominator/tesla_act()
qdel(src)
/obj/machinery/dominator/update_icon()
cut_overlays()
if(stat & BROKEN)
@@ -148,9 +145,9 @@
new /obj/item/stack/sheet/plasteel(src.loc)
qdel(src)
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user)
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
add_fingerprint(user)
..()
return ..()
/obj/machinery/dominator/attack_hand(mob/user)
if(operating || (stat & BROKEN))
@@ -243,4 +240,4 @@
#undef DOM_BLOCKED_SPAM_CAP
#undef DOM_REQUIRED_TURFS
#undef DOM_HULK_HITS_REQUIRED
#undef DOM_HULK_HITS_REQUIRED
+1 -1
View File
@@ -10,7 +10,7 @@
/obj/effect/decal/cleanable/crayon/gang
icon = 'icons/effects/crayondecal.dmi'
layer = ABOVE_NORMAL_TURF_LAYER //Harder to hide
plane = GAME_PLANE
plane = ABOVE_WALL_PLANE
do_icon_rotate = FALSE //These are designed to always face south, so no rotation please.
var/datum/team/gang/gang
+1 -1
View File
@@ -288,7 +288,7 @@ datum/gang_item/clothing/shades //Addition: Why not have cool shades on a gang m
name = "Fragmentation Grenade"
id = "frag nade"
cost = 5
item_path = /obj/item/grenade/syndieminibomb/concussion/frag
item_path = /obj/item/grenade/frag
/datum/gang_item/equipment/implant_breaker
name = "Implant Breaker"
+4 -1
View File
@@ -201,10 +201,13 @@ GLOBAL_LIST_EMPTY(objectives)
return won || ..()
/datum/objective/assassinate/once/process()
won = check_completion()
won = check_midround_completion()
if(won)
STOP_PROCESSING(SSprocessing,src)
/datum/objective/assassinate/once/proc/check_midround_completion()
return won || !considered_alive(target) //The target afking / logging off for a bit during the round doesn't complete it, but them being afk at roundend does.
/datum/objective/assassinate/internal
var/stolen = 0 //Have we already eliminated this target?
+1
View File
@@ -36,6 +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 either the alt verson of the hos gun or the beacon picker.
/datum/objective_item/steal/handtele
name = "a hand teleporter."
+1 -2
View File
@@ -2,8 +2,7 @@
GLOBAL_VAR_INIT(hsboxspawn, TRUE)
/mob
var/datum/hSB/sandbox = null
/mob/proc/CanBuild()
sandbox = new/datum/hSB
sandbox.owner = src.ckey
+9 -1
View File
@@ -44,7 +44,7 @@
/datum/game_mode/wizard/are_special_antags_dead()
for(var/datum/mind/wizard in wizards)
for(var/datum/mind/wizard in wizards | apprentices)
if(isliving(wizard.current) && wizard.current.stat!=DEAD)
return FALSE
@@ -58,6 +58,14 @@
return TRUE
/datum/game_mode/wizard/check_finished()
. = ..()
if(.)
finished = TRUE
else if(gamemode_ready && are_special_antags_dead() && !CONFIG_GET(keyed_list/continuous)[config_tag])
finished = TRUE
. = TRUE
/datum/game_mode/wizard/set_round_result()
..()
if(finished)
+47
View File
@@ -37,6 +37,11 @@
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)
@@ -429,3 +434,45 @@
/obj/machinery/sleeper/old
icon_state = "oldpod"
/obj/machinery/sleeper/party
name = "party pod"
desc = "'Sleeper' units were once known for their healing properties, until a lengthy investigation revealed they were also dosing patients with deadly lead acetate. This appears to be one of those old 'sleeper' units repurposed as a 'Party Pod'. Its probably not a good idea to use it."
icon_state = "partypod"
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(
list(/datum/reagent/consumable/ethanol/beer, /datum/reagent/consumable/laughter),
list(/datum/reagent/spraytan,/datum/reagent/barbers_aid),
list(/datum/reagent/colorful_reagent,/datum/reagent/hair_dye),
list(/datum/reagent/drug/space_drugs,/datum/reagent/baldium)
)//Exclusively uses non-lethal, "fun" chems. At an obvious downside.
var/spray_chems = list(
/datum/reagent/spraytan, /datum/reagent/hair_dye, /datum/reagent/baldium, /datum/reagent/barbers_aid
)//Chemicals that need to have a touch or vapor reaction to be applied, not the standard chamber reaction.
enter_message = "<span class='notice'><b>You're surrounded by some funky music inside the chamber. You zone out as you feel waves of krunk vibe within you.</b></span>"
/obj/machinery/sleeper/party/inject_chem(chem, mob/user)
if(leddit)
occupant.reagents.add_reagent(/datum/reagent/toxin/leadacetate, 4) //You're injecting chemicals into yourself from a recalled, decrepit medical machine. What did you expect?
else if (prob(20))
occupant.reagents.add_reagent(/datum/reagent/toxin/leadacetate, rand(1,3))
if(chem in spray_chems)
var/datum/reagents/holder = new()
holder.add_reagent(chem_buttons[chem], 10) //I hope this is the correct way to do this.
holder.reaction(occupant, VAPOR, 0)
holder.trans_to(occupant, 10)
playsound(src.loc, 'sound/effects/spray2.ogg', 50, TRUE, -6)
if(user)
log_combat(user, occupant, "sprayed [chem] into", addition = "via [src]")
return TRUE
..()
/obj/machinery/sleeper/party/emag_act(mob/user)
..()
leddit = TRUE
+9 -5
View File
@@ -92,6 +92,8 @@ 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_ricochet = RICOCHET_HARD
ricochet_chance_mod = 0.3
anchored = TRUE
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
@@ -110,7 +112,8 @@ Class Procs:
var/state_open = FALSE
var/critical_machine = FALSE //If this machine is critical to station operation and should have the area be excempted from power failures.
var/list/occupant_typecache //if set, turned into typecache in Initialize, other wise, defaults to mob/living typecache
var/atom/movable/occupant = null
var/atom/movable/occupant
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
// For storing and overriding ui id and dimensions
@@ -217,6 +220,7 @@ Class Procs:
if(target && !target.has_buckled_mobs() && (!isliving(target) || !mobtarget.buckled))
occupant = target
target.forceMove(src)
target.setDir(new_occupant_dir)
updateUsrDialog()
update_icon()
@@ -520,11 +524,11 @@ Class Procs:
/obj/machinery/proc/can_be_overridden()
. = 1
/obj/machinery/tesla_act(power, tesla_flags, shocked_objects)
..()
if(prob(85) && (tesla_flags & TESLA_MACHINE_EXPLOSIVE))
/obj/machinery/zap_act(power, zap_flags, shocked_objects)
. = ..()
if(prob(85) && (zap_flags & ZAP_MACHINE_EXPLOSIVE))
explosion(src, 1, 2, 4, flame_range = 2, adminlog = FALSE, smoke = FALSE)
if(tesla_flags & TESLA_OBJ_DAMAGE)
else if(zap_flags & ZAP_OBJ_DAMAGE)
take_damage(power/2000, BURN, "energy")
if(prob(40))
emp_act(EMP_LIGHT)
+5 -17
View File
@@ -46,28 +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
)
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
+6 -4
View File
@@ -16,10 +16,13 @@
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/machinery/button/Initialize(mapload, ndir = 0, built = 0)
if(istext(id) && mapload)
if(copytext(id, 1, 2) == "!")
id = SSmapping.get_obfuscated_id(id)
if(istext(id) && mapload && id[1] == "!")
id = SSmapping.get_obfuscated_id(id)
. = ..()
var/turf/T = get_turf_pixel(src)
if(iswallturf(T))
plane = ABOVE_WALL_PLANE
if(built)
setDir(ndir)
pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
@@ -27,7 +30,6 @@
panel_open = TRUE
update_icon()
if(!built && !device && device_type)
device = new device_type(src)
+1 -1
View File
@@ -75,7 +75,7 @@
// UPGRADE PROCS
/obj/machinery/camera/proc/upgradeEmpProof()
AddComponent(/datum/component/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES | EMP_PROTECT_CONTENTS)
AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES | EMP_PROTECT_CONTENTS)
assembly.upgrades.Add(new /obj/item/stack/sheet/mineral/plasma(assembly))
upgrades |= CAMERA_UPGRADE_EMP_PROOF
+57 -33
View File
@@ -26,6 +26,7 @@
var/efficiency
var/datum/mind/clonemind
var/get_clone_mind = CLONEPOD_GET_MIND
var/grab_ghost_when = CLONER_MATURE_CLONE
var/internal_radio = TRUE
@@ -134,43 +135,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 +194,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 +218,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 +286,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 +411,8 @@
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()
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 +488,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 +558,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.
*/
+3 -3
View File
@@ -42,9 +42,9 @@
/obj/item/clothing/mask/facehugger/toy = ARCADE_WEIGHT_RARE,
/obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = ARCADE_WEIGHT_TRICK,
/obj/item/hot_potato/harmless/toy = ARCADE_WEIGHT_RARE,
/obj/item/twohanded/dualsaber/toy = ARCADE_WEIGHT_RARE,
/obj/item/twohanded/dualsaber/hypereutactic/toy = ARCADE_WEIGHT_RARE,
/obj/item/twohanded/dualsaber/hypereutactic/toy/rainbow = ARCADE_WEIGHT_RARE,
/obj/item/dualsaber/toy = ARCADE_WEIGHT_RARE,
/obj/item/dualsaber/hypereutactic/toy = ARCADE_WEIGHT_RARE,
/obj/item/dualsaber/hypereutactic/toy/rainbow = ARCADE_WEIGHT_RARE,
/obj/item/storage/box/snappops = ARCADE_WEIGHT_TRICK,
/obj/item/clothing/under/syndicate/tacticool = ARCADE_WEIGHT_TRICK,
+15
View File
@@ -175,6 +175,12 @@
clockwork = TRUE //it'd look very weird
light_power = 0
/obj/machinery/computer/security/telescreen/Initialize()
. = ..()
var/turf/T = get_turf_pixel(src)
if(iswallturf(T))
plane = ABOVE_WALL_PLANE
/obj/machinery/computer/security/telescreen/update_icon_state()
icon_state = initial(icon_state)
if(stat & BROKEN)
@@ -251,3 +257,12 @@
name = "AI upload monitor"
desc = "A telescreen that connects to the AI upload's camera network."
network = list("aiupload")
// Subtype that connects to shuttles.
/obj/machinery/computer/security/shuttle
circuit = /obj/item/circuitboard/computer/security/shuttle
/obj/machinery/computer/security/shuttle/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]"
+179 -92
View File
@@ -8,6 +8,7 @@
circuit = /obj/item/circuitboard/computer/cloning
req_access = list(ACCESS_HEADS) //ONLY USED FOR RECORD DELETION RIGHT NOW.
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/clonepod_type = /obj/machinery/clonepod
var/list/pods //Linked cloning pods
var/temp = "Inactive"
var/scantemp_ckey
@@ -17,6 +18,7 @@
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
var/loading = 0 // Nice loading text
var/autoprocess = 0
var/use_records = TRUE // Old experimental cloner.
var/list/records = list()
light_color = LIGHT_COLOR_BLUE
@@ -36,29 +38,32 @@
return ..()
/obj/machinery/computer/cloning/proc/GetAvailablePod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
if(!pods)
return
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.get_clone_mind == CLONEPOD_GET_MIND && pod.clonemind == mind)
return null
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
/obj/machinery/computer/cloning/proc/HasEfficientPod()
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.is_operational() && pod.efficiency > 5)
return TRUE
if(!pods)
return
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.is_operational() && pod.efficiency > 5)
return TRUE
/obj/machinery/computer/cloning/proc/GetAvailableEfficientPod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return pod
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
if(!pods)
return
for(var/P in pods)
var/obj/machinery/clonepod/pod = P
if(pod.occupant && pod.clonemind == mind)
return pod
else if(!. && pod.is_operational() && !(pod.occupant || pod.mess) && pod.efficiency > 5)
. = pod
/obj/machinery/computer/cloning/process()
if(!(scanner && LAZYLEN(pods) && autoprocess))
@@ -73,7 +78,7 @@
if(pod.occupant)
continue //how though?
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], R.fields["bank_account"]))
if(pod.growclone(R.fields["ckey"], R.fields["name"], R.fields["UI"], R.fields["SE"], R.fields["mind"], R.fields["blood_type"], R.fields["mrace"], R.fields["features"], R.fields["factions"], R.fields["quirks"], R.fields["bank_account"], R.fields["traumas"]))
temp = "[R.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
records -= R
@@ -103,12 +108,10 @@
return null
/obj/machinery/computer/cloning/proc/findcloner()
var/obj/machinery/clonepod/podf = null
var/obj/machinery/clonepod/podf
for(var/direction in GLOB.cardinals)
podf = locate(/obj/machinery/clonepod, get_step(src, direction))
if (!isnull(podf) && podf.is_operational())
podf = locate(clonepod_type, get_step(src, direction))
if(podf?.is_operational())
AttachCloner(podf)
/obj/machinery/computer/cloning/proc/AttachCloner(obj/machinery/clonepod/pod)
@@ -132,7 +135,7 @@
else if(istype(W, /obj/item/multitool))
var/obj/item/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod))
if(istype(P.buffer, clonepod_type))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
@@ -157,13 +160,14 @@
var/dat = ""
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
if(!autoprocess)
dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>"
if(use_records)
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
if(!autoprocess)
dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>"
else
dat += "<a href='byond://?src=[REF(src)];task=stopautoprocess'>Stop autoclone</a>"
else
dat += "<a href='byond://?src=[REF(src)];task=stopautoprocess'>Stop autoclone</a>"
else
dat += "<span class='linkOff'>Autoclone</span>"
dat += "<span class='linkOff'>Autoclone</span>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
@@ -190,26 +194,29 @@
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
if(use_records)
if(scanner_occupant.ckey != scantemp_ckey)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
else
scantemp = "Ready to Clone"
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=[REF(src)];scan=1'>Start Scan</a>"
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
dat += "<a href='byond://?src=[REF(src)];scan=1'>[use_records ? "Start Scan" : "Clone"]</a>"
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>Start Scan</span>"
// Database
dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0)
dat += "<a href='byond://?src=[REF(src)];menu=2'>View Records ([src.records.len])</a><br>"
else
dat += "<span class='linkOff'>View Records (0)</span><br>"
if (src.diskette)
dat += "<a href='byond://?src=[REF(src)];disk=eject'>Eject Disk</a><br>"
dat += "<span class='linkOff'>[use_records ? "Start Scan" : "Clone"]</span>"
if(use_records)
// Database
dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0)
dat += "<a href='byond://?src=[REF(src)];menu=2'>View Records ([src.records.len])</a><br>"
else
dat += "<span class='linkOff'>View Records (0)</span><br>"
if (src.diskette)
dat += "<a href='byond://?src=[REF(src)];disk=eject'>Eject Disk</a><br>"
@@ -290,24 +297,19 @@
autoprocess = FALSE
STOP_PROCESSING(SSmachines, src)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = 1
loading = TRUE
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
var/prev_locked = scanner.locked
scanner.locked = TRUE
spawn(20)
src.scan_occupant(scanner.occupant)
loading = 0
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
scanner.locked = prev_locked
addtimer(CALLBACK(src, .proc/finish_scan, scanner.occupant, prev_locked), 2 SECONDS)
. = TRUE
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
@@ -317,8 +319,17 @@
else
scanner.locked = FALSE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
. = TRUE
else if(href_list["view_rec"])
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
. = TRUE
if(. || !use_records)
return
if(href_list["view_rec"])
playsound(src, "terminal_type", 25, 0)
src.active_record = find_record("id", href_list["view_rec"], records)
if(active_record)
@@ -330,6 +341,7 @@
src.menu = 3
else
src.temp = "Record missing."
. = TRUE
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
@@ -353,8 +365,9 @@
else
src.temp = "<font class='bad'>Access Denied.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if (href_list["disk"]) //Load or eject.
else if (href_list["disk"] && use_records) //Load or eject.
switch(href_list["disk"])
if("load")
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
@@ -392,10 +405,7 @@
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
src.temp = "Save successful."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
. = TRUE
else if (href_list["clone"])
var/datum/data/record/C = find_record("id", href_list["clone"], records)
@@ -415,7 +425,7 @@
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"]))
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["blood_type"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"], C.fields["traumas"]))
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
@@ -429,53 +439,49 @@
else
temp = "<font class='bad'>Data corruption.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if (href_list["menu"])
src.menu = text2num(href_list["menu"])
else if (href_list["menu"] && use_records)
menu = text2num(href_list["menu"])
playsound(src, "terminal_type", 25, 0)
. = TRUE
/obj/machinery/computer/cloning/proc/finish_scan(mob/living/L, prev_locked)
if(!scanner || !L)
return
src.add_fingerprint(usr)
src.updateUsrDialog()
return
if(use_records)
scan_occupant(L)
else
clone_occupant(L)
loading = FALSE
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
scanner.locked = prev_locked
/obj/machinery/computer/cloning/proc/scan_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
var/datum/bank_account/has_bank_account
// Do not use unless you know what they are.
var/mob/living/carbon/C = mob_occupant
var/mob/living/brain/B = mob_occupant
if(ishuman(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
var/obj/item/card/id/I = C.get_idcard()
if(I)
has_bank_account = I.registered_account
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if ((!mob_occupant.ckey) || (!mob_occupant.client))
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(SSeconomy.full_ancap && !has_bank_account)
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
if(!can_scan(dna, mob_occupant, FALSE, has_bank_account))
return
var/datum/data/record/R = new()
if(dna.species)
// We store the instance rather than the path, because some
@@ -497,11 +503,17 @@
R.fields["features"] = dna.features
R.fields["factions"] = mob_occupant.faction
R.fields["quirks"] = list()
R.fields["bank_account"] = has_bank_account
for(var/V in mob_occupant.roundstart_quirks)
var/datum/quirk/T = V
R.fields["quirks"][T.type] = T.clone_data()
R.fields["traumas"] = list()
if(ishuman(mob_occupant))
R.fields["traumas"] = C.get_traumas()
if(isbrain(mob_occupant))
R.fields["traumas"] = B.get_traumas()
R.fields["bank_account"] = has_bank_account
if (!isnull(mob_occupant.mind)) //Save that mind so traitors can continue traitoring after cloning.
R.fields["mind"] = "[REF(mob_occupant.mind)]"
@@ -520,3 +532,78 @@
board.records = records
scantemp = "Subject successfully scanned."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//Used by the experimental cloning computer.
/obj/machinery/computer/cloning/proc/clone_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(ishuman(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!can_scan(dna, mob_occupant, TRUE))
return
var/clone_species
if(dna.species)
clone_species = dna.species
else
var/datum/species/rando_race = pick(GLOB.roundstart_races)
clone_species = rando_race.type
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
/obj/machinery/computer/cloning/proc/can_scan(datum/dna/dna, mob/living/mob_occupant, experimental = FALSE, datum/bank_account/account)
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(!experimental)
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if (!experimental)
if(!mob_occupant.ckey || !mob_occupant.client)
scantemp = "<font class='bad'>Mental interface failure.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(SSeconomy.full_ancap && !account)
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
return TRUE
//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks.
/obj/machinery/computer/cloning/prototype
name = "prototype cloning console"
desc = "Used to operate an experimental cloner."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/cloning/prototype
clonepod_type = /obj/machinery/clonepod/experimental
+6
View File
@@ -242,6 +242,7 @@
if((isnull(user) || istype(user)) && state_open && !panel_open)
..(user)
var/mob/living/mob_occupant = occupant
investigate_log("Cryogenics machine closed with occupant [key_name(occupant)] by user [key_name(user)].", INVESTIGATE_CRYOGENICS)
if(mob_occupant && mob_occupant.stat != DEAD)
to_chat(occupant, "<span class='boldnotice'>You feel cool air surround you. You go numb as your senses turn inward.</span>")
if(mob_occupant.client)//if they're logged in
@@ -251,12 +252,15 @@
icon_state = "cryopod"
/obj/machinery/cryopod/open_machine()
if(occupant)
investigate_log("Cryogenics machine opened with occupant [key_name(occupant)] inside.", INVESTIGATE_CRYOGENICS)
..()
icon_state = "cryopod-open"
density = TRUE
name = initial(name)
/obj/machinery/cryopod/container_resist(mob/living/user)
investigate_log("Cryogenics machine container resisted by [key_name(user)] with occupant [key_name(occupant)].", INVESTIGATE_CRYOGENICS)
visible_message("<span class='notice'>[occupant] emerges from [src]!</span>",
"<span class='notice'>You climb out of [src]!</span>")
open_machine()
@@ -304,6 +308,8 @@
var/mob/living/mob_occupant = occupant
var/list/obj/item/cryo_items = list()
investigate_log("Despawning [key_name(mob_occupant)].", INVESTIGATE_CRYOGENICS)
//Handle Borg stuff first
if(iscyborg(mob_occupant))
+9 -9
View File
@@ -70,14 +70,13 @@
if(W.amount < 5)
to_chat(user, "<span class='warning'>You need at least five wooden planks to make a wall!</span>")
return
else
to_chat(user, "<span class='notice'>You start adding [I] to [src]...</span>")
if(do_after(user, 50, target=src))
W.use(5)
var/turf/T = get_turf(src)
T.PlaceOnTop(/turf/closed/wall/mineral/wood/nonmetal)
qdel(src)
return
to_chat(user, "<span class='notice'>You start adding [I] to [src]...</span>")
if(do_after(user, 50, target=src))
W.use(5)
var/turf/T = get_turf(src)
T.PlaceOnTop(/turf/closed/wall/mineral/wood/nonmetal)
qdel(src)
return
return ..()
@@ -170,7 +169,8 @@
to_chat(user, "[src] is now in [mode] mode.")
/obj/item/grenade/barrier/prime()
/obj/item/grenade/barrier/prime(mob/living/lanced_by)
. = ..()
new /obj/structure/barricade/security(get_turf(src.loc))
switch(mode)
if(VERTICAL)
+15 -9
View File
@@ -413,8 +413,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?
@@ -577,11 +577,17 @@
cut_overlays()
add_overlay(frame_overlay)
add_overlay(filling_overlay)
add_overlay(lights_overlay)
if(lights_overlay)
add_overlay(lights_overlay)
var/mutable_appearance/lights_vis = mutable_appearance(lights_overlay.icon, lights_overlay.icon_state)
add_overlay(lights_vis)
add_overlay(panel_overlay)
add_overlay(weld_overlay)
add_overlay(sparks_overlay)
add_overlay(damag_overlay)
if(damag_overlay)
add_overlay(damag_overlay)
var/mutable_appearance/damage_vis = mutable_appearance(damag_overlay.icon, damag_overlay.icon_state)
add_overlay(damage_vis)
add_overlay(note_overlay)
check_unres()
@@ -1052,11 +1058,11 @@
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)
@@ -1,7 +1,7 @@
/obj/item/electronics/airlock
name = "airlock electronics"
req_access = list(ACCESS_MAINT_TUNNELS)
custom_price = 50
custom_price = PRICE_CHEAP
var/list/accesses = list()
var/one_access = 0
+1
View File
@@ -21,6 +21,7 @@
icon = 'icons/obj/status_display.dmi'
icon_state = "frame"
desc = "A remote control for a door."
plane = ABOVE_WALL_PLANE
req_access = list(ACCESS_SECURITY)
density = FALSE
var/id // id of linked machinery/lockers
+3 -2
View File
@@ -12,13 +12,14 @@
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
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
@@ -207,7 +208,7 @@
return max_moles - min_moles > 20
/obj/machinery/door/attackby(obj/item/I, mob/user, params)
if(user.a_intent != INTENT_HARM && (I.tool_behaviour == TOOL_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(I.tool_behaviour == TOOL_WELDER)
+1 -1
View File
@@ -408,7 +408,7 @@
/obj/item/electronics/firelock
name = "firelock circuitry"
custom_price = 50
custom_price = PRICE_CHEAP
desc = "A circuit board used in construction of firelocks."
icon_state = "mainboard"
+3 -1
View File
@@ -53,7 +53,9 @@
if("opening")
rad_insulation = 1
if("closing")
rad_insulation = 0.2
rad_insulation = -0.5
// A 3x3 N2 SM setup won't irradiate you if you're behind the shutter at -0.9 insulation. If it starts to delam, it'll start irradiating you slowly. Keep the value between -0.1 to -0.9
/obj/machinery/door/poddoor/shutters/window
name = "windowed shutters"
+20 -6
View File
@@ -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)
@@ -34,7 +34,7 @@
/obj/machinery/embedded_controller/radio/simple_vent_controller
icon = 'icons/obj/airlock_machines.dmi'
icon_state = "airlock_control_standby"
plane = ABOVE_WALL_PLANE
name = "vent controller"
density = FALSE
-298
View File
@@ -1,298 +0,0 @@
//Experimental cloner; clones a body regardless of the owner's status, letting a ghost control it instead
/obj/machinery/clonepod/experimental
name = "experimental cloning pod"
desc = "An ancient cloning pod. It seems to be an early prototype of the experimental cloners used in Nanotrasen Stations."
icon = 'icons/obj/machines/cloning.dmi'
icon_state = "pod_0"
req_access = null
circuit = /obj/item/circuitboard/machine/clonepod/experimental
internal_radio = FALSE
//Start growing a human clone in the pod!
/obj/machinery/clonepod/experimental/growclone(clonename, ui, mutation_index, mindref, last_death, blood_type, datum/species/mrace, list/features, factions, list/quirks)
if(panel_open)
return FALSE
if(mess || attempting)
return FALSE
attempting = TRUE //One at a time!!
countdown.start()
var/mob/living/carbon/human/H = new /mob/living/carbon/human(src)
H.hardset_dna(ui, mutation_index, H.real_name, blood_type, mrace, features)
if(efficiency > 2)
var/list/unclean_mutations = (GLOB.not_good_mutations|GLOB.bad_mutations)
H.dna.remove_mutation_group(unclean_mutations)
if(efficiency > 5 && prob(20))
H.easy_randmut(POSITIVE)
if(efficiency < 3 && prob(50))
var/mob/M = H.easy_randmut(NEGATIVE+MINOR_NEGATIVE)
if(ismob(M))
H = M
H.silent = 20 //Prevents an extreme edge case where clones could speak if they said something at exactly the right moment.
occupant = H
if(!clonename) //to prevent null names
clonename = "clone ([rand(1,999)])"
H.real_name = clonename
icon_state = "pod_1"
//Get the clone body ready
maim_clone(H)
ADD_TRAIT(H, TRAIT_STABLEHEART, "cloning")
ADD_TRAIT(H, TRAIT_EMOTEMUTE, "cloning")
ADD_TRAIT(H, TRAIT_MUTE, "cloning")
ADD_TRAIT(H, TRAIT_NOBREATH, "cloning")
ADD_TRAIT(H, TRAIT_NOCRITDAMAGE, "cloning")
H.Unconscious(80)
var/list/candidates = pollCandidatesForMob("Do you want to play as [clonename]'s defective clone?", null, null, null, 100, H)
if(LAZYLEN(candidates))
var/mob/C = pick(candidates)
H.key = C.key
if(grab_ghost_when == CLONER_FRESH_CLONE)
H.grab_ghost()
to_chat(H, "<span class='notice'><b>Consciousness slowly creeps over you as your body regenerates.</b><br><i>So this is what cloning feels like?</i></span>")
if(grab_ghost_when == CLONER_MATURE_CLONE)
H.ghostize(TRUE) //Only does anything if they were still in their old body and not already a ghost
to_chat(H.get_ghost(TRUE), "<span class='notice'>Your body is beginning to regenerate in a cloning pod. You will become conscious when it is complete.</span>")
if(H)
H.faction |= factions
H.set_cloned_appearance()
H.suiciding = FALSE
attempting = FALSE
return TRUE
//Prototype cloning console, much more rudimental and lacks modern functions such as saving records, autocloning, or safety checks.
/obj/machinery/computer/prototype_cloning
name = "prototype cloning console"
desc = "Used to operate an experimental cloner."
icon_screen = "dna"
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/prototype_cloning
var/obj/machinery/dna_scannernew/scanner = null //Linked scanner. For scanning.
var/list/pods //Linked experimental cloning pods
var/temp = "Inactive"
var/scantemp = "Ready to Scan"
var/loading = FALSE // Nice loading text
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/prototype_cloning/Initialize()
. = ..()
updatemodules(TRUE)
/obj/machinery/computer/prototype_cloning/Destroy()
if(pods)
for(var/P in pods)
DetachCloner(P)
pods = null
return ..()
/obj/machinery/computer/prototype_cloning/proc/GetAvailablePod(mind = null)
if(pods)
for(var/P in pods)
var/obj/machinery/clonepod/experimental/pod = P
if(pod.is_operational() && !(pod.occupant || pod.mess))
return pod
/obj/machinery/computer/prototype_cloning/proc/updatemodules(findfirstcloner)
scanner = findscanner()
if(findfirstcloner && !LAZYLEN(pods))
findcloner()
/obj/machinery/computer/prototype_cloning/proc/findscanner()
var/obj/machinery/dna_scannernew/scannerf = null
// Loop through every direction
for(var/direction in GLOB.cardinals)
// Try to find a scanner in that direction
scannerf = locate(/obj/machinery/dna_scannernew, get_step(src, direction))
// If found and operational, return the scanner
if (!isnull(scannerf) && scannerf.is_operational())
return scannerf
// If no scanner was found, it will return null
return null
/obj/machinery/computer/prototype_cloning/proc/findcloner()
var/obj/machinery/clonepod/experimental/podf = null
for(var/direction in GLOB.cardinals)
podf = locate(/obj/machinery/clonepod/experimental, get_step(src, direction))
if (!isnull(podf) && podf.is_operational())
AttachCloner(podf)
/obj/machinery/computer/prototype_cloning/proc/AttachCloner(obj/machinery/clonepod/experimental/pod)
if(!pod.connected)
pod.connected = src
LAZYADD(pods, pod)
/obj/machinery/computer/prototype_cloning/proc/DetachCloner(obj/machinery/clonepod/experimental/pod)
pod.connected = null
LAZYREMOVE(pods, pod)
/obj/machinery/computer/prototype_cloning/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/multitool))
var/obj/item/multitool/P = W
if(istype(P.buffer, /obj/machinery/clonepod/experimental))
if(get_area(P.buffer) != get_area(src))
to_chat(user, "<font color = #666633>-% Cannot link machines across power zones. Buffer cleared %-</font color>")
P.buffer = null
return
to_chat(user, "<font color = #666633>-% Successfully linked [P.buffer] with [src] %-</font color>")
var/obj/machinery/clonepod/experimental/pod = P.buffer
if(pod.connected)
pod.connected.DetachCloner(pod)
AttachCloner(pod)
else
P.buffer = src
to_chat(user, "<font color = #666633>-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-</font color>")
return
else
return ..()
/obj/machinery/computer/prototype_cloning/attack_hand(mob/user)
if(..())
return
interact(user)
/obj/machinery/computer/prototype_cloning/interact(mob/user)
user.set_machine(src)
add_fingerprint(user)
if(..())
return
updatemodules(TRUE)
var/dat = ""
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
if (isnull(src.scanner) || !LAZYLEN(pods))
dat += "<h3>Modules</h3>"
//dat += "<a href='byond://?src=[REF(src)];relmodules=1'>Reload Modules</a>"
if (isnull(src.scanner))
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
if (!LAZYLEN(pods))
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
// Scan-n-Clone
if (!isnull(src.scanner))
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
dat += "<h3>Cloning</h3>"
dat += "<div class='statusDisplay'>"
if(!scanner_occupant)
dat += "Scanner Unoccupied"
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
scantemp = "Ready to Clone"
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=[REF(src)];clone=1'>Clone</a>"
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[src.scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>Clone</span>"
var/datum/browser/popup = new(user, "cloning", "Prototype Cloning System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/prototype_cloning/Topic(href, href_list)
if(..())
return
if(loading)
return
else if ((href_list["clone"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = TRUE
updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
spawn(20)
clone_occupant(scanner.occupant)
loading = FALSE
updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
if ((!scanner.locked) && (scanner.occupant))
scanner.locked = TRUE
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
scanner.locked = FALSE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else if (href_list["refresh"])
updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
add_fingerprint(usr)
updateUsrDialog()
return
/obj/machinery/computer/prototype_cloning/proc/clone_occupant(occupant)
var/mob/living/mob_occupant = get_mob_or_brainmob(occupant)
var/datum/dna/dna
if(ishuman(mob_occupant))
var/mob/living/carbon/C = mob_occupant
dna = C.has_dna()
if(isbrain(mob_occupant))
var/mob/living/brain/B = mob_occupant
dna = B.stored_dna
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
var/clone_species
if(dna.species)
clone_species = dna.species
else
var/datum/species/rando_race = pick(GLOB.roundstart_races)
clone_species = rando_race.type
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
pod.growclone(mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
+2 -1
View File
@@ -2,7 +2,7 @@
/obj/item/electronics/firealarm
name = "fire alarm electronics"
custom_price = 50
custom_price = PRICE_CHEAP
desc = "A fire alarm circuit. Can handle heat levels up to 40 degrees celsius."
/obj/item/wallframe/firealarm
@@ -17,6 +17,7 @@
desc = "<i>\"Pull this in case of emergency\"</i>. Thus, keep pulling it forever."
icon = 'icons/obj/monitors.dmi'
icon_state = "fire0"
plane = ABOVE_WALL_PLANE
max_integrity = 250
integrity_failure = 0.4
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
+2
View File
@@ -5,6 +5,7 @@
desc = "A wall-mounted flashbulb device."
icon = 'icons/obj/stationobjs.dmi'
icon_state = "mflash1"
plane = ABOVE_WALL_PLANE
max_integrity = 250
integrity_failure = 0.4
light_color = LIGHT_COLOR_WHITE
@@ -20,6 +21,7 @@
name = "portable flasher"
desc = "A portable flashing device. Wrench to activate and deactivate. Cannot detect slow movements."
icon_state = "pflash1-p"
plane = GAME_PLANE
strength = 80
anchored = FALSE
base_state = "pflash"
+5
View File
@@ -20,6 +20,11 @@
. = ..()
if(prob(1))
name = "auto-autopsy"
new_occupant_dir = dir
/obj/machinery/harvester/setDir(newdir)
. = ..()
new_occupant_dir = dir
/obj/machinery/harvester/RefreshParts()
interval = 0
+1 -1
View File
@@ -34,7 +34,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
desc = "It's a floor-mounted device for projecting holographic images."
icon_state = "holopad0"
layer = LOW_OBJ_LAYER
plane = FLOOR_PLANE
plane = ABOVE_WALL_PLANE
flags_1 = HEAR_1
use_power = IDLE_POWER_USE
idle_power_usage = 5
+205
View File
@@ -0,0 +1,205 @@
/obj/machinery/hypnochair
name = "enhanced interrogation chamber"
desc = "A device used to perform \"enhanced interrogation\" through invasive mental conditioning."
icon = 'icons/obj/machines/implantchair.dmi'
icon_state = "hypnochair"
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()
. = ..()
open_machine()
update_icon()
/obj/machinery/hypnochair/attackby(obj/item/I, mob/user, params)
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)
if(!ui)
ui = new(user, src, ui_key, "hypnochair", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/hypnochair/ui_data()
var/list/data = list()
data["occupied"] = occupant ? TRUE : FALSE
data["open"] = state_open
data["interrogating"] = interrogating
data["occupant"] = list()
if(occupant)
var/mob/living/mob_occupant = occupant
data["occupant"]["name"] = mob_occupant.name
data["occupant"]["stat"] = mob_occupant.stat
data["trigger"] = trigger_phrase
return data
/obj/machinery/hypnochair/ui_act(action, params)
if(..())
return
switch(action)
if("door")
if(state_open)
close_machine()
else
if(!interrogating)
open_machine()
. = TRUE
if("set_phrase")
set_phrase(params["phrase"])
. = TRUE
if("interrogate")
if(!interrogating)
interrogate()
else
interrupt_interrogation()
. = TRUE
/obj/machinery/hypnochair/proc/set_phrase(phrase)
trigger_phrase = phrase
/obj/machinery/hypnochair/proc/interrogate()
if(!trigger_phrase)
playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 25, TRUE)
return
var/mob/living/carbon/C = occupant
if(!istype(C))
playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 25, TRUE)
return
victim = C
if(!(C.get_eye_protection() > 0))
to_chat(C, "<span class='warning'>Strobing coloured lights assault you relentlessly! You're losing your ability to think straight!</span>")
C.become_blind("hypnochair")
ADD_TRAIT(C, TRAIT_DEAF, "hypnochair")
interrogating = TRUE
START_PROCESSING(SSobj, src)
start_time = world.time
update_icon()
timerid = addtimer(CALLBACK(src, .proc/finish_interrogation), 450, TIMER_STOPPABLE)
/obj/machinery/hypnochair/process()
var/mob/living/carbon/C = occupant
if(!istype(C) || C != victim)
interrupt_interrogation()
return
if(prob(10) && !(C.get_eye_protection() > 0))
to_chat(C, "<span class='hypnophrase'>[pick(\
"...blue... red... green... blue, red, green, blueredgreen<span class='small'>blueredgreen</span>",\
"...pretty colors...",\
"...you keep hearing words, but you can't seem to understand them...",\
"...so peaceful...",\
"...an annoying buzz in your ears..."\
)]</span>")
/obj/machinery/hypnochair/proc/finish_interrogation()
interrogating = FALSE
STOP_PROCESSING(SSobj, src)
update_icon()
var/temp_trigger = trigger_phrase
trigger_phrase = "" //Erase evidence, in case the subject is able to look at the panel afterwards
audible_message("<span class='notice'>[src] pings!</span>")
playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
if(QDELETED(victim) || victim != occupant)
victim = null
return
victim.cure_blind("hypnochair")
REMOVE_TRAIT(victim, TRAIT_DEAF, "hypnochair")
if(!(victim.get_eye_protection() > 0))
victim.cure_trauma_type(/datum/brain_trauma/severe/hypnotic_trigger, TRAUMA_RESILIENCE_SURGERY)
if(prob(90))
victim.gain_trauma(new /datum/brain_trauma/severe/hypnotic_trigger(temp_trigger), TRAUMA_RESILIENCE_SURGERY)
else
victim.gain_trauma(new /datum/brain_trauma/severe/hypnotic_stupor(), TRAUMA_RESILIENCE_SURGERY)
victim = null
/obj/machinery/hypnochair/proc/interrupt_interrogation()
deltimer(timerid)
interrogating = FALSE
STOP_PROCESSING(SSobj, src)
update_icon()
if(QDELETED(victim))
victim = null
return
victim.cure_blind("hypnochair")
REMOVE_TRAIT(victim, TRAIT_DEAF, "hypnochair")
if(!(victim.get_eye_protection() > 0))
var/time_diff = world.time - start_time
switch(time_diff)
if(0 to 100)
victim.confused += 10
victim.Dizzy(100)
victim.blur_eyes(5)
if(101 to 200)
victim.confused += 15
victim.Dizzy(200)
victim.blur_eyes(10)
if(prob(25))
victim.apply_status_effect(/datum/status_effect/trance, rand(50,150), FALSE)
if(201 to INFINITY)
victim.confused += 20
victim.Dizzy(300)
victim.blur_eyes(15)
if(prob(65))
victim.apply_status_effect(/datum/status_effect/trance, rand(50,150), FALSE)
victim = null
/obj/machinery/hypnochair/update_icon_state()
icon_state = initial(icon_state)
if(state_open)
icon_state += "_open"
if(occupant)
if(interrogating)
icon_state += "_active"
else
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>")
if(do_after(user,(600), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open)
return
user.visible_message("<span class='warning'>[user] successfully broke out of [src]!</span>", \
"<span class='notice'>You successfully break out of [src]!</span>")
open_machine()
/obj/machinery/hypnochair/relaymove(mob/user)
if(message_cooldown <= world.time)
message_cooldown = world.time + 50
to_chat(user, "<span class='warning'>[src]'s door won't budge!</span>")
/obj/machinery/hypnochair/MouseDrop_T(mob/target, mob/user)
if(user.stat || !Adjacent(user) || !user.Adjacent(target) || !isliving(target) || !user.IsAdvancedToolUser())
return
if(isliving(user))
var/mob/living/L = user
if(!(L.mobility_flags & MOBILITY_STAND))
return
close_machine(target)
+2 -1
View File
@@ -13,7 +13,8 @@
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)
. = ..()
+1
View File
@@ -5,6 +5,7 @@
name = "light switch"
icon = 'icons/obj/power.dmi'
icon_state = "light1"
plane = ABOVE_WALL_PLANE
desc = "Make dark."
var/on = TRUE
var/area/area = null
@@ -679,7 +679,7 @@
/obj/machinery/porta_turret/syndicate/ComponentInitialize()
. = ..()
AddComponent(/datum/component/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES)
AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES)
/obj/machinery/porta_turret/syndicate/energy
icon_state = "standard_stun"
@@ -788,7 +788,7 @@
/obj/machinery/porta_turret/centcom_shuttle/ComponentInitialize()
. = ..()
AddComponent(/datum/component/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES)
AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES)
/obj/machinery/porta_turret/centcom_shuttle/assess_perp(mob/living/carbon/human/perp)
return 0
@@ -70,8 +70,8 @@
else
return ..()
/obj/machinery/porta_turret_cover/attacked_by(obj/item/I, mob/user)
parent_turret.attacked_by(I, user)
/obj/machinery/porta_turret_cover/attacked_by(obj/item/I, mob/user, attackchain_flags = NONE, damage_multiplier = 1)
return parent_turret.attacked_by(I, user)
/obj/machinery/porta_turret_cover/attack_alien(mob/living/carbon/alien/humanoid/user)
parent_turret.attack_alien(user)
+26 -1
View File
@@ -17,7 +17,9 @@
/obj/item/melee/baton,
/obj/item/ammo_box/magazine/recharge,
/obj/item/modular_computer,
/obj/item/twohanded/electrostaff,
/obj/item/ammo_casing/mws_batt,
/obj/item/ammo_box/magazine/mws_mag,
/obj/item/electrostaff,
/obj/item/gun/ballistic/automatic/magrifle))
/obj/machinery/recharger/RefreshParts()
@@ -143,6 +145,29 @@
using_power = TRUE
update_icon()
return
if(istype(charging, /obj/item/ammo_casing/mws_batt))
var/obj/item/ammo_casing/mws_batt/R = charging
if(R.cell.charge < R.cell.maxcharge)
R.cell.give(R.cell.chargerate * recharge_coeff)
use_power(250 * recharge_coeff)
using_power = 1
if(R.BB == null)
R.chargeshot()
update_icon(using_power)
if(istype(charging, /obj/item/ammo_box/magazine/mws_mag))
var/obj/item/ammo_box/magazine/mws_mag/R = charging
for(var/B in R.stored_ammo)
var/obj/item/ammo_casing/mws_batt/batt = B
if(batt.cell.charge < batt.cell.maxcharge)
batt.cell.give(batt.cell.chargerate * recharge_coeff)
use_power(250 * recharge_coeff)
using_power = 1
if(batt.BB == null)
batt.chargeshot()
update_icon(using_power)
else
return PROCESS_KILL
+30 -12
View File
@@ -100,44 +100,61 @@
eat(AM)
. = ..()
/obj/machinery/recycler/proc/eat(atom/AM0, sound=TRUE)
/obj/machinery/recycler/proc/eat(atom/AM0)
if(stat & (BROKEN|NOPOWER) || safety_mode)
return
var/list/to_eat
to_eat = AM0.GetAllContentsIgnoring(GLOB.typecache_mob)
to_eat = list(AM0)
var/items_recycled = 0
var/buzz = FALSE
for(var/i in to_eat)
var/atom/movable/AM = i
if(QDELETED(AM))
continue
var/obj/item/bodypart/head/as_head = AM
var/obj/item/mmi/as_mmi = AM
var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || isbrain(AM) || istype(AM, /obj/item/dullahan_relay)
var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /obj/item/dullahan_relay)
if(brain_holder)
emergency_stop(AM)
else if(isliving(AM))
if((obj_flags & EMAGGED)||((!allowed(AM))&&(!ishuman(AM))))
crush_living(AM)
if(obj_flags & EMAGGED)
continue
else
emergency_stop(AM)
return
else if(isliving(AM))
if((obj_flags & EMAGGED)||((!allowed(AM))&&(!ishuman(AM))))
to_eat += crush_living(AM)
else
emergency_stop(AM)
return
else if(isitem(AM))
var/obj/O = AM
if(O.resistance_flags & INDESTRUCTIBLE)
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
buzz = TRUE
O.forceMove(loc)
else
recycle_item(AM)
to_eat += recycle_item(AM)
items_recycled++
else
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
buzz = TRUE
AM.forceMove(loc)
if(items_recycled && sound)
if(items_recycled)
playsound(src, item_recycle_sound, 50, 1)
if(buzz)
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
/obj/machinery/recycler/proc/recycle_item(obj/item/I)
. = list()
for(var/A in I)
var/atom/movable/AM = A
AM.forceMove(loc)
if(AM.loc == loc)
. += AM
I.forceMove(loc)
var/obj/item/grown/log/L = I
if(istype(L))
@@ -172,6 +189,7 @@
/obj/machinery/recycler/proc/crush_living(mob/living/L)
. = list()
L.forceMove(loc)
if(issilicon(L))
@@ -193,7 +211,7 @@
if(eat_victim_items)
for(var/obj/item/I in L.get_equipped_items(TRUE))
if(L.dropItemToGround(I))
eat(I, sound=FALSE)
. += I
// Instantly lie down, also go unconscious from the pain, before you die.
L.Unconscious(100)
+250 -227
View File
@@ -9,13 +9,14 @@ GLOBAL_LIST_EMPTY(allConsoles)
#define NO_NEW_MESSAGE 0
#define NORMAL_MESSAGE_PRIORITY 1
#define HIGH_MESSAGE_PRIORITY 2
#define EXTREME_MESSAGE_PRIORITY 3 // not implemented, will probably require some hacking... everything needs to have a hidden feature in this game.
#define EXTREME_MESSAGE_PRIORITY 3 // is implimented, does require hacking. everything needs to have a hidden feature in this game.
/obj/machinery/requests_console
name = "requests console"
desc = "A console intended to send requests to different departments on the station."
icon = 'icons/obj/terminals.dmi'
icon_state = "req_comp0"
plane = ABOVE_WALL_PLANE
var/department = "Unknown" //The list of all departments on the station (Determined from this variable on each unit) Set this to the same thing if you want several consoles in one department
var/list/messages = list() //List of all messages
var/departmentType = 0
@@ -47,9 +48,9 @@ GLOBAL_LIST_EMPTY(allConsoles)
var/announceAuth = FALSE //Will be set to 1 when you authenticate yourself for announcements
var/msgVerified = "" //Will contain the name of the person who verified it
var/msgStamped = "" //If a message is stamped, this will contain the stamp name
var/message = "";
var/dpt = ""; //the department which will be receiving the message
var/priority = -1 ; //Priority of the message being sent
var/message = ""
var/dpt = "" //the department which will be receiving the message
var/priority = NORMAL_MESSAGE_PRIORITY //Priority of the message being sent. why is the default -1??
var/obj/item/radio/Radio
var/emergency //If an emergency has been called by this device. Acts as both a cooldown and lets the responder know where it the emergency was triggered from
var/receive_ore_updates = FALSE //If ore redemption machines will send an update when it receives new ores.
@@ -61,16 +62,17 @@ GLOBAL_LIST_EMPTY(allConsoles)
update_icon()
/obj/machinery/requests_console/update_icon_state()
if(stat & NOPOWER)
if(CHECK_BITFIELD(stat, NOPOWER))
set_light(0)
else
set_light(1.4,0.7,"#34D352")//green light
set_light(1.4, 0.7, "#34D352")//green light
if(open)
if(!hackState)
icon_state="req_comp_open"
else
icon_state="req_comp_rewired"
else if(stat & NOPOWER)
else if(CHECK_BITFIELD(stat, NOPOWER))
if(icon_state != "req_comp_off")
icon_state = "req_comp_off"
else
@@ -121,7 +123,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
GLOB.req_console_information += department
Radio = new /obj/item/radio(src)
Radio.listening = 0
Radio.listening = FALSE
/obj/machinery/requests_console/Destroy()
QDEL_NULL(Radio)
@@ -130,164 +132,173 @@ GLOBAL_LIST_EMPTY(allConsoles)
/obj/machinery/requests_console/ui_interact(mob/user)
. = ..()
if(open) //no.
return
var/dat = ""
if(!open)
switch(screen)
if(1) //req. assistance
dat += "Which department do you need assistance from?<BR><BR>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_assistance)
if (dpt != department)
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'><A href='?src=[REF(src)];write=[ckey(dpt)]'>Normal</A> <A href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</A>"
if(hackState)
dat += "<A href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</A>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
switch(screen)
if(1) //req. assistance
dat += "Which department do you need assistance from?<br><br>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_assistance)
if(dpt == department)
continue
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=1'>Normal</a>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</a>"
if(hackState)
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</a>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<br><A href='?src=[REF(src)];setScreen=0'><< Back</A><br>"
if(2) //req. supplies
dat += "Which department do you need supplies from?<BR><BR>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_supplies)
if (dpt != department)
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'><A href='?src=[REF(src)];write=[ckey(dpt)]'>Normal</A> <A href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</A>"
if(hackState)
dat += "<A href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</A>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
if(2) //req. supplies
dat += "Which department do you need supplies from?<br><br>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_supplies)
if(dpt == department)
continue
if(3) //relay information
dat += "Which department would you like to send information to?<BR><BR>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_information)
if (dpt != department)
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'><A href='?src=[REF(src)];write=[ckey(dpt)]'>Normal</A> <A href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</A>"
if(hackState)
dat += "<A href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</A>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=1'>Normal</a>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</a>"
if(hackState)
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</a>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<br><A href='?src=[REF(src)];setScreen=0'><< Back</A><br>"
if(6) //sent successfully
dat += "<span class='good'>Message sent.</span><BR><BR>"
dat += "<A href='?src=[REF(src)];setScreen=0'>Continue</A><BR>"
if(3) //relay information
dat += "Which department would you like to send information to?<br><br>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_information)
if(dpt == department)
continue
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=1'>Normal</a>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</a>"
if(hackState)
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</a>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<br><a href='?src=[REF(src)];setScreen=0'><< Back</a><br>"
if(7) //unsuccessful; not sent
dat += "<span class='bad'>An error occurred.</span><BR><BR>"
dat += "<A href='?src=[REF(src)];setScreen=0'>Continue</A><BR>"
if(6) //sent successfully
dat += "<span class='good'>Message sent.</span><br><br>"
dat += "<a href='?src=[REF(src)];setScreen=0'>Continue</a><br>"
if(8) //view messages
for (var/obj/machinery/requests_console/Console in GLOB.allConsoles)
if (Console.department == department)
Console.newmessagepriority = NO_NEW_MESSAGE
Console.update_icon()
if(7) //unsuccessful; not sent
dat += "<span class='bad'>An error occurred.</span><br><br>"
dat += "<a href='?src=[REF(src)];setScreen=0'>Continue</a><br>"
newmessagepriority = NO_NEW_MESSAGE
update_icon()
var/messageComposite = ""
for(var/msg in messages) // This puts more recent messages at the *top*, where they belong.
messageComposite = "<div class='block'>[msg]</div>" + messageComposite
dat += messageComposite
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back to Main Menu</A><BR>"
if(8) //view messages
for(var/obj/machinery/requests_console/Console in GLOB.allConsoles)
if(Console.department == department)
Console.newmessagepriority = NO_NEW_MESSAGE
Console.update_icon()
if(9) //authentication before sending
dat += "<B>Message Authentication</B><BR><BR>"
dat += "<b>Message for [dpt]: </b>[message]<BR><BR>"
dat += "<div class='notice'>You may authenticate your message now by scanning your ID or your stamp</div><BR>"
dat += "<b>Validated by:</b> [msgVerified ? msgVerified : "<i>Not Validated</i>"]<br>"
dat += "<b>Stamped by:</b> [msgStamped ? msgStamped : "<i>Not Stamped</i>"]<br><br>"
dat += "<A href='?src=[REF(src)];department=[dpt]'>Send Message</A><BR>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Discard Message</A><BR>"
newmessagepriority = NO_NEW_MESSAGE
update_icon()
var/messageComposite = ""
for(var/msg in messages) // This puts more recent messages at the *top*, where they belong.
messageComposite = "<div class='block'>[msg]</div>" + messageComposite
dat += messageComposite
dat += "<br><a href='?src=[REF(src)];setScreen=0'><< Back to Main Menu</a><br>"
if(10) //send announcement
dat += "<h3>Station-wide Announcement</h3>"
if(announceAuth)
dat += "<div class='notice'>Authentication accepted</div><BR>"
else
dat += "<div class='notice'>Swipe your card to authenticate yourself</div><BR>"
dat += "<b>Message: </b>[message ? message : "<i>No Message</i>"]<BR>"
dat += "<A href='?src=[REF(src)];writeAnnouncement=1'>[message ? "Edit" : "Write"] Message</A><BR><BR>"
if ((announceAuth || IsAdminGhost(user)) && message)
dat += "<A href='?src=[REF(src)];sendAnnouncement=1'>Announce Message</A><BR>"
else
dat += "<span class='linkOff'>Announce Message</span><BR>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
if(9) //authentication before sending
dat += "<b>Message Authentication</b> <br><br>"
dat += "<b>Message for [dpt]:</b> [message] <br><br>"
dat += "<div class='notice'>You may authenticate your message now by scanning your ID or your stamp</div> <br>"
dat += "<b>Validated by:</b> [msgVerified ? "<span class='good'><b>[msgVerified]</b></span>" : "<i>Not Validated</i>"] <br>"
dat += "<b>Stamped by:</b> [msgStamped ? "<span class='boldnotice'>[msgStamped]</span>" : "<i>Not Stamped</i>"] <br><br>"
dat += "<a href='?src=[REF(src)];department=[dpt]'>Send Message</a> <br><br>"
dat += "<a href='?src=[REF(src)];setScreen=0'><< Discard Message</a> <br>"
else //main menu
screen = 0
announceAuth = FALSE
if (newmessagepriority == NORMAL_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new messages</div><BR>"
if (newmessagepriority == HIGH_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new <b>PRIORITY</b> messages</div><BR>"
if (newmessagepriority == EXTREME_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new <b>EXTREME PRIORITY</b> messages</div><BR>"
dat += "<A href='?src=[REF(src)];setScreen=8'>View Messages</A><BR><BR>"
if(10) //send announcement
dat += "<h3>Station-wide Announcement</h3>"
if(announceAuth)
dat += "<div class='notice'>Authentication accepted</div><br>"
else
dat += "<div class='notice'>Swipe your card to authenticate yourself</div> <br>"
dat += "<b>Message: </b>[message ? message : "<i>No Message</i>"] <br>"
dat += "<a href='?src=[REF(src)];writeAnnouncement=1'>[message ? "Edit" : "Write"] Message</a> <br><br>"
if((announceAuth || IsAdminGhost(user)) && message)
dat += "<a href='?src=[REF(src)];sendAnnouncement=1'>Announce Message</a> <br>"
else
dat += "<span class='linkOff'>Announce Message</span> <br>"
dat += "<br><a href='?src=[REF(src)];setScreen=0'><< Back</a> <br>"
dat += "<A href='?src=[REF(src)];setScreen=1'>Request Assistance</A><BR>"
dat += "<A href='?src=[REF(src)];setScreen=2'>Request Supplies</A><BR>"
dat += "<A href='?src=[REF(src)];setScreen=3'>Relay Anonymous Information</A><BR><BR>"
else //main menu
screen = 0
announceAuth = FALSE
if(newmessagepriority == NORMAL_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new messages</div><br>"
if(newmessagepriority == HIGH_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new <b>PRIORITY</b> messages</div><br>"
if(newmessagepriority == EXTREME_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new <b>EXTREME PRIORITY</b> messages</div><br>"
if(!emergency)
dat += "<A href='?src=[REF(src)];emergency=1'>Emergency: Security</A><BR>"
dat += "<A href='?src=[REF(src)];emergency=2'>Emergency: Engineering</A><BR>"
dat += "<A href='?src=[REF(src)];emergency=3'>Emergency: Medical</A><BR><BR>"
else
dat += "<B><font color='red'>[emergency] has been dispatched to this location.</font></B><BR><BR>"
dat += "<a href='?src=[REF(src)];setScreen=8'>View Messages</a> <br><br>"
if(announcementConsole)
dat += "<A href='?src=[REF(src)];setScreen=10'>Send Station-wide Announcement</A><BR><BR>"
if (silent)
dat += "Speaker <A href='?src=[REF(src)];setSilent=0'>OFF</A>"
else
dat += "Speaker <A href='?src=[REF(src)];setSilent=1'>ON</A>"
var/datum/browser/popup = new(user, "req_console", "[department] Requests Console", 450, 440)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
dat += "<a href='?src=[REF(src)];setScreen=1'>Request Assistance</a> <br>"
dat += "<a href='?src=[REF(src)];setScreen=2'>Request Supplies</a> <br>"
dat += "<a href='?src=[REF(src)];setScreen=3'>Relay Anonymous Information</a> <br><br>"
if(!emergency)
dat += "<a href='?src=[REF(src)];emergency=1'>Emergency: Security</a> <br>"
dat += "<a href='?src=[REF(src)];emergency=2'>Emergency: Engineering</a> <br>"
dat += "<a href='?src=[REF(src)];emergency=3'>Emergency: Medical</a> <br><br>"
else
dat += "<b><div class='bad'>[emergency] has been dispatched to this location.</div></b> <br><br>"
if(announcementConsole)
dat += "<a href='?src=[REF(src)];setScreen=10'>Send Station-wide Announcement</a> <br><br>"
if(silent)
dat += "Speaker <a href='?src=[REF(src)];setSilent=0'>OFF</a>"
else
dat += "Speaker <a href='?src=[REF(src)];setSilent=1'>ON</a>"
var/datum/browser/popup = new(user, "req_console", "[department] Requests Console", 450, 440)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/requests_console/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
add_fingerprint(usr)
if(href_list["write"])
dpt = ckey(reject_bad_text(href_list["write"])) //write contains the string of the receiving department's name
var/new_message = stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN)
if(new_message)
message = new_message
screen = 9
if (text2num(href_list["priority"]) < 2)
priority = -1
else
priority = text2num(href_list["priority"])
priority = text2num(href_list["priority"])
else
dpt = "";
msgVerified = ""
msgStamped = ""
screen = 0
priority = -1
priority = NORMAL_MESSAGE_PRIORITY //:salt:
if(href_list["writeAnnouncement"])
var/new_message = reject_bad_text(stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN))
if(new_message)
message = new_message
if (text2num(href_list["priority"]) < 2)
priority = -1
else
priority = text2num(href_list["priority"])
priority = text2num(href_list["priority"])
else
message = ""
announceAuth = FALSE
@@ -295,106 +306,116 @@ GLOBAL_LIST_EMPTY(allConsoles)
if(href_list["sendAnnouncement"])
if(!announcementConsole)
updateUsrDialog()
return
if(isliving(usr))
var/mob/living/L = usr
message = L.treat_message(message)
minor_announce(message, "[department] Announcement:")
GLOB.news_network.SubmitArticle(message, department, "Station Announcements", null)
usr.log_talk(message, LOG_SAY, tag="station announcement from [src]")
usr.log_talk(message, LOG_SAY, tag = "station announcement from [src]")
message_admins("[ADMIN_LOOKUPFLW(usr)] has made a station announcement from [src] at [AREACOORD(usr)].")
announceAuth = FALSE
message = ""
screen = 0
if(href_list["emergency"])
if(!emergency)
var/radio_freq
switch(text2num(href_list["emergency"]))
if(1) //Security
radio_freq = FREQ_SECURITY
emergency = "Security"
if(2) //Engineering
radio_freq = FREQ_ENGINEERING
emergency = "Engineering"
if(3) //Medical
radio_freq = FREQ_MEDICAL
emergency = "Medical"
if(radio_freq)
Radio.set_frequency(radio_freq)
Radio.talk_into(src,"[emergency] emergency in [department]!!",radio_freq)
update_icon()
addtimer(CALLBACK(src, .proc/clear_emergency), 3000)
if(emergency) //already has an emergency? do not continue
updateUsrDialog()
return
if( href_list["department"] && message )
var/log_msg = message
var/radio_freq
switch(text2num(href_list["emergency"]))
if(1) //Security
radio_freq = FREQ_SECURITY
emergency = "Security"
if(2) //Engineering
radio_freq = FREQ_ENGINEERING
emergency = "Engineering"
if(3) //Medical
radio_freq = FREQ_MEDICAL
emergency = "Medical"
if(radio_freq)
Radio.set_frequency(radio_freq)
Radio.talk_into(src, "[emergency] emergency in [department]!!", radio_freq)
update_icon()
addtimer(CALLBACK(src, .proc/clear_emergency), 5 MINUTES)
if(href_list["department"] && message)
var/sending = message
sending += "<br>"
if (msgVerified)
sending += msgVerified
sending += "<br>"
if (msgStamped)
sending += msgStamped
sending += "<br>"
screen = 7 //if it's successful, this will get overrwritten (7 = unsufccessfull, 6 = successfull)
if (sending)
var/pass = FALSE
var/datum/data_rc_msg/log = new(href_list["department"], department, log_msg, msgStamped, msgVerified, priority)
for (var/obj/machinery/telecomms/message_server/MS in GLOB.telecomms_list)
if (MS.toggled)
MS.rc_msgs += log
pass = TRUE
if(msgVerified)
sending += "<span class='good'><b>[msgVerified]</b></span> <br>"
if(msgStamped)
sending += "<span class='boldnotice'>[msgStamped]</span> <br>"
//so you're telling me is you cheated, by making fail happen, then quickly replacing it with 6
if(pass)
var/radio_freq = 0
switch(href_list["department"])
if("bridge")
radio_freq = FREQ_COMMAND
if("medbay")
radio_freq = FREQ_MEDICAL
if("science")
radio_freq = FREQ_SCIENCE
if("engineering")
radio_freq = FREQ_ENGINEERING
if("security")
radio_freq = FREQ_SECURITY
if("cargobay" || "mining")
radio_freq = FREQ_SUPPLY
Radio.set_frequency(radio_freq)
var/authentic
if(msgVerified || msgStamped)
authentic = " (Authenticated)"
var/workingServer = FALSE
var/datum/data_rc_msg/log = new(href_list["department"], department, message, msgStamped, msgVerified, priority)
for(var/obj/machinery/telecomms/message_server/MS in GLOB.telecomms_list)
if(MS.on) //on does the calculations. why would this server still work even though the apc is off??
LAZYADD(MS.rc_msgs, log)
workingServer = TRUE
var/alert = ""
for (var/obj/machinery/requests_console/Console in GLOB.allConsoles)
if (ckey(Console.department) == ckey(href_list["department"]))
switch(priority)
if(2) //High priority
alert = "PRIORITY Alert in [department][authentic]"
Console.createmessage(src, alert, sending, 2, 1)
if(3) // Extreme Priority
alert = "EXTREME PRIORITY Alert from [department][authentic]"
Console.createmessage(src, alert , sending, 3, 1)
else // Normal priority
alert = "Message from [department][authentic]"
Console.createmessage(src, alert , sending, 1, 1)
screen = 6
if(!workingServer)
screen = 7
say("NOTICE: No server detected! Please contact your local engineering team.")
updateUsrDialog()
return
if(radio_freq)
Radio.talk_into(src, "[alert]: <i>[message]</i>", radio_freq)
var/radio_freq = 0
switch(href_list["department"])
if("bridge")
radio_freq = FREQ_COMMAND
if("medbay")
radio_freq = FREQ_MEDICAL
if("science")
radio_freq = FREQ_SCIENCE
if("engineering")
radio_freq = FREQ_ENGINEERING
if("security")
radio_freq = FREQ_SECURITY
if("cargobay" || "mining")
radio_freq = FREQ_SUPPLY
Radio.set_frequency(radio_freq)
switch(priority)
if(2)
messages += "<span class='bad'>High Priority</span><BR><b>To:</b> [dpt]<BR>[sending]"
else
messages += "<b>To: [dpt]</b><BR>[sending]"
var/authentic = ""
if(msgVerified || msgStamped)
authentic = " (Authenticated)"
var/alert = ""
for(var/obj/machinery/requests_console/C in GLOB.allConsoles)
if(ckey(C.department) != ckey(href_list["department"]))
continue
switch(priority)
if(HIGH_MESSAGE_PRIORITY) //High priority
alert = "PRIORITY Alert from [department][authentic]"
C.createmessage(src, alert, sending, HIGH_MESSAGE_PRIORITY)
if(EXTREME_MESSAGE_PRIORITY) // Extreme Priority
alert = "EXTREME PRIORITY Alert from [department][authentic]"
C.createmessage(src, alert, sending, EXTREME_MESSAGE_PRIORITY)
else // Normal priority
alert = "Message from [department][authentic]"
C.createmessage(src, alert, sending, NORMAL_MESSAGE_PRIORITY)
screen = 6 //if it ever gets here that means (c.department == href_ls["dept"])
if(radio_freq)
Radio.talk_into(src, "[alert]: <i>[message]</i>", radio_freq)
//log to (this)
switch(priority)
if(HIGH_MESSAGE_PRIORITY)
messages += "<span class='bad'>High Priority</span><br><b>To:</b> [dpt]<br>[sending]"
if(EXTREME_MESSAGE_PRIORITY)
messages += "<span class='bad'>!!!Extreme Priority!!!</span><br><b>To:</b> [dpt]<br>[sending]"
else
say("NOTICE: No server detected!")
messages += "<b>To:</b> [dpt]<br>[sending]"
//Handle screen switching
switch(text2num(href_list["setScreen"]))
if(null) //skip
updateUsrDialog()
return
if(1) //req. assistance
screen = 1
if(2) //req. supplies
@@ -422,16 +443,14 @@ GLOBAL_LIST_EMPTY(allConsoles)
msgVerified = ""
msgStamped = ""
message = ""
priority = -1
priority = NORMAL_MESSAGE_PRIORITY // :salt:
screen = 0
//Handle silencing the console
switch( href_list["setSilent"] )
if(null) //skip
if("1")
silent = TRUE
else
silent = FALSE
if(href_list["setSilent"] == "1")
silent = TRUE
else
silent = FALSE
updateUsrDialog()
return
@@ -456,31 +475,32 @@ GLOBAL_LIST_EMPTY(allConsoles)
linkedsender = source
capitalize(title)
switch(priority)
if(2) //High priority
if(HIGH_MESSAGE_PRIORITY) //High priority
if(newmessagepriority < HIGH_MESSAGE_PRIORITY)
newmessagepriority = HIGH_MESSAGE_PRIORITY
update_icon()
if(!silent)
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
say(title)
messages += "<span class='bad'>High Priority</span><BR><b>From:</b> [linkedsender]<BR>[message]"
messages += "<span class='bad'>High Priority</span><br><b>From:</b> [linkedsender]<br>[message]" //the fuck is this not being sent
if(3) // Extreme Priority
if(EXTREME_MESSAGE_PRIORITY) // Extreme Priority
if(newmessagepriority < EXTREME_MESSAGE_PRIORITY)
newmessagepriority = EXTREME_MESSAGE_PRIORITY
update_icon()
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
say(title)
messages += "<span class='bad'>!!!Extreme Priority!!!</span><BR><b>From:</b> [linkedsender]<BR>[message]"
//we ignore the silent option because this is !!!IMPORTANT!!!
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
say(title)
messages += "<span class='bad'><b>!!!Extreme Priority!!!</span></b><br><b>From:</b> [linkedsender]<br>[message]"
else // Normal priority
if(newmessagepriority < NORMAL_MESSAGE_PRIORITY)
newmessagepriority = NORMAL_MESSAGE_PRIORITY
update_icon()
if(!src.silent)
if(!silent)
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
say(title)
messages += "<b>From:</b> [linkedsender]<BR>[message]"
messages += "<b>From:</b> [linkedsender]<br>[message]"
/obj/machinery/requests_console/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/crowbar))
@@ -504,23 +524,26 @@ GLOBAL_LIST_EMPTY(allConsoles)
to_chat(user, "<span class='warning'>You must open the maintenance panel first!</span>")
return
var/obj/item/card/id/ID = O.GetID()
if(ID)
if(istype(O, /obj/item/card/id))
var/obj/item/card/id/ID = O.GetID()
if(!ID)
return
if(screen == 9)
msgVerified = "<font color='green'><b>Verified by [ID.registered_name] ([ID.assignment])</b></font>"
msgVerified = "Verified by [ID.registered_name] ([ID.assignment])"
updateUsrDialog()
if(screen == 10)
if (ACCESS_RC_ANNOUNCE in ID.access)
if(ACCESS_RC_ANNOUNCE in ID.access)
announceAuth = TRUE
else
announceAuth = FALSE
to_chat(user, "<span class='warning'>You are not authorized to send announcements!</span>")
updateUsrDialog()
return
if (istype(O, /obj/item/stamp))
if(istype(O, /obj/item/stamp))
if(screen == 9)
var/obj/item/stamp/T = O
msgStamped = "<span class='boldnotice'>Stamped with the [T.name]</span>"
msgStamped = "Stamped with the [T.name]"
updateUsrDialog()
return
return ..()
+44
View File
@@ -0,0 +1,44 @@
/obj/machinery/sheetifier
name = "Sheet-meister 2000"
desc = "A very sheety machine"
icon = 'icons/obj/machines/sheetifier.dmi'
icon_state = "base_machine"
density = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 10
active_power_usage = 100
circuit = /obj/item/circuitboard/machine/sheetifier
layer = BELOW_OBJ_LAYER
var/busy_processing = FALSE
/obj/machinery/sheetifier/Initialize()
. = ..()
AddComponent(/datum/component/material_container, list(/datum/material/meat), MINERAL_MATERIAL_AMOUNT * MAX_STACK_SIZE * 2, TRUE, /obj/item/reagent_containers/food/snacks/meat/slab, CALLBACK(src, .proc/CanInsertMaterials), CALLBACK(src, .proc/AfterInsertMaterials))
/obj/machinery/sheetifier/update_overlays()
. = ..()
if(stat & (BROKEN|NOPOWER))
return
var/mutable_appearance/on_overlay = mutable_appearance(icon, "buttons_on")
. += on_overlay
/obj/machinery/sheetifier/update_icon_state()
icon_state = "base_machine[busy_processing ? "_processing" : ""]"
/obj/machinery/sheetifier/proc/CanInsertMaterials()
return !busy_processing
/obj/machinery/sheetifier/proc/AfterInsertMaterials(item_inserted, id_inserted, amount_inserted)
busy_processing = TRUE
update_icon()
var/datum/material/last_inserted_material = id_inserted
var/mutable_appearance/processing_overlay = mutable_appearance(icon, "processing")
processing_overlay.color = last_inserted_material.color
flick_overlay_static(processing_overlay, src, 64)
addtimer(CALLBACK(src, .proc/finish_processing), 64)
/obj/machinery/sheetifier/proc/finish_processing()
busy_processing = FALSE
update_icon()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all() //Returns all as sheets
@@ -0,0 +1,33 @@
/obj/machinery/shuttle
name = "shuttle component"
desc = "Something for shuttles."
density = TRUE
obj_integrity = 250
max_integrity = 250
icon = 'icons/turf/shuttle.dmi'
icon_state = "burst_plasma"
idle_power_usage = 150
circuit = /obj/item/circuitboard/machine/shuttle/engine
var/icon_state_closed = "burst_plasma"
var/icon_state_open = "burst_plasma_open"
var/icon_state_off = "burst_plasma_off"
/obj/machinery/shuttle/Initialize()
. = ..()
GLOB.custom_shuttle_machines += src
/obj/machinery/shuttle/Destroy()
. = ..()
GLOB.custom_shuttle_machines -= src
/obj/machinery/shuttle/attackby(obj/item/I, mob/living/user, params)
if(default_deconstruction_screwdriver(user, icon_state_open, icon_state_closed, I))
return
if(default_pry_open(I))
return
if(panel_open)
if(default_change_direction_wrench(user, I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
@@ -0,0 +1,138 @@
//-----------------------------------------------
//-------------Engine Thrusters------------------
//-----------------------------------------------
#define ENGINE_HEAT_TARGET 600
#define ENGINE_HEATING_POWER 5000000
/obj/machinery/shuttle/engine
name = "shuttle thruster"
desc = "A thruster for shuttles."
density = TRUE
obj_integrity = 250
max_integrity = 250
icon = 'icons/turf/shuttle.dmi'
icon_state = "burst_plasma"
idle_power_usage = 150
circuit = /obj/item/circuitboard/machine/shuttle/engine
var/thrust = 0
var/fuel_use = 0
var/bluespace_capable = TRUE
var/cooldown = 0
var/thruster_active = FALSE
var/datum/weakref/attached_heater
/obj/machinery/shuttle/engine/plasma
name = "plasma thruster"
desc = "A thruster that burns plasma stored in an adjacent plasma thruster heater."
icon_state = "burst_plasma"
icon_state_off = "burst_plasma_off"
idle_power_usage = 0
circuit = /obj/item/circuitboard/machine/shuttle/engine/plasma
thrust = 25
fuel_use = 0.24
bluespace_capable = FALSE
cooldown = 45
/obj/machinery/shuttle/engine/void
name = "void thruster"
desc = "A thruster using technology to breach voidspace for propulsion."
icon_state = "burst_void"
icon_state_off = "burst_void"
icon_state_closed = "burst_void"
icon_state_open = "burst_void_open"
idle_power_usage = 0
circuit = /obj/item/circuitboard/machine/shuttle/engine/void
thrust = 400
fuel_use = 0
bluespace_capable = TRUE
cooldown = 90
/obj/machinery/shuttle/engine/Initialize()
. = ..()
check_setup()
/obj/machinery/shuttle/engine/on_construction()
. = ..()
check_setup()
/obj/machinery/shuttle/engine/Destroy()
attached_heater = FALSE
thruster_active = FALSE
return ..()
/obj/machinery/shuttle/engine/proc/check_setup()
if(!anchored)
attached_heater = null
update_engine()
return
var/heater_turf
switch(dir)
if(NORTH)
heater_turf = get_offset_target_turf(src, 0, 1)
if(SOUTH)
heater_turf = get_offset_target_turf(src, 0, -1)
if(EAST)
heater_turf = get_offset_target_turf(src, 1, 0)
if(WEST)
heater_turf = get_offset_target_turf(src, -1, 0)
if(!heater_turf)
attached_heater = null
update_engine()
return
attached_heater = null
for(var/obj/machinery/atmospherics/components/unary/shuttle/heater/as_heater in heater_turf)
if(as_heater.dir != dir)
continue
if(as_heater.panel_open)
continue
if(!as_heater.anchored)
continue
attached_heater = WEAKREF(as_heater)
break
update_engine()
return
/obj/machinery/shuttle/engine/proc/update_engine()
if(!attached_heater)
icon_state = icon_state_off
thruster_active = FALSE
return
var/obj/machinery/atmospherics/components/unary/shuttle/heater/resolved_heater = attached_heater.resolve()
if(panel_open)
thruster_active = FALSE
else if(resolved_heater?.hasFuel(1))
icon_state = icon_state_closed
thruster_active = TRUE
else
thruster_active = FALSE
icon_state = icon_state_off
return
/obj/machinery/shuttle/engine/void/update_engine()
if(panel_open)
thruster_active = FALSE
return
thruster_active = TRUE
icon_state = icon_state_closed
return
//Thanks to spaceheater.dm for inspiration :)
/obj/machinery/shuttle/engine/proc/fireEngine()
var/turf/heatTurf = loc
if(!heatTurf)
return
var/datum/gas_mixture/env = heatTurf.return_air()
var/heat_cap = env.heat_capacity()
var/req_power = abs(env.return_temperature() - ENGINE_HEAT_TARGET) * heat_cap
req_power = min(req_power, ENGINE_HEATING_POWER)
var/deltaTemperature = req_power / heat_cap
if(deltaTemperature < 0)
return
env.temperature += deltaTemperature
air_update_turf()
/obj/machinery/shuttle/engine/default_change_direction_wrench(mob/user, obj/item/I)
. = ..()
update_engine()
@@ -0,0 +1,132 @@
//-----------------------------------------------
//--------------Engine Heaters-------------------
//This uses atmospherics, much like a thermomachine,
//but instead of changing temp, it stores plasma and uses
//it for the engine.
//-----------------------------------------------
/obj/machinery/atmospherics/components/unary/shuttle
name = "shuttle atmospherics device"
desc = "This does something to do with shuttle atmospherics"
icon_state = "heater"
icon = 'icons/turf/shuttle.dmi'
/obj/machinery/atmospherics/components/unary/shuttle/heater
name = "engine heater"
desc = "Directs energy into compressed particles in order to power an attached thruster."
icon_state = "heater_pipe"
var/icon_state_closed = "heater_pipe"
var/icon_state_open = "heater_pipe_open"
var/icon_state_off = "heater_pipe"
idle_power_usage = 50
circuit = /obj/item/circuitboard/machine/shuttle/heater
density = TRUE
max_integrity = 400
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 30)
layer = OBJ_LAYER
showpipe = TRUE
pipe_flags = PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY
var/gas_type = /datum/gas/plasma
var/efficiency_multiplier = 1
var/gas_capacity = 0
/obj/machinery/atmospherics/components/unary/shuttle/heater/New()
. = ..()
GLOB.custom_shuttle_machines += src
SetInitDirections()
update_adjacent_engines()
updateGasStats()
/obj/machinery/atmospherics/components/unary/shuttle/heater/Destroy()
. = ..()
update_adjacent_engines()
GLOB.custom_shuttle_machines -= src
/obj/machinery/atmospherics/components/unary/shuttle/heater/on_construction()
..(dir, dir)
SetInitDirections()
update_adjacent_engines()
/obj/machinery/atmospherics/components/unary/shuttle/heater/default_change_direction_wrench(mob/user, obj/item/I)
if(!..())
return FALSE
SetInitDirections()
var/obj/machinery/atmospherics/node = nodes[1]
if(node)
node.disconnect(src)
nodes[1] = null
if(!parents[1])
return
nullifyPipenet(parents[1])
atmosinit()
node = nodes[1]
if(node)
node.atmosinit()
node.addMember(src)
build_network()
return TRUE
/obj/machinery/atmospherics/components/unary/shuttle/heater/RefreshParts()
var/cap = 0
var/eff = 0
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
cap += M.rating
for(var/obj/item/stock_parts/micro_laser/L in component_parts)
eff += L.rating
gas_capacity = 5000 * ((cap - 1) ** 2) + 1000
efficiency_multiplier = round(((eff / 2) / 2.8) ** 2, 0.1)
updateGasStats()
/obj/machinery/atmospherics/components/unary/shuttle/heater/examine(mob/user)
. = ..()
var/datum/gas_mixture/air_contents = airs[1]
. += "The engine heater's gas dial reads [air_contents.return_volume()] liters in internal tank.<br>"
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/updateGasStats()
var/datum/gas_mixture/air_contents = airs[1]
if(!air_contents)
return
air_contents.volume = gas_capacity
air_contents.temperature = T20C
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/hasFuel(var/required)
var/datum/gas_mixture/air_contents = airs[1]
var/moles = air_contents.total_moles()
return moles >= required
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/consumeFuel(var/amount)
var/datum/gas_mixture/air_contents = airs[1]
air_contents.remove(amount)
return
/obj/machinery/atmospherics/components/unary/shuttle/heater/attackby(obj/item/I, mob/living/user, params)
update_adjacent_engines()
if(default_deconstruction_screwdriver(user, icon_state_open, icon_state_closed, I))
return
if(default_pry_open(I))
return
if(panel_open)
if(default_change_direction_wrench(user, I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/update_adjacent_engines()
var/engine_turf
switch(dir)
if(NORTH)
engine_turf = get_offset_target_turf(src, 0, -1)
if(SOUTH)
engine_turf = get_offset_target_turf(src, 0, 1)
if(EAST)
engine_turf = get_offset_target_turf(src, -1, 0)
if(WEST)
engine_turf = get_offset_target_turf(src, 1, 0)
if(!engine_turf)
return
for(var/obj/machinery/shuttle/engine/E in engine_turf)
E.check_setup()
+7 -2
View File
@@ -115,8 +115,8 @@
return PROCESS_KILL
/obj/machinery/space_heater/RefreshParts()
var/laser = 0
var/cap = 0
var/laser = 2
var/cap = 1
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
laser += M.rating
for(var/obj/item/stock_parts/capacitor/M in component_parts)
@@ -166,6 +166,11 @@
else
return ..()
/obj/machinery/space_heater/wrench_act(mob/living/user, obj/item/I)
..()
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)
+2 -1
View File
@@ -21,6 +21,7 @@
desc = null
icon = 'icons/obj/status_display.dmi'
icon_state = "frame"
plane = ABOVE_WALL_PLANE
density = FALSE
use_power = IDLE_POWER_USE
idle_power_usage = 10
@@ -289,7 +290,7 @@
if("shuttle_id")
update()
/obj/machinery/status_display/shuttle/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
/obj/machinery/status_display/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
if (port && (shuttle_id == initial(shuttle_id) || override))
shuttle_id = port.id
update()
@@ -1,215 +1,164 @@
/*
The log console for viewing the entire telecomms
network log
*/
/obj/machinery/computer/telecomms/server
name = "telecommunications server monitoring console"
icon_screen = "comm_logs"
desc = "Has full access to all details and record of the telecommunications network it's monitoring."
circuit = /obj/item/circuitboard/computer/comm_server
req_access = list(ACCESS_TCOMSAT)
var/screen = 0 // the screen number:
var/list/servers = list() // the servers located by the computer
var/obj/machinery/telecomms/server/SelectedServer
var/list/machinelist = list() // the servers located by the computer
var/obj/machinery/telecomms/server/SelectedMachine = null
var/network = "NULL" // the network to probe
var/temp = "" // temporary feedback messages
var/notice = ""
var/universal_translate = FALSE // set to TRUE(1) if it can translate nonhuman speech
var/universal_translate = 0 // set to 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)
if(!ui)
ui = new(user, src, ui_key, "tcommsserver", "Telecomms Server Monitor", 575, 400, master_ui, state)
ui.open()
req_access = list(ACCESS_TCOMSAT)
circuit = /obj/item/circuitboard/computer/comm_server
/obj/machinery/computer/telecomms/server/ui_data(mob/user)
var/list/data_out = list()
data_out["network"] = network
data_out["notice"] = notice
/obj/machinery/computer/telecomms/server/ui_interact(mob/user)
. = ..()
var/dat = "<TITLE>Telecommunication Server Monitor</TITLE><center><b>Telecommunications Server Monitor</b></center>"
data_out["servers"] = list()
for(var/obj/machinery/telecomms/server/T in machinelist)
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
data_out["servers"] += list(data)
data_out["servers"] = sortList(data_out["servers"]) //a-z sort
switch(screen)
if(!SelectedMachine) //null is bad.
data_out["selected"] = null //but in js, null is good.
return data_out
data_out["selected"] = list(
name = SelectedMachine.name,
id = SelectedMachine.id,
status = SelectedMachine.on,
traffic = SelectedMachine.totaltraffic, //note: total traffic, not traffic!
ref = REF(SelectedMachine)
)
data_out["selected_logs"] = list()
// --- Main Menu ---
if(!LAZYLEN(SelectedMachine.log_entries))
return data_out
for(var/datum/comm_log_entry/C in SelectedMachine.log_entries)
var/list/data = list()
data["name"] = C.name //name of the file
data["ref"] = REF(C)
data["input_type"] = C.input_type //type of input ("Speech File" | "Execution Error").
if(0)
dat += "<br>[temp]<br>"
dat += "<br>Current Network: <a href='?src=[REF(src)];network=1'>[network]</a><br>"
if(servers.len)
dat += "<br>Detected Telecommunication Servers:<ul>"
for(var/obj/machinery/telecomms/T in servers)
dat += "<li><a href='?src=[REF(src)];viewserver=[T.id]'>[REF(T)] [T.name]</a> ([T.id])</li>"
dat += "</ul>"
dat += "<br><a href='?src=[REF(src)];operation=release'>\[Flush Buffer\]</a>"
if(C.input_type == "Speech File") //there is a reason why this is not a switch.
data["source"] = list(
name = C.parameters["name"], //name of the mob | obj
job = C.parameters["job"] //job of the mob | obj
)
// -- Determine race of orator --
var/mobtype = C.parameters["mobtype"]
var/race // The actual race of the mob
if(ispath(mobtype, /mob/living/carbon/human) || ispath(mobtype, /mob/living/brain))
race = "Humanoid"
else if(ispath(mobtype, /mob/living/simple_animal/slime))
race = "Slime" // NT knows a lot about slimes, but not aliens. Can identify slimes
else if(ispath(mobtype, /mob/living/carbon/monkey))
race = "Monkey"
else if(ispath(mobtype, /mob/living/silicon) || C.parameters["job"] == "AI")
race = "Artificial Life" // sometimes M gets deleted prematurely for AIs... just check the job
else if(isobj(mobtype))
race = "Machinery"
else if(ispath(mobtype, /mob/living/simple_animal))
race = "Domestic Animal"
else
dat += "<br>No servers detected. Scan for servers: <a href='?src=[REF(src)];operation=scan'>\[Scan\]</a>"
race = "Unidentifiable"
data["race"] = race
// based on [/atom/movable/proc/lang_treat]
var/message = C.parameters["message"]
var/language = C.parameters["language"]
// --- Viewing Server ---
if(universal_translate || user.has_language(language))
message = message
else if(!user.has_language(language))
var/datum/language/D = GLOB.language_datum_instances[language]
message = D.scramble(message)
else if(language)
message = "(unintelligible)"
if(1)
dat += "<br>[temp]<br>"
dat += "<center><a href='?src=[REF(src)];operation=mainmenu'>\[Main Menu\]</a> <a href='?src=[REF(src)];operation=refresh'>\[Refresh\]</a></center>"
dat += "<br>Current Network: [network]"
dat += "<br>Selected Server: [SelectedServer.id]"
data["message"] = message
if(SelectedServer.totaltraffic >= 1024)
dat += "<br>Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes<br><br>"
else
dat += "<br>Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes<br><br>"
else if(C.input_type == "Execution Error")
data["message"] = C.parameters["message"]
else
data["message"] = "(unintelligible)"
data_out["selected_logs"] += list(data)
return data_out
dat += "Stored Logs: <ol>"
var/i = 0
for(var/datum/comm_log_entry/C in SelectedServer.log_entries)
i++
// If the log is a speech file
if(C.input_type == "Speech File")
dat += "<li><font color = #008F00>[C.name]</font> <font color = #FF0000><a href='?src=[REF(src)];delete=[i]'>\[X\]</a></font><br>"
// -- Determine race of orator --
var/mobtype = C.parameters["mobtype"]
var/race // The actual race of the mob
if(ispath(mobtype, /mob/living/carbon/human) || ispath(mobtype, /mob/living/brain))
race = "Humanoid"
// NT knows a lot about slimes, but not aliens. Can identify slimes
else if(ispath(mobtype, /mob/living/simple_animal/slime))
race = "Slime"
else if(ispath(mobtype, /mob/living/carbon/monkey))
race = "Monkey"
// sometimes M gets deleted prematurely for AIs... just check the job
else if(ispath(mobtype, /mob/living/silicon) || C.parameters["job"] == "AI")
race = "Artificial Life"
else if(isobj(mobtype))
race = "Machinery"
else if(ispath(mobtype, /mob/living/simple_animal))
race = "Domestic Animal"
else
race = "<i>Unidentifiable</i>"
dat += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
dat += "<u><font color = #18743E>Source</font></u>: [C.parameters["name"]] (Job: [C.parameters["job"]])<br>"
dat += "<u><font color = #18743E>Class</font></u>: [race]<br>"
var/message = C.parameters["message"]
var/language = C.parameters["language"]
// based on [/atom/movable/proc/lang_treat]
if (universal_translate || user.has_language(language))
message = "\"[message]\""
else if (!user.has_language(language))
var/datum/language/D = GLOB.language_datum_instances[language]
message = "\"[D.scramble(message)]\""
else if (language)
message = "<i>(unintelligible)</i>"
dat += "<u><font color = #18743E>Contents</font></u>: [message]<br>"
dat += "</li><br>"
else if(C.input_type == "Execution Error")
dat += "<li><font color = #990000>[C.name]</font> <a href='?src=[REF(src)];delete=[i]'>\[X\]</a><br>"
dat += "<u><font color = #787700>Error</font></u>: \"[C.parameters["message"]]\"<br>"
dat += "</li><br>"
else
dat += "<li><font color = #000099>[C.name]</font> <a href='?src=[REF(src)];delete=[i]'>\[X\]</a><br>"
dat += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
dat += "<u><font color = #18743E>Contents</font></u>: <i>(unintelligible)</i><br>"
dat += "</li><br>"
dat += "</ol>"
user << browse(dat, "window=comm_monitor;size=575x400")
onclose(user, "server_control")
temp = ""
return
/obj/machinery/computer/telecomms/server/Topic(href, href_list)
/obj/machinery/computer/telecomms/server/ui_act(action, params)
if(..())
return
add_fingerprint(usr)
usr.set_machine(src)
if(href_list["viewserver"])
screen = 1
for(var/obj/machinery/telecomms/T in servers)
if(T.id == href_list["viewserver"])
SelectedServer = T
break
if(href_list["operation"])
switch(href_list["operation"])
if("release")
servers = list()
screen = 0
if("mainmenu")
screen = 0
if("scan")
if(servers.len > 0)
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font color>"
else
for(var/obj/machinery/telecomms/server/T in urange(25, src))
if(T.network == network)
servers.Add(T)
if(!servers.len)
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -</font color>"
else
temp = "<font color = #336699>- [servers.len] SERVERS PROBED & BUFFERED -</font color>"
screen = 0
if(href_list["delete"])
if(!src.allowed(usr) && !(obj_flags & EMAGGED))
to_chat(usr, "<span class='danger'>ACCESS DENIED.</span>")
switch(action)
if("mainmenu")
SelectedMachine = null
notice = ""
return
if("release")
machinelist = list()
notice = ""
return
if("network") //network change, flush the selected machine and buffer
var/newnet = sanitize(sanitize_text(params["value"], network))
if(length(newnet) > 15) //i'm looking at you, you href fuckers
notice = "FAILED: Network tag string too lengthy"
return
network = newnet
SelectedMachine = null
machinelist = list()
return
if("probe")
if(LAZYLEN(machinelist) > 0)
notice = "FAILED: Cannot probe when buffer full"
return
for(var/obj/machinery/telecomms/T in GLOB.telecomms_list) //telecomms just went global!
if(T.network == network)
LAZYADD(machinelist, T)
if(SelectedServer)
if(!LAZYLEN(machinelist))
notice = "FAILED: Unable to locate network entities in \[[network]\]"
return
if("viewmachine")
for(var/obj/machinery/telecomms/T in machinelist)
if(T.id == params["value"])
SelectedMachine = T
break
if("delete")
if(!src.allowed(usr) && !CHECK_BITFIELD(obj_flags, EMAGGED))
to_chat(usr, "<span class='danger'>ACCESS DENIED.</span>")
return
var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(href_list["delete"])]
temp = "<font color = #336699>- DELETED ENTRY: [D.name] -</font color>"
SelectedServer.log_entries.Remove(D)
if(!SelectedMachine)
notice = "ALERT: No server detected. Server may be nonresponsive."
return
var/datum/comm_log_entry/D = locate(params["value"])
if(!istype(D))
notice = "NOTICE: Object not found"
return
notice = "Deleted entry: [D.name]"
LAZYREMOVE(SelectedMachine.log_entries, D)
qdel(D)
else
temp = "<font color = #D70B00>- FAILED: NO SELECTED MACHINE -</font color>"
if(href_list["network"])
var/newnet = stripped_input(usr, "Which network do you want to view?", "Comm Monitor", network)
if(newnet && ((usr in range(1, src)) || hasSiliconAccessInArea(usr)))
if(length(newnet) > 15)
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LENGHTLY -</font color>"
else
network = newnet
screen = 0
servers = list()
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font color>"
updateUsrDialog()
return
/obj/machinery/computer/telecomms/server/attackby()
. = ..()
updateUsrDialog()
+315 -382
View File
@@ -3,241 +3,360 @@
Lets you read PDA and request console messages.
*/
#define LINKED_SERVER_NONRESPONSIVE (!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN)))
// The monitor itself.
/obj/machinery/computer/message_monitor
name = "message monitor console"
desc = "Used to monitor the crew's PDA messages, as well as request console messages."
icon_screen = "comm_logs"
circuit = /obj/item/circuitboard/computer/message_monitor
//Server linked to.
//Servers, and server linked to.
var/network = "tcommsat" // the network to probe
var/list/machinelist = list() // the servers located by the computer
var/obj/machinery/telecomms/message_server/linkedServer = null
//Sparks effect - For emag
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
//Messages - Saves me time if I want to change something.
var/noserver = "<span class='alert'>ALERT: No server detected.</span>"
var/incorrectkey = "<span class='warning'>ALERT: Incorrect decryption key!</span>"
var/defaultmsg = "<span class='notice'>Welcome. Please select an option.</span>"
var/rebootmsg = "<span class='warning'>%$&(: Critical %$$@ Error // !RestArting! <lOadiNg backUp iNput ouTput> - ?pLeaSe wAit!</span>"
var/noserver = "ALERT: No server detected. Server may be nonresponsive."
var/incorrectkey = "ALERT: Incorrect decryption key!"
var/rebootmsg = "%$(:SYS&EM INTRN@L ACfES VIOLTIa█ DEtE₡TED! Ree3ARcinG A█ BAaKUP RdSTRE PbINT \[0xcff32ca/ - PLfASE aAIT"
//Computer properties
var/screen = 0 // 0 = Main menu, 1 = Message Logs, 2 = Hacked screen, 3 = Custom Message
var/hacking = FALSE // Is it being hacked into by the AI/Cyborg
var/message = "<span class='notice'>System bootup complete. Please select an option.</span>" // The message that shows on the main menu.
var/auth = FALSE // Are they authenticated?
var/optioncount = 7
var/message = "" // The message that shows on the main menu.
var/auth = FALSE // Are they authenticated?
// Custom Message Properties
var/customsender = "System Administrator"
var/obj/item/pda/customrecepient = null
var/customsender = "System Administrator"
var/customjob = "Admin"
var/custommessage = "This is a test, please ignore."
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)
if(!ui)
ui = new(user, src, ui_key, "telepdalog", name, 727, 510, master_ui, state)
ui.open()
/obj/machinery/computer/message_monitor/ui_static_data(mob/user)
var/list/data_out = list()
if(!linkedServer || !auth) // no need building this if the usr isn't authenticated
return data_out
data_out["recon_logs"] = list()
var/i1 = 0
for(var/datum/data_rc_msg/rc in linkedServer.rc_msgs)
i1++
if(i1 > 3000)
break
var/list/data = list(
sender = rc.send_dpt,
recipient = rc.rec_dpt,
message = rc.message,
stamp = rc.stamp,
auth = rc.id_auth,
priority = rc.priority,
ref = REF(rc)
)
data_out["recon_logs"] += list(data)
data_out["message_logs"] = list()
var/i2 = 0
for(var/datum/data_pda_msg/pda in linkedServer.pda_msgs)
i2++
if(i2 > 3000)
break
var/list/data = list(
sender = pda.sender,
recipient = pda.recipient,
message = pda.message,
picture = pda.picture ? TRUE : FALSE,
ref = REF(pda)
)
data_out["message_logs"] += list(data)
return data_out
/obj/machinery/computer/message_monitor/ui_data(mob/user)
var/list/data_out = list()
data_out["notice"] = message
data_out["authenticated"] = auth
data_out["network"] = network
var/mob/living/silicon/S = user
if(istype(S) && S.hack_software)
data_out["canhack"] = TRUE
data_out["hacking"] = (hacking || CHECK_BITFIELD(obj_flags, EMAGGED))
if(hacking)
data_out["borg"] = ((isAI(user) || iscyborg(user)) && !CHECK_BITFIELD(obj_flags, EMAGGED)) //even borgs can't read emag
return data_out
data_out["servers"] = list()
for(var/obj/machinery/telecomms/message_server/T in machinelist)
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
data_out["servers"] += list(data) // This /might/ cause an oom. Too bad!
data_out["servers"] = sortList(data_out["servers"]) //a-z sort
data_out["fake_message"] = list(
sender = customsender,
job = customjob,
message = custommessage,
recepient = (customrecepient ? "[customrecepient.owner] ([customrecepient.ownjob])" : null)
)
if(!linkedServer)
data_out["selected"] = null
return data_out
data_out["selected"] = list(
name = linkedServer.name,
id = linkedServer.id,
ref = REF(linkedServer),
status = (linkedServer.on && (linkedServer.toggled != FALSE)) // returns true if server is running
)
return data_out
/obj/machinery/computer/message_monitor/ui_act(action, params)
if(..())
return
switch(action)
if("mainmenu") //deselect
linkedServer = null
auth = FALSE
message = ""
return
if("release") //release server listing
machinelist = list()
message = ""
return
if("network") //network change, flush the selected machine and buffer, and de-auth them, if blank, return default
var/newnet = sanitize(sanitize_text(params["value"], network))
if(length(newnet) > 15) //i'm looking at you, you href fuckers
message = "FAILED: Network tag string too lengthy"
return
network = newnet
linkedServer = null
machinelist = list()
auth = FALSE
message = "NOTICE: Network change detected. Server disconnected, please re-authenticate."
return
if("probe") //probe network for the pda serbs
if(LAZYLEN(machinelist) > 0)
message = "FAILED: Cannot probe when buffer full"
return
for(var/obj/machinery/telecomms/message_server/T in GLOB.telecomms_list)
if(T.network == network)
LAZYADD(machinelist, T)
if(!LAZYLEN(machinelist))
message = "FAILED: Unable to locate network entities in \[[network]\]"
return
if("viewmachine") //selected but not authorized
for(var/obj/machinery/telecomms/message_server/T in machinelist)
if(T.id == params["value"])
linkedServer = T
break
if("auth")
if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
if(auth)
auth = FALSE
update_static_data(usr) //make sure it's cleared!
return
var/dkey = stripped_input(usr, "Please enter the decryption key.")
if(dkey && dkey == "")
return
if(linkedServer.decryptkey == dkey)
auth = TRUE
else
message = incorrectkey
update_static_data(usr)
if("change_auth")
if(!auth)
message = "WARNING: Auth failed! Please log in to change the password!"
return
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
var/dkey = stripped_input(usr, "Please enter the old decryption key.")
if(dkey && dkey != "")
if(linkedServer.decryptkey == dkey)
var/newkey = stripped_input(usr, "Please enter the new key (3 - 20 characters max):")
if(!ISINRANGE(length(newkey), 3, 20))
message = "NOTICE: Decryption key length too long/short!"
return
if(newkey && newkey != "")
linkedServer.decryptkey = newkey
message = "NOTICE: Decryption key set."
return
message = incorrectkey
if("hack")
if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
var/mob/living/silicon/S = usr
if(istype(S) && S.hack_software)
hacking = TRUE
//Time it takes to bruteforce is dependant on the password length.
addtimer(CALLBACK(src, .proc/BruteForce, usr), (10 SECONDS) * length(linkedServer.decryptkey))
if("del_log")
if(!auth)
message = "WARNING: Auth failed! Delete aborted!"
return
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
var/datum/data_ref = locate(params["ref"])
if(istype(data_ref, /datum/data_rc_msg))
LAZYREMOVE(linkedServer.rc_msgs, data_ref)
message = "NOTICE: Log Deleted!"
else if(istype(data_ref, /datum/data_pda_msg))
LAZYREMOVE(linkedServer.pda_msgs, data_ref)
message = "NOTICE: Log Deleted!"
else
message = "NOTICE: Log not found! It may have already been deleted"
update_static_data(usr)
if("clear_log")
if(!auth)
message = "WARNING: Auth failed! Delete aborted!"
return
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
var/what = params["value"]
if(what == "pda_logs")
linkedServer.pda_msgs = list()
if(what == "rc_msgs")
linkedServer.rc_msgs = list()
update_static_data(usr)
if("fake")
if(!auth)
message = "WARNING: Auth failed!"
return
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
if("reset" in params)
ResetMessage()
return
if("send" in params)
if(isnull(customrecepient))
message = "NOTICE: No recepient selected!"
return
if(length(custommessage) <= 0 || custommessage == "")
message = "NOTICE: No message entered!"
return
if(length(customjob) <= 0 || customjob == "")
customjob = "Admin"
return
if(length(customsender) <= 0 || customsender == "")
customsender = "UNKNOWN"
//sanitize text!!!
var/datum/signal/subspace/pda/signal = new(src, list(
"name" = sanitize(customsender),
"job" = sanitize(customjob),
"message" = sanitize(custommessage),
"emojis" = TRUE,
"targets" = list("[customrecepient.owner] ([customrecepient.ownjob])")
))
// this will log the signal and transmit it to the target
linkedServer.receive_information(signal, null)
usr.log_message("(PDA: [name] | [usr.real_name]) sent \"[sanitize(custommessage)]\" to [signal.format_target()]", LOG_PDA)
message = ""
return
// Do not check if it's blank yet
// But do check if it's above our set limit (for people who manualy send hrefs at us!)
if("sender" in params)
var/S = params["sender"]
if(length(S) > MAX_NAME_LEN)
message = "FAILED: Job string too lengthy"
return
customsender = S
return
if("job" in params)
var/J = params["job"]
if(length(J) > 100)
message = "FAILED: Job string too lengthy"
return
customjob = J
return
if("message" in params)
var/M = params["message"]
if(length(M) > MAX_MESSAGE_LEN)
message = "FAILED: Message string too lengthy"
return
custommessage = M
return
if("recepient" in params)
// Get out list of viable PDAs
var/list/obj/item/pda/sendPDAs = get_viewable_pdas()
if(GLOB.PDAs && LAZYLEN(GLOB.PDAs) > 0)
customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortNames(sendPDAs)
else
customrecepient = null
return
if("refresh")
update_static_data(usr)
/obj/machinery/computer/message_monitor/attackby(obj/item/O, mob/living/user, params)
if(istype(O, /obj/item/screwdriver) && (obj_flags & EMAGGED))
//Stops people from just unscrewing the monitor and putting it back to get the console working again.
if(istype(O, /obj/item/screwdriver) && CHECK_BITFIELD(obj_flags, EMAGGED))
//Stops people from just unscrewing the monitor and putting it back to get the console working again.
//Why this though, you should make it emag to a board level. (i wont do it)
to_chat(user, "<span class='warning'>It is too hot to mess with!</span>")
else
return ..()
/obj/machinery/computer/message_monitor/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
if(CHECK_BITFIELD(obj_flags, EMAGGED))
return
if(isnull(linkedServer))
to_chat(user, "<span class='notice'>A no server error appears on the screen.</span>")
return
obj_flags |= EMAGGED
screen = 2
ENABLE_BITFIELD(obj_flags, EMAGGED)
spark_system.set_up(5, 0, src)
spark_system.start()
var/obj/item/paper/monitorkey/MK = new(loc, linkedServer)
// Will help make emagging the console not so easy to get away with.
MK.info += "<br><br><font color='red'>%@%(*$%&(&?*(%&/{}</font>"
var/time = 100 * length(linkedServer.decryptkey)
addtimer(CALLBACK(src, .proc/UnmagConsole), time)
message = rebootmsg
addtimer(CALLBACK(src, .proc/UnmagConsole), (10 SECONDS) * length(linkedServer.decryptkey))
//message = rebootmsg
return TRUE
/obj/machinery/computer/message_monitor/New()
. = ..()
GLOB.telecomms_list += src
/obj/machinery/computer/message_monitor/Initialize()
..()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/message_monitor/LateInitialize()
//Is the server isn't linked to a server, and there's a server available, default it to the first one in the list.
if(!linkedServer)
for(var/obj/machinery/telecomms/message_server/S in GLOB.telecomms_list)
linkedServer = S
break
/obj/machinery/computer/message_monitor/Destroy()
GLOB.telecomms_list -= src
. = ..()
/obj/machinery/computer/message_monitor/ui_interact(mob/living/user)
. = ..()
//If the computer is being hacked or is emagged, display the reboot message.
if(hacking || (obj_flags & EMAGGED))
message = rebootmsg
var/dat = "<center><font color='blue'[message]</font></center>"
if(auth)
dat += "<h4><dd><A href='?src=[REF(src)];auth=1'>&#09;<font color='green'>\[Authenticated\]</font></a>&#09;/"
dat += " Server Power: <A href='?src=[REF(src)];active=1'>[linkedServer && linkedServer.toggled ? "<font color='green'>\[On\]</font>":"<font color='red'>\[Off\]</font>"]</a></h4>"
else
dat += "<h4><dd><A href='?src=[REF(src)];auth=1'>&#09;<font color='red'>\[Unauthenticated\]</font></a>&#09;/"
dat += " Server Power: <u>[linkedServer && linkedServer.toggled ? "<font color='green'>\[On\]</font>":"<font color='red'>\[Off\]</font>"]</u></h4>"
if(hacking || (obj_flags & EMAGGED))
screen = 2
else if(!auth || LINKED_SERVER_NONRESPONSIVE)
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
screen = 0
switch(screen)
//Main menu
if(0)
//&#09; = TAB
var/i = 0
dat += "<dd><A href='?src=[REF(src)];find=1'>&#09;[++i]. Link To A Server</a></dd>"
if(auth)
if(LINKED_SERVER_NONRESPONSIVE)
dat += "<dd><A>&#09;ERROR: Server not found!</A><br></dd>"
else
dat += "<dd><A href='?src=[REF(src)];view_logs=1'>&#09;[++i]. View Message Logs </a><br></dd>"
dat += "<dd><A href='?src=[REF(src)];view_requests=1'>&#09;[++i]. View Request Console Logs </a></br></dd>"
dat += "<dd><A href='?src=[REF(src)];clear_logs=1'>&#09;[++i]. Clear Message Logs</a><br></dd>"
dat += "<dd><A href='?src=[REF(src)];clear_requests=1'>&#09;[++i]. Clear Request Console Logs</a><br></dd>"
dat += "<dd><A href='?src=[REF(src)];pass=1'>&#09;[++i]. Set Custom Key</a><br></dd>"
dat += "<dd><A href='?src=[REF(src)];msg=1'>&#09;[++i]. Send Admin Message</a><br></dd>"
else
for(var/n = ++i; n <= optioncount; n++)
dat += "<dd><font color='blue'>&#09;[n]. ---------------</font><br></dd>"
var/mob/living/silicon/S = usr
if(istype(S) && S.hack_software)
//Malf/Traitor AIs can bruteforce into the system to gain the Key.
dat += "<dd><A href='?src=[REF(src)];hack=1'><i><font color='Red'>*&@#. Bruteforce Key</font></i></font></a><br></dd>"
else
dat += "<br>"
//Bottom message
if(!auth)
dat += "<br><hr><dd><span class='notice'>Please authenticate with the server in order to show additional options.</span>"
else
dat += "<br><hr><dd><span class='warning'>Reg, #514 forbids sending messages to a Head of Staff containing Erotic Rendering Properties.</span>"
//Message Logs
if(1)
var/index = 0
dat += "<center><A href='?src=[REF(src)];back=1'>Back</a> - <A href='?src=[REF(src)];refresh=1'>Refresh</a></center><hr>"
dat += "<table border='1' width='100%'><tr><th width = '5%'>X</th><th width='15%'>Sender</th><th width='15%'>Recipient</th><th width='300px' word-wrap: break-word>Message</th></tr>"
for(var/datum/data_pda_msg/pda in linkedServer.pda_msgs)
index++
if(index > 3000)
break
// Del - Sender - Recepient - Message
// X - Al Green - Your Mom - WHAT UP!?
dat += "<tr><td width = '5%'><center><A href='?src=[REF(src)];delete_logs=[REF(pda)]' style='color: rgb(255,0,0)'>X</a></center></td><td width='15%'>[pda.sender]</td><td width='15%'>[pda.recipient]</td><td width='300px'>[pda.message][pda.picture ? " <a href='byond://?src=[REF(pda)];photo=1'>(Photo)</a>":""]</td></tr>"
dat += "</table>"
//Hacking screen.
if(2)
if(isAI(user) || iscyborg(user))
dat += "Brute-forcing for server key.<br> It will take 20 seconds for every character that the password has."
dat += "In the meantime, this console can reveal your true intentions if you let someone access it. Make sure no humans enter the room during that time."
else
//It's the same message as the one above but in binary. Because robots understand binary and humans don't... well I thought it was clever.
dat += {"01000010011100100111010101110100011001010010110<br>
10110011001101111011100100110001101101001011011100110011<br>
10010000001100110011011110111001000100000011100110110010<br>
10111001001110110011001010111001000100000011010110110010<br>
10111100100101110001000000100100101110100001000000111011<br>
10110100101101100011011000010000001110100011000010110101<br>
10110010100100000001100100011000000100000011100110110010<br>
10110001101101111011011100110010001110011001000000110011<br>
00110111101110010001000000110010101110110011001010111001<br>
00111100100100000011000110110100001100001011100100110000<br>
10110001101110100011001010111001000100000011101000110100<br>
00110000101110100001000000111010001101000011001010010000<br>
00111000001100001011100110111001101110111011011110111001<br>
00110010000100000011010000110000101110011001011100010000<br>
00100100101101110001000000111010001101000011001010010000<br>
00110110101100101011000010110111001110100011010010110110<br>
10110010100101100001000000111010001101000011010010111001<br>
10010000001100011011011110110111001110011011011110110110<br>
00110010100100000011000110110000101101110001000000111001<br>
00110010101110110011001010110000101101100001000000111100<br>
10110111101110101011100100010000001110100011100100111010<br>
10110010100100000011010010110111001110100011001010110111<br>
00111010001101001011011110110111001110011001000000110100<br>
10110011000100000011110010110111101110101001000000110110<br>
00110010101110100001000000111001101101111011011010110010<br>
10110111101101110011001010010000001100001011000110110001<br>
10110010101110011011100110010000001101001011101000010111<br>
00010000001001101011000010110101101100101001000000111001<br>
10111010101110010011001010010000001101110011011110010000<br>
00110100001110101011011010110000101101110011100110010000<br>
00110010101101110011101000110010101110010001000000111010<br>
00110100001100101001000000111001001101111011011110110110<br>
10010000001100100011101010111001001101001011011100110011<br>
10010000001110100011010000110000101110100001000000111010<br>
001101001011011010110010100101110"}
//Fake messages
if(3)
dat += "<center><A href='?src=[REF(src)];back=1'>Back</a> - <A href='?src=[REF(src)];Reset=1'>Reset</a></center><hr>"
dat += {"<table border='1' width='100%'>
<tr><td width='20%'><A href='?src=[REF(src)];select=Sender'>Sender</a></td>
<td width='20%'><A href='?src=[REF(src)];select=RecJob'>Sender's Job</a></td>
<td width='20%'><A href='?src=[REF(src)];select=Recepient'>Recipient</a></td>
<td width='300px' word-wrap: break-word><A href='?src=[REF(src)];select=Message'>Message</a></td></tr>"}
//Sender - Sender's Job - Recepient - Message
//Al Green- Your Dad - Your Mom - WHAT UP!?
dat += {"<tr><td width='20%'>[customsender]</td>
<td width='20%'>[customjob]</td>
<td width='20%'>[customrecepient ? customrecepient.owner : "NONE"]</td>
<td width='300px'>[custommessage]</td></tr>"}
dat += "</table><br><center><A href='?src=[REF(src)];select=Send'>Send</a>"
//Request Console Logs
if(4)
var/index = 0
/* data_rc_msg
X - 5%
var/rec_dpt = "Unspecified" //name of the person - 15%
var/send_dpt = "Unspecified" //name of the sender- 15%
var/message = "Blank" //transferred message - 300px
var/stamp = "Unstamped" - 15%
var/id_auth = "Unauthenticated" - 15%
var/priority = "Normal" - 10%
*/
dat += "<center><A href='?src=[REF(src)];back=1'>Back</a> - <A href='?src=[REF(src)];refresh=1'>Refresh</a></center><hr>"
dat += {"<table border='1' width='100%'><tr><th width = '5%'>X</th><th width='15%'>Sending Dep.</th><th width='15%'>Receiving Dep.</th>
<th width='300px' word-wrap: break-word>Message</th><th width='15%'>Stamp</th><th width='15%'>ID Auth.</th><th width='15%'>Priority.</th></tr>"}
for(var/datum/data_rc_msg/rc in linkedServer.rc_msgs)
index++
if(index > 3000)
break
// Del - Sender - Recepient - Message
// X - Al Green - Your Mom - WHAT UP!?
dat += {"<tr><td width = '5%'><center><A href='?src=[REF(src)];delete_requests=[REF(rc)]' style='color: rgb(255,0,0)'>X</a></center></td><td width='15%'>[rc.send_dpt]</td>
<td width='15%'>[rc.rec_dpt]</td><td width='300px'>[rc.message]</td><td width='15%'>[rc.stamp]</td><td width='15%'>[rc.id_auth]</td><td width='15%'>[rc.priority]</td></tr>"}
dat += "</table>"
message = defaultmsg
var/datum/browser/popup = new(user, "hologram_console", name, 700, 700)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/message_monitor/proc/BruteForce(mob/user)
if(isnull(linkedServer))
to_chat(user, "<span class='warning'>Could not complete brute-force: Linked Server Disconnected!</span>")
@@ -245,10 +364,11 @@
var/currentKey = linkedServer.decryptkey
to_chat(user, "<span class='warning'>Brute-force completed! The key is '[currentKey]'.</span>")
hacking = FALSE
screen = 0 // Return the screen back to normal
message = ""
/obj/machinery/computer/message_monitor/proc/UnmagConsole()
obj_flags &= ~EMAGGED
DISABLE_BITFIELD(obj_flags, EMAGGED)
message = ""
/obj/machinery/computer/message_monitor/proc/ResetMessage()
customsender = "System Administrator"
@@ -256,199 +376,12 @@
custommessage = "This is a test, please ignore."
customjob = "Admin"
/obj/machinery/computer/message_monitor/Topic(href, href_list)
if(..())
return
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || hasSiliconAccessInArea(usr))
//Authenticate
if (href_list["auth"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
auth = FALSE
screen = 0
else
var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null)
if(dkey && dkey != "")
if(linkedServer.decryptkey == dkey)
auth = TRUE
else
message = incorrectkey
//Turn the server on/off.
if (href_list["active"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
linkedServer.toggled = !linkedServer.toggled
//Find a server
if (href_list["find"])
var/list/message_servers = list()
for (var/obj/machinery/telecomms/message_server/M in GLOB.telecomms_list)
message_servers += M
if(message_servers.len > 1)
linkedServer = input(usr, "Please select a server.", "Select a server.", null) as null|anything in message_servers
message = "<span class='alert'>NOTICE: Server selected.</span>"
else if(message_servers.len > 0)
linkedServer = message_servers[1]
message = "<span class='notice'>NOTICE: Only Single Server Detected - Server selected.</span>"
else
message = noserver
//View the logs - KEY REQUIRED
if (href_list["view_logs"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
screen = 1
//Clears the logs - KEY REQUIRED
if (href_list["clear_logs"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
linkedServer.pda_msgs = list()
message = "<span class='notice'>NOTICE: Logs cleared.</span>"
//Clears the request console logs - KEY REQUIRED
if (href_list["clear_requests"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
linkedServer.rc_msgs = list()
message = "<span class='notice'>NOTICE: Logs cleared.</span>"
//Change the password - KEY REQUIRED
if (href_list["pass"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
var/dkey = stripped_input(usr, "Please enter the decryption key.")
if(dkey && dkey != "")
if(linkedServer.decryptkey == dkey)
var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):"))
if(length(newkey) <= 3)
message = "<span class='notice'>NOTICE: Decryption key too short!</span>"
else if(length(newkey) > 16)
message = "<span class='notice'>NOTICE: Decryption key too long!</span>"
else if(newkey && newkey != "")
linkedServer.decryptkey = newkey
message = "<span class='notice'>NOTICE: Decryption key set.</span>"
else
message = incorrectkey
//Hack the Console to get the password
if (href_list["hack"])
var/mob/living/silicon/S = usr
if(istype(S) && S.hack_software)
hacking = TRUE
screen = 2
//Time it takes to bruteforce is dependant on the password length.
spawn(100*length(linkedServer.decryptkey))
if(src && linkedServer && usr)
BruteForce(usr)
//Delete the log.
if (href_list["delete_logs"])
//Are they on the view logs screen?
if(screen == 1)
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else //if(istype(href_list["delete_logs"], /datum/data_pda_msg))
linkedServer.pda_msgs -= locate(href_list["delete_logs"])
message = "<span class='notice'>NOTICE: Log Deleted!</span>"
//Delete the request console log.
if (href_list["delete_requests"])
//Are they on the view logs screen?
if(screen == 4)
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else //if(istype(href_list["delete_logs"], /datum/data_pda_msg))
linkedServer.rc_msgs -= locate(href_list["delete_requests"])
message = "<span class='notice'>NOTICE: Log Deleted!</span>"
//Create a custom message
if (href_list["msg"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
screen = 3
//Fake messaging selection - KEY REQUIRED
if (href_list["select"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
screen = 0
else
switch(href_list["select"])
//Reset
if("Reset")
ResetMessage()
//Select Your Name
if("Sender")
customsender = stripped_input(usr, "Please enter the sender's name.") || customsender
//Select Receiver
if("Recepient")
//Get out list of viable PDAs
var/list/obj/item/pda/sendPDAs = get_viewable_pdas()
if(GLOB.PDAs && GLOB.PDAs.len > 0)
customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortNames(sendPDAs)
else
customrecepient = null
//Enter custom job
if("RecJob")
customjob = stripped_input(usr, "Please enter the sender's job.") || customjob
//Enter message
if("Message")
custommessage = stripped_input(usr, "Please enter your message.") || custommessage
//Send message
if("Send")
if(isnull(customsender) || customsender == "")
customsender = "UNKNOWN"
if(isnull(customrecepient))
message = "<span class='notice'>NOTICE: No recepient selected!</span>"
return attack_hand(usr)
if(isnull(custommessage) || custommessage == "")
message = "<span class='notice'>NOTICE: No message entered!</span>"
return attack_hand(usr)
var/datum/signal/subspace/pda/signal = new(src, list(
"name" = "[customsender]",
"job" = "[customjob]",
"message" = custommessage,
"emojis" = TRUE,
"targets" = list("[customrecepient.owner] ([customrecepient.ownjob])")
))
// this will log the signal and transmit it to the target
linkedServer.receive_information(signal, null)
usr.log_message("(PDA: [name] | [usr.real_name]) sent \"[custommessage]\" to [signal.format_target()]", LOG_PDA)
//Request Console Logs - KEY REQUIRED
if(href_list["view_requests"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
screen = 4
if (href_list["back"])
screen = 0
return attack_hand(usr)
#undef LINKED_SERVER_NONRESPONSIVE
/obj/item/paper/monitorkey
name = "monitor decryption key"
/obj/item/paper/monitorkey/Initialize(mapload, obj/machinery/telecomms/message_server/server)
..()
if (server)
if(server)
print(server)
return INITIALIZE_HINT_NORMAL
else
@@ -460,7 +393,7 @@
add_overlay("paper_words")
/obj/item/paper/monitorkey/LateInitialize()
for (var/obj/machinery/telecomms/message_server/server in GLOB.telecomms_list)
if (server.decryptkey)
for(var/obj/machinery/telecomms/message_server/server in GLOB.telecomms_list)
if(server.decryptkey)
print(server)
break
@@ -1,4 +1,3 @@
/*
Telecomms monitor tracks the overall trafficing of a telecommunications network
and displays a heirarchy of linked machines.
@@ -10,117 +9,98 @@
icon_screen = "comm_monitor"
desc = "Monitors the details of the telecommunications network it's synced with."
var/screen = 0 // the screen number:
var/list/machinelist = list() // the machines located by the computer
var/obj/machinery/telecomms/SelectedMachine
var/obj/machinery/telecomms/SelectedMachine = null
var/network = "NULL" // the network to probe
var/notice = ""
var/temp = "" // temporary feedback messages
circuit = /obj/item/circuitboard/computer/comm_monitor
/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user)
. = ..()
var/dat = "<TITLE>Telecommunications Monitor</TITLE><center><b>Telecommunications Monitor</b></center>"
/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)
switch(screen)
if(!ui)
ui = new(user, src, ui_key, "telemonitor", name, 575, 400, master_ui, state)
ui.open()
/obj/machinery/computer/telecomms/monitor/ui_data(mob/user)
var/list/data_out = list()
data_out["network"] = network
data_out["notice"] = notice
// --- Main Menu ---
data_out["servers"] = list()
for(var/obj/machinery/telecomms/T in machinelist)
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
data_out["servers"] += list(data)
data_out["servers"] = sortList(data_out["servers"])
if(0)
dat += "<br>[temp]<br><br>"
dat += "<br>Current Network: <a href='?src=[REF(src)];network=1'>[network]</a><br>"
if(machinelist.len)
dat += "<br>Detected Network Entities:<ul>"
for(var/obj/machinery/telecomms/T in machinelist)
dat += "<li><a href='?src=[REF(src)];viewmachine=[T.id]'>[REF(T)] [T.name]</a> ([T.id])</li>"
dat += "</ul>"
dat += "<br><a href='?src=[REF(src)];operation=release'>\[Flush Buffer\]</a>"
else
dat += "<a href='?src=[REF(src)];operation=probe'>\[Probe Network\]</a>"
if(!SelectedMachine) //null is bad.
data_out["selected"] = null //but in js, null is good.
return data_out
data_out["selected"] = list(
name = SelectedMachine.name,
id = SelectedMachine.id,
status = SelectedMachine.on,
traffic = SelectedMachine.traffic,
netspeed = SelectedMachine.netspeed,
freq_listening = SelectedMachine.freq_listening,
long_range_link = SelectedMachine.long_range_link,
ref = REF(SelectedMachine)
)
data_out["selected_servers"] = list()
for(var/obj/machinery/telecomms/T in SelectedMachine.links)
if(!T.hide)
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
data_out["selected_servers"] += list(data)
return data_out
// --- Viewing Machine ---
if(1)
dat += "<br>[temp]<br>"
dat += "<center><a href='?src=[REF(src)];operation=mainmenu'>\[Main Menu\]</a></center>"
dat += "<br>Current Network: [network]<br>"
dat += "Selected Network Entity: [SelectedMachine.name] ([SelectedMachine.id])<br>"
dat += "Linked Entities: <ol>"
for(var/obj/machinery/telecomms/T in SelectedMachine.links)
if(!T.hide)
dat += "<li><a href='?src=[REF(src)];viewmachine=[T.id]'>[REF(T.id)] [T.name]</a> ([T.id])</li>"
dat += "</ol>"
user << browse(dat, "window=comm_monitor;size=575x400")
onclose(user, "server_control")
temp = ""
return
/obj/machinery/computer/telecomms/monitor/Topic(href, href_list)
/obj/machinery/computer/telecomms/monitor/ui_act(action, params)
if(..())
return
switch(action)
if("mainmenu")
SelectedMachine = null
notice = ""
return
if("release")
machinelist = list()
notice = ""
return
if("network") //network change, flush the selected machine and buffer
var/newnet = sanitize(sanitize_text(params["value"], network))
if(length(newnet) > 15) //i'm looking at you, you href fuckers
notice = "FAILED: Network tag string too lengthy"
return
network = newnet
SelectedMachine = null
machinelist = list()
return
if("probe")
if(LAZYLEN(machinelist) > 0)
notice = "FAILED: Cannot probe when buffer full"
return
for(var/obj/machinery/telecomms/T in GLOB.telecomms_list)
if(T.network == network)
LAZYADD(machinelist, T)
add_fingerprint(usr)
usr.set_machine(src)
if(href_list["viewmachine"])
screen = 1
for(var/obj/machinery/telecomms/T in machinelist)
if(T.id == href_list["viewmachine"])
SelectedMachine = T
break
if(href_list["operation"])
switch(href_list["operation"])
if("release")
machinelist = list()
screen = 0
if("mainmenu")
screen = 0
if("probe")
if(machinelist.len > 0)
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font color>"
else
for(var/obj/machinery/telecomms/T in urange(25, src))
if(T.network == network)
machinelist.Add(T)
if(!machinelist.len)
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\] -</font color>"
else
temp = "<font color = #336699>- [machinelist.len] ENTITIES LOCATED & BUFFERED -</font color>"
screen = 0
if(href_list["network"])
var/newnet = stripped_input(usr, "Which network do you want to view?", "Comm Monitor", network)
if(newnet && ((usr in range(1, src)) || hasSiliconAccessInArea(usr)))
if(length(newnet) > 15)
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LENGHTLY -</font color>"
else
network = newnet
screen = 0
machinelist = list()
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font color>"
updateUsrDialog()
return
/obj/machinery/computer/telecomms/monitor/attackby()
. = ..()
updateUsrDialog()
if(!LAZYLEN(machinelist))
notice = "FAILED: Unable to locate network entities in \[[network]\]"
return
if("viewmachine")
for(var/obj/machinery/telecomms/T in machinelist)
if(T.id == params["value"])
SelectedMachine = T
break
@@ -9,9 +9,9 @@
var/temp = "" // output message
/obj/machinery/telecomms/attackby(obj/item/P, mob/user, params)
var/icon_closed = initial(icon_state)
var/icon_open = "[initial(icon_state)]_o"
if(!on)
icon_closed = "[initial(icon_state)]_off"
icon_open = "[initial(icon_state)]_o_off"
@@ -27,78 +27,240 @@
else
return ..()
/obj/machinery/telecomms/ui_interact(mob/user)
. = ..()
// You need a multitool to use this, or be silicon
if(!hasSiliconAccessInArea(user))
// istype returns false if the value is null
if(!istype(user.get_active_held_item(), /obj/item/multitool))
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)
if(!canInteract(user))
if(ui)
ui.close() //haha no.
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "teleinteract", "[name] Access", 520, 500, master_ui, state)
ui.open()
/obj/machinery/telecomms/ui_data(mob/user)
. = list() //cpypaste from the vending bus
.["notice"] = temp
.["multitool"] = FALSE
var/obj/item/multitool/P = get_multitool(user)
var/dat
dat = "<font face = \"Courier\"><HEAD><TITLE>[name]</TITLE></HEAD><center><H3>[name] Access</H3></center>"
dat += "<br>[temp]<br>"
dat += "<br>Power Status: <a href='?src=[REF(src)];input=toggle'>[toggled ? "On" : "Off"]</a>"
if(on && toggled)
if(id != "" && id)
dat += "<br>Identification String: <a href='?src=[REF(src)];input=id'>[id]</a>"
else
dat += "<br>Identification String: <a href='?src=[REF(src)];input=id'>NULL</a>"
dat += "<br>Network: <a href='?src=[REF(src)];input=network'>[network]</a>"
dat += "<br>Prefabrication: [autolinkers.len ? "TRUE" : "FALSE"]"
if(hide)
dat += "<br>Shadow Link: ACTIVE</a>"
if(P)
.["multitool"] = TRUE
.["multitool_buf"] = null //to clean the list!
var/obj/machinery/telecomms/T = P.buffer
if(istype(T))
.["multitool_buf"] = list(
name = T.name,
id = T.id
)
//Show additional options for certain machines.
dat += Options_Menu()
.["machine"] = list()
.["machine"]["power"] = toggled
.["machine"]["id"] = id
.["machine"]["network"] = network
.["machine"]["prefab"] = LAZYLEN(autolinkers) ? TRUE : FALSE
.["machine"]["hidden"] = hide
dat += "<br>Linked Network Entities: <ol>"
.["links"] = list()
for(var/obj/machinery/telecomms/T in links)
if(T.hide && !hide)
continue
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
.["links"] += list(data)
var/i = 0
for(var/obj/machinery/telecomms/T in links)
i++
if(T.hide && !hide)
continue
dat += "<li>[REF(T)] [T.name] ([T.id]) <a href='?src=[REF(src)];unlink=[i]'>\[X\]</a></li>"
dat += "</ol>"
.["freq_listening"] = freq_listening
dat += "<br>Filtering Frequencies: "
/obj/machinery/telecomms/relay/ui_data(mob/user)
. = ..()
.["machine"]["isrelay"] = TRUE
.["machine"]["broadcast"] = broadcasting
.["machine"]["receiving"] = receiving
i = 0
if(length(freq_listening))
for(var/x in freq_listening)
i++
if(i < length(freq_listening))
dat += "[format_frequency(x)] GHz<a href='?src=[REF(src)];delete=[x]'>\[X\]</a>; "
else
dat += "[format_frequency(x)] GHz<a href='?src=[REF(src)];delete=[x]'>\[X\]</a>"
else
dat += "NONE"
/obj/machinery/telecomms/bus/ui_data(mob/user)
. = ..()
.["machine"]["isbus"] = TRUE
.["machine"]["chang_frequency"] = change_frequency
.["machine"]["chang_freq_value"] = change_freq_value
dat += "<br> <a href='?src=[REF(src)];input=freq'>\[Add Filter\]</a>"
dat += "<hr>"
if(P)
var/obj/machinery/telecomms/T = P.buffer
if(istype(T))
dat += "<br><br>MULTITOOL BUFFER: [T] ([T.id]) <a href='?src=[REF(src)];link=1'>\[Link\]</a> <a href='?src=[REF(src)];flush=1'>\[Flush\]"
else
dat += "<br><br>MULTITOOL BUFFER: <a href='?src=[REF(src)];buffer=1'>\[Add Machine\]</a>"
dat += "</font>"
/obj/machinery/telecomms/ui_act(action, params, datum/tgui/ui)
if(!canInteract(usr))
if(ui)
ui.close() //haha no.
return
temp = ""
user << browse(dat, "window=tcommachine;size=520x500;can_resize=0")
onclose(user, "tcommachine")
return TRUE
switch(action)
if("toggle")
toggled = !toggled
temp = "-% [src.name] has been [toggled ? "activated" : "deactivated"]. %-"
update_power()
return
if("machine")
if("id" in params)
if(!canAccess(usr))
return
//if the text is blank, return the id it was using
var/newid = sanitize_text(reject_bad_text(params["id"]), id) // reject_bad_text can return null!
if(length(newid) > 255)
temp = "-% Too many characters in new id tag. %-"
return
temp = "-% New ID assigned: \"[newid]\". %-"
id = newid
return
if("network" in params)
if(!canAccess(usr))
return
var/newnet = sanitize(sanitize_text(params["network"], network))
if(length(newnet) > 15)
temp = "-% Too many characters in new network tag. %-"
return
network = newnet
links = list()
temp = "-% New network tag assigned: \"[network]\" %-"
return
if("multitool")
var/obj/item/multitool/P = get_multitool(usr)
if("Link" in params)
if(!canAccess(usr))
return
if(!istype(P))
temp = "-% Unable to acquire buffer %-"
return
var/obj/machinery/telecomms/T = P.buffer
if(!istype(T) || T == src)
temp = "-% Unable to acquire buffer %-"
return
if(!(src in T.links))
LAZYADD(T.links, src)
if(!(T in links))
LAZYADD(links, T)
temp = "-% Successfully linked with [REF(T)] [T.name] %-"
if("Flush" in params)
if(!istype(P))
temp = "-% Unable to acquire multitool %-"
return
temp = "-% Buffer successfully flushed. %-"
P.buffer = null
if("Add" in params)
if(!canAccess(usr))
return
if(!istype(P))
temp = "-% Unable to acquire multitool %-"
return
P.buffer = src
temp = "% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-"
if("unlink")
var/obj/machinery/telecomms/T = locate(params["value"])
if(!canAccess(usr))
return
if(!istype(T))
temp = "-% Unable to locate machine to unlink from, try again. %-"
return
temp = "-% Removed [REF(T)] [T.name] from linked entities. %-"
if(T.links) //lazyrem makes blank list null, which is good but some might cause runtime ee's
T.links.Remove(src)
links.Remove(T)
if("freq")
if("add" in params)
var/newfreq = input("Specify a new frequency to filter (GHz). Decimals assigned automatically.", src.name, null) as null|num
if(!canAccess(usr) || !newfreq || isnull(newfreq))
return
if(findtext(num2text(newfreq), ".")) // did they not read the text?
newfreq *= 10 // shift the decimal one place
newfreq = sanitize_frequency(newfreq, TRUE) //sanitize
if(newfreq == FREQ_SYNDICATE)
temp = "-% Error: Interference preventing filtering frequency: \"[newfreq] GHz\" %-"
return
if(newfreq in freq_listening)
temp = "-% Error: Frequency already filtered %-"
return
LAZYADD(freq_listening, newfreq)
temp = "-% New frequency filter assigned: \"[newfreq] GHz\" %-"
if("remove" in params)
if(!canAccess(usr))
return
var/x = text2num(params["remove"])
temp = "-% Removed frequency filter [x] %-"
freq_listening.Remove(x)
/obj/machinery/telecomms/relay/ui_act(action, params)
..()
switch(action)
if("relay")
if("broadcast" in params)
if(!canAccess(usr))
return
broadcasting = !broadcasting
temp = "-% Broadcasting mode changed. %-"
return
if("receiving" in params)
if(!canAccess(usr))
return
receiving = !receiving
temp = "-% Receiving mode changed. %-"
/obj/machinery/telecomms/bus/ui_act(action, params)
..()
switch(action)
if("frequency")
if("toggle" in params)
if(!canAccess(usr))
return
change_frequency = !change_frequency
return
if("adjust" in params)
var/newfreq = text2num(params["adjust"])
if(!canAccess(usr) || !newfreq)
return
// this should return true, unless the href is handcrafted
if(findtext(num2text(newfreq), "."))
newfreq *= 10 // shift the decimal one place
newfreq = sanitize_frequency(newfreq, TRUE)
if(newfreq == FREQ_SYNDICATE)
temp = "-% Error: Interference preventing filtering frequency: \"[newfreq] GHz\" %-"
return
change_freq_value = newfreq
temp = "-% New frequency to change to assigned: \"[newfreq] GHz\" %-"
return
// Check if the user can use it.
/obj/machinery/telecomms/proc/canInteract(mob/user)
if(hasSiliconAccessInArea(user) || istype(user.get_active_held_item(), /obj/item/multitool))
return TRUE
return FALSE
// Check if the user is nearby and has a multitool.
/obj/machinery/telecomms/proc/canAccess(mob/user)
if((canInteract(user) && in_range(user, src)) || hasSiliconAccessInArea(user))
return TRUE
return FALSE
// Returns a multitool from a user depending on their mobtype.
/obj/machinery/telecomms/proc/get_multitool(mob/user)
var/obj/item/multitool/P = null
// Let's double check
if(!hasSiliconAccessInArea(user) && istype(user.get_active_held_item(), /obj/item/multitool))
P = user.get_active_held_item()
if(!canInteract(user))
return null
var/obj/item/multitool/P = user.get_active_held_item()
// Is the ref not a null? and is it the actual type?
if(istype(P))
return P
else if(isAI(user))
var/mob/living/silicon/ai/U = user
P = U.aiMulti
@@ -106,170 +268,3 @@
if(istype(user.get_active_held_item(), /obj/item/multitool))
P = user.get_active_held_item()
return P
// Additional Options for certain machines. Use this when you want to add an option to a specific machine.
// Example of how to use below.
/obj/machinery/telecomms/proc/Options_Menu()
return ""
// The topic for Additional Options. Use this for checking href links for your specific option.
// Example of how to use below.
/obj/machinery/telecomms/proc/Options_Topic(href, href_list)
return
// RELAY
/obj/machinery/telecomms/relay/Options_Menu()
var/dat = ""
dat += "<br>Broadcasting: <A href='?src=[REF(src)];broadcast=1'>[broadcasting ? "YES" : "NO"]</a>"
dat += "<br>Receiving: <A href='?src=[REF(src)];receive=1'>[receiving ? "YES" : "NO"]</a>"
return dat
/obj/machinery/telecomms/relay/Options_Topic(href, href_list)
if(href_list["receive"])
receiving = !receiving
temp = "<font color = #666633>-% Receiving mode changed. %-</font color>"
if(href_list["broadcast"])
broadcasting = !broadcasting
temp = "<font color = #666633>-% Broadcasting mode changed. %-</font color>"
// BUS
/obj/machinery/telecomms/bus/Options_Menu()
var/dat = "<br>Change Signal Frequency: <A href='?src=[REF(src)];change_freq=1'>[change_frequency ? "YES ([change_frequency])" : "NO"]</a>"
return dat
/obj/machinery/telecomms/bus/Options_Topic(href, href_list)
if(href_list["change_freq"])
var/newfreq = input(usr, "Specify a new frequency for new signals to change to. Enter null to turn off frequency changing. Decimals assigned automatically.", src, network) as null|num
if(canAccess(usr))
if(newfreq)
if(findtext(num2text(newfreq), "."))
newfreq *= 10 // shift the decimal one place
if(newfreq < 10000)
change_frequency = newfreq
temp = "<font color = #666633>-% New frequency to change to assigned: \"[newfreq] GHz\" %-</font color>"
else
change_frequency = 0
temp = "<font color = #666633>-% Frequency changing deactivated %-</font color>"
/obj/machinery/telecomms/Topic(href, href_list)
if(..())
return
if(!hasSiliconAccessInArea(usr))
if(!istype(usr.get_active_held_item(), /obj/item/multitool))
return
var/obj/item/multitool/P = get_multitool(usr)
if(href_list["input"])
switch(href_list["input"])
if("toggle")
toggled = !toggled
temp = "<font color = #666633>-% [src] has been [toggled ? "activated" : "deactivated"].</font color>"
update_power()
if("id")
var/newid = reject_bad_text(stripped_input(usr, "Specify the new ID for this machine", src, id, MAX_MESSAGE_LEN))
if(newid && canAccess(usr))
id = newid
temp = "<font color = #666633>-% New ID assigned: \"[id]\" %-</font color>"
if("network")
var/newnet = stripped_input(usr, "Specify the new network for this machine. This will break all current links.", src, network)
if(newnet && canAccess(usr))
if(length(newnet) > 15)
temp = "<font color = #666633>-% Too many characters in new network tag %-</font color>"
else
for(var/obj/machinery/telecomms/T in links)
T.links.Remove(src)
network = newnet
links = list()
temp = "<font color = #666633>-% New network tag assigned: \"[network]\" %-</font color>"
if("freq")
var/newfreq = input(usr, "Specify a new frequency to filter (GHz). Decimals assigned automatically.", src, network) as null|num
if(newfreq && canAccess(usr))
if(findtext(num2text(newfreq), "."))
newfreq *= 10 // shift the decimal one place
if(newfreq == FREQ_SYNDICATE)
temp = "<font color = #FF0000>-% Error: Interference preventing filtering frequency: \"[newfreq] GHz\" %-</font color>"
else
if(!(newfreq in freq_listening) && newfreq < 10000)
freq_listening.Add(newfreq)
temp = "<font color = #666633>-% New frequency filter assigned: \"[newfreq] GHz\" %-</font color>"
if(href_list["delete"])
// changed the layout about to workaround a pesky runtime -- Doohl
var/x = text2num(href_list["delete"])
temp = "<font color = #666633>-% Removed frequency filter [x] %-</font color>"
freq_listening.Remove(x)
if(href_list["unlink"])
if(text2num(href_list["unlink"]) <= length(links))
var/obj/machinery/telecomms/T = links[text2num(href_list["unlink"])]
if(T)
temp = "<font color = #666633>-% Removed [REF(T)] [T.name] from linked entities. %-</font color>"
// Remove link entries from both T and src.
if(T.links)
T.links.Remove(src)
links.Remove(T)
else
temp = "<font color = #666633>-% Unable to locate machine to unlink from, try again. %-</font color>"
if(href_list["link"])
if(P)
var/obj/machinery/telecomms/T = P.buffer
if(istype(T) && T != src)
if(!(src in T.links))
T.links += src
if(!(T in links))
links += T
temp = "<font color = #666633>-% Successfully linked with [REF(T)] [T.name] %-</font color>"
else
temp = "<font color = #666633>-% Unable to acquire buffer %-</font color>"
if(href_list["buffer"])
P.buffer = src
temp = "<font color = #666633>-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-</font color>"
if(href_list["flush"])
temp = "<font color = #666633>-% Buffer successfully flushed. %-</font color>"
P.buffer = null
Options_Topic(href, href_list)
usr.set_machine(src)
updateUsrDialog()
/obj/machinery/telecomms/proc/canAccess(mob/user)
if(hasSiliconAccessInArea(user) || in_range(user, src))
return TRUE
return FALSE
@@ -17,7 +17,8 @@
idle_power_usage = 50
netspeed = 40
circuit = /obj/item/circuitboard/machine/telecomms/bus
var/change_frequency = 0
var/change_frequency = FALSE
var/change_freq_value = 0
/obj/machinery/telecomms/bus/RefreshParts()
idle_power_usage = 50
@@ -28,8 +29,8 @@
if(!istype(signal) || !is_freq_listening(signal))
return
if(change_frequency && signal.frequency != FREQ_SYNDICATE)
signal.frequency = change_frequency
if(change_frequency && (change_freq_value && signal.frequency != FREQ_SYNDICATE))
signal.frequency = change_freq_value
if(!istype(machine_from, /obj/machinery/telecomms/processor) && machine_from != src) // Signal must be ready (stupid assuming machine), let's send it
// send to one linked processor unit
@@ -140,11 +140,16 @@
..()
if(href_list["photo"])
var/mob/M = usr
M << browse_rsc(picture.picture_image, "pda_photo.png")
M << browse("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>PDA Photo</title></head>" \
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
+ "<img src='pda_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />" \
+ "</body></html>", "window=pdaphoto;size=[picture.psize_x]x[picture.psize_y];can-close=true")
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>"
var/datum/browser/popup = new(M, "pdaphoto", "PDA Photo", picture.psize_x, picture.psize_y)
popup.set_content(dat)
popup.open()
onclose(M, "pdaphoto")
/datum/data_rc_msg
@@ -33,7 +33,7 @@
totaltraffic += traffic // add current traffic to total traffic
// Delete particularly old logs
if (log_entries.len >= 400)
if(LAZYLEN(log_entries) >= 400) //[list].len is not safe
log_entries.Cut(1, 2)
var/datum/comm_log_entry/log = new
@@ -117,9 +117,9 @@ GLOBAL_LIST_EMPTY(telecomms_list)
icon_state = "[initial(icon_state)]_off"
/obj/machinery/telecomms/proc/update_power()
if(toggled)
if(stat & (BROKEN|NOPOWER|EMPED)) // if powered, on. if not powered, off. if too damaged, off
// if powered, on. if not powered, off. if too damaged, off
if(CHECK_BITFIELD(stat, (BROKEN | NOPOWER | EMPED)))
on = FALSE
else
on = TRUE
@@ -137,11 +137,11 @@ GLOBAL_LIST_EMPTY(telecomms_list)
/obj/machinery/telecomms/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
if(CHECK_BITFIELD(., EMP_PROTECT_SELF))
return
if(prob(100/severity))
if(!(stat & EMPED))
stat |= EMPED
var/duration = (300 * 10)/severity
if(prob(100 / severity))
if(!CHECK_BITFIELD(stat, EMPED))
ENABLE_BITFIELD(stat, EMPED)
var/duration = (300 * 10) / severity
spawn(rand(duration - 20, duration + 20)) // Takes a long time for the machines to reboot.
stat &= ~EMPED
DISABLE_BITFIELD(stat, EMPED)
+105 -14
View File
@@ -11,9 +11,6 @@
var/insisting = 0
/obj/machinery/wish_granter/attack_hand(mob/living/carbon/user)
. = ..()
if(.)
return
if(charges <= 0)
to_chat(user, "The Wish Granter lies silent.")
return
@@ -22,22 +19,116 @@
to_chat(user, "You feel a dark stirring inside of the Wish Granter, something you want nothing of. Your instincts are better than any man's.")
return
else if(is_special_character(user))
to_chat(user, "Even to a heart as dark as yours, you know nothing good will come of this. Something instinctual makes you pull away.")
else if (!insisting)
to_chat(user, "Your first touch makes the Wish Granter stir, listening to you. Are you really sure you want to do this?")
insisting++
else
to_chat(user, "You speak. [pick("I want the station to disappear","Humanity is corrupt, mankind must be destroyed","I want to be rich", "I want to rule the world","I want immortality.")]. The Wish Granter answers.")
to_chat(user, "Your head pounds for a moment, before your vision clears. You are the avatar of the Wish Granter, and your power is LIMITLESS! And it's all yours. You need to make sure no one can take it from you. No one can know, first.")
if(is_special_character(user))
to_chat(user, "You speak. [pick("I want power","Humanity is corrupt, mankind must be destroyed", "I want to rule the world","I want immortality")]. The Wish Granter answers.")
to_chat(user, "Your head pounds for a moment, before your vision clears. The Wish Granter, sensing the darkness in your heart, has given you limitless power, and it's all yours!")
user.dna.add_mutation(HULK)
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!
to_chat(user, "Things around you feel slower!")
charges--
insisting = FALSE
to_chat(user, "You have a very great feeling about this!")
else
to_chat(user, "The Wish Granter awaits your wish.")
var/wish = input("You want...","Wish") as null|anything in list("Power","Wealth","The Station To Disappear","To Kill","Nothing")
switch(wish)
if("Power") //Gives infinite power in exchange for infinite power going off in your face!
if(charges <= 0)
return
to_chat(user, "<B>Your wish is granted, but at a terrible cost...</B>")
to_chat(user, "The Wish Granter punishes you for your selfishness, warping itself into a delaminating supermatter shard!")
var/obj/item/stock_parts/cell/infinite/powah = new /obj/item/stock_parts/cell/infinite(get_turf(user))
if(user.put_in_hands(powah))
to_chat(user, "[powah] materializes into your hands!")
else
to_chat(user, "[powah] materializes onto the floor.")
var/obj/machinery/power/supermatter_crystal/powerwish = new /obj/machinery/power/supermatter_crystal(loc)
powerwish.damage = 700 //right at the emergency threshold
powerwish.produces_gas = FALSE
charges--
insisting = FALSE
if(!charges)
qdel(src)
if("Wealth") //Gives 1 million space bucks in exchange for being turned into gold!
if(charges <= 0)
return
to_chat(user, "<B>Your wish is granted, but at a cost...</B>")
to_chat(user, "The Wish Granter punishes you for your selfishness, warping your body to match the greed in your heart.")
new /obj/structure/closet/crate/trashcart/moneywish(loc)
new /obj/structure/closet/crate/trashcart/moneywish(loc)
user.set_species(/datum/species/golem/gold)
charges--
insisting = FALSE
if(!charges)
qdel(src)
if("The Station To Disappear") //teleports you to the station and makes you blind, making the station disappear for you!
if(charges <= 0)
return
to_chat(user, "<B>Your wish is 'granted', but at a terrible cost...</B>")
to_chat(user, "The Wish Granter punishes you for your selfishness, claiming your soul and warping your eyes to match the darkness in your heart.")
user.dna.add_mutation(BLINDMUT)
var/obj/item/organ/eyes/eyes = user.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
eyes.applyOrganDamage(eyes.maxHealth)
var/list/destinations = list()
for(var/obj/item/beacon/B in GLOB.teleportbeacons)
var/turf/T = get_turf(B)
if(is_station_level(T.z))
destinations += B
var/chosen_beacon = pick(destinations)
var/obj/effect/portal/jaunt_tunnel/J = new (get_turf(src), src, 100, null, FALSE, get_turf(chosen_beacon))
try_move_adjacent(J)
playsound(src,'sound/effects/sparks4.ogg',50,1)
charges--
insisting = FALSE
if(!charges)
qdel(src)
if("To Kill") //Makes you kill things in exchange for rewards!
if(charges <= 0)
return
to_chat(user, "<B>Your wish is granted, but at a terrible cost...</B>")
to_chat(user, "The Wish Granter punishes you for your wickedness, warping itself into a dastardly creature for you to kill! ...but it almost seems to reward you for this.")
var/obj/item/melee/transforming/energy/sword/cx/killreward = new /obj/item/melee/transforming/energy/sword/cx(get_turf(user))
if(user.put_in_hands(killreward))
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!
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/dualsaber/hypereutactic)
charges--
insisting = FALSE
if(!charges)
qdel(src)
if("Nothing") //Makes the wish granter disappear
if(charges <= 0)
return
to_chat(user, "<B>The Wish Granter vanishes from sight!</B>")
to_chat(user, "You feel as if you just narrowly avoided a terrible fate...")
charges--
insisting = FALSE
qdel(src)
charges--
insisting = 0
//ITEMS THAT IT USES
user.mind.add_antag_datum(/datum/antagonist/wishgranter)
/obj/structure/closet/crate/trashcart/moneywish
desc = "A heavy, metal trashcart with wheels. Filled with cash."
name = "loaded trash cart"
to_chat(user, "You have a very bad feeling about this.")
return
/obj/structure/closet/crate/trashcart/moneywish/PopulateContents() //25*20*1000=500,000
for(var/i in 1 to 25)
var/obj/item/stack/spacecash/c1000/lodsamoney = new /obj/item/stack/spacecash/c1000(src)
lodsamoney.amount = lodsamoney.max_amount
+12 -9
View File
@@ -62,18 +62,21 @@
/obj/mecha/combat/neovgre/process()
..()
if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hople to stop the superweapon
if(GLOB.ratvar_awakens) // At this point only timley intervention by lord singulo could hope to stop the superweapon
cell.charge = INFINITY
max_integrity = INFINITY
obj_integrity = max_integrity
CHECK_TICK //Just to be on the safe side lag wise
else if(cell.charge < cell.maxcharge)
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
var/delta = min(recharge_rate, cell.maxcharge - cell.charge)
if (get_clockwork_power() <= delta)
cell.charge += delta
adjust_clockwork_power(-delta)
CHECK_TICK
else
if(cell.charge < cell.maxcharge)
for(var/obj/effect/clockwork/sigil/transmission/T in range(SIGIL_ACCESS_RANGE, src))
var/delta = min(recharge_rate, cell.maxcharge - cell.charge)
if (get_clockwork_power() >= delta)
cell.charge += delta
adjust_clockwork_power(-delta)
if(obj_integrity < max_integrity && istype(loc, /turf/open/floor/clockwork))
obj_integrity += min(max_integrity - obj_integrity, max_integrity / 200)
CHECK_TICK
/obj/mecha/combat/neovgre/Initialize()
.=..()
@@ -90,7 +93,7 @@
energy_drain = 30
name = "Aribter 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"
fire_sound = 'sound/weapons/neovgre_laser.ogg'
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy/neovgre/can_attach(obj/mecha/combat/neovgre/M)
if(istype(M))
@@ -388,7 +388,7 @@
/obj/item/mecha_parts/mecha_equipment/generator/get_equip_info()
var/output = ..()
if(output)
return "[output] \[[fuel]: [round(fuel.amount*fuel.mats_per_stack,0.1)] cm<sup>3</sup>\] - <a href='?src=[REF(src)];toggle=1'>[equip_ready?"A":"Dea"]ctivate</a>"
return "[output] \[[fuel]: [round(fuel.amount*MINERAL_MATERIAL_AMOUNT,0.1)] cm<sup>3</sup>\] - <a href='?src=[REF(src)];toggle=1'>[equip_ready?"A":"Dea"]ctivate</a>"
/obj/item/mecha_parts/mecha_equipment/generator/action(target)
if(chassis)
@@ -398,9 +398,9 @@
/obj/item/mecha_parts/mecha_equipment/generator/proc/load_fuel(var/obj/item/stack/sheet/P)
if(P.type == fuel.type && P.amount > 0)
var/to_load = max(max_fuel - fuel.amount*fuel.mats_per_stack,0)
var/to_load = max(max_fuel - fuel.amount*MINERAL_MATERIAL_AMOUNT,0)
if(to_load)
var/units = min(max(round(to_load / P.mats_per_stack),1),P.amount)
var/units = min(max(round(to_load / MINERAL_MATERIAL_AMOUNT),1),P.amount)
fuel.amount += units
P.use(units)
occupant_message("[units] unit\s of [fuel] successfully loaded.")
@@ -454,7 +454,7 @@
if(cur_charge < chassis.cell.maxcharge)
use_fuel = fuel_per_cycle_active
chassis.give_power(power_per_cycle)
fuel.amount -= min(use_fuel/fuel.mats_per_stack,fuel.amount)
fuel.amount -= min(use_fuel/MINERAL_MATERIAL_AMOUNT,fuel.amount)
update_equip_info()
return 1
+1
View File
@@ -26,6 +26,7 @@
"Firefighter",
"Odysseus",
"Gygax",
"Medical-Spec Gygax",
"Durand",
"H.O.N.K",
"Phazon",
+7 -3
View File
@@ -23,11 +23,11 @@
layer = BELOW_MOB_LAYER//icon draw layer
infra_luminosity = 15 //byond implementation is bugged.
force = 5
flags_1 = HEAR_1
flags_1 = HEAR_1|BLOCK_FACE_ATOM_1
var/can_move = 0 //time of next allowed movement
var/mob/living/carbon/occupant = null
var/mob/living/occupant = null
var/step_in = 10 //make a step in step_in/10 sec.
var/dir_in = 2//What direction will the mech face when entered/powered on? Defaults to South.
var/dir_in = SOUTH //What direction will the mech face when entered/powered on? Defaults to South.
var/normal_step_energy_drain = 10 //How much energy the mech will consume each time it moves. This variable is a backup for when leg actuators affect the energy drain.
var/step_energy_drain = 10
var/melee_energy_drain = 15
@@ -495,6 +495,10 @@
occupant_message("<span class='warning'>Air port connection teared off!</span>")
mecha_log_message("Lost connection to gas port.")
/obj/mecha/setDir(newdir)
. = ..()
occupant?.setDir(newdir)
/obj/mecha/Process_Spacemove(var/movement_dir = 0)
. = ..()
if(.)
+315 -19
View File
@@ -5,44 +5,42 @@
var/base_icon
var/looky_helpy = TRUE
/datum/component/construction/mecha/examine(mob/user)
/datum/component/construction/mecha/examine(datum/source, mob/user, list/examine_list)
. = ..()
if(looky_helpy)
switch(steps[index]["key"])
if(TOOL_WRENCH)
. += "<span class='notice'>The mech could be <b>wrenched</b> into place.</span>"
examine_list += "<span class='notice'>The mech could be <b>wrenched</b> into place.</span>"
if(TOOL_SCREWDRIVER)
. += "<span class='notice'>The mech could be <b>screwed</b> into place.</span>"
examine_list += "<span class='notice'>The mech could be <b>screwed</b> into place.</span>"
if(TOOL_WIRECUTTER)
. += "<span class='notice'>The mech wires could be <b>trimmed</b> into place.</span>"
examine_list += "<span class='notice'>The mech wires could be <b>trimmed</b> into place.</span>"
if(/obj/item/stack/cable_coil)
. += "<span class='notice'>The mech could use some <b>wiring</b>.</span>"
examine_list += "<span class='notice'>The mech could use some <b>wiring</b>.</span>"
if(/obj/item/circuitboard)
. += "<span class='notice'>The mech could use a type of<b>circuitboard</b>.</span>"
examine_list += "<span class='notice'>The mech could use a type of<b>circuitboard</b>.</span>"
if(/obj/item/stock_parts/scanning_module)
. += "<span class='notice'>The mech could use a <b>scanning stock part</b>.</span>"
examine_list += "<span class='notice'>The mech could use a <b>scanning stock part</b>.</span>"
if(/obj/item/stock_parts/capacitor)
. += "<span class='notice'>The mech could use a <b>power based stock part</b>.</span>"
examine_list += "<span class='notice'>The mech could use a <b>power based stock part</b>.</span>"
if(/obj/item/stock_parts/cell)
. += "<span class='notice'>The mech could use a <b>power source</b>.</span>"
examine_list += "<span class='notice'>The mech could use a <b>power source</b>.</span>"
if(/obj/item/stack/sheet/metal)
. += "<span class='notice'>The mech could use some <b>sheets of metal</b>.</span>"
examine_list += "<span class='notice'>The mech could use some <b>sheets of metal</b>.</span>"
if(/obj/item/stack/sheet/plasteel)
. += "<span class='notice'>The mech could use some <b>sheets of strong steel</b>.</span>"
examine_list += "<span class='notice'>The mech could use some <b>sheets of strong steel</b>.</span>"
if(/obj/item/bikehorn)
. += "<span class='notice'>HONK IT!.</span>"
examine_list += "<span class='notice'>HONK IT!.</span>"
if(/obj/item/clothing/mask/gas/clown_hat)
. += "<span class='notice'>GIVE IT CLOWN MAKEUP HONK!.</span>"
examine_list += "<span class='notice'>GIVE IT CLOWN MAKEUP HONK!.</span>"
if(/obj/item/clothing/shoes/clown_shoes)
. += "<span class='notice'>GIVE IT GOOFY SHOES HONK HONK!.</span>"
examine_list += "<span class='notice'>GIVE IT GOOFY SHOES HONK HONK!.</span>"
if(/obj/item/mecha_parts/part)
. += "<span class='notice'>The mech could use a mech <b>part</b>.</span>"
examine_list += "<span class='notice'>The mech could use a mech <b>part</b>.</span>"
if(/obj/item/stack/ore/bluespace_crystal)
. += "<span class='notice'>The mech could use a <b>crystal</b> of sorts.</span>"
examine_list += "<span class='notice'>The mech could use a <b>crystal</b> of sorts.</span>"
if(/obj/item/assembly/signaler/anomaly)
. += "<span class='notice'>The mech could use a <b>anomaly</b> of sorts.</span>"
else
return
examine_list += "<span class='notice'>The mech could use a <b>anomaly</b> of sorts.</span>"
/datum/component/construction/mecha/spawn_result()
if(!result)
@@ -644,6 +642,304 @@
user.visible_message("[user] unfastens Gygax Armor Plates.", "<span class='notice'>You unfasten Gygax Armor Plates.</span>")
return TRUE
//Begin Medigax
/datum/component/construction/unordered/mecha_chassis/medigax
result = /datum/component/construction/mecha/medigax
steps = list(
/obj/item/mecha_parts/part/medigax_torso,
/obj/item/mecha_parts/part/medigax_left_arm,
/obj/item/mecha_parts/part/medigax_right_arm,
/obj/item/mecha_parts/part/medigax_left_leg,
/obj/item/mecha_parts/part/medigax_right_leg,
/obj/item/mecha_parts/part/medigax_head
)
/datum/component/construction/mecha/medigax
result = /obj/mecha/medical/medigax
base_icon = "medigax"
steps = list(
//1
list(
"key" = TOOL_WRENCH,
"desc" = "The hydraulic systems are disconnected."
),
//2
list(
"key" = TOOL_SCREWDRIVER,
"back_key" = TOOL_WRENCH,
"desc" = "The hydraulic systems are connected."
),
//3
list(
"key" = /obj/item/stack/cable_coil,
"amount" = 5,
"back_key" = TOOL_SCREWDRIVER,
"desc" = "The hydraulic systems are active."
),
//4
list(
"key" = TOOL_WIRECUTTER,
"back_key" = TOOL_SCREWDRIVER,
"desc" = "The wiring is added."
),
//5
list(
"key" = /obj/item/circuitboard/mecha/gygax/main,
"action" = ITEM_DELETE,
"back_key" = TOOL_SCREWDRIVER,
"desc" = "The wiring is adjusted."
),
//6
list(
"key" = TOOL_SCREWDRIVER,
"back_key" = TOOL_CROWBAR,
"desc" = "Central control module is installed."
),
//7
list(
"key" = /obj/item/circuitboard/mecha/gygax/peripherals,
"action" = ITEM_DELETE,
"back_key" = TOOL_SCREWDRIVER,
"desc" = "Central control module is secured."
),
//8
list(
"key" = TOOL_SCREWDRIVER,
"back_key" = TOOL_CROWBAR,
"desc" = "Peripherals control module is installed."
),
//9
list(
"key" = /obj/item/circuitboard/mecha/gygax/targeting,
"action" = ITEM_DELETE,
"back_key" = TOOL_SCREWDRIVER,
"desc" = "Peripherals control module is secured."
),
//10
list(
"key" = TOOL_SCREWDRIVER,
"back_key" = TOOL_CROWBAR,
"desc" = "Weapon control module is installed."
),
//11
list(
"key" = /obj/item/stock_parts/scanning_module,
"action" = ITEM_MOVE_INSIDE,
"back_key" = TOOL_SCREWDRIVER,
"desc" = "Weapon control module is secured."
),
//12
list(
"key" = TOOL_SCREWDRIVER,
"back_key" = TOOL_CROWBAR,
"desc" = "Scanner module is installed."
),
//13
list(
"key" = /obj/item/stock_parts/capacitor,
"action" = ITEM_MOVE_INSIDE,
"back_key" = TOOL_SCREWDRIVER,
"desc" = "Scanner module is secured."
),
//14
list(
"key" = TOOL_SCREWDRIVER,
"back_key" = TOOL_CROWBAR,
"desc" = "Capacitor is installed."
),
//15
list(
"key" = /obj/item/stock_parts/cell,
"action" = ITEM_MOVE_INSIDE,
"back_key" = TOOL_SCREWDRIVER,
"desc" = "Capacitor is secured."
),
//16
list(
"key" = TOOL_SCREWDRIVER,
"back_key" = TOOL_CROWBAR,
"desc" = "The power cell is installed."
),
//17
list(
"key" = /obj/item/stack/sheet/metal,
"amount" = 5,
"back_key" = TOOL_SCREWDRIVER,
"desc" = "The power cell is secured."
),
//18
list(
"key" = TOOL_WRENCH,
"back_key" = TOOL_CROWBAR,
"desc" = "Internal armor is installed."
),
//19
list(
"key" = TOOL_WELDER,
"back_key" = TOOL_WRENCH,
"desc" = "Internal armor is wrenched."
),
//20
list(
"key" = /obj/item/mecha_parts/part/medigax_armor,
"action" = ITEM_DELETE,
"back_key" = TOOL_WELDER,
"desc" = "Internal armor is welded."
),
//21
list(
"key" = TOOL_WRENCH,
"back_key" = TOOL_CROWBAR,
"desc" = "External armor is installed."
),
//22
list(
"key" = TOOL_WELDER,
"back_key" = TOOL_WRENCH,
"desc" = "External armor is wrenched."
),
)
/datum/component/construction/mecha/medigax/action(datum/source, atom/used_atom, mob/user)
return check_step(used_atom,user)
/datum/component/construction/mecha/medigax/custom_action(obj/item/I, mob/living/user, diff)
if(!..())
return FALSE
switch(index)
if(1)
user.visible_message("[user] connects [parent] hydraulic systems", "<span class='notice'>You connect [parent] hydraulic systems.</span>")
if(2)
if(diff==FORWARD)
user.visible_message("[user] activates [parent] hydraulic systems.", "<span class='notice'>You activate [parent] hydraulic systems.</span>")
else
user.visible_message("[user] disconnects [parent] hydraulic systems", "<span class='notice'>You disconnect [parent] hydraulic systems.</span>")
if(3)
if(diff==FORWARD)
user.visible_message("[user] adds the wiring to [parent].", "<span class='notice'>You add the wiring to [parent].</span>")
else
user.visible_message("[user] deactivates [parent] hydraulic systems.", "<span class='notice'>You deactivate [parent] hydraulic systems.</span>")
if(4)
if(diff==FORWARD)
user.visible_message("[user] adjusts the wiring of [parent].", "<span class='notice'>You adjust the wiring of [parent].</span>")
else
user.visible_message("[user] removes the wiring from [parent].", "<span class='notice'>You remove the wiring from [parent].</span>")
if(5)
if(diff==FORWARD)
user.visible_message("[user] installs [I] into [parent].", "<span class='notice'>You install [I] into [parent].</span>")
else
user.visible_message("[user] disconnects the wiring of [parent].", "<span class='notice'>You disconnect the wiring of [parent].</span>")
if(6)
if(diff==FORWARD)
user.visible_message("[user] secures the mainboard.", "<span class='notice'>You secure the mainboard.</span>")
else
user.visible_message("[user] removes the central control module from [parent].", "<span class='notice'>You remove the central computer mainboard from [parent].</span>")
if(7)
if(diff==FORWARD)
user.visible_message("[user] installs [I] into [parent].", "<span class='notice'>You install [I] into [parent].</span>")
else
user.visible_message("[user] unfastens the mainboard.", "<span class='notice'>You unfasten the mainboard.</span>")
if(8)
if(diff==FORWARD)
user.visible_message("[user] secures the peripherals control module.", "<span class='notice'>You secure the peripherals control module.</span>")
else
user.visible_message("[user] removes the peripherals control module from [parent].", "<span class='notice'>You remove the peripherals control module from [parent].</span>")
if(9)
if(diff==FORWARD)
user.visible_message("[user] installs [I] into [parent].", "<span class='notice'>You install [I] into [parent].</span>")
else
user.visible_message("[user] unfastens the peripherals control module.", "<span class='notice'>You unfasten the peripherals control module.</span>")
if(10)
if(diff==FORWARD)
user.visible_message("[user] secures the weapon control module.", "<span class='notice'>You secure the weapon control module.</span>")
else
user.visible_message("[user] removes the weapon control module from [parent].", "<span class='notice'>You remove the weapon control module from [parent].</span>")
if(11)
if(diff==FORWARD)
user.visible_message("[user] installs [I] to [parent].", "<span class='notice'>You install [I] to [parent].</span>")
else
user.visible_message("[user] unfastens the weapon control module.", "<span class='notice'>You unfasten the weapon control module.</span>")
if(12)
if(diff==FORWARD)
user.visible_message("[user] secures the scanner module.", "<span class='notice'>You secure the scanner module.</span>")
else
user.visible_message("[user] removes the scanner module from [parent].", "<span class='notice'>You remove the scanner module from [parent].</span>")
if(13)
if(diff==FORWARD)
user.visible_message("[user] installs [I] to [parent].", "<span class='notice'>You install [I] to [parent].</span>")
else
user.visible_message("[user] unfastens the scanner module.", "<span class='notice'>You unfasten the scanner module.</span>")
if(14)
if(diff==FORWARD)
user.visible_message("[user] secures the capacitor.", "<span class='notice'>You secure the capacitor.</span>")
else
user.visible_message("[user] removes the capacitor from [parent].", "<span class='notice'>You remove the capacitor from [parent].</span>")
if(15)
if(diff==FORWARD)
user.visible_message("[user] installs [I] into [parent].", "<span class='notice'>You install [I] into [parent].</span>")
else
user.visible_message("[user] unfastens the capacitor.", "<span class='notice'>You unfasten the capacitor.</span>")
if(16)
if(diff==FORWARD)
user.visible_message("[user] secures the power cell.", "<span class='notice'>You secure the power cell.</span>")
else
user.visible_message("[user] pries the power cell from [parent].", "<span class='notice'>You pry the power cell from [parent].</span>")
if(17)
if(diff==FORWARD)
user.visible_message("[user] installs the internal armor layer to [parent].", "<span class='notice'>You install the internal armor layer to [parent].</span>")
else
user.visible_message("[user] unfastens the power cell.", "<span class='notice'>You unfasten the power cell.</span>")
if(18)
if(diff==FORWARD)
user.visible_message("[user] secures the internal armor layer.", "<span class='notice'>You secure the internal armor layer.</span>")
else
user.visible_message("[user] pries internal armor layer from [parent].", "<span class='notice'>You pry internal armor layer from [parent].</span>")
if(19)
if(diff==FORWARD)
user.visible_message("[user] welds the internal armor layer to [parent].", "<span class='notice'>You weld the internal armor layer to [parent].</span>")
else
user.visible_message("[user] unfastens the internal armor layer.", "<span class='notice'>You unfasten the internal armor layer.</span>")
if(20)
if(diff==FORWARD)
user.visible_message("[user] installs [I] to [parent].", "<span class='notice'>You install [I] to [parent].</span>")
else
user.visible_message("[user] cuts the internal armor layer from [parent].", "<span class='notice'>You cut the internal armor layer from [parent].</span>")
if(21)
if(diff==FORWARD)
user.visible_message("[user] secures Gygax Armor Plates.", "<span class='notice'>You secure Medical Gygax Armor Plates.</span>")
else
user.visible_message("[user] pries Gygax Armor Plates from [parent].", "<span class='notice'>You pry Medical Gygax Armor Plates from [parent].</span>")
if(22)
if(diff==FORWARD)
user.visible_message("[user] welds Gygax Armor Plates to [parent].", "<span class='notice'>You weld Medical Gygax Armor Plates to [parent].</span>")
else
user.visible_message("[user] unfastens Gygax Armor Plates.", "<span class='notice'>You unfasten Medical Gygax Armor Plates.</span>")
return TRUE
// End Medigax
/datum/component/construction/unordered/mecha_chassis/firefighter
result = /datum/component/construction/mecha/firefighter
steps = list(
+3 -3
View File
@@ -77,7 +77,7 @@
/obj/mecha/attack_animal(mob/living/simple_animal/user)
mecha_log_message("Attack by simple animal. Attacker - [user].", color="red")
if(!user.melee_damage_upper && !user.obj_damage)
user.emote("custom", message = "[user.friendly] [src].")
user.emote("custom", message = "[user.friendly_verb_continuous] [src].")
return 0
else
var/play_soundeffect = 1
@@ -282,9 +282,9 @@
else
return ..()
/obj/mecha/attacked_by(obj/item/I, mob/living/user)
/obj/mecha/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
mecha_log_message("Attacked by [I]. Attacker - [user]")
..()
return ..()
/obj/mecha/proc/mech_toxin_damage(mob/living/target)
playsound(src, 'sound/effects/spray2.ogg', 50, 1)
+41
View File
@@ -129,6 +129,47 @@
desc = "A set of armor plates designed for the Gygax. Designed to effectively deflect damage with a lightweight construction."
icon_state = "gygax_armor"
///////// Medical Gygax
/obj/item/mecha_parts/chassis/medigax
name = "\improper Medical Gygax chassis"
construct_type = /datum/component/construction/unordered/mecha_chassis/medigax
/obj/item/mecha_parts/part/medigax_torso
name = "\improper Medical Gygax torso"
desc = "A torso part of Gygax. Contains power unit, processing core and life support systems."
icon_state = "medigax_harness"
/obj/item/mecha_parts/part/medigax_head
name = "\improper Medical Gygax head"
desc = "A Gygax head. Houses advanced surveillance and targeting sensors."
icon_state = "medigax_head"
/obj/item/mecha_parts/part/medigax_left_arm
name = "\improper Medical Gygax left arm"
desc = "A Gygax left arm. Data and power sockets are compatible with most exosuit tools and weapons."
icon_state = "medigax_l_arm"
/obj/item/mecha_parts/part/medigax_right_arm
name = "\improper Medical Gygax right arm"
desc = "A Gygax right arm. Data and power sockets are compatible with most exosuit tools and weapons."
icon_state = "medigax_r_arm"
/obj/item/mecha_parts/part/medigax_left_leg
name = "\improper Medical Gygax left leg"
desc = "A Gygax left leg. Constructed with advanced servomechanisms and actuators to enable faster speed."
icon_state = "medigax_l_leg"
/obj/item/mecha_parts/part/medigax_right_leg
name = "\improper Medical Gygax right leg"
desc = "A Gygax right leg. Constructed with advanced servomechanisms and actuators to enable faster speed."
icon_state = "medigax_r_leg"
/obj/item/mecha_parts/part/medigax_armor
gender = PLURAL
name = "\improper Medical Gygax armor plates"
desc = "A set of armor plates designed for the Gygax. Designed to effectively deflect damage with a lightweight construction."
icon_state = "medigax_armor"
//////////// Durand
+7 -4
View File
@@ -256,7 +256,7 @@
output_access_dialog(id_card, usr)
if(href_list["del_req_access"] && add_req_access)
operation_req_access -= text2num(href_list["add_req_access"])
operation_req_access -= text2num(href_list["del_req_access"])
output_access_dialog(id_card, usr)
if(href_list["finish_req_access"])
@@ -333,10 +333,13 @@
send_byjax(occupant,"exosuit.browser","t_port_connection","[internal_tank.connected_port?"Disconnect from":"Connect to"] gas port")
if(href_list["dna_lock"])
if(occupant && !iscarbon(occupant))
to_chat(occupant, "<span class='danger'> You do not have any DNA!</span>")
if(!occupant)
return
dna_lock = occupant.dna.unique_enzymes
var/mob/living/carbon/C = occupant
if(!istype(C) || !C.dna)
to_chat(C, "<span class='danger'> You do not have any DNA!</span>")
return
dna_lock = C.dna.unique_enzymes
occupant_message("You feel a prick as the needle takes your DNA sample.")
if(href_list["reset_dna"])
+18
View File
@@ -125,6 +125,24 @@
name = "\improper Dark Gygax wreckage"
icon_state = "darkgygax-broken"
/obj/structure/mecha_wreckage/medigax
name = "\improper Medical Gygax wreckage"
icon_state = "medigax-broken"
/obj/structure/mecha_wreckage/medigax/Initialize()
. = ..()
var/list/parts = list(/obj/item/mecha_parts/part/medigax_torso,
/obj/item/mecha_parts/part/medigax_head,
/obj/item/mecha_parts/part/medigax_left_arm,
/obj/item/mecha_parts/part/medigax_right_arm,
/obj/item/mecha_parts/part/medigax_left_leg,
/obj/item/mecha_parts/part/medigax_right_leg)
for(var/i = 0; i < 2; i++)
if(parts.len && prob(40))
var/part = pick(parts)
welder_salvage += part
parts -= part
/obj/structure/mecha_wreckage/marauder
name = "\improper Marauder wreckage"
icon_state = "marauder-broken"
+34
View File
@@ -0,0 +1,34 @@
/obj/mecha/medical/medigax
desc = "A Gygax with it's actuator overload stripped and a slick white paint scheme, for medical use, These exosuits are developed and produced by Vey-Med. (&copy; All rights reserved)."
name = "\improper Medical Gygax"
icon_state = "medigax"
step_in = 1.75 // a little faster than an odysseus
max_temperature = 25000
max_integrity = 250
wreckage = /obj/structure/mecha_wreckage/odysseus
armor = list("melee" = 25, "bullet" = 20, "laser" = 30, "energy" = 15, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
internal_damage_threshold = 35
deflect_chance = 15
step_energy_drain = 6
infra_luminosity = 6
/obj/mecha/medical/medigax/moved_inside(mob/living/carbon/human/H)
. = ..()
if(.)
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
hud.add_hud_to(H)
/obj/mecha/medical/medigax/go_out()
if(isliving(occupant))
var/mob/living/carbon/human/L = occupant
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
hud.remove_hud_from(L)
..()
/obj/mecha/medical/medigax/mmi_moved_inside(obj/item/mmi/mmi_as_oc, mob/user)
. = ..()
if(.)
var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
var/mob/living/brain/B = mmi_as_oc.brainmob
hud.add_hud_to(B)
+9
View File
@@ -49,7 +49,9 @@
var/original_name
desc = "A large piece of space-resistant printed paper."
icon = 'icons/obj/contraband.dmi'
plane = ABOVE_WALL_PLANE
anchored = TRUE
buildable_sign = FALSE //Cannot be unwrenched from a wall.
var/ruined = FALSE
var/random_basetype
var/never_random = FALSE // used for the 'random' subclasses.
@@ -68,6 +70,8 @@
name = "poster - [name]"
desc = "A large piece of space-resistant printed paper. [desc]"
addtimer(CALLBACK(src, /datum.proc/_AddElement, list(/datum/element/beauty, 300)), 0)
/obj/structure/sign/poster/proc/randomise(base_type)
var/list/poster_types = subtypesof(base_type)
var/list/approved_types = list()
@@ -424,6 +428,11 @@
desc = "A poster decipting a snake shaped into an ominous 'S'!"
icon_state = "poster47"
/obj/structure/sign/poster/contraband/bountyhunters
name = "Bounty Hunters"
desc = "A poster advertising bounty hunting services. \"I hear you got a problem.\""
icon_state = "poster48"
/obj/structure/sign/poster/official
poster_item_name = "motivational poster"
poster_item_desc = "An official Nanotrasen-issued poster to foster a compliant and obedient workforce. It comes with state-of-the-art adhesive backing, for easy pinning to any vertical surface."
@@ -5,6 +5,7 @@
var/blood_state = "" //I'm sorry but cleanable/blood code is ass, and so is blood_DNA
var/bloodiness = 0 //0-100, amount of blood in this decal, used for making footprints and affecting the alpha of bloody footprints
var/mergeable_decal = TRUE //when two of these are on a same tile or do we need to merge them into just one?
var/beauty = 0
/obj/effect/decal/cleanable/Initialize(mapload, list/datum/disease/diseases)
. = ..()
@@ -26,6 +27,8 @@
if(LAZYLEN(diseases_to_add))
AddComponent(/datum/component/infective, diseases_to_add)
addtimer(CALLBACK(src, /datum.proc/_AddElement, list(/datum/element/beauty, beauty)), 0)
/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C) // Returns true if we should give up in favor of the pre-existing decal
if(mergeable_decal)
qdel(C)
@@ -3,6 +3,7 @@
name = "xeno blood"
desc = "It's green and acidic. It looks like... <i>blood?</i>"
color = BLOOD_COLOR_XENO
beauty = -250
/obj/effect/decal/cleanable/blood/splatter/xeno
color = BLOOD_COLOR_XENO
@@ -7,6 +7,7 @@
blood_state = BLOOD_STATE_BLOOD
bloodiness = BLOOD_AMOUNT_PER_DECAL
color = BLOOD_COLOR_HUMAN //default so we don't have white splotches everywhere.
beauty = -100
/obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C)
if (C.blood_DNA)
@@ -45,12 +46,14 @@
icon_state = "tracks"
desc = "They look like tracks left by wheels."
random_icon_states = null
beauty = -50
/obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose
name = "blood"
icon_state = "ltrails_1"
desc = "Your instincts say you shouldn't be following these."
random_icon_states = null
beauty = -50
var/list/existing_dirs = list()
/obj/effect/decal/cleanable/trail_holder/update_icon()
@@ -88,7 +91,7 @@
var/mob/living/carbon/human/H = O
var/obj/item/clothing/shoes/S = H.shoes
if(S && S.bloody_shoes[blood_state])
if(color != bloodtype_to_color(S.last_bloodtype))
if(color != S.last_blood_color)
return
S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
shoe_types |= S.type
@@ -101,7 +104,7 @@
var/mob/living/carbon/human/H = O
var/obj/item/clothing/shoes/S = H.shoes
if(S && S.bloody_shoes[blood_state])
if(color != bloodtype_to_color(S.last_bloodtype))//last entry - we check its color
if(color != S.last_blood_color)//last entry - we check its color
return
S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
shoe_types |= S.type
@@ -3,6 +3,7 @@
desc = "Someone should clean that up."
icon = 'icons/obj/objects.dmi'
icon_state = "shards"
beauty = -50
/obj/effect/decal/cleanable/ash
name = "ashes"
@@ -10,6 +11,7 @@
icon = 'icons/obj/objects.dmi'
icon_state = "ash"
mergeable_decal = FALSE
beauty = -50
/obj/effect/decal/cleanable/ash/Initialize()
. = ..()
@@ -24,6 +26,7 @@
/obj/effect/decal/cleanable/ash/large
name = "large pile of ashes"
icon_state = "big_ash"
beauty = -100
/obj/effect/decal/cleanable/ash/large/Initialize()
. = ..()
@@ -34,6 +37,7 @@
desc = "Back to sand."
icon = 'icons/obj/shards.dmi'
icon_state = "tiny"
beauty = -100
/obj/effect/decal/cleanable/glass/Initialize()
. = ..()
@@ -52,6 +56,7 @@
canSmoothWith = list(/obj/effect/decal/cleanable/dirt, /turf/closed/wall, /obj/structure/falsewall)
smooth = SMOOTH_FALSE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
beauty = -75
/obj/effect/decal/cleanable/dirt/Initialize()
. = ..()
@@ -72,6 +77,10 @@
desc = "It's still good. Four second rule!"
icon_state = "flour"
/obj/effect/decal/cleanable/dirt/dust
name = "dust"
desc = "A thin layer of dust coating the floor."
/obj/effect/decal/cleanable/greenglow/ecto
name = "ectoplasmic puddle"
desc = "You know who to call."
@@ -80,8 +89,11 @@
/obj/effect/decal/cleanable/greenglow
name = "glowing goo"
desc = "Jeez. I hope that's not for lunch."
light_power = 1
light_range = 1
light_color = LIGHT_COLOR_GREEN
icon_state = "greenglow"
beauty = -300
/obj/effect/decal/cleanable/greenglow/Initialize(mapload)
. = ..()
@@ -97,6 +109,7 @@
layer = WALL_OBJ_LAYER
icon_state = "cobweb1"
resistance_flags = FLAMMABLE
beauty = -100
/obj/effect/decal/cleanable/cobweb/cobweb2
icon_state = "cobweb2"
@@ -108,10 +121,12 @@
icon = 'icons/effects/effects.dmi'
icon_state = "molten"
mergeable_decal = FALSE
beauty = -150
/obj/effect/decal/cleanable/molten_object/large
name = "big gooey grey mass"
icon_state = "big_molten"
beauty = -300
//Vomit (sorry)
/obj/effect/decal/cleanable/vomit
@@ -120,6 +135,7 @@
icon = 'icons/effects/blood.dmi'
icon_state = "vomit_1"
random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4")
beauty = -150
/obj/effect/decal/cleanable/vomit/attack_hand(mob/user)
. = ..()
@@ -152,6 +168,7 @@
gender = NEUTER
icon = 'icons/effects/tomatodecal.dmi'
random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3")
beauty = -100
/obj/effect/decal/cleanable/plant_smudge
name = "plant smudge"
@@ -10,6 +10,7 @@
blood_state = BLOOD_STATE_OIL
bloodiness = BLOOD_AMOUNT_PER_DECAL
mergeable_decal = FALSE
beauty = -50
/obj/effect/decal/cleanable/robot_debris/Initialize(mapload, list/datum/disease/diseases)
. = ..()
@@ -50,6 +51,7 @@
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
blood_state = BLOOD_STATE_OIL
bloodiness = BLOOD_AMOUNT_PER_DECAL
beauty = -100
/obj/effect/decal/cleanable/oil/Initialize()
. = ..()
@@ -58,6 +60,7 @@
/obj/effect/decal/cleanable/oil/streak
random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5")
beauty = -50
/obj/effect/decal/cleanable/oil/slippery
+1 -1
View File
@@ -3,7 +3,7 @@
desc = "Graffiti. Damn kids."
icon = 'icons/effects/crayondecal.dmi'
icon_state = "rune1"
plane = GAME_PLANE //makes the graffiti visible over a wall.
plane = ABOVE_WALL_PLANE //makes the graffiti visible over a wall.
gender = NEUTER
mergeable_decal = FALSE
var/do_icon_rotate = TRUE
+2 -1
View File
@@ -35,6 +35,7 @@
icon = 'icons/turf/decals.dmi'
icon_state = "warningline"
layer = TURF_DECAL_LAYER
plane = ABOVE_WALL_PLANE
/obj/effect/turf_decal/Initialize()
..()
@@ -45,4 +46,4 @@
var/turf/T = loc
if(!istype(T)) //you know this will happen somehow
CRASH("Turf decal initialized in an object/nullspace")
T.AddComponent(/datum/component/decal, icon, icon_state, dir, CLEAN_GOD, color, null, null, alpha)
T.AddElement(/datum/element/decal, icon, icon_state, turn(dir, -dir2angle(T.dir)), CLEAN_GOD, color, null, null, alpha)
+1
View File
@@ -469,6 +469,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
/obj/effect/landmark/stationroom
var/list/templates = list()
layer = BULLET_HOLE_LAYER
plane = ABOVE_WALL_PLANE
/obj/effect/landmark/stationroom/New()
..()
+29 -12
View File
@@ -5,19 +5,21 @@
anchored = TRUE
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "uglymine"
var/triggered = 0
/// We manually check to see if we've been triggered in case multiple atoms cross us in the time between the mine being triggered and it actually deleting, to avoid a race condition with multiple detonations
var/triggered = FALSE
/obj/effect/mine/proc/mineEffect(mob/victim)
to_chat(victim, "<span class='danger'>*click*</span>")
/obj/effect/mine/Crossed(AM as mob|obj)
if(isturf(loc))
if(ismob(AM))
var/mob/MM = AM
if(!(MM.movement_type & FLYING))
triggermine(AM)
else
triggermine(AM)
/obj/effect/mine/Crossed(atom/movable/AM)
if(triggered || !isturf(loc))
return
. = ..()
if(AM.movement_type & FLYING)
return
triggermine(AM)
/obj/effect/mine/proc/triggermine(mob/victim)
if(triggered)
@@ -27,9 +29,13 @@
s.set_up(3, 1, src)
s.start()
mineEffect(victim)
SEND_SIGNAL(src, COMSIG_MINE_TRIGGERED)
triggered = 1
qdel(src)
/obj/effect/mine/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir)
. = ..()
triggermine()
/obj/effect/mine/explosive
name = "explosive mine"
@@ -50,6 +56,18 @@
if(isliving(victim))
victim.DefaultCombatKnockdown(stun_time)
/obj/effect/mine/shrapnel
name = "shrapnel mine"
var/shrapnel_type = /obj/item/projectile/bullet/shrapnel
var/shrapnel_magnitude = 3
/obj/effect/mine/shrapnel/mineEffect(mob/victim)
AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_magnitude)
/obj/effect/mine/shrapnel/sting
name = "stinger mine"
shrapnel_type = /obj/item/projectile/bullet/pellet/stingball
/obj/effect/mine/kickmine
name = "kick mine"
@@ -105,7 +123,7 @@
/obj/effect/mine/pickup/triggermine(mob/victim)
if(triggered)
return
triggered = 1
triggered = TRUE
invisibility = INVISIBILITY_ABSTRACT
mineEffect(victim)
qdel(src)
@@ -128,14 +146,13 @@
spawn(0)
new /datum/hallucination/delusion(victim, TRUE, "demon",duration,0)
var/obj/item/twohanded/required/chainsaw/doomslayer/chainsaw = new(victim.loc)
var/obj/item/chainsaw/doomslayer/chainsaw = new(victim.loc)
victim.log_message("entered a blood frenzy", LOG_ATTACK)
ADD_TRAIT(chainsaw, TRAIT_NODROP, CHAINSAW_FRENZY_TRAIT)
victim.drop_all_held_items()
victim.put_in_hands(chainsaw, forced = TRUE)
chainsaw.attack_self(victim)
chainsaw.wield(victim)
victim.reagents.add_reagent(/datum/reagent/medicine/adminordrazine,25)
to_chat(victim, "<span class='warning'>KILL, KILL, KILL! YOU HAVE NO ALLIES ANYMORE, KILL THEM ALL!</span>")
+78 -5
View File
@@ -451,7 +451,7 @@
lootcount = 1
spawn_on_turf = FALSE
//Note this is out of a 100 - Meaning the number you see is also the percent its going to pick that
//This is ment for "low" loot that anyone could fine in a toilet, for better gear use high loot toilet
//This is meant for "low" loot that anyone could find in a toilet, for better gear use high loot toilet
loot = list("" = 30,
/obj/item/lighter = 2,
/obj/item/tape/random = 1,
@@ -476,7 +476,7 @@
lootcount = 1
spawn_on_turf = FALSE
//Note this is out of a 100 - Meaning the number you see is also the percent its going to pick that
//This is ment for "prison" loot that is rather rare and ment for "prisoners if they get a crowbar to fine, or sec.
//This is meant for "prison" loot that is rather rare and meant for "prisoners if they get a crowbar to fine, or sec.
loot = list("" = 10,
/obj/item/lighter = 5,
/obj/item/poster/random_contraband = 5,
@@ -491,7 +491,7 @@
/obj/item/kitchen/knife = 5,
/obj/item/screwdriver = 5,
/obj/item/crowbar/red = 1, //Dont you need a crowbar to open this?
/obj/item/stack/medical/bruise_pack = 3,
/obj/item/stack/medical/suture = 3,
/obj/item/reagent_containers/food/drinks/bottle/vodka = 2,
/obj/item/radio = 5,
/obj/item/flashlight = 4,
@@ -611,13 +611,13 @@
/obj/item/clothing/mask/breath = 5,
/obj/item/clothing/mask/breath/medical = 1
)
/obj/effect/spawner/lootdrop/welder_tools/no_turf
spawn_on_turf = FALSE
/obj/effect/spawner/lootdrop/low_tools/no_turf
spawn_on_turf = FALSE
/obj/effect/spawner/lootdrop/breathing_tanks/no_turf
spawn_on_turf = FALSE
@@ -644,3 +644,76 @@
/obj/effect/spawner/lootdrop/glowstick/no_turf
spawn_on_turf = FALSE
// Random Parts
/obj/effect/spawner/lootdrop/stock_parts
name = "random stock parts spawner"
lootcount = 1
loot = list(
/obj/item/stock_parts/capacitor,
/obj/item/stock_parts/scanning_module,
/obj/item/stock_parts/manipulator,
/obj/item/stock_parts/micro_laser,
/obj/item/stock_parts/matter_bin,
/obj/item/stock_parts/cell
)
// Random Weapon Parts
/obj/effect/spawner/lootdrop/weapon_parts
name = "random weapon parts spawner 50%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 50,
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 13,
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 13,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 12,
)
/obj/effect/spawner/lootdrop/weapon_parts
name = "random weapon parts spawner 20%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 80,
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 5,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 5,
)
/obj/effect/spawner/lootdrop/ammo
name = "random ammo 75%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 25,
/obj/item/ammo_box/magazine/wt550m9 = 1,
/obj/item/ammo_casing/shotgun/buckshot = 7,
/obj/item/ammo_casing/shotgun/rubbershot = 7,
/obj/item/ammo_casing/a762 = 15,
/obj/item/ammo_box/a762 = 15,
)
/obj/effect/spawner/lootdrop/ammo/fiftypercent
name = "random ammo 50%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 50,
/obj/item/ammo_box/magazine/wt550m9 = 2,
/obj/item/ammo_casing/shotgun/buckshot = 10,
/obj/item/ammo_casing/shotgun/rubbershot = 10,
/obj/item/ammo_casing/a762 = 7,
/obj/item/ammo_box/a762 = 7,
)
/obj/effect/spawner/lootdrop/ammo/shotgun
name = "random ammo 50%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 50,
/obj/item/ammo_box/shotgun/loaded/buckshot = 5,
/obj/item/ammo_box/shotgun/loaded/beanbag = 5,
/obj/item/ammo_box/shotgun/loaded/incendiary = 5,
/obj/item/ammo_casing/shotgun/buckshot = 8,
/obj/item/ammo_casing/shotgun/rubbershot = 9,
/obj/item/ammo_casing/shotgun = 8,
/obj/item/ammo_casing/shotgun/incendiary = 10,
)
@@ -24,6 +24,23 @@ again.
name = "window spawner"
spawn_list = list(/obj/structure/grille, /obj/structure/window/fulltile)
dir = SOUTH
var/electrochromatic
var/electrochromatic_id
/obj/effect/spawner/structure/window/Initialize()
. = ..()
if(!electrochromatic)
return
if(!electrochromatic_id)
stack_trace("Electrochromatic window spawner set without electromatic id.")
return
if(electrochromatic_id[1] == "!")
electrochromatic_id = SSmapping.get_obfuscated_id(electrochromatic_id)
for(var/obj/structure/window/W in get_turf(src))
W.electrochromatic_id = electrochromatic_id
W.make_electrochromatic()
if(electrochromatic == ELECTROCHROMATIC_DIMMED)
W.electrochromatic_dim()
/obj/effect/spawner/structure/window/hollow
name = "hollow window spawner"
@@ -140,13 +157,16 @@ again.
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/spawner/north, /obj/structure/window/reinforced/spawner/west)
. = ..()
//tinted
//tinted and electrochromatic
/obj/effect/spawner/structure/window/reinforced/tinted
name = "tinted reinforced window spawner"
icon_state = "twindow_spawner"
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/tinted/fulltile)
/obj/effect/spawner/structure/window/reinforced/tinted/electrochromatic
name = "electrochromatic reinforced window spawner"
electrochromatic = ELECTROCHROMATIC_DIMMED
//shuttle window
@@ -95,6 +95,56 @@
icon_state = "warden_gaze"
duration = 3
/obj/effect/temp_visual/ratvar/volt_hit
name = "volt blast"
layer = ABOVE_MOB_LAYER
duration = 8
icon_state = "volt_hit"
light_range = 1.5
light_power = 2
light_color = LIGHT_COLOR_ORANGE
var/mob/user
var/damage = 20
/obj/effect/temp_visual/ratvar/volt_hit/Initialize(mapload, caster)
. = ..()
user = caster
if(user)
var/matrix/M = new
M.Turn(Get_Angle(src, user))
transform = M
INVOKE_ASYNC(src, .proc/volthit)
/obj/effect/temp_visual/ratvar/volt_hit/proc/volthit()
if(user)
Beam(get_turf(user), "volt_ray", time=duration, maxdistance=8, beam_type=/obj/effect/ebeam/volt_ray)
var/hit_amount = 0
var/turf/T = get_turf(src)
for(var/mob/living/L in T)
if(is_servant_of_ratvar(L))
continue
var/obj/item/I = L.anti_magic_check()
if(I)
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
continue
L.visible_message("<span class='warning'>[L] is struck by a [name]!</span>", "<span class='userdanger'>You're struck by a [name]!</span>")
L.apply_damage(damage, BURN, "chest", L.run_armor_check("chest", "laser", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 0, "Your armor was penetrated by [src]!"))
log_combat(user, L, "struck with a volt blast")
hit_amount++
for(var/obj/mecha/M in T)
if(M.occupant)
if(is_servant_of_ratvar(M.occupant))
continue
to_chat(M.occupant, "<span class='userdanger'>Your [M.name] is struck by a [name]!</span>")
M.visible_message("<span class='warning'>[M] is struck by a [name]!</span>")
M.take_damage(damage, BURN, 0, 0)
hit_amount++
if(hit_amount)
playsound(src, 'sound/machines/defib_zap.ogg', damage*hit_amount, 1, -1)
else
playsound(src, "sparks", 50, 1)
/obj/effect/temp_visual/ratvar/ocular_warden/Initialize()
. = ..()
pixel_x = rand(-8, 8)
+236 -35
View File
@@ -4,6 +4,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// if true, everyone item when created will have its name changed to be
// more... RPG-like.
GLOBAL_VAR_INIT(stickpocalypse, FALSE) // if true, all non-embeddable items will be able to harmlessly stick to people when thrown
GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to embed in people, takes precedence over stickpocalypse
/obj/item
name = "item"
icon = 'icons/obj/items_and_weapons.dmi'
@@ -55,7 +58,17 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/// How long, in deciseconds, this staggers for, if null it will autocalculate from w_class and force. Unlike total mass this supports 0 and negatives.
var/stagger_force
/**
* Set FALSE and then checked at the end of on mob/living/attackby(), set TRUE on living/pre_attacked_by().
* Should it be FALSE by the end of the item/attack(), that means the item overrode the standard attack behaviour
* and the user still needs the delay applied. We can't be using return values since that'll stop afterattack() from being triggered.
*/
var/attack_delay_done = FALSE
///next_move click/attack delay of this item.
var/click_delay = CLICK_CD_MELEE
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
var/current_equipped_slot
pass_flags = PASSTABLE
pressure_resistance = 4
var/obj/item/master = null
@@ -95,7 +108,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
var/datum/embedding_behavior/embedding
var/list/embedding = NONE
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
var/heat = 0
@@ -132,15 +145,25 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
/* Our block parry data. Should be set in init, or something if you are using it.
* This won't be accessed without ITEM_CAN_BLOCK or ITEM_CAN_PARRY so do not set it unless you have to to save memory.
* If you decide it's a good idea to leave this unset while turning the flags on, you will runtime. Enjoy.
* If this is set to a path, it'll run get_block_parry_data(path). YOU MUST RUN [get_block_parry_data(this)] INSTEAD OF DIRECTLY ACCESSING!
*/
var/datum/block_parry_data/block_parry_data
///Skills vars
//list of skill PATHS exercised when using this item. An associated bitfield can be set to indicate additional ways the skill is used by this specific item.
var/list/datum/skill/used_skills
var/skill_difficulty = THRESHOLD_COMPETENT //how difficult it's to use this item in general.
var/skill_difficulty = THRESHOLD_UNTRAINED //how difficult it's to use this item in general.
var/skill_gain = DEF_SKILL_GAIN //base skill value gain from using this item.
var/canMouseDown = FALSE
/obj/item/Initialize()
if (attack_verb)
if(attack_verb)
attack_verb = typelist("attack_verb", attack_verb)
. = ..()
@@ -148,9 +171,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
new path(src)
actions_types = null
if(GLOB.rpg_loot_items)
AddComponent(/datum/component/fantasy)
if(force_string)
item_flags |= FORCE_STRING_OVERRIDE
@@ -160,15 +180,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(damtype == "brute")
hitsound = "swing_hit"
if (!embedding)
embedding = getEmbeddingBehavior()
else if (islist(embedding))
embedding = getEmbeddingBehavior(arglist(embedding))
else if (!istype(embedding, /datum/embedding_behavior))
stack_trace("Invalid type [embedding.type] found in .embedding during /obj/item Initialize()")
if(sharpness) //give sharp objects butchering functionality, for consistency
AddComponent(/datum/component/butchering, 80 * toolspeed)
if(used_skills)
for(var/path in used_skills)
var/datum/skill/S = GLOB.skill_datums[path]
LAZYADD(used_skills[path], S.skill_traits)
/obj/item/Destroy()
item_flags &= ~DROPDEL //prevent reqdels
@@ -179,6 +194,26 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
qdel(X)
return ..()
/obj/item/ComponentInitialize()
. = ..()
// this proc says it's for initializing components, but we're initializing elements too because it's you and me against the world >:)
if(!LAZYLEN(embedding))
if(GLOB.embedpocalypse)
embedding = EMBED_POINTY
name = "pointy [name]"
else if(GLOB.stickpocalypse)
embedding = EMBED_HARMLESS
name = "sticky [name]"
updateEmbedding()
if(GLOB.rpg_loot_items)
AddComponent(/datum/component/fantasy)
if(sharpness) //give sharp objects butchering functionality, for consistency
AddComponent(/datum/component/butchering, 80 * toolspeed)
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside))
return 0
@@ -229,8 +264,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(resistance_flags & FIRE_PROOF)
. += "[src] is made of fire-retardant materials."
if(item_flags & (ITEM_CAN_BLOCK | ITEM_CAN_PARRY))
var/datum/block_parry_data/data = return_block_parry_datum(block_parry_data)
. += "[src] has the capacity to be used to block and/or parry. <a href='?src=[REF(data)];name=[name];block=[item_flags & ITEM_CAN_BLOCK];parry=[item_flags & ITEM_CAN_PARRY];render=1'>\[Show Stats\]</a>"
if(!user.research_scanner)
return
@@ -285,6 +321,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return
if(anchored)
return
if(loc == user && current_equipped_slot && current_equipped_slot != SLOT_HANDS)
if(current_equipped_slot in user.check_obscured_slots())
to_chat(src, "<span class='warning'>You are unable to unequip that while wearing other garments over it!</span>")
return FALSE
if(resistance_flags & ON_FIRE)
var/mob/living/carbon/C = user
@@ -306,7 +346,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
C.update_damage_overlays()
return
if(acid_level > 20 && !ismob(loc))// so we can still remove the clothes on us that have acid.
if(acid_level > 20 && ismob(loc))// so we can still remove the clothes on us that have acid.
var/mob/living/carbon/C = user
if(istype(C))
if(!C.gloves || (!(C.gloves.resistance_flags & (UNACIDABLE|ACID_PROOF))))
@@ -349,6 +389,11 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return
if(anchored)
return
if(loc == user && current_equipped_slot && current_equipped_slot != SLOT_HANDS)
if(current_equipped_slot in user.check_obscured_slots())
to_chat(src, "<span class='warning'>You are unable to unequip that while wearing other garments over it!</span>")
return FALSE
SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE)
@@ -392,6 +437,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return ITALICS | REDUCE_RANGE
/obj/item/proc/dropped(mob/user)
SHOULD_CALL_PARENT(TRUE)
current_equipped_slot = null
for(var/X in actions)
var/datum/action/A = X
A.Remove(user)
@@ -404,6 +451,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// called just as an item is picked up (loc is not yet changed)
/obj/item/proc/pickup(mob/user)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user)
item_flags |= IN_INVENTORY
@@ -420,14 +468,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return usr.client.Click(src, src_location, src_control, params)
var/list/directaccess = usr.DirectAccess() //This, specifically, is what requires the copypaste. If this were after the adjacency check, then it'd be impossible to use items in your inventory, among other things.
//If this were before the above checks, then trying to click on items would act a little funky and signal overrides wouldn't work.
if(iscarbon(usr))
var/mob/living/carbon/C = usr
if((C.combat_flags & COMBAT_FLAG_COMBAT_ACTIVE) && ((C.CanReach(src) || (src in directaccess)) && (C.CanReach(over) || (over in directaccess))))
if(!C.get_active_held_item())
C.UnarmedAttack(src, TRUE)
if(C.get_active_held_item() == src)
melee_attack_chain(C, over)
return TRUE //returning TRUE as a "is this overridden?" flag
if(SEND_SIGNAL(usr, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE) && ((usr.CanReach(src) || (src in directaccess)) && (usr.CanReach(over) || (over in directaccess))))
if(!usr.get_active_held_item())
usr.UnarmedAttack(src, TRUE)
if(usr.get_active_held_item() == src)
melee_attack_chain(usr, over)
return TRUE //returning TRUE as a "is this overridden?" flag
if(!Adjacent(usr) || !over.Adjacent(usr))
return // should stop you from dragging through windows
@@ -440,7 +486,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// for items that can be placed in multiple slots
// note this isn't called during the initial dressing of a player
/obj/item/proc/equipped(mob/user, slot)
SHOULD_CALL_PARENT(TRUE)
. = SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot)
current_equipped_slot = slot
if(!(. & COMPONENT_NO_GRANT_ACTIONS))
for(var/X in actions)
var/datum/action/A = X
@@ -466,11 +514,11 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
//if this is being done by a mob other than M, it will include the mob equipper, who is trying to equip the item to mob M. equipper will be null otherwise.
//If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen.
//Set disable_warning to TRUE if you wish it to not give you outputs.
/obj/item/proc/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
/obj/item/proc/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning)
if(!M)
return FALSE
return M.can_equip(src, slot, disable_warning, bypass_equip_delay_self)
return M.can_equip(src, slot, disable_warning, bypass_equip_delay_self, clothing_check, return_warning)
/obj/item/verb/verb_pickup()
set src in oview(1)
@@ -605,6 +653,18 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/itempush = 1
if(w_class < 4)
itempush = 0 //too light to push anything
if(isliving(hit_atom)) //Living mobs handle hit sounds differently.
var/volume = get_volume_by_throwforce_and_or_w_class()
if (throwforce > 0)
if (throwhitsound)
playsound(hit_atom, throwhitsound, volume, TRUE, -1)
else if(hitsound)
playsound(hit_atom, hitsound, volume, TRUE, -1)
else
playsound(hit_atom, 'sound/weapons/genhit.ogg',volume, TRUE, -1)
else
playsound(hit_atom, 'sound/weapons/throwtap.ogg', 1, volume, -1)
return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum)
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE)
@@ -736,6 +796,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
..()
/obj/item/proc/microwave_act(obj/machinery/microwave/M)
SEND_SIGNAL(src, COMSIG_ITEM_MICROWAVE_ACT, M)
if(istype(M) && M.dirty < 100)
M.dirty++
@@ -782,14 +843,17 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/user = usr
tip_timer = addtimer(CALLBACK(src, .proc/openTip, location, control, params, user), timedelay, TIMER_STOPPABLE)//timer takes delay in deciseconds, but the pref is in milliseconds. dividing by 100 converts it.
/obj/item/MouseExited()
/obj/item/MouseExited(location,control,params)
SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_EXIT, location, control, params)
deltimer(tip_timer)//delete any in-progress timer if the mouse is moved off the item before it finishes
closeToolTip(usr)
/obj/item/MouseEntered(location,control,params)
SEND_SIGNAL(src, COMSIG_ITEM_MOUSE_ENTER, location, control, params)
// Called when a mob tries to use the item as a tool.
// Handles most checks.
/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks, skill_gain_mult = 1, max_level = INFINITY)
/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks, skill_gain_mult = STD_USE_TOOL_MULT)
// No delay means there is no start message, and no reason to call tool_start_check before use_tool.
// Run the start check here so we wouldn't have to call it manually.
if(!delay && !tool_start_check(user, amount))
@@ -802,7 +866,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(delay)
if(user.mind && used_skills)
delay = user.mind.skill_holder.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, NONE, FALSE)
delay = user.mind.item_action_skills_mod(src, delay, skill_difficulty, SKILL_USE_TOOL, null, FALSE)
// Create a callback with checks that would be called every tick by do_after.
var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks)
@@ -828,11 +892,14 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(delay >= MIN_TOOL_SOUND_DELAY)
play_tool_sound(target, volume)
if(user.mind && used_skills && skill_gain_mult)
var/gain = skill_gain + delay/SKILL_GAIN_DELAY_DIVISOR
for(var/skill in used_skills)
if(!(used_skills[skill] & SKILL_TRAINING_TOOL))
if(!(SKILL_TRAINING_TOOL in used_skills[skill]))
continue
user.mind.skill_holder.auto_gain_experience(skill, skill_gain*skill_gain_mult, GET_STANDARD_LVL(max_level))
var/datum/skill/S = GLOB.skill_datums[skill]
user.mind.auto_gain_experience(skill, gain*skill_gain_mult*S.item_skill_gain_multi)
return TRUE
@@ -893,11 +960,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// if w_volume is 0 you fucked up anyways lol
return w_volume || AUTO_SCALE_VOLUME(w_class)
/obj/item/proc/embedded(mob/living/carbon/human/embedded_mob)
/obj/item/proc/embedded(atom/embedded_target)
return
/obj/item/proc/unembedded()
return
if(item_flags & DROPDEL)
QDEL_NULL(src)
return TRUE
/**
* Sets our slowdown and updates equipment slowdown of any mob we're equipped on.
@@ -913,3 +982,135 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
. = ..()
if(var_name == NAMEOF(src, slowdown))
set_slowdown(var_value) //don't care if it's a duplicate edit as slowdown'll be set, do it anyways to force normal behavior.
/**
* Does the current embedding var meet the criteria for being harmless? Namely, does it explicitly define the pain multiplier and jostle pain mult to be 0? If so, return true.
*
*/
/obj/item/proc/isEmbedHarmless()
if(embedding)
return !isnull(embedding["pain_mult"]) && !isnull(embedding["jostle_pain_mult"]) && embedding["pain_mult"] == 0 && embedding["jostle_pain_mult"] == 0
///In case we want to do something special (like self delete) upon failing to embed in something, return true
/obj/item/proc/failedEmbed()
if(item_flags & DROPDEL)
QDEL_NULL(src)
return TRUE
/**
* tryEmbed() is for when you want to try embedding something without dealing with the damage + hit messages of calling hitby() on the item while targetting the target.
*
* Really, this is used mostly with projectiles with shrapnel payloads, from [/datum/element/embed/proc/checkEmbedProjectile], and called on said shrapnel. Mostly acts as an intermediate between different embed elements.
*
* Arguments:
* * target- Either a body part, a carbon, or a closed turf. What are we hitting?
* * forced- Do we want this to go through 100%?
*/
/obj/item/proc/tryEmbed(atom/target, forced=FALSE, silent=FALSE)
if(!isbodypart(target) && !iscarbon(target) && !isclosedturf(target))
return
if(!forced && !LAZYLEN(embedding))
return
if(SEND_SIGNAL(src, COMSIG_EMBED_TRY_FORCE, target, forced, silent))
return TRUE
failedEmbed()
///For when you want to disable an item's embedding capabilities (like transforming weapons and such), this proc will detach any active embed elements from it.
/obj/item/proc/disableEmbedding()
SEND_SIGNAL(src, COMSIG_ITEM_DISABLE_EMBED)
return
///For when you want to add/update the embedding on an item. Uses the vars in [/obj/item/embedding], and defaults to config values for values that aren't set. Will automatically detach previous embed elements on this item.
/obj/item/proc/updateEmbedding()
if(!islist(embedding) || !LAZYLEN(embedding))
return
AddElement(/datum/element/embed,\
embed_chance = (!isnull(embedding["embed_chance"]) ? embedding["embed_chance"] : EMBED_CHANCE),\
fall_chance = (!isnull(embedding["fall_chance"]) ? embedding["fall_chance"] : EMBEDDED_ITEM_FALLOUT),\
pain_chance = (!isnull(embedding["pain_chance"]) ? embedding["pain_chance"] : EMBEDDED_PAIN_CHANCE),\
pain_mult = (!isnull(embedding["pain_mult"]) ? embedding["pain_mult"] : EMBEDDED_PAIN_MULTIPLIER),\
remove_pain_mult = (!isnull(embedding["remove_pain_mult"]) ? embedding["remove_pain_mult"] : EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER),\
rip_time = (!isnull(embedding["rip_time"]) ? embedding["rip_time"] : EMBEDDED_UNSAFE_REMOVAL_TIME),\
ignore_throwspeed_threshold = (!isnull(embedding["ignore_throwspeed_threshold"]) ? embedding["ignore_throwspeed_threshold"] : FALSE),\
impact_pain_mult = (!isnull(embedding["impact_pain_mult"]) ? embedding["impact_pain_mult"] : EMBEDDED_IMPACT_PAIN_MULTIPLIER),\
jostle_chance = (!isnull(embedding["jostle_chance"]) ? embedding["jostle_chance"] : EMBEDDED_JOSTLE_CHANCE),\
jostle_pain_mult = (!isnull(embedding["jostle_pain_mult"]) ? embedding["jostle_pain_mult"] : EMBEDDED_JOSTLE_PAIN_MULTIPLIER),\
pain_stam_pct = (!isnull(embedding["pain_stam_pct"]) ? embedding["pain_stam_pct"] : EMBEDDED_PAIN_STAM_PCT),\
embed_chance_turf_mod = (!isnull(embedding["embed_chance_turf_mod"]) ? embedding["embed_chance_turf_mod"] : EMBED_CHANCE_TURF_MOD))
return TRUE
+13 -6
View File
@@ -143,8 +143,8 @@ RLD
//if user can't be seen from A (only checks surroundings' opaqueness) and can't see A.
//jarring, but it should stop people from targetting atoms they can't see...
//excluding darkness, to allow RLD to be used to light pitch black dark areas.
if(!((user in view(view_range, A)) || (user in viewers(view_range, A))))
to_chat(user, "<span class='warning'>You focus, pointing \the [src] at whatever outside your field of vision in the given direction... to no avail.</span>")
if(!((user in view(view_range, A)) || (user in fov_viewers(view_range, A))))
to_chat(user, "<span class='warning'>You focus, pointing \the [src] at whatever outside your field of vision in that direction... to no avail.</span>")
return FALSE
return TRUE
@@ -154,7 +154,8 @@ RLD
icon_state = "rcd"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
custom_price = 900
custom_price = PRICE_ABOVE_EXPENSIVE
custom_premium_price = PRICE_ALMOST_ONE_GRAND
max_matter = 160
item_flags = NO_MAT_REDEMPTION | NOBLUDGEON
has_ammobar = TRUE
@@ -745,7 +746,7 @@ RLD
if(istype(A, /obj/machinery/light/))
if(checkResource(deconcost, user))
to_chat(user, "<span class='notice'>You start deconstructing [A]...</span>")
user.Beam(A,icon_state="nzcrentrs_power",time=15)
user.Beam(A,icon_state="light_beam",time=15)
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
if(do_after(user, decondelay, target = A))
if(!useResource(deconcost, user))
@@ -759,7 +760,7 @@ RLD
var/turf/closed/wall/W = A
if(checkResource(floorcost, user))
to_chat(user, "<span class='notice'>You start building a wall light...</span>")
user.Beam(A,icon_state="nzcrentrs_power",time=15)
user.Beam(A,icon_state="light_beam",time=15)
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, 0)
if(do_after(user, floordelay, target = A))
@@ -805,7 +806,7 @@ RLD
var/turf/open/floor/F = A
if(checkResource(floorcost, user))
to_chat(user, "<span class='notice'>You start building a floor light...</span>")
user.Beam(A,icon_state="nzcrentrs_power",time=15)
user.Beam(A,icon_state="light_beam",time=15)
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, 1)
if(do_after(user, floordelay, target = A))
@@ -834,6 +835,12 @@ RLD
return TRUE
return FALSE
/obj/item/construction/rld/mini
name = "mini-rapid-light-device (MRLD)"
desc = "A device used to rapidly provide lighting sources to an area. Reload with metal, plasteel, glass or compressed matter cartridges."
matter = 100
max_matter = 100
/obj/item/rcd_upgrade
name = "RCD advanced design disk"
desc = "It seems to be empty."
+35 -29
View File
@@ -1,4 +1,4 @@
/obj/item/twohanded/rcl
/obj/item/rcl
name = "rapid cable layer"
desc = "A device used to rapidly deploy cables. It has screws on the side which can be removed to slide off the cables. Do not use without insulation!"
icon = 'icons/obj/tools.dmi'
@@ -23,15 +23,26 @@
var/datum/radial_menu/persistent/wiring_gui_menu
var/mob/listeningTo
/obj/item/twohanded/rcl/Initialize()
/obj/item/rcl/Initialize()
. = ..()
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
update_icon()
/obj/item/twohanded/rcl/ComponentInitialize()
/obj/item/rcl/ComponentInitialize()
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
AddComponent(/datum/component/two_handed)
/obj/item/twohanded/rcl/attackby(obj/item/W, mob/user)
/// triggered on wield of two handed item
/obj/item/rcl/proc/on_wield(obj/item/source, mob/user)
active = TRUE
/// triggered on unwield of two handed item
/obj/item/rcl/proc/on_unwield(obj/item/source, mob/user)
active = FALSE
/obj/item/rcl/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
@@ -86,26 +97,26 @@
else
..()
/obj/item/twohanded/rcl/examine(mob/user)
/obj/item/rcl/examine(mob/user)
. = ..()
if(loaded)
. += "<span class='info'>It contains [loaded.amount]/[max_amount] cables.</span>"
/obj/item/twohanded/rcl/Destroy()
/obj/item/rcl/Destroy()
QDEL_NULL(loaded)
last = null
listeningTo = null
QDEL_NULL(wiring_gui_menu)
return ..()
/obj/item/twohanded/rcl/update_icon_state()
/obj/item/rcl/update_icon_state()
icon_state = initial(icon_state)
item_state = initial(item_state)
if(!loaded || !loaded.amount)
icon_state += "-empty"
item_state += "-0"
/obj/item/twohanded/rcl/update_overlays()
/obj/item/rcl/update_overlays()
. = ..()
if(!loaded || !loaded.amount)
return
@@ -113,7 +124,7 @@
cable_overlay.color = GLOB.cable_colors[colors[current_color_index]]
. += cable_overlay
/obj/item/twohanded/rcl/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE)
/obj/item/rcl/worn_overlays(isinhands, icon_file, used_state, style_flags = NONE)
. = ..()
if(!isinhands || !(loaded?.amount))
return
@@ -121,7 +132,7 @@
cable_overlay.color = GLOB.cable_colors[colors[current_color_index]]
. += cable_overlay
/obj/item/twohanded/rcl/proc/is_empty(mob/user, loud = 1)
/obj/item/rcl/proc/is_empty(mob/user, loud = 1)
update_icon()
if(!loaded || !loaded.amount)
if(loud)
@@ -130,26 +141,23 @@
QDEL_NULL(loaded)
loaded = null
QDEL_NULL(wiring_gui_menu)
unwield(user)
active = wielded
return TRUE
return FALSE
/obj/item/twohanded/rcl/pickup(mob/user)
/obj/item/rcl/pickup(mob/user)
..()
getMobhook(user)
/obj/item/twohanded/rcl/dropped(mob/wearer)
/obj/item/rcl/dropped(mob/wearer)
..()
UnregisterSignal(wearer, COMSIG_MOVABLE_MOVED)
listeningTo = null
last = null
/obj/item/twohanded/rcl/attack_self(mob/user)
/obj/item/rcl/attack_self(mob/user)
..()
active = wielded
if(!active)
last = null
else if(!last)
@@ -158,7 +166,7 @@
last = C
break
obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
obj/item/rcl/proc/getMobhook(mob/to_hook)
if(listeningTo == to_hook)
return
if(listeningTo)
@@ -166,7 +174,7 @@ obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
RegisterSignal(to_hook, COMSIG_MOVABLE_MOVED, .proc/trigger)
listeningTo = to_hook
/obj/item/twohanded/rcl/proc/trigger(mob/user)
/obj/item/rcl/proc/trigger(mob/user)
if(active)
layCable(user)
if(wiring_gui_menu) //update the wire options as you move
@@ -174,7 +182,7 @@ obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
//previous contents of trigger(), lays cable each time the player moves
/obj/item/twohanded/rcl/proc/layCable(mob/user)
/obj/item/rcl/proc/layCable(mob/user)
if(!isturf(user.loc))
return
if(is_empty(user, 0))
@@ -207,7 +215,7 @@ obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
update_icon()
//searches the current tile for a stub cable of the same colour
/obj/item/twohanded/rcl/proc/findLinkingCable(mob/user)
/obj/item/rcl/proc/findLinkingCable(mob/user)
var/turf/T
if(!isturf(user.loc))
return
@@ -223,10 +231,8 @@ obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
continue
if(C.d1 == 0)
return C
return
/obj/item/twohanded/rcl/proc/wiringGuiGenerateChoices(mob/user)
/obj/item/rcl/proc/wiringGuiGenerateChoices(mob/user)
var/fromdir = 0
var/obj/structure/cable/linkingCable = findLinkingCable(user)
if(linkingCable)
@@ -243,12 +249,12 @@ obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
wiredirs[icondir] = img
return wiredirs
/obj/item/twohanded/rcl/proc/showWiringGui(mob/user)
/obj/item/rcl/proc/showWiringGui(mob/user)
var/list/choices = wiringGuiGenerateChoices(user)
wiring_gui_menu = show_radial_menu_persistent(user, src , choices, select_proc = CALLBACK(src, .proc/wiringGuiReact, user), radius = 42)
/obj/item/twohanded/rcl/proc/wiringGuiUpdate(mob/user)
/obj/item/rcl/proc/wiringGuiUpdate(mob/user)
if(!wiring_gui_menu)
return
@@ -259,7 +265,7 @@ obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
//Callback used to respond to interactions with the wiring menu
/obj/item/twohanded/rcl/proc/wiringGuiReact(mob/living/user,choice)
/obj/item/rcl/proc/wiringGuiReact(mob/living/user,choice)
if(!choice) //close on a null choice (the center button)
QDEL_NULL(wiring_gui_menu)
return
@@ -290,7 +296,7 @@ obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
wiringGuiUpdate(user)
/obj/item/twohanded/rcl/ui_action_click(mob/user, action)
/obj/item/rcl/ui_action_click(mob/user, action)
if(istype(action, /datum/action/item_action/rcl_col))
current_color_index++;
if (current_color_index > colors.len)
@@ -308,13 +314,13 @@ obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
else //open the menu
showWiringGui(user)
/obj/item/twohanded/rcl/pre_loaded/Initialize() //Comes preloaded with cable, for testing stuff
/obj/item/rcl/pre_loaded/Initialize() //Comes preloaded with cable, for testing stuff
loaded = new()
loaded.max_amount = max_amount
loaded.amount = max_amount
return ..()
/obj/item/twohanded/rcl/ghetto
/obj/item/rcl/ghetto
actions_types = list()
max_amount = 30
name = "makeshift rapid cable layer"
+2 -2
View File
@@ -7,7 +7,7 @@ RSF
name = "\improper Rapid-Service-Fabricator"
desc = "A device used to rapidly deploy service items."
icon = 'icons/obj/tools.dmi'
icon_state = "rcd"
icon_state = "rsf"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
opacity = 0
@@ -110,7 +110,7 @@ RSF
name = "Cookie Synthesizer"
desc = "A self-recharging device used to rapidly deploy cookies."
icon = 'icons/obj/tools.dmi'
icon_state = "rcd"
icon_state = "rsf"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
var/matter = 10
+109
View File
@@ -125,3 +125,112 @@
user.put_in_hands(ink)
to_chat(user, "<span class='notice'>You remove [ink] from [src].</span>")
ink = null
/obj/item/airlock_painter/decal
name = "decal painter"
desc = "An airlock painter, reprogramed to use a different style of paint in order to apply decals for floor tiles as well, in addition to repainting doors. Decals break when the floor tiles are removed. Alt-Click to change design."
icon = 'icons/obj/objects.dmi'
icon_state = "decal_sprayer"
item_state = "decalsprayer"
custom_materials = list(/datum/material/iron=2000, /datum/material/glass=500)
var/stored_dir = 2
var/stored_color = ""
var/stored_decal = "warningline"
var/stored_decal_total = "warningline"
var/color_list = list("","red","white")
var/dir_list = list(1,2,4,8)
var/decal_list = list(list("Warning Line","warningline"),
list("Warning Line Corner","warninglinecorner"),
list("Caution Label","caution"),
list("Directional Arrows","arrows"),
list("Stand Clear Label","stand_clear"),
list("Box","box"),
list("Box Corner","box_corners"),
list("Delivery Marker","delivery"),
list("Warning Box","warn_full"))
/obj/item/airlock_painter/decal/afterattack(atom/target, mob/user, proximity)
. = ..()
var/turf/open/floor/F = target
if(!proximity)
to_chat(user, "<span class='notice'>You need to get closer!</span>")
return
if(use_paint(user) && isturf(F))
F.AddElement(/datum/element/decal, 'icons/turf/decals.dmi', stored_decal_total, turn(stored_dir, -dir2angle(F.dir)), CLEAN_STRONG, color, null, null, alpha)
/obj/item/airlock_painter/decal/attack_self(mob/user)
if((ink) && (ink.charges >= 1))
to_chat(user, "<span class='notice'>[src] beeps to prevent you from removing the toner until out of charges.</span>")
return
. = ..()
/obj/item/airlock_painter/decal/AltClick(mob/user)
. = ..()
ui_interact(user)
/obj/item/airlock_painter/decal/Initialize()
. = ..()
ink = new /obj/item/toner/large(src)
/obj/item/airlock_painter/decal/proc/update_decal_path()
var/yellow_fix = "" //This will have to do until someone refactor's markings.dm
if (stored_color)
yellow_fix = "_"
stored_decal_total = "[stored_decal][yellow_fix][stored_color]"
return
/obj/item/airlock_painter/decal/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)
if(!ui)
ui = new(user, src, ui_key, "decal_painter", name, 500, 400, master_ui, state)
ui.open()
/obj/item/airlock_painter/decal/ui_data(mob/user)
var/list/data = list()
data["decal_direction"] = stored_dir
data["decal_color"] = stored_color
data["decal_style"] = stored_decal
data["decal_list"] = list()
data["color_list"] = list()
data["dir_list"] = list()
for(var/i in decal_list)
data["decal_list"] += list(list(
"name" = i[1],
"decal" = i[2]
))
for(var/j in color_list)
data["color_list"] += list(list(
"colors" = j
))
for(var/k in dir_list)
data["dir_list"] += list(list(
"dirs" = k
))
return data
/obj/item/airlock_painter/decal/ui_act(action,list/params)
if(..())
return
switch(action)
//Lists of decals and designs
if("select decal")
var/selected_decal = params["decals"]
stored_decal = selected_decal
if("select color")
var/selected_color = params["colors"]
stored_color = selected_color
if("selected direction")
var/selected_direction = text2num(params["dirs"])
stored_dir = selected_direction
update_decal_path()
. = TRUE
/obj/item/airlock_painter/decal/debug
name = "extreme decal painter"
icon_state = "decal_sprayer_ex"
/obj/item/airlock_painter/decal/debug/Initialize()
. = ..()
ink = new /obj/item/toner/extreme(src)
+12 -8
View File
@@ -58,18 +58,22 @@
/obj/item/wallframe/proc/after_attach(var/obj/O)
transfer_fingerprints_to(O)
/obj/item/wallframe/attackby(obj/item/W, mob/user, params)
..()
if(istype(W, /obj/item/screwdriver))
// For camera-building borgs
var/turf/T = get_step(get_turf(user), user.dir)
if(iswallturf(T))
T.attackby(src, user, params)
/obj/item/wallframe/screwdriver_act(mob/user, obj/item/I)
. = ..()
if(.)
return
// For camera-building borgs
var/turf/T = get_step(get_turf(user), user.dir)
if(iswallturf(T))
T.attackby(src, user)
/obj/item/wallframe/wrench_act(mob/user, obj/item/I)
if(!custom_materials)
return
var/metal_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/iron)]/MINERAL_MATERIAL_AMOUNT)
var/glass_amt = round(custom_materials[SSmaterials.GetMaterialRef(/datum/material/glass)]/MINERAL_MATERIAL_AMOUNT)
if(istype(W, /obj/item/wrench) && (metal_amt || glass_amt))
if(metal_amt || glass_amt)
to_chat(user, "<span class='notice'>You dismantle [src].</span>")
if(metal_amt)
new /obj/item/stack/sheet/metal(get_turf(src), metal_amt)
+65
View File
@@ -0,0 +1,65 @@
/obj/item/binoculars
name = "binoculars"
desc = "Used for long-distance surveillance."
item_state = "binoculars"
icon_state = "binoculars"
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
var/mob/listeningTo
var/zoom_out_amt = 6
var/zoom_amt = 10
/obj/item/binoculars/Initialize()
. = ..()
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
/obj/item/binoculars/ComponentInitialize()
. = ..()
AddComponent(/datum/component/two_handed, force_unwielded=8, force_wielded=12)
/obj/item/binoculars/Destroy()
listeningTo = null
return ..()
/obj/item/binoculars/proc/on_wield(obj/item/source, mob/user)
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/unwield)
listeningTo = user
user.visible_message("<span class='notice'>[user] holds [src] up to [user.p_their()] eyes.</span>", "<span class='notice'>You hold [src] up to your eyes.</span>")
item_state = "binoculars_wielded"
user.regenerate_icons()
if(!user?.client)
return
var/client/C = user.client
var/_x = 0
var/_y = 0
switch(user.dir)
if(NORTH)
_y = zoom_amt
if(EAST)
_x = zoom_amt
if(SOUTH)
_y = -zoom_amt
if(WEST)
_x = -zoom_amt
C.change_view(world.view + zoom_out_amt)
C.pixel_x = world.icon_size*_x
C.pixel_y = world.icon_size*_y
/obj/item/binoculars/proc/on_unwield(obj/item/source, mob/user)
unwield(user)
/obj/item/binoculars/proc/unwield(mob/user)
if(listeningTo)
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
user.visible_message("<span class='notice'>[user] lowers [src].</span>", "<span class='notice'>You lower [src].</span>")
item_state = "binoculars"
user.regenerate_icons()
if(user && user.client)
user.regenerate_icons()
var/client/C = user.client
C.change_view(CONFIG_GET(string/default_view))
user.client.pixel_x = 0
user.client.pixel_y = 0
+69
View File
@@ -0,0 +1,69 @@
/obj/item/broom
name = "broom"
desc = "This is my BROOMSTICK! It can be used manually or braced with two hands to sweep items as you move. It has a telescopic handle for compact storage."
icon = 'icons/obj/janitor.dmi'
icon_state = "broom0"
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
force = 8
throwforce = 10
throw_speed = 3
throw_range = 7
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("swept", "brushed off", "bludgeoned", "whacked")
resistance_flags = FLAMMABLE
/obj/item/broom/Initialize()
. = ..()
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
/obj/item/broom/ComponentInitialize()
. = ..()
AddComponent(/datum/component/two_handed, force_unwielded=8, force_wielded=12, icon_wielded="broom1")
/obj/item/broom/update_icon_state()
icon_state = "broom0"
/// triggered on wield of two handed item
/obj/item/broom/proc/on_wield(obj/item/source, mob/user)
to_chat(user, "<span class='notice'>You brace the [src] against the ground in a firm sweeping stance.</span>")
RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/sweep)
/// triggered on unwield of two handed item
/obj/item/broom/proc/on_unwield(obj/item/source, mob/user)
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
/obj/item/broom/afterattack(atom/A, mob/user, proximity)
. = ..()
if(!proximity)
return
sweep(user, A, FALSE)
/obj/item/broom/proc/sweep(mob/user, atom/A, moving = TRUE)
var/turf/target
if (!moving)
if (isturf(A))
target = A
else
target = A.loc
else
target = user.loc
if (!isturf(target))
return
if (locate(/obj/structure/table) in target.contents)
return
var/i = 0
for(var/obj/item/garbage in target.contents)
if(!garbage.anchored)
garbage.Move(get_step(target, user.dir), user.dir)
i++
if(i >= 20)
break
if(i >= 1)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 30, TRUE, -1)
/obj/item/broom/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J) //bless you whoever fixes this copypasta
J.put_in_cart(src, user)
J.mybroom=src
J.update_icon()
+59 -14
View File
@@ -83,7 +83,7 @@
/obj/item/card/emag/bluespace
name = "bluespace cryptographic sequencer"
desc = "It's a blue card with a magnetic strip attached to some circuitry. It appears to have some sort of transmitter attached to it."
color = rgb(40, 130, 255)
icon_state = "emag_bs"
prox_check = FALSE
/obj/item/card/emag/attack()
@@ -166,6 +166,7 @@
slot_flags = ITEM_SLOT_ID
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
resistance_flags = FIRE_PROOF | ACID_PROOF
var/id_type_name = "identification card"
var/mining_points = 0 //For redeeming at mining equipment vendors
var/list/access = list()
var/registered_name = null // The name registered_name on the card
@@ -174,6 +175,8 @@
var/bank_support = ID_FREE_BANK_ACCOUNT
var/datum/bank_account/registered_account
var/obj/machinery/paystand/my_store
var/uses_overlays = TRUE
var/icon/cached_flat_icon
/obj/item/card/id/Initialize(mapload)
. = ..()
@@ -187,6 +190,15 @@
if(ID_LOCKED_BANK_ACCOUNT)
registered_account = new /datum/bank_account/remote/non_transferable(pick(GLOB.redacted_strings))
/obj/item/card/id/Destroy()
if(bank_support == ID_LOCKED_BANK_ACCOUNT)
QDEL_NULL(registered_account)
else
registered_account = null
if(my_store)
my_store.my_card = null
my_store = null
return ..()
/obj/item/card/id/vv_edit_var(var_name, var_value)
. = ..()
@@ -311,20 +323,19 @@
registered_account.bank_card_talk("<span class='warning'>ERROR: UNABLE TO LOGIN DUE TO SCHEDULED MAINTENANCE. MAINTENANCE IS SCHEDULED TO COMPLETE IN [(registered_account.withdrawDelay - world.time)/10] SECONDS.</span>", TRUE)
return
var/amount_to_remove = FLOOR(input(user, "How much do you want to withdraw? Current Balance: [registered_account.account_balance]", "Withdraw Funds", 5) as num|null, 1)
var/amount_to_remove = input(user, "How much do you want to withdraw? Current Balance: [registered_account.account_balance]", "Withdraw Funds", 5) as num|null
if(!amount_to_remove || amount_to_remove < 0)
return
if(!alt_click_can_use_id(user))
return
if(registered_account.adjust_money(-amount_to_remove))
amount_to_remove = FLOOR(min(amount_to_remove, registered_account.account_balance), 1)
if(amount_to_remove && registered_account.adjust_money(-amount_to_remove))
var/obj/item/holochip/holochip = new (user.drop_location(), amount_to_remove)
user.put_in_hands(holochip)
to_chat(user, "<span class='notice'>You withdraw [amount_to_remove] credits into a holochip.</span>")
return
else
var/difference = amount_to_remove - registered_account.account_balance
registered_account.bank_card_talk("<span class='warning'>ERROR: The linked account requires [difference] more credit\s to perform that withdrawal.</span>", TRUE)
registered_account.bank_card_talk("<span class='warning'>ERROR: The linked account has no sufficient credits to perform that withdrawal.</span>", TRUE)
/obj/item/card/id/examine(mob/user)
. = ..()
@@ -354,20 +365,38 @@
/obj/item/card/id/RemoveID()
return src
/*
Usage:
update_label()
Sets the id name to whatever registered_name and assignment is
/obj/item/card/id/update_overlays()
. = ..()
if(!uses_overlays)
return
cached_flat_icon = null
var/job = assignment ? ckey(GetJobName()) : null
if(registered_name == "Captain")
job = "captain"
if(registered_name && registered_name != "Captain")
. += mutable_appearance(icon, "assigned")
if(job)
. += mutable_appearance(icon, "id[job]")
/obj/item/card/id/proc/get_cached_flat_icon()
if(!cached_flat_icon)
cached_flat_icon = getFlatIcon(src)
return cached_flat_icon
/obj/item/card/id/get_examine_string(mob/user, thats = FALSE)
if(uses_overlays)
return "[icon2html(get_cached_flat_icon(), user)] [thats? "That's ":""][get_examine_name(user)]" //displays all overlays in chat
return ..()
update_label("John Doe", "Clowny")
Properly formats the name and occupation and sets the id name to the arguments
*/
/obj/item/card/id/proc/update_label(newname, newjob)
if(newname || newjob)
name = "[(!newname) ? "identification card" : "[newname]'s ID Card"][(!newjob) ? "" : " ([newjob])"]"
update_icon()
return
name = "[(!registered_name) ? "identification card" : "[registered_name]'s ID Card"][(!assignment) ? "" : " ([assignment])"]"
update_icon()
/obj/item/card/id/silver
name = "silver identification card"
@@ -380,6 +409,7 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/silver/reaper
name = "Thirteen's ID Card (Reaper)"
access = list(ACCESS_MAINT_TUNNELS)
icon_state = "reaper"
assignment = "Reaper"
registered_name = "Thirteen"
@@ -531,7 +561,7 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/ert
name = "\improper CentCom ID"
desc = "An ERT ID card."
icon_state = "centcom"
icon_state = "ert_commander"
registered_name = "Emergency Response Team Commander"
assignment = "Emergency Response Team Commander"
@@ -540,6 +570,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/Security
icon_state = "ert_security"
registered_name = "Security Response Officer"
assignment = "Security Response Officer"
@@ -548,6 +579,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/Engineer
icon_state = "ert_engineer"
registered_name = "Engineer Response Officer"
assignment = "Engineer Response Officer"
@@ -556,6 +588,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/Medical
icon_state = "ert_medical"
registered_name = "Medical Response Officer"
assignment = "Medical Response Officer"
@@ -564,6 +597,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/chaplain
icon_state = "ert_chaplain"
registered_name = "Religious Response Officer"
assignment = "Religious Response Officer"
@@ -616,40 +650,49 @@ update_label("John Doe", "Clowny")
. += "<span class='notice'>Your sentence is up! You're free!</span>"
/obj/item/card/id/prisoner/one
icon_state = "prisoner_001"
name = "Prisoner #13-001"
registered_name = "Prisoner #13-001"
/obj/item/card/id/prisoner/two
icon_state = "prisoner_002"
name = "Prisoner #13-002"
registered_name = "Prisoner #13-002"
/obj/item/card/id/prisoner/three
icon_state = "prisoner_003"
name = "Prisoner #13-003"
registered_name = "Prisoner #13-003"
/obj/item/card/id/prisoner/four
icon_state = "prisoner_004"
name = "Prisoner #13-004"
registered_name = "Prisoner #13-004"
/obj/item/card/id/prisoner/five
icon_state = "prisoner_005"
name = "Prisoner #13-005"
registered_name = "Prisoner #13-005"
/obj/item/card/id/prisoner/six
icon_state = "prisoner_006"
name = "Prisoner #13-006"
registered_name = "Prisoner #13-006"
/obj/item/card/id/prisoner/seven
icon_state = "prisoner_007"
name = "Prisoner #13-007"
registered_name = "Prisoner #13-007"
/obj/item/card/id/mining
name = "mining ID"
icon_state = "retro"
access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/away
name = "a perfectly generic identification card"
desc = "A perfectly generic identification card. Looks like it could use some flavor."
icon_state = "retro"
access = list(ACCESS_AWAY_GENERAL)
/obj/item/card/id/away/hotel
@@ -692,6 +735,7 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/departmental_budget
name = "departmental card (FUCK)"
desc = "Provides access to the departmental budget."
icon_state = "budgetcard"
var/department_ID = ACCOUNT_CIV
var/department_name = ACCOUNT_CIV_NAME
@@ -704,6 +748,7 @@ update_label("John Doe", "Clowny")
B.bank_cards += src
name = "departmental card ([department_name])"
desc = "Provides access to the [department_name]."
icon_state = "[lowertext(department_ID)]_budget"
SSeconomy.dep_cards += src
/obj/item/card/id/departmental_budget/Destroy()
+93
View File
@@ -0,0 +1,93 @@
// CHAINSAW
/obj/item/chainsaw
name = "chainsaw"
desc = "A versatile power tool. Useful for limbing trees and delimbing humans."
icon_state = "chainsaw_off"
lefthand_file = 'icons/mob/inhands/weapons/chainsaw_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi'
flags_1 = CONDUCT_1
force = 13
var/force_on = 24
w_class = WEIGHT_CLASS_HUGE
throwforce = 13
throw_speed = 2
throw_range = 4
custom_materials = list(/datum/material/iron=13000)
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = "swing_hit"
sharpness = IS_SHARP
actions_types = list(/datum/action/item_action/startchainsaw)
tool_behaviour = TOOL_SAW
toolspeed = 0.5
var/on = FALSE
var/wielded = FALSE // track wielded status on item
/obj/item/chainsaw/Initialize()
. = ..()
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
/obj/item/chainsaw/ComponentInitialize()
. = ..()
AddComponent(/datum/component/butchering, 30, 100, 0, 'sound/weapons/chainsawhit.ogg', TRUE)
AddComponent(/datum/component/two_handed, require_twohands=TRUE)
AddElement(/datum/element/update_icon_updates_onmob)
/// triggered on wield of two handed item
/obj/item/chainsaw/proc/on_wield(obj/item/source, mob/user)
wielded = TRUE
/// triggered on unwield of two handed item
/obj/item/chainsaw/proc/on_unwield(obj/item/source, mob/user)
wielded = FALSE
/obj/item/chainsaw/suicide_act(mob/living/carbon/user)
if(on)
user.visible_message("<span class='suicide'>[user] begins to tear [user.p_their()] head off with [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
playsound(src, 'sound/weapons/chainsawhit.ogg', 100, 1)
var/obj/item/bodypart/head/myhead = user.get_bodypart(BODY_ZONE_HEAD)
if(myhead)
myhead.dismember()
else
user.visible_message("<span class='suicide'>[user] smashes [src] into [user.p_their()] neck, destroying [user.p_their()] esophagus! It looks like [user.p_theyre()] trying to commit suicide!</span>")
playsound(src, 'sound/weapons/genhit1.ogg', 100, 1)
return(BRUTELOSS)
/obj/item/chainsaw/attack_self(mob/user)
on = !on
to_chat(user, "As you pull the starting cord dangling from [src], [on ? "it begins to whirr." : "the chain stops moving."]")
force = on ? force_on : initial(force)
throwforce = on ? force_on : force
update_icon()
var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering)
butchering.butchering_enabled = on
if(on)
hitsound = 'sound/weapons/chainsawhit.ogg'
else
hitsound = "swing_hit"
/obj/item/chainsaw/update_icon_state()
icon_state = "chainsaw_[on ? "on" : "off"]"
/obj/item/chainsaw/get_dismemberment_chance()
if(wielded)
. = ..()
/obj/item/chainsaw/doomslayer
name = "THE GREAT COMMUNICATOR"
desc = "<span class='warning'>VRRRRRRR!!!</span>"
armour_penetration = 100
force_on = 30
/obj/item/chainsaw/doomslayer/check_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
block_return[BLOCK_RETURN_REFLECT_PROJECTILE_CHANCE] = 100
return ..()
/obj/item/chainsaw/doomslayer/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(attack_type & ATTACK_TYPE_PROJECTILE)
owner.visible_message("<span class='danger'>Ranged attacks just make [owner] angrier!</span>")
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
return BLOCK_SUCCESS | BLOCK_PHYSICAL_EXTERNAL
return ..()
+1 -1
View File
@@ -65,7 +65,7 @@
. = ..()
AddElement(/datum/element/update_icon_blocker)
/obj/item/gun/energy/chrono_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
/obj/item/gun/energy/chrono_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
if(field)
field_disconnect(field)
..()
+7 -1
View File
@@ -8,6 +8,9 @@ CIGARS
SMOKING PIPES
CHEAP LIGHTERS
ZIPPO
ROLLING PAPER
VAPES
BONGS
CIGARETTE PACKETS ARE IN FANCY.DM
*/
@@ -506,7 +509,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
resistance_flags = FIRE_PROOF
light_color = LIGHT_COLOR_FIRE
grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/oil = 5)
custom_price = 55
custom_price = PRICE_ALMOST_CHEAP
/obj/item/lighter/Initialize()
. = ..()
@@ -616,6 +619,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
desc = "A cheap-as-free lighter."
icon_state = "lighter"
fancy = FALSE
custom_price = PRICE_CHEAP_AS_FREE
overlay_list = list(
"transp",
"tall",
@@ -790,6 +794,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
reagents.clear_reagents()
/obj/item/clothing/mask/vape/equipped(mob/user, slot)
. = ..()
if(slot == SLOT_WEAR_MASK)
if(!screw)
to_chat(user, "<span class='notice'>You start puffing on the vape.</span>")
@@ -799,6 +804,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
to_chat(user, "<span class='warning'>You need to close the cap first!</span>")
/obj/item/clothing/mask/vape/dropped(mob/user)
. = ..()
var/mob/living/carbon/C = user
if(C.get_item_by_slot(SLOT_WEAR_MASK) == src)
ENABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
@@ -14,6 +14,10 @@
name = "Security Cameras (Computer Board)"
build_path = /obj/machinery/computer/security
/obj/item/circuitboard/computer/security/shuttle
name = "Shuttlelinking Security Cameras (Computer Board)"
build_path = /obj/machinery/computer/security/shuttle
/obj/item/circuitboard/computer/xenobiology
name = "circuit board (Xenobiology Console)"
build_path = /obj/machinery/computer/camera_advanced/xenobio
@@ -112,9 +116,9 @@
build_path = /obj/machinery/computer/cloning
var/list/records = list()
/obj/item/circuitboard/computer/prototype_cloning
/obj/item/circuitboard/computer/cloning/prototype
name = "Prototype Cloning (Computer Board)"
build_path = /obj/machinery/computer/prototype_cloning
build_path = /obj/machinery/computer/cloning/prototype
/obj/item/circuitboard/computer/arcade/battle
name = "Arcade Battle (Computer Board)"
@@ -293,6 +297,10 @@
name = "Mining Shuttle (Computer Board)"
build_path = /obj/machinery/computer/shuttle/mining
/obj/item/circuitboard/computer/snow_taxi
name = "Snow Taxi (Computer Board)"
build_path = /obj/machinery/computer/shuttle/snow_taxi
/obj/item/circuitboard/computer/white_ship
name = "White Ship (Computer Board)"
build_path = /obj/machinery/computer/shuttle/white_ship
@@ -375,3 +383,11 @@
/obj/item/circuitboard/computer/nanite_cloud_controller
name = "Nanite Cloud Control (Computer Board)"
build_path = /obj/machinery/computer/nanite_cloud_controller
/obj/item/circuitboard/computer/shuttle/flight_control
name = "Shuttle Flight Control (Computer Board)"
build_path = /obj/machinery/computer/custom_shuttle
/obj/item/circuitboard/computer/shuttle/docker
name = "Shuttle Navigation Computer (Computer Board)"
build_path = /obj/machinery/computer/camera_advanced/shuttle_docker/custom
@@ -61,6 +61,14 @@
name = "Experimental Clone Pod (Machine Board)"
build_path = /obj/machinery/clonepod/experimental
/obj/item/circuitboard/machine/sheetifier
name = "Sheet-meister 2000 (Machine Board)"
icon_state = "supply"
build_path = /obj/machinery/sheetifier
req_components = list(
/obj/item/stock_parts/manipulator = 2,
/obj/item/stock_parts/matter_bin = 2)
/obj/item/circuitboard/machine/abductor
name = "alien board (Report This)"
icon_state = "abductor_mod"
@@ -692,6 +700,17 @@
def_components = list(/obj/item/stock_parts/cell = /obj/item/stock_parts/cell/high)
needs_anchored = FALSE
/obj/item/circuitboard/machine/chem_dispenser/apothecary
name = "Apotechary Chem Dispenser (Machine Board)"
build_path = /obj/machinery/chem_dispenser/apothecary
req_components = list(
/obj/item/stock_parts/matter_bin = 1,
/obj/item/stock_parts/capacitor = 1,
/obj/item/stock_parts/manipulator = 1,
/obj/item/stack/sheet/glass = 1,
/obj/item/stock_parts/cell = 1)
def_components = list(/obj/item/stock_parts/cell = /obj/item/stock_parts/cell/upgraded/plus)
/obj/item/circuitboard/machine/chem_dispenser/drinks
name = "Soda Dispenser (Machine Board)"
build_path = /obj/machinery/chem_dispenser/drinks
@@ -707,6 +726,10 @@
def_components = list(/obj/item/stock_parts/cell = /obj/item/stock_parts/cell/high)
needs_anchored = FALSE
/obj/item/circuitboard/machine/sleeper/party
name = "Party Pod (Machine Board)"
build_path = /obj/machinery/sleeper/party
/obj/item/circuitboard/machine/smoke_machine
name = "Smoke Machine (Machine Board)"
build_path = /obj/machinery/smoke_machine
@@ -884,6 +907,16 @@
name = "Departmental Protolathe - Service (Machine Board)"
build_path = /obj/machinery/rnd/production/protolathe/department/service
/obj/item/circuitboard/machine/bepis
name = "BEPIS Chamber (Machine Board)"
build_path = /obj/machinery/rnd/bepis
req_components = list(
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/capacitor = 1,
/obj/item/stock_parts/manipulator = 1,
/obj/item/stock_parts/micro_laser = 1,
/obj/item/stock_parts/scanning_module = 1)
/obj/item/circuitboard/machine/techfab
name = "\improper Techfab (Machine Board)"
build_path = /obj/machinery/rnd/production/techfab
@@ -1068,3 +1101,37 @@
/obj/item/stock_parts/matter_bin = 3,
/obj/item/stock_parts/manipulator = 1,
/obj/item/stack/sheet/glass = 1)
/obj/item/circuitboard/machine/hypnochair
name = "Enhanced Interrogation Chamber (Machine Board)"
icon_state = "security"
build_path = /obj/machinery/hypnochair
req_components = list(
/obj/item/stock_parts/micro_laser = 2,
/obj/item/stock_parts/scanning_module = 2
)
/obj/item/circuitboard/machine/shuttle/engine
name = "Thruster (Machine Board)"
build_path = /obj/machinery/shuttle/engine
req_components = list()
/obj/item/circuitboard/machine/shuttle/engine/plasma
name = "Plasma Thruster (Machine Board)"
build_path = /obj/machinery/shuttle/engine/plasma
req_components = list(/obj/item/stock_parts/capacitor = 2,
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/micro_laser = 1)
/obj/item/circuitboard/machine/shuttle/engine/void
name = "Void Thruster (Machine Board)"
build_path = /obj/machinery/shuttle/engine/void
req_components = list(/obj/item/stock_parts/capacitor/quadratic = 2,
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/micro_laser/quadultra = 1)
/obj/item/circuitboard/machine/shuttle/heater
name = "Electronic Engine Heater (Machine Board)"
build_path = /obj/machinery/atmospherics/components/unary/shuttle/heater
req_components = list(/obj/item/stock_parts/micro_laser = 2,
/obj/item/stock_parts/matter_bin = 1)

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