Merge remote-tracking branch 'citadel/master' into combat_rework_experimental

This commit is contained in:
silicons
2020-09-19 15:56:13 -07:00
1781 changed files with 68073 additions and 31311 deletions
+2 -1
View File
@@ -43,6 +43,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
outdoors = TRUE
ambientsounds = SPACE
blob_allowed = FALSE //Eating up space doesn't count for victory as a blob.
considered_hull_exterior = TRUE
/area/space/nearstation
icon_state = "space_near"
@@ -1592,4 +1593,4 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
valid_territory = FALSE
outdoors = TRUE
ambientsounds = SPACE
blob_allowed = FALSE //While part of the station, what good will it do you?
blob_allowed = FALSE //While part of the station, what good will it do you?
+6
View File
@@ -16,6 +16,8 @@
/// If it's valid territory for gangs/cults to summon
var/valid_territory = TRUE
/// malf ais can hack this
var/valid_malf_hack = TRUE
/// if blobs can spawn there and if it counts towards their score.
var/blob_allowed = TRUE
/// whether servants can warp into this area from Reebe
@@ -32,6 +34,9 @@
/// If megafauna can be spawned by natural random generation
var/megafauna_spawn_allowed = FALSE
/// Considered space for hull shielding
var/considered_hull_exterior = FALSE
var/fire = null
var/atmos = TRUE
var/atmosalm = FALSE
@@ -572,6 +577,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
power_environ = FALSE
always_unpowered = FALSE
valid_territory = FALSE
valid_malf_hack = FALSE
blob_allowed = FALSE
addSorted()
+18 -11
View File
@@ -26,7 +26,6 @@
var/list/atom_colours //used to store the different colors on an atom
//its inherent color, the colored paint applied on it, special color effect etc...
var/list/priority_overlays //overlays that should remain on top and not normally removed when using cut_overlay functions, like c4.
var/list/remove_overlays // a very temporary list of overlays to remove
var/list/add_overlays // a very temporary list of overlays to add
@@ -145,7 +144,6 @@
qdel(reagents)
LAZYCLEARLIST(overlays)
LAZYCLEARLIST(priority_overlays)
for(var/i in targeted_by)
var/mob/M = i
@@ -962,15 +960,16 @@
if(source != target)
target.log_talk(message, message_type, tag="[tag] from [key_name(source)]", log_globally=FALSE)
/*
Proc for attack log creation, because really why not
1 argument is the actor performing the action
2 argument is the target of the action
3 is a verb describing the action (e.g. punched, throwed, kicked, etc.)
4 is a tool with which the action was made (usually an item)
5 is any additional text, which will be appended to the rest of the log line
*/
/**
* Log a combat message in the attack log
*
* Arguments:
* * atom/user - argument is the actor performing the action
* * atom/target - argument is the target of the action
* * what_done - is a verb describing the action (e.g. punched, throwed, kicked, etc.)
* * atom/object - is a tool with which the action was made (usually an item)
* * addition - is any additional text, which will be appended to the rest of the log line
*/
/proc/log_combat(atom/user, atom/target, what_done, atom/object=null, addition=null)
var/ssource = key_name(user)
var/starget = key_name(target)
@@ -1120,3 +1119,11 @@ Proc for attack log creation, because really why not
max_grav = max(G.setting,max_grav)
return max_grav
return SSmapping.level_trait(T.z, ZTRAIT_GRAVITY)
/**
* Causes effects when the atom gets hit by a rust effect from heretics
*
* Override this if you want custom behaviour in whatever gets hit by the rust
*/
/atom/proc/rust_heretic_act()
return
+7
View File
@@ -646,3 +646,10 @@
animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = M, easing = CUBIC_EASING)
sleep(1)
animate(I, alpha = 0, transform = matrix(), time = 1)
/atom/movable/proc/set_anchored(anchorvalue) //literally only for plumbing ran
SHOULD_CALL_PARENT(TRUE)
if(anchored == anchorvalue)
return
. = anchored
anchored = anchorvalue
+4 -2
View File
@@ -213,6 +213,9 @@ Credit where due:
var/list/slots = list("In your left pocket" = SLOT_L_STORE, "In your right pocket" = SLOT_R_STORE, "In your backpack" = SLOT_IN_BACKPACK)
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/obj/item/clockwork/replica_fabricator/F = new
if(H.equip_to_slot_or_del(F, SLOT_IN_BACKPACK))
to_chat(H, "<span class='brass'>You have been equipped with a replica fabricator, an advanced tool that can convert objects like doors, tables or even coats into clockwork equivalents.</span>")
slot = H.equip_in_one_of_slots(S, slots)
if(slot == "In your backpack")
slot = "In your [H.back.name]"
@@ -221,8 +224,7 @@ Credit where due:
qdel(S)
if(S && !QDELETED(S))
to_chat(L, "<span class='alloy'>[slot] is a <b>clockwork slab</b>, a multipurpose tool used to construct machines and invoke ancient words of power. If this is your first time \
as a servant, you can find a concise tutorial in the Recollection category of its interface.</span>")
to_chat(L, "<span class='alloy italics'>If you want more information, you can read <a href=\"https://tgstation13.org/wiki/Clockwork_Cult\">the wiki page</a> to learn more.</span>")
as a servant, you can read <a href=\"https://citadel-station.net/wikimain/index.php?title=Clockwork_Cult\">the wiki page</a> to learn more.</span>")
return TRUE
return FALSE
@@ -62,7 +62,7 @@
hitsound = null
attack_verb_on = list("slipped")
clumsy_check = FALSE
sharpness = IS_BLUNT
sharpness = SHARP_NONE
sword_color = "yellow"
heat = 0
light_color = "#ffff00"
+2 -36
View File
@@ -6,10 +6,6 @@ GLOBAL_VAR_INIT(dynamic_latejoin_delay_max, (30 MINUTES))
GLOBAL_VAR_INIT(dynamic_midround_delay_min, (10 MINUTES))
GLOBAL_VAR_INIT(dynamic_midround_delay_max, (30 MINUTES))
GLOBAL_VAR_INIT(dynamic_event_delay_min, (10 MINUTES))
GLOBAL_VAR_INIT(dynamic_event_delay_max, (30 MINUTES)) // this is on top of regular events, so can't be quite as often
// -- Roundstart injection delays
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_min, (2 MINUTES))
GLOBAL_VAR_INIT(dynamic_first_latejoin_delay_max, (30 MINUTES))
@@ -58,7 +54,7 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
// Threat logging vars
/// Starting threat level, for things that increase it but can bring it back down.
var/initial_threat_level = 0
/// Target threat level right now. Events and antags will try to keep the round at this level.
/// Target threat level right now. Antags will try to keep the round at this level.
var/threat_level = 0
/// The current antag threat. Recalculated every time a ruletype starts or ends.
var/threat = 0
@@ -80,8 +76,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
var/list/latejoin_rules = list()
/// List of midround rules used for selecting the rules.
var/list/midround_rules = list()
/// List of events used for reducing threat without causing antag injection (necessarily).
var/list/events = list()
/** # Pop range per requirement.
* If the value is five the range is:
* 0-4, 5-9, 10-14, 15-19, 20-24, 25-29, 30-34, 35-39, 40-54, 45+
@@ -119,8 +113,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
var/latejoin_injection_cooldown = 0
/// When world.time is over this number the mode tries to inject a midround ruleset.
var/midround_injection_cooldown = 0
/// When wor.dtime is over this number the mode tries to do an event.
var/event_injection_cooldown = 0
/// When TRUE GetInjectionChance returns 100.
var/forced_injection = FALSE
/// Forced ruleset to be executed for the next latejoin.
@@ -184,7 +176,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
dat += "<br>Injection Timers: (<b>[storyteller.get_injection_chance(TRUE)]%</b> chance)<BR>"
dat += "Latejoin: [(latejoin_injection_cooldown-world.time)>60*10 ? "[round((latejoin_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(latejoin_injection_cooldown-world.time)/10] seconds"] <a href='?src=\ref[src];[HrefToken()];injectlate=1'>\[Now!\]</a><BR>"
dat += "Midround: [(midround_injection_cooldown-world.time)>60*10 ? "[round((midround_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(midround_injection_cooldown-world.time)/10] seconds"] <a href='?src=\ref[src];[HrefToken()];injectmid=1'>\[Now!\]</a><BR>"
dat += "Event: [(event_injection_cooldown-world.time)>60*10 ? "[round((event_injection_cooldown-world.time)/60/10,0.1)] minutes" : "[(event_injection_cooldown-world.time)/10] seconds"] <a href='?src=\ref[src];[HrefToken()];forceevent=1'>\[Now!\]</a><BR>"
usr << browse(dat.Join(), "window=gamemode_panel;size=500x500")
/datum/game_mode/dynamic/Topic(href, href_list)
@@ -204,10 +195,7 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
var/threatadd = input("Specify how much threat to add (negative to subtract). This can inflate the threat level.", "Adjust Threat", 0) as null|num
if(!threatadd)
return
if(threatadd > 0)
create_threat(threatadd)
else
remove_threat(threatadd)
create_threat(threatadd)
else if (href_list["injectlate"])
latejoin_injection_cooldown = 0
forced_injection = TRUE
@@ -216,10 +204,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
midround_injection_cooldown = 0
forced_injection = TRUE
message_admins("[key_name(usr)] forced a midround injection.", 1)
else if (href_list["forceevent"])
event_injection_cooldown = 0
// events always happen anyway
message_admins("[key_name(usr)] forced an event.", 1)
else if (href_list["threatlog"])
show_threatlog(usr)
else if (href_list["stacking_limit"])
@@ -377,8 +361,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
generate_threat()
storyteller.start_injection_cooldowns()
SSevents.frequency_lower = storyteller.event_frequency_lower // 6 minutes by default
SSevents.frequency_upper = storyteller.event_frequency_upper // 20 minutes by default
log_game("DYNAMIC: Dynamic Mode initialized with a Threat Level of... [threat_level]!")
initial_threat_level = threat_level
return TRUE
@@ -397,9 +379,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
if ("Midround")
if (ruleset.weight)
midround_rules += ruleset
if("Event")
if(ruleset.weight)
events += ruleset
for(var/mob/dead/new_player/player in GLOB.player_list)
if(player.ready == PLAYER_READY_TO_PLAY && player.mind)
roundstart_pop_ready++
@@ -596,8 +575,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
latejoin_rules = remove_from_list(latejoin_rules, rule.type)
else if(rule.ruletype == "Midround")
midround_rules = remove_from_list(midround_rules, rule.type)
else if(rule.ruletype == "Event")
events = remove_from_list(events,rule.type)
addtimer(CALLBACK(src, /datum/game_mode/dynamic/.proc/execute_midround_latejoin_rule, rule), rule.delay)
return TRUE
@@ -706,17 +683,6 @@ GLOBAL_VAR_INIT(dynamic_forced_storyteller, null)
picking_midround_latejoin_rule(drafted_rules)
// get_injection_chance can do things on fail
if(event_injection_cooldown < world.time)
SSblackbox.record_feedback("tally","dynamic",1,"Attempted event injections")
event_injection_cooldown = storyteller.get_event_cooldown() + world.time
message_admins("DYNAMIC: Doing event injection.")
log_game("DYNAMIC: Doing event injection.")
update_playercounts()
var/list/drafted_rules = storyteller.event_draft()
if(drafted_rules.len > 0)
SSblackbox.record_feedback("tally","dynamic",1,"Successful event injections")
picking_midround_latejoin_rule(drafted_rules)
/// Updates current_players.
/datum/game_mode/dynamic/proc/update_playercounts()
current_players[CURRENT_LIVING_PLAYERS] = list()
@@ -1,454 +0,0 @@
/datum/dynamic_ruleset/event
ruletype = "Event"
var/typepath // typepath of the event
var/triggering
var/earliest_start = 20 MINUTES
/datum/dynamic_ruleset/event/get_blackbox_info()
var/list/ruleset_data = list()
ruleset_data["name"] = name
ruleset_data["rule_type"] = ruletype
ruleset_data["cost"] = total_cost
ruleset_data["weight"] = weight
ruleset_data["scaled_times"] = scaled_times
ruleset_data["event_type"] = typepath
ruleset_data["population_tier"] = indice_pop
return ruleset_data
/datum/dynamic_ruleset/event/execute()
var/datum/round_event/E = new typepath()
E.current_players = get_active_player_count(alive_check = 1, afk_check = 1, human_check = 1)
// E.control = src // can't be done! we just don't use events that require these, those can be from_ghost almost always
testing("[time2text(world.time, "hh:mm:ss")] [E.type]")
deadchat_broadcast("<span class='deadsay'><b>[name]</b> has just been triggered by dynamic!</span>")
log_game("Random Event triggering: [name] ([typepath])")
return E
/datum/dynamic_ruleset/event/ready(forced = FALSE)
if (!forced)
if(earliest_start >= world.time-SSticker.round_start_time)
return FALSE
var/job_check = 0
if (enemy_roles.len > 0)
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
if (M.stat == DEAD)
continue // Dead players cannot count as opponents
if (M.mind && M.mind.assigned_role && (M.mind.assigned_role in enemy_roles))
job_check++ // Checking for "enemies" (such as sec officers). To be counters, they must either not be candidates to that rule, or have a job that restricts them from it
var/threat = round(mode.threat_level/10)
if (job_check < required_enemies[threat])
SSblackbox.record_feedback("tally","dynamic",1,"Times rulesets rejected due to not enough enemy roles")
return FALSE
return TRUE
//////////////////////////////////////////////
// //
// PIRATES //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/event/pirates
name = "Space Pirates"
config_tag = "pirates"
typepath = /datum/round_event/pirates
antag_flag = ROLE_TRAITOR
enemy_roles = list("AI","Security Officer","Head of Security","Captain")
required_enemies = list(2,2,1,1,0,0,0,0,0,0)
weight = 5
cost = 10
earliest_start = 30 MINUTES
blocking_rules = list(/datum/dynamic_ruleset/roundstart/nuclear,/datum/dynamic_ruleset/midround/from_ghosts/nuclear)
requirements = list(70,60,50,50,40,40,40,30,20,15)
property_weights = list("story_potential" = 1, "trust" = 1, "chaos" = 1)
high_population_requirement = 15
/datum/dynamic_ruleset/event/pirates/ready(forced = FALSE)
if (!SSmapping.empty_space)
return FALSE
return ..()
//////////////////////////////////////////////
// //
// SPIDERS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/event/spiders
name = "Spider Infestation"
config_tag = "spiders"
typepath = /datum/round_event/spider_infestation
enemy_roles = list("AI","Security Officer","Head of Security","Captain")
required_enemies = list(2,2,1,1,0,0,0,0,0,0)
weight = 5
cost = 10
requirements = list(70,60,50,50,40,40,40,30,20,15)
high_population_requirement = 15
property_weights = list("chaos" = 1, "valid" = 1)
//////////////////////////////////////////////
// //
// CLOGGED VENTS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/event/ventclog
name = "Clogged Vents"
config_tag = "ventclog"
typepath = /datum/round_event/vent_clog
enemy_roles = list("Chemist","Medical Doctor","Chief Medical Officer")
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
cost = 2
weight = 4
repeatable_weight_decrease = 3
requirements = list(5,5,5,5,5,5,5,5,5,5) // yes, can happen on fake-extended
high_population_requirement = 5
repeatable = TRUE
property_weights = list("chaos" = 1, "extended" = 2)
/datum/dynamic_ruleset/event/ventclog/ready()
if(mode.threat_level > 30 && mode.threat >= 5 && prob(20))
name = "Clogged Vents: Threatening"
cost = 5
required_enemies = list(3,3,3,2,2,2,1,1,1,1)
typepath = /datum/round_event/vent_clog/threatening
else if(mode.threat_level > 15 && mode.threat > 15 && prob(30))
name = "Clogged Vents: Catastrophic"
cost = 15
required_enemies = list(2,2,1,1,1,1,0,0,0,0)
typepath = /datum/round_event/vent_clog/catastrophic
else
cost = 2
name = "Clogged Vents: Normal"
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
typepath = /datum/round_event/vent_clog
return ..()
//////////////////////////////////////////////
// //
// ION STORM //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/event/ion_storm
name = "Ion Storm"
config_tag = "ion_storm"
typepath = /datum/round_event/ion_storm
enemy_roles = list("Research Director","Captain","Chief Engineer")
required_enemies = list(1,1,0,0,0,0,0,0,0,0)
weight = 4
// no repeatable weight decrease. too variable to be unfun multiple times in one round
cost = 1
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 5
repeatable = TRUE
property_weights = list("story_potential" = 1, "extended" = 1)
always_max_weight = TRUE
//////////////////////////////////////////////
// //
// METEORS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/event/meteor_wave
name = "Meteor Wave"
config_tag = "meteor_wave"
typepath = /datum/round_event/meteor_wave
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Captain","Cyborg")
required_enemies = list(3,3,3,3,3,3,3,3,3,3)
cost = 15
weight = 3
earliest_start = 25 MINUTES
repeatable_weight_decrease = 2
requirements = list(60,50,40,30,30,30,30,30,30,30)
high_population_requirement = 30
property_weights = list("extended" = -2)
/datum/dynamic_ruleset/event/meteor_wave/ready()
if(world.time-SSticker.round_start_time > 35 MINUTES && mode.threat_level > 40 && mode.threat >= 25 && prob(30))
name = "Meteor Wave: Threatening"
cost = 25
typepath = /datum/round_event/meteor_wave/threatening
else if(world.time-SSticker.round_start_time > 45 MINUTES && mode.threat_level > 50 && mode.threat >= 40 && prob(30))
name = "Meteor Wave: Catastrophic"
cost = 40
typepath = /datum/round_event/meteor_wave/catastrophic
else
name = "Meteor Wave: Normal"
cost = 15
typepath = /datum/round_event/meteor_wave
return ..()
//////////////////////////////////////////////
// //
// ANOMALIES //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/event/anomaly_bluespace
name = "Anomaly: Bluespace"
config_tag = "anomaly_bluespace"
typepath = /datum/round_event/anomaly/anomaly_bluespace
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
weight = 2
repeatable_weight_decrease = 1
cost = 3
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 5
repeatable = TRUE
property_weights = list("extended" = 1)
/datum/dynamic_ruleset/event/anomaly_flux
name = "Anomaly: Hyper-Energetic Flux"
config_tag = "anomaly_flux"
typepath = /datum/round_event/anomaly/anomaly_flux
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain")
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
weight = 2
repeatable_weight_decrease = 1
cost = 5
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 10
repeatable = TRUE
property_weights = list("extended" = 1)
/datum/dynamic_ruleset/event/anomaly_gravitational
name = "Anomaly: Gravitational"
config_tag = "anomaly_gravitational"
typepath = /datum/round_event/anomaly/anomaly_grav
weight = 2
repeatable_weight_decrease = 1
cost = 3
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 5
repeatable = TRUE
property_weights = list("extended" = 1)
/datum/dynamic_ruleset/event/anomaly_pyroclastic
name = "Anomaly: Pyroclastic"
config_tag = "anomaly_pyroclastic"
typepath = /datum/round_event/anomaly/anomaly_pyro
weight = 2
repeatable_weight_decrease = 1
cost = 5
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
requirements = list(10,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
repeatable = TRUE
property_weights = list("extended" = 1)
/datum/dynamic_ruleset/event/anomaly_vortex
name = "Anomaly: Vortex"
config_tag = "anomaly_vortex"
typepath = /datum/round_event/anomaly/anomaly_vortex
weight = 2
repeatable_weight_decrease = 1
cost = 5
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
requirements = list(10,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
repeatable = TRUE
property_weights = list("extended" = 1)
//////////////////////////////////////////////
// //
// WOW THAT'S A LOT OF EVENTS //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/event/brand_intelligence
name = "Brand Intelligence"
config_tag = "brand_intelligence"
typepath = /datum/round_event/brand_intelligence
weight = 1
repeatable_weight_decrease = 1
cost = 2
enemy_roles = list("Chief Engineer","Station Engineer","Atmospheric Technician","Research Director","Scientist","Captain","Cyborg")
required_enemies = list(1,1,1,1,0,0,0,0,0,0)
requirements = list(10,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
repeatable = TRUE
property_weights = list("extended" = -1, "chaos" = 1)
/datum/dynamic_ruleset/event/carp_migration
name = "Carp Migration"
config_tag = "carp_migration"
typepath = /datum/round_event/carp_migration
weight = 7
repeatable_weight_decrease = 3
cost = 4
requirements = list(10,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
earliest_start = 10 MINUTES
repeatable = TRUE
property_weights = list("extended" = 1)
/datum/dynamic_ruleset/event/communications_blackout
name = "Communications Blackout"
config_tag = "communications_blackout"
typepath = /datum/round_event/communications_blackout
cost = 4
weight = 2
repeatable_weight_decrease = 3
enemy_roles = list("Chief Engineer","Station Engineer")
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 5
repeatable = TRUE
property_weights = list("extended" = 1, "chaos" = 1)
/datum/dynamic_ruleset/event/processor_overload
name = "Processor Overload"
config_tag = "processor_overload"
typepath = /datum/round_event/processor_overload
cost = 4
weight = 2
repeatable_weight_decrease = 3
enemy_roles = list("Chief Engineer","Station Engineer")
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 5
repeatable = TRUE
property_weights = list("extended" = 1, "chaos" = 1)
always_max_weight = TRUE
/datum/dynamic_ruleset/event/space_dust
name = "Minor Space Dust"
config_tag = "space_dust"
typepath = /datum/round_event/space_dust
cost = 2
weight = 2
repeatable_weight_decrease = 1
enemy_roles = list("Chief Engineer","Station Engineer")
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 5
repeatable = TRUE
earliest_start = 0 MINUTES
property_weights = list("extended" = 1)
always_max_weight = TRUE
/datum/dynamic_ruleset/event/major_dust
name = "Major Space Dust"
config_tag = "major_dust"
typepath = /datum/round_event/meteor_wave/major_dust
cost = 4
weight = 2
repeatable_weight_decrease = 1
enemy_roles = list("Chief Engineer","Station Engineer")
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
requirements = list(10,10,10,10,10,10,10,10,10,10)
high_population_requirement = 10
repeatable = TRUE
property_weights = list("extended" = 1)
/datum/dynamic_ruleset/event/electrical_storm
name = "Electrical Storm"
config_tag = "electrical_storm"
typepath = /datum/round_event/electrical_storm
cost = 1
weight = 2
repeatable_weight_decrease = 1
enemy_roles = list("Chief Engineer","Station Engineer")
required_enemies = list(1,1,1,0,0,0,0,0,0,0)
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 5
repeatable = TRUE
property_weights = list("extended" = 1)
/datum/dynamic_ruleset/event/heart_attack
name = "Random Heart Attack"
config_tag = "heart_attack"
typepath = /datum/round_event/heart_attack
cost = 3
weight = 2
repeatable_weight_decrease = 1
enemy_roles = list("Medical Doctor","Chief Medical Officer")
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
requirements = list(101,101,101,5,5,5,5,5,5,5)
high_population_requirement = 5
repeatable = TRUE
property_weights = list("extended" = 1)
always_max_weight = TRUE
/datum/dynamic_ruleset/event/radiation_storm
name = "Radiation Storm"
config_tag = "radiation_storm"
typepath = /datum/round_event/radiation_storm
cost = 3
weight = 1
enemy_roles = list("Chemist","Chief Medical Officer","Geneticist","Medical Doctor","AI","Captain")
required_enemies = list(1,1,1,1,1,1,1,1,1,1)
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 5
property_weights = list("extended" = 1,"chaos" = 1)
/datum/dynamic_ruleset/event/portal_storm_syndicate
name = "Portal Storm"
config_tag = "portal_storm"
typepath = /datum/round_event/portal_storm/syndicate_shocktroop
cost = 10
weight = 1
enemy_roles = list("Head of Security","Security Officer","AI","Captain","Shaft Miner")
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
requirements = list(101,101,101,30,30,30,30,30,30,30)
high_population_requirement = 30
earliest_start = 30 MINUTES
property_weights = list("teamwork" = 1,"chaos" = 1, "extended" = -1)
/datum/dynamic_ruleset/event/wormholes
name = "Wormholes"
config_tag = "wormhole"
typepath = /datum/round_event/wormholes
cost = 3
weight = 4
enemy_roles = list("AI","Medical Doctor","Station Engineer","Head of Personnel","Captain")
required_enemies = list(2,2,2,2,2,2,2,2,2,2)
requirements = list(5,5,5,5,5,5,5,5,5,5)
high_population_requirement = 5
property_weights = list("extended" = 1)
/datum/dynamic_ruleset/event/swarmers
name = "Swarmers"
config_tag = "swarmer"
typepath = /datum/round_event/spawn_swarmer
cost = 10
weight = 1
earliest_start = 30 MINUTES
enemy_roles = list("AI","Security Officer","Head of Security","Captain","Station Engineer","Atmos Technician","Chief Engineer")
required_enemies = list(4,4,4,4,3,3,2,2,1,1)
requirements = list(101,101,101,101,101,101,101,101,101,101)
high_population_requirement = 5
property_weights = list("extended" = -2)
/datum/dynamic_ruleset/event/sentient_disease
name = "Sentient Disease"
config_tag = "sentient_disease"
typepath = /datum/round_event/ghost_role/sentient_disease
enemy_roles = list("Virologist","Chief Medical Officer","Captain","Chemist")
required_enemies = list(2,1,1,1,0,0,0,0,0,0)
required_candidates = 1
weight = 4
cost = 5
requirements = list(30,30,20,20,15,10,10,10,10,5) // yes, it can even happen in "extended"!
property_weights = list("story_potential" = 1, "extended" = 1, "valid" = -2)
high_population_requirement = 5
/datum/dynamic_ruleset/event/revenant
name = "Revenant"
config_tag = "revenant"
typepath = /datum/round_event/ghost_role/revenant
enemy_roles = list("Chief Engineer","Station Engineer","Captain","Chaplain","AI")
required_enemies = list(2,1,1,1,0,0,0,0,0,0)
required_candidates = 1
weight = 4
cost = 5
requirements = list(30,30,30,30,20,15,15,15,15,15)
high_population_requirement = 15
property_weights = list("story_potential" = -2, "extended" = -1)
@@ -191,6 +191,26 @@
SSticker.mode_result = "loss - rev heads killed"
SSticker.news_report = REVS_LOSE
//////////////////////////////////////////////
// //
// HERETIC SMUGGLER //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/latejoin/heretic_smuggler
name = "Heretic Smuggler"
antag_datum = /datum/antagonist/heretic
antag_flag = "latejoin_heretic"
protected_roles = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster")
restricted_roles = list("AI","Cyborg")
required_candidates = 1
weight = 4
cost = 25
requirements = list(60,60,60,55,50,50,50,50,50,50)
high_population_requirement = 50
property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2)
repeatable = TRUE
//////////////////////////////////////////////
// //
// BLOODSUCKERS //
@@ -538,7 +538,7 @@
name = "Slaughter Demon"
config_tag = "slaughter_demon"
antag_flag = ROLE_ALIEN
enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg")
enemy_roles = list("Security Officer","Shaft Miner","Head of Security","Captain","Janitor","AI","Cyborg","Bartender")
required_enemies = list(3,2,2,2,2,1,1,1,1,0)
required_candidates = 1
weight = 4
@@ -143,6 +143,48 @@
changeling.add_antag_datum(new_antag)
return TRUE
//////////////////////////////////////////////
// //
// ELDRITCH CULT //
// //
//////////////////////////////////////////////
/datum/dynamic_ruleset/roundstart/heretics
name = "Heretics"
antag_flag = "heretic"
antag_datum = /datum/antagonist/heretic
protected_roles = list("Prisoner","Security Officer", "Warden", "Detective", "Head of Security", "Captain")
restricted_roles = list("AI", "Cyborg")
required_candidates = 1
weight = 3
cost = 25
scaling_cost = 15
requirements = list(60,60,60,55,50,50,50,50,50,50)
property_weights = list("story_potential" = 1, "trust" = -1, "chaos" = 2, "extended" = -1, "valid" = 2)
antag_cap = list(1,1,1,1,2,2,2,2,3,3)
high_population_requirement = 50
/datum/dynamic_ruleset/roundstart/heretics/pre_execute()
. = ..()
var/num_ecult = antag_cap[indice_pop] * (scaled_times + 1)
for (var/i = 1 to num_ecult)
var/mob/picked_candidate = pick_n_take(candidates)
assigned += picked_candidate.mind
picked_candidate.mind.restricted_roles = restricted_roles
picked_candidate.mind.special_role = ROLE_HERETIC
return TRUE
/datum/dynamic_ruleset/roundstart/heretics/execute()
for(var/c in assigned)
var/datum/mind/cultie = c
var/datum/antagonist/heretic/new_antag = new antag_datum()
cultie.add_antag_datum(new_antag)
return TRUE
//////////////////////////////////////////////
// //
// WIZARDS //
@@ -22,14 +22,14 @@
var/datum/game_mode/dynamic/mode = null // Cached as soon as it's made, by dynamic.
/**
Property weights are:
Property weights are added to the config weight of the ruleset. They are:
"story_potential" -- essentially how many different ways the antag can be played.
"trust" -- How much it makes the crew trust each other. Negative values means they're suspicious. Team antags are like this.
"chaos" -- How chaotic it makes the round. Has some overlap with "valid" and somewhat contradicts "extended".
"valid" -- How likely the non-antag-enemy crew are to get involved, e.g. nukies encouraging the warden to
let everyone into the armory, wizard moving around and being a nuisance, nightmare busting lights.
"extended" -- How much the antag is conducive to a long round. Nukies and cults are bad for this; Wizard is less bad; and so on.
"conversion" -- Basically a bool. Conversion antags, well, convert. It's its own class for a good reason.
"conversion" -- Basically a bool. Conversion antags, well, convert. It's in its own class 'cause people kinda hate conversion.
*/
/datum/dynamic_storyteller/proc/start_injection_cooldowns()
@@ -39,9 +39,6 @@ Property weights are:
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_first_midround_delay_min + GLOB.dynamic_first_midround_delay_max)
mode.midround_injection_cooldown = round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_first_midround_delay_min, GLOB.dynamic_first_midround_delay_max)) + world.time
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
mode.event_injection_cooldown = (round(clamp(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max)) + world.time)
/datum/dynamic_storyteller/proc/calculate_threat()
var/threat = 0
for(var/datum/antagonist/A in GLOB.antagonists)
@@ -50,10 +47,6 @@ Property weights are:
for(var/r in SSevents.running)
var/datum/round_event/R = r
threat += R.threat()
for(var/mob/living/simple_animal/hostile/H in GLOB.mob_living_list)
var/turf/T = get_turf(H)
if(H.stat != DEAD && is_station_level(T.z) && !("Station" in H.faction))
threat += H.threat()
for(var/obj/item/phylactery/P in GLOB.poi_list)
threat += 25 // can't be giving them too much of a break
for (var/mob/M in mode.current_players[CURRENT_LIVING_PLAYERS])
@@ -91,6 +84,8 @@ Property weights are:
mean += 2.5
if(CHAOS_MAX)
mean += 5
else
voters += 0.5
if(voters)
GLOB.dynamic_curve_centre += (mean/voters)
if(flags & USE_PREV_ROUND_WEIGHTS)
@@ -101,10 +96,6 @@ Property weights are:
var/midround_injection_cooldown_middle = 0.5*(GLOB.dynamic_midround_delay_max + GLOB.dynamic_midround_delay_min)
return round(clamp(EXP_DISTRIBUTION(midround_injection_cooldown_middle), GLOB.dynamic_midround_delay_min, GLOB.dynamic_midround_delay_max))
/datum/dynamic_storyteller/proc/get_event_cooldown()
var/event_injection_cooldown_middle = 0.5*(GLOB.dynamic_event_delay_max + GLOB.dynamic_event_delay_min)
return round(clamp(EXP_DISTRIBUTION(event_injection_cooldown_middle), GLOB.dynamic_event_delay_min, GLOB.dynamic_event_delay_max))
/datum/dynamic_storyteller/proc/get_latejoin_cooldown()
var/latejoin_injection_cooldown_middle = 0.5*(GLOB.dynamic_latejoin_delay_max + GLOB.dynamic_latejoin_delay_min)
return round(clamp(EXP_DISTRIBUTION(latejoin_injection_cooldown_middle), GLOB.dynamic_latejoin_delay_min, GLOB.dynamic_latejoin_delay_max))
@@ -128,7 +119,9 @@ Property weights are:
for(var/property in property_weights)
if(property in rule.property_weights) // just treat it as 0 if it's not in there
property_weight += rule.property_weights[property] * property_weights[property]
drafted_rules[rule] = (rule.get_weight() * property_weight)*rule.weight_mult
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult
if(calced_weight > 0) // negatives in the list might cause problems
drafted_rules[rule] = calced_weight
return drafted_rules
/datum/dynamic_storyteller/proc/midround_draft()
@@ -140,25 +133,29 @@ Property weights are:
if (GLOB.dynamic_classic_secret && !((rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)))
continue
rule.trim_candidates()
var/threat_weight = 1
if(!(rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
pick this particular ruleset.
Let's use a toy example: there's 60 threat level and 10 threat spent.
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
is 2.26 times as likely to be picked, all other things considered.
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
*/
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
if (rule.ready())
var/property_weight = 0
for(var/property in property_weights)
if(property in rule.property_weights)
if(property in rule.property_weights) // just treat it as 0 if it's not in there
property_weight += rule.property_weights[property] * property_weights[property]
drafted_rules[rule] = round(((rule.get_weight() * property_weight)*rule.weight_mult*threat_weight)*1000,1)
var/threat_weight = 1
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET)) // makes the traitor rulesets always possible anyway
var/cost_difference = rule.cost-(mode.threat_level-mode.threat)
/* Basically, the closer the cost is to the current threat-level-away-from-threat, the more likely it is to
pick this particular ruleset.
Let's use a toy example: there's 60 threat level and 10 threat spent.
We want to pick a ruleset that's close to that, so we run the below equation, on two rulesets.
Ruleset 1 has 30 cost, ruleset 2 has 5 cost.
When we do the math, ruleset 1's threat_weight is 0.538, and ruleset 2's is 0.238, meaning ruleset 1
is 2.26 times as likely to be picked, all other things considered.
Of course, we don't want it to GUARANTEE the closest, that's no fun, so it's just a weight.
*/
threat_weight = abs(1-abs(1-LOGISTIC_FUNCTION(2,0.05,abs(cost_difference),0)))
if(cost_difference > 0)
threat_weight /= (1+(cost_difference*0.1))
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult * threat_weight
if(calced_weight > 0)
drafted_rules[rule] = calced_weight
return drafted_rules
/datum/dynamic_storyteller/proc/latejoin_draft(mob/living/carbon/human/newPlayer)
@@ -175,31 +172,22 @@ Property weights are:
rule.candidates = list(newPlayer)
rule.trim_candidates()
var/threat_weight = 1
if(!(rule.flags & MINOR_RULESET))
var/cost_difference = abs(rule.cost-(mode.threat_level-mode.threat))
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,cost_difference,0)))
if (rule.ready())
var/property_weight = 0
for(var/property in property_weights)
if(property in rule.property_weights)
property_weight += rule.property_weights[property] * property_weights[property]
drafted_rules[rule] = round(((rule.get_weight() * property_weight)*rule.weight_mult*threat_weight)*1000,1)
var/threat_weight = 1
if(!(rule.flags & TRAITOR_RULESET) || (rule.flags & MINOR_RULESET))
var/cost_difference = rule.cost-(mode.threat_level-mode.threat)
threat_weight = 1-abs(1-(LOGISTIC_FUNCTION(2,0.05,abs(cost_difference),0)))
if(cost_difference > 0)
threat_weight /= (1+(cost_difference*0.1))
var/calced_weight = (rule.get_weight() + property_weight) * rule.weight_mult * threat_weight
if(calced_weight > 0)
drafted_rules[rule] = calced_weight
return drafted_rules
/datum/dynamic_storyteller/proc/event_draft()
var/list/drafted_rules = list()
for(var/datum/dynamic_ruleset/event/rule in mode.events)
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level) && (mode.threat_level - mode.threat) >= rule.cost)
if(rule.ready())
var/property_weight = 0
for(var/property in property_weights)
if(property in rule.property_weights)
property_weight += rule.property_weights[property] * property_weights[property]
drafted_rules[rule] = (rule.get_weight() + property_weight)*rule.weight_mult
return drafted_rules
/datum/dynamic_storyteller/chaotic
name = "Chaotic"
config_tag = "chaotic"
@@ -262,9 +250,6 @@ Property weights are:
/datum/dynamic_storyteller/random/get_midround_cooldown()
return rand(GLOB.dynamic_midround_delay_min/2, GLOB.dynamic_midround_delay_max*2)
/datum/dynamic_storyteller/random/get_event_cooldown()
return rand(GLOB.dynamic_event_delay_min/2, GLOB.dynamic_event_delay_max*2)
/datum/dynamic_storyteller/random/get_latejoin_cooldown()
return rand(GLOB.dynamic_latejoin_delay_min/2, GLOB.dynamic_latejoin_delay_max*2)
@@ -310,14 +295,6 @@ Property weights are:
drafted_rules[rule] = 1
return drafted_rules
/datum/dynamic_storyteller/random/event_draft()
var/list/drafted_rules = list()
for(var/datum/dynamic_ruleset/event/rule in mode.events)
if(rule.acceptable(mode.current_players[CURRENT_LIVING_PLAYERS].len, mode.threat_level))
if(rule.ready())
drafted_rules[rule] = 1
return drafted_rules
/datum/dynamic_storyteller/story
name = "Story"
config_tag = "story"
@@ -327,12 +304,6 @@ Property weights are:
flags = USE_PREV_ROUND_WEIGHTS
property_weights = list("story_potential" = 2)
/datum/dynamic_storyteller/story/calculate_threat()
var/current_time = (world.time / SSautotransfer.targettime)*180
mode.threat_level = round(mode.initial_threat_level*(sin(current_time)+0.25),0.1)
return ..()
/datum/dynamic_storyteller/classic
name = "Classic"
config_tag = "classic"
@@ -363,7 +334,7 @@ Property weights are:
/datum/dynamic_storyteller/no_antag
name = "Extended"
config_tag = "semiextended"
desc = "No standard antags. Threatening events may still spawn."
desc = "No standard antags."
curve_centre = -5
curve_width = 0.5
flags = NO_ASSASSIN | FORCE_IF_WON
@@ -375,15 +346,3 @@ Property weights are:
/datum/dynamic_storyteller/no_antag/get_injection_chance(dry_run)
return 0
/datum/dynamic_storyteller/extended
name = "Super Extended"
config_tag = "extended"
desc = "No antags. No dangerous events."
curve_centre = -20
weight = 0
curve_width = 0.5
/datum/dynamic_storyteller/extended/on_start()
..()
GLOB.dynamic_forced_extended = TRUE
@@ -0,0 +1,67 @@
/datum/game_mode/heretics
name = "heresy"
config_tag = "heresy"
antag_flag = ROLE_HERETIC
false_report_weight = 5
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Chief Engineer", "Chief Medical Officer", "Research Director", "Quartermaster") //citadel change - adds HoP, CE, CMO, and RD to heretic role blacklist
required_players = 15
required_enemies = 1
recommended_enemies = 4
reroll_friendly = 1
enemy_minimum_age = 0
round_ends_with_antag_death = 0
announce_span = "danger"
announce_text = "Heretics have been spotted on the station!\n\
<span class='danger'>Heretics</span>: Accomplish your objectives.\n\
<span class='notice'>Crew</span>: Do not let the madman succeed!"
var/ecult_possible = 4 //hard limit on culties if scaling is turned off
var/num_ecult = 1
var/list/culties = list()
/datum/game_mode/heretics/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += "Assistant"
var/esc = CONFIG_GET(number/ecult_scaling_coeff)
if(esc)
num_ecult = min(max(1, min(round(num_players() / (esc * 2)) + 2, round(num_players() / esc))),4)
else
num_ecult = max(1, min(num_players(), ecult_possible))
for(var/i in 1 to num_ecult)
if(!antag_candidates.len)
break
var/datum/mind/cultie = antag_pick(antag_candidates)
antag_candidates -= cultie
cultie.special_role = ROLE_HERETIC
cultie.restricted_roles = restricted_jobs
culties += cultie
var/enough_heretics = culties.len > 0
if(!enough_heretics)
setup_error = "Not enough heretic candidates"
return FALSE
else
for(var/antag in culties)
return TRUE
/datum/game_mode/heretics/post_setup()
for(var/c in culties)
var/datum/mind/cultie = c
log_game("[key_name(cultie)] has been selected as a heretic!")
var/datum/antagonist/heretic/new_antag = new()
cultie.add_antag_datum(new_antag)
return ..()
/datum/game_mode/heretics/generate_report()
return "Cybersun Industries has announced that they have successfully raided a high-security library. The library contained a very dangerous book that was \
shown to posses anomalous properties. We suspect that the book has been copied over, Stay vigilant!"
+3 -2
View File
@@ -112,7 +112,7 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
var/turf/T = get_turf(loc)
ram_turf(T)
if(prob(10) && !isspaceturf(T))//randomly takes a 'hit' from ramming
if(prob(10) && !isspaceturf(T) && !istype(T, /turf/closed/mineral) && !istype(T, /turf/open/floor/plating/asteroid))//randomly takes a 'hit' from ramming
get_hit()
/obj/effect/meteor/Destroy()
@@ -136,7 +136,8 @@ GLOBAL_LIST_INIT(meteorsC, list(/obj/effect/meteor/dust)) //for space dust event
if(A)
ram_turf(get_turf(A))
playsound(src.loc, meteorsound, 40, 1)
get_hit()
if(!istype(A, /turf/closed/mineral) && !istype(A, /turf/open/floor/plating/asteroid))
get_hit()
/obj/effect/meteor/proc/ram_turf(turf/T)
//first bust whatever is in the turf
+58 -174
View File
@@ -12,9 +12,9 @@
density = FALSE
state_open = TRUE
circuit = /obj/item/circuitboard/machine/sleeper
req_access = list(ACCESS_CMO) //Used for reagent deletion and addition of non medicines
var/efficiency = 1
var/min_health = 30
var/min_health = -25
var/list/available_chems
var/controls_inside = FALSE
var/list/possible_chems = list(
@@ -31,32 +31,13 @@
/obj/machinery/sleeper/Initialize()
. = ..()
create_reagents(500, NO_REACT)
// if(mapload)
// component_parts -= circuit
// QDEL_NULL(circuit)
occupant_typecache = GLOB.typecache_living
update_icon()
reset_chem_buttons()
RefreshParts()
add_inital_chems()
new_occupant_dir = dir
/obj/machinery/sleeper/setDir(newdir)
. = ..()
new_occupant_dir = dir
/obj/machinery/sleeper/on_deconstruction()
var/obj/item/reagent_containers/sleeper_buffer/buffer = new (loc)
buffer.volume = reagents.maximum_volume
buffer.reagents.maximum_volume = reagents.maximum_volume
reagents.trans_to(buffer.reagents, reagents.total_volume)
/obj/machinery/sleeper/proc/add_inital_chems()
for(var/i in available_chems)
var/datum/reagent/R = reagents.has_reagent(i)
if(!R)
reagents.add_reagent(i, (20))
continue
if(R.volume < 20)
reagents.add_reagent(i, (20 - R.volume))
/obj/machinery/sleeper/RefreshParts()
var/E
@@ -73,15 +54,11 @@
available_chems |= possible_chems[i]
reset_chem_buttons()
//Total container size 500 - 2000u
if(reagents)
reagents.maximum_volume = (500*E)
/obj/machinery/sleeper/update_icon_state()
icon_state = initial(icon_state)
if(state_open)
icon_state += "-open"
icon_state = "[initial(icon_state)]-open"
else
icon_state = initial(icon_state)
/obj/machinery/sleeper/container_resist(mob/living/user)
visible_message("<span class='notice'>[occupant] emerges from [src]!</span>",
@@ -98,10 +75,12 @@
/obj/machinery/sleeper/open_machine()
if(!state_open && !panel_open)
// flick("[initial(icon_state)]-anim", src)
..()
/obj/machinery/sleeper/close_machine(mob/user)
if((isnull(user) || istype(user)) && state_open && !panel_open)
// flick("[initial(icon_state)]-anim", src)
..(user)
var/mob/living/mob_occupant = occupant
if(mob_occupant && mob_occupant.stat != DEAD)
@@ -112,46 +91,23 @@
if (. & EMP_PROTECT_SELF)
return
if(is_operational() && occupant)
var/datum/reagent/R = pick(reagents.reagent_list)
var/datum/reagent/R = pick(reagents.reagent_list) //cit specific
inject_chem(R.type, occupant)
open_machine()
//Is this too much?
//Is this too much? Cit specific
if(severity == EMP_HEAVY)
var/chem = pick(available_chems)
available_chems -= chem
available_chems += get_random_reagent_id()
reset_chem_buttons()
/obj/machinery/sleeper/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/reagent_containers/sleeper_buffer))
var/obj/item/reagent_containers/sleeper_buffer/SB = I
if((SB.reagents.total_volume + reagents.total_volume) < reagents.maximum_volume)
SB.reagents.trans_to(reagents, SB.reagents.total_volume)
visible_message("[user] places the [SB] into the [src].")
qdel(SB)
return
else
SB.reagents.trans_to(reagents, SB.reagents.total_volume)
visible_message("[user] adds as much as they can to the [src] from the [SB].")
return
if(istype(I, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = I
if(RC.reagents.total_volume == 0)
to_chat(user, "<span class='notice'>The [I] is empty!</span>")
for(var/datum/reagent/R in RC.reagents.reagent_list)
if((obj_flags & EMAGGED) || (allowed(usr)))
break
if(!istype(R, /datum/reagent/medicine))
visible_message("The [src] gives out a hearty boop and rejects the [I]. The Sleeper's screen flashes with a pompous \"Medicines only, please.\"")
return
RC.reagents.trans_to(reagents, 1000)
visible_message("[user] adds as much as they can to the [src] from the [I].")
return
/obj/machinery/sleeper/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
if(user.stat || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser())
return
if(isliving(user))
var/mob/living/L = user
if(!(L.mobility_flags & MOBILITY_STAND))
return
close_machine(target)
/obj/machinery/sleeper/screwdriver_act(mob/living/user, obj/item/I)
@@ -187,31 +143,29 @@
visible_message("<span class='notice'>[usr] pries open [src].</span>", "<span class='notice'>You pry open [src].</span>")
open_machine()
/obj/machinery/sleeper/ui_state(mob/user)
if(controls_inside)
return GLOB.contained_state
return GLOB.default_state
/obj/machinery/sleeper/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Sleeper", name)
ui.open()
/obj/machinery/sleeper/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, !hasSiliconAccessInArea(user)))
if(!user.canUseTopic(src, !issilicon(user)))
return
if(state_open)
close_machine()
else
open_machine()
return TRUE
/obj/machinery/sleeper/examine(mob/user)
. = ..()
. += "<span class='notice'>Alt-click [src] to [state_open ? "close" : "open"] it.</span>"
/obj/machinery/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
if(controls_inside && state == GLOB.notcontained_state)
state = GLOB.default_state // If it has a set of controls on the inside, make it actually controllable by the mob in it.
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "Sleeper", name, 550, 700, master_ui, state)
ui.open()
/obj/machinery/sleeper/process()
..()
check_nap_violations()
@@ -221,22 +175,13 @@
/obj/machinery/sleeper/ui_data()
var/list/data = list()
var/chemical_list = list()
var/blood_percent = 0
data["occupied"] = occupant ? 1 : 0
data["open"] = state_open
data["blood_levels"] = blood_percent
data["blood_status"] = "Patient either has no blood, or does not require it to function."
data["chemical_list"] = chemical_list
data["chems"] = list()
for(var/chem in available_chems)
var/datum/reagent/R = reagents.has_reagent(chem)
R = GLOB.chemical_reagents_list[chem]
data["synthchems"] += list(list("name" = R.name, "id" = R.type, "synth_allowed" = synth_allowed(chem)))
for(var/datum/reagent/R in reagents.reagent_list)
data["chems"] += list(list("name" = R.name, "id" = R.type, "vol" = R.volume, "purity" = R.purity, "allowed" = chem_allowed(R.type)))
var/datum/reagent/R = GLOB.chemical_reagents_list[chem]
data["chems"] += list(list("name" = R.name, "id" = R.type, "allowed" = chem_allowed(chem)))
data["occupant"] = list()
var/mob/living/mob_occupant = occupant
@@ -264,40 +209,10 @@
data["occupant"]["fireLoss"] = mob_occupant.getFireLoss()
data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss()
data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN)
if(mob_occupant.reagents.reagent_list.len)
data["occupant"]["reagents"] = list()
if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len)
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
chemical_list += list(list("name" = R.name, "volume" = R.volume))
else
chemical_list = "Patient has no reagents."
data["occupant"]["failing_organs"] = list()
var/mob/living/carbon/C = mob_occupant
if(C)
for(var/obj/item/organ/Or in C.getFailingOrgans())
if(istype(Or, /obj/item/organ/brain))
continue
data["occupant"]["failing_organs"] += list(list("name" = Or.name))
if(istype(C)) //Non-carbons shouldn't be able to enter sleepers, but this is to prevent runtimes if something ever breaks
if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner.
blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100)
var/blood_id = C.get_blood_id()
var/blood_warning = ""
if(blood_percent < 80)
blood_warning = "Patient has low blood levels."
if(blood_percent < 60)
blood_warning = "Patient has DANGEROUSLY low blood levels."
if(blood_id)
var/blood_type = C.dna.blood_type
if(!(blood_id in GLOB.blood_reagent_types)) // special blood substance
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
if(R)
blood_type = R.name
else
blood_type = blood_id
data["blood_status"] = "Patient has [blood_type] type blood. [blood_warning]"
data["blood_levels"] = blood_percent
data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume))
return data
/obj/machinery/sleeper/ui_act(action, params)
@@ -314,37 +229,14 @@
. = TRUE
if("inject")
var/chem = text2path(params["chem"])
var/amount = text2num(params["volume"])
if(!is_operational() || !mob_occupant || isnull(chem))
return
if(mob_occupant.health < min_health && chem != /datum/reagent/medicine/epinephrine)
return
if(inject_chem(chem, usr, amount))
if(inject_chem(chem, usr))
. = TRUE
if(scrambled_chems && prob(5))
to_chat(usr, "<span class='warning'>Chemical system re-route detected, results may not be as expected!</span>")
if("synth")
var/chem = text2path(params["chem"])
if(!is_operational())
return
reagents.add_reagent(chem_buttons[chem], 10) //other_purity = 0.75 for when the mechanics are in
if("purge")
var/chem = text2path(params["chem"])
if(allowed(usr))
if(!is_operational())
return
reagents.remove_reagent(chem, 1000)
return
if(chem in available_chems)
if(!is_operational())
return
/*var/datum/reagent/R = reagents.has_reagent(chem) //For when purity effects are in
if(R.purity < 0.8)*/
reagents.remove_reagent(chem, 1000)
else
visible_message("<span class='warning'>Access Denied.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
/obj/machinery/sleeper/emag_act(mob/user)
. = ..()
@@ -353,10 +245,9 @@
to_chat(user, "<span class='warning'>You scramble the sleeper's user interface!</span>")
return TRUE
//trans to
/obj/machinery/sleeper/proc/inject_chem(chem, mob/user, volume = 10)
if(chem_allowed(chem))
reagents.trans_id_to(occupant, chem, volume)//emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU
/obj/machinery/sleeper/proc/inject_chem(chem, mob/user)
if((chem in available_chems) && chem_allowed(chem))
occupant.reagents.add_reagent(chem_buttons[chem], 10) //emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU
if(user)
log_combat(user, occupant, "injected [chem] into", addition = "via [src]")
return TRUE
@@ -369,14 +260,6 @@
var/occ_health = mob_occupant.health > min_health || chem == /datum/reagent/medicine/epinephrine
return amount && occ_health
/obj/machinery/sleeper/proc/synth_allowed(chem)
var/datum/reagent/R = reagents.has_reagent(chem)
if(!R)
return TRUE
if(R.volume < 50)
return TRUE
return FALSE
/obj/machinery/sleeper/proc/reset_chem_buttons()
scrambled_chems = FALSE
LAZYINITLIST(chem_buttons)
@@ -416,23 +299,6 @@
component_parts += new /obj/item/stack/cable_coil(null)
RefreshParts()
/obj/machinery/sleeper/clockwork
name = "soothing sleeper"
desc = "A large cryogenics unit built from brass. Its surface is pleasantly cool the touch."
icon_state = "sleeper_clockwork"
enter_message = "<span class='bold inathneq_small'>You hear the gentle hum and click of machinery, and are lulled into a sense of peace.</span>"
possible_chems = list(list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/salbutamol, /datum/reagent/medicine/bicaridine,
/datum/reagent/medicine/kelotane, /datum/reagent/medicine/oculine, /datum/reagent/medicine/inacusiate, /datum/reagent/medicine/mannitol))
/obj/machinery/sleeper/clockwork/process()
if(occupant && isliving(occupant))
var/mob/living/L = occupant
if(GLOB.clockwork_vitality) //If there's Vitality, the sleeper has passive healing
GLOB.clockwork_vitality = max(0, GLOB.clockwork_vitality - 1)
L.adjustBruteLoss(-1)
L.adjustFireLoss(-1)
L.adjustOxyLoss(-5)
/obj/machinery/sleeper/old
icon_state = "oldpod"
@@ -443,8 +309,6 @@
idle_power_usage = 3000
circuit = /obj/item/circuitboard/machine/sleeper/party
var/leddit = FALSE //Get it like reddit and lead alright fine
ui_x = 310
ui_y = 400
controls_inside = TRUE
possible_chems = list(
@@ -477,3 +341,23 @@
/obj/machinery/sleeper/party/emag_act(mob/user)
..()
leddit = TRUE
/obj/machinery/sleeper/clockwork
name = "soothing sleeper"
desc = "A large cryogenics unit built from brass. Its surface is pleasantly cool the touch."
icon_state = "sleeper_clockwork"
enter_message = "<span class='bold inathneq_small'>You hear the gentle hum and click of machinery, and are lulled into a sense of peace.</span>"
possible_chems = list(
list(/datum/reagent/medicine/epinephrine, /datum/reagent/medicine/salbutamol, /datum/reagent/medicine/bicaridine, /datum/reagent/medicine/kelotane, /datum/reagent/medicine/oculine, /datum/reagent/medicine/inacusiate, /datum/reagent/medicine/mannitol)
) //everything is available at start
fair_market_price = 0 //it's free
/obj/machinery/sleeper/clockwork/process()
..()
if(occupant && isliving(occupant))
var/mob/living/L = occupant
if(GLOB.clockwork_vitality) //If there's Vitality, the sleeper has passive healing
GLOB.clockwork_vitality = max(0, GLOB.clockwork_vitality - 1)
L.adjustBruteLoss(-1)
L.adjustFireLoss(-1)
L.adjustOxyLoss(-5)
+6
View File
@@ -92,6 +92,7 @@ Class Procs:
pressure_resistance = 15
max_integrity = 200
layer = BELOW_OBJ_LAYER //keeps shit coming out of the machine from ending up underneath it.
flags_1 = DEFAULT_RICOCHET_1
flags_ricochet = RICOCHET_HARD
ricochet_chance_mod = 0.3
@@ -116,6 +117,7 @@ Class Procs:
var/new_occupant_dir = SOUTH //The direction the occupant will be set to look at when entering the machine.
var/speed_process = FALSE // Process as fast as possible?
var/obj/item/circuitboard/circuit // Circuit to be created and inserted when the machinery is created
var/wire_compatible = FALSE
// For storing and overriding ui id and dimensions
var/tgui_id // ID of TGUI interface
var/ui_style // ID of custom TGUI style (optional)
@@ -432,6 +434,7 @@ Class Procs:
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [src].</span>")
setAnchored(!anchored)
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
SEND_SIGNAL(src, COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH, anchored)
return SUCCESSFUL_UNFASTEN
return FAILED_UNFASTEN
return CANT_UNFASTEN
@@ -546,3 +549,6 @@ Class Procs:
. = . % 9
AM.pixel_x = -8 + ((.%3)*8)
AM.pixel_y = -8 + (round( . / 3)*8)
/obj/machinery/rust_heretic_act()
take_damage(500, BRUTE, "melee", 1)
+3 -6
View File
@@ -93,13 +93,10 @@ GLOBAL_LIST_EMPTY(announcement_systems)
for(var/channel in channels)
radio.talk_into(src, message, channel)
//config stuff
/obj/machinery/announcement_system/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
. = ..()
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/announcement_system/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "AutomatedAnnouncement", "Automated Announcement System", 500, 225, master_ui, state)
ui = new(user, src, "AutomatedAnnouncement")
ui.open()
/obj/machinery/announcement_system/ui_data()
+10 -7
View File
@@ -3,6 +3,7 @@
desc = "A machine used to deposit and withdraw station funds."
icon = 'goon/icons/obj/goon_terminals.dmi'
idle_power_usage = 100
var/siphoning = FALSE
var/next_warning = 0
var/obj/item/radio/radio
@@ -38,7 +39,6 @@
return
return ..()
/obj/machinery/computer/bank_machine/process()
..()
if(siphoning)
@@ -51,7 +51,7 @@
end_syphon()
return
playsound(src.loc, 'sound/items/poster_being_created.ogg', 100, 1)
playsound(src, 'sound/items/poster_being_created.ogg', 100, TRUE)
syphoning_credits += 200
D.adjust_money(-200)
if(next_warning < world.time && prob(15))
@@ -60,17 +60,20 @@
radio.talk_into(src, message, radio_channel)
next_warning = world.time + minimum_time_between_warnings
/obj/machinery/computer/bank_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/bank_machine/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "BankMachine", name, 320, 165, master_ui, state)
ui = new(user, src, "BankMachine", name)
ui.open()
/obj/machinery/computer/bank_machine/ui_data(mob/user)
var/list/data = list()
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
data["current_balance"] = D.account_balance
if(D)
data["current_balance"] = D.account_balance
else
data["current_balance"] = 0
data["siphoning"] = siphoning
data["station_name"] = station_name()
+8 -3
View File
@@ -43,10 +43,13 @@
table.computer = src
break
/obj/machinery/computer/operating/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/operating/ui_state(mob/user)
return GLOB.not_incapacitated_state
/obj/machinery/computer/operating/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "OperatingComputer", name, 350, 470, master_ui, state)
ui = new(user, src, "OperatingComputer", name)
ui.open()
/obj/machinery/computer/operating/ui_data(mob/user)
@@ -153,6 +156,8 @@
))
return data
/obj/machinery/computer/operating/ui_act(action, params)
if(..())
return
+36 -67
View File
@@ -2,14 +2,13 @@
name = "\improper AI system integrity restorer"
desc = "Used with intelliCards containing nonfunctional AIs to restore them to working order."
req_access = list(ACCESS_CAPTAIN, ACCESS_ROBOTICS, ACCESS_HEADS)
var/mob/living/silicon/ai/occupier = null
var/active = 0
circuit = /obj/item/circuitboard/computer/aifixer
icon_keyboard = "tech_key"
icon_screen = "ai-fixer"
light_color = LIGHT_COLOR_PINK
ui_x = 370
ui_y = 360
circuit = /obj/item/circuitboard/computer/aifixer
var/mob/living/silicon/ai/occupier = null
var/active = FALSE
/obj/machinery/computer/aifixer/attackby(obj/I, mob/user, params)
if(occupier && istype(I, /obj/item/screwdriver))
@@ -20,64 +19,45 @@
else
return ..()
/obj/machinery/computer/aifixer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/aifixer/ui_interact(mob/user, datum/tgui/ui) //artur didn't port this correctly
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "AiRestorer", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "AiRestorer", name)
ui.open()
var/dat = ""
/obj/machinery/computer/aifixer/ui_data(mob/user)
var/list/data = list()
if (src.occupier)
var/laws
dat += "<h3>Stored AI: [src.occupier.name]</h3>"
dat += "<b>System integrity:</b> [(src.occupier.health+100)/2]%<br>"
data["ejectable"] = FALSE
data["AI_present"] = FALSE
data["error"] = null
if(!occupier)
data["error"] = "Please transfer an AI unit."
else
data["AI_present"] = TRUE
data["name"] = occupier.name
data["restoring"] = active
data["health"] = (occupier.health + 100) / 2
data["isDead"] = occupier.stat == DEAD
data["laws"] = occupier.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE)
if (src.occupier.laws.zeroth)
laws += "<b>0:</b> [src.occupier.laws.zeroth]<BR>"
return data
for (var/index = 1, index <= src.occupier.laws.hacked.len, index++)
var/law = src.occupier.laws.hacked[index]
if (length(law) > 0)
var/num = ionnum()
laws += "<b>[num]:</b> [law]<BR>"
/obj/machinery/computer/aifixer/ui_act(action, params)
if(..())
return
if(!occupier)
active = FALSE
for (var/index = 1, index <= src.occupier.laws.ion.len, index++)
var/law = src.occupier.laws.ion[index]
if (length(law) > 0)
var/num = ionnum()
laws += "<b>[num]:</b> [law]<BR>"
var/number = 1
for (var/index = 1, index <= src.occupier.laws.inherent.len, index++)
var/law = src.occupier.laws.inherent[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
for (var/index = 1, index <= src.occupier.laws.supplied.len, index++)
var/law = src.occupier.laws.supplied[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
dat += "<b>Laws:</b><br>[laws]<br>"
if (src.occupier.stat == DEAD)
dat += "<span class='bad'>AI non-functional</span>"
else
dat += "<span class='good'>AI functional</span>"
if (!src.active)
dat += {"<br><br><A href='byond://?src=[REF(src)];fix=1'>Begin Reconstruction</A>"}
else
dat += "<br><br>Reconstruction in process, please wait.<br>"
dat += {"<br><A href='?src=[REF(user)];mach_close=computer'>Close</A>"}
var/datum/browser/popup = new(user, "computer", "AI System Integrity Restorer", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
switch(action)
if("PRG_beginReconstruction")
if(occupier?.health < 100)
to_chat(usr, "<span class='notice'>Reconstruction in progress. This will take several minutes.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
active = TRUE
occupier.notify_ghost_cloning("Your core files are being restored!", source = src)
. = TRUE
/obj/machinery/computer/aifixer/proc/Fix()
use_power(1000)
@@ -97,17 +77,6 @@
active = Fix()
if(oldstat != occupier.stat)
update_icon()
updateDialog()
/obj/machinery/computer/aifixer/Topic(href, href_list)
if(..())
return
if(href_list["fix"])
to_chat(usr, "<span class='notice'>Reconstruction in progress. This will take several minutes.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0)
active = TRUE
add_fingerprint(usr)
updateUsrDialog()
/obj/machinery/computer/aifixer/update_overlays()
. = ..()
+153 -161
View File
@@ -3,19 +3,19 @@
desc = "Used to remotely control the flow of power to different parts of the station."
icon_screen = "solar"
icon_keyboard = "power_key"
req_access = list(ACCESS_ENGINE)
req_access = list(ACCESS_CE)
circuit = /obj/item/circuitboard/computer/apc_control
light_color = LIGHT_COLOR_YELLOW
var/mob/living/operator //Who's operating the computer right now
var/obj/machinery/power/apc/active_apc //The APC we're using right now
var/list/result_filters //For sorting the results
var/checking_logs = 0
var/should_log = TRUE
var/restoring = FALSE
var/list/logs
var/auth_id = "\[NULL\]"
var/auth_id = "\[NULL\]:"
/obj/machinery/computer/apc_control/Initialize()
/obj/machinery/computer/apc_control/Initialize(mapload, obj/item/circuitboard/C)
. = ..()
result_filters = list("Name" = null, "Charge Above" = null, "Charge Below" = null, "Responsive" = null)
logs = list()
/obj/machinery/computer/apc_control/process()
if(operator && (!operator.Adjacent(src) || stat))
@@ -23,8 +23,8 @@
if(active_apc)
if(!active_apc.locked)
active_apc.say("Remote access canceled. Interface locked.")
playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, 0)
playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, 0)
playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, FALSE)
playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, FALSE)
active_apc.locked = TRUE
active_apc.update_icon()
active_apc.remote_control = null
@@ -34,171 +34,163 @@
if(!IsAdminGhost(user))
to_chat(user,"<span class='warning'>[src] does not support AI control.</span>") //You already have APC access, cheater!
return
..(user)
..()
/obj/machinery/computer/apc_control/proc/check_apc(obj/machinery/power/apc/APC)
return APC.z == z && !APC.malfhack && !APC.aidisabled && !(APC.obj_flags & EMAGGED) && !APC.stat && !istype(APC.area, /area/ai_monitored) && !APC.area.outdoors
/obj/machinery/computer/apc_control/ui_interact(mob/living/user)
. = ..()
var/dat
if(authenticated)
if(!checking_logs)
dat += "Logged in as [auth_id].<br><br>"
dat += "<i>Filters</i><br>"
dat += "<b>Name:</b> <a href='?src=[REF(src)];name_filter=1'>[result_filters["Name"] ? result_filters["Name"] : "None set"]</a><br>"
dat += "<b>Charge:</b> <a href='?src=[REF(src)];above_filter=1'>\>[result_filters["Charge Above"] ? result_filters["Charge Above"] : "NaN"]%</a> and <a href='?src=[REF(src)];below_filter=1'>\<[result_filters["Charge Below"] ? result_filters["Charge Below"] : "NaN"]%</a><br>"
dat += "<b>Accessible:</b> <a href='?src=[REF(src)];access_filter=1'>[result_filters["Responsive"] ? "Non-Responsive Only" : "All"]</a><br><br>"
for(var/A in GLOB.apcs_list)
if(check_apc(A))
var/obj/machinery/power/apc/APC = A
if(result_filters["Name"] && !findtext(APC.name, result_filters["Name"]) && !findtext(APC.area.name, result_filters["Name"]))
continue
if(result_filters["Charge Above"] && (!APC.cell || (APC.cell && (APC.cell.charge / APC.cell.maxcharge) < result_filters["Charge Above"] / 100)))
continue
if(result_filters["Charge Below"] && APC.cell && (APC.cell.charge / APC.cell.maxcharge) > result_filters["Charge Below"] / 100)
continue
if(result_filters["Responsive"] && !APC.aidisabled)
continue
dat += "<a href='?src=[REF(src)];access_apc=[REF(APC)]'>[A]</a><br>\
<b>Charge:</b> [APC.cell ? "[DisplayEnergy(APC.cell.charge)] / [DisplayEnergy(APC.cell.maxcharge)] ([round((APC.cell.charge / APC.cell.maxcharge) * 100)]%)" : "No Powercell Installed"]<br>\
<b>Area:</b> [APC.area]<br>\
[APC.aidisabled || APC.panel_open ? "<font color='#FF0000'>APC does not respond to interface query.</font>" : "<font color='#00FF00'>APC responds to interface query.</font>"]<br><br>"
dat += "<a href='?src=[REF(src)];check_logs=1'>Check Logs</a><br>"
dat += "<a href='?src=[REF(src)];log_out=1'>Log Out</a><br>"
if(obj_flags & EMAGGED)
dat += "<font color='#FF0000'>WARNING: Logging functionality partially disabled from outside source.</font><br>"
dat += "<a href='?src=[REF(src)];restore_logging=1'>Restore logging functionality?</a><br>"
else
if(logs.len)
for(var/entry in logs)
dat += "[entry]<br>"
else
dat += "<i>No activity has been recorded at this time.</i><br>"
if(obj_flags & EMAGGED)
dat += "<a href='?src=[REF(src)];clear_logs=1'><font color='#FF0000'>@#%! CLEAR LOGS</a>"
dat += "<a href='?src=[REF(src)];check_apcs=1'>Return</a>"
operator = user
else
dat = "<a href='?src=[REF(src)];authenticate=1'>Please swipe a valid ID to log in...</a>"
var/datum/browser/popup = new(user, "apc_control", name, 600, 400)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/apc_control/ui_interact(mob/user, datum/tgui/ui)
operator = user
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ApcControl")
ui.open()
/obj/machinery/computer/apc_control/Topic(href, href_list)
/obj/machinery/computer/apc_control/ui_data(mob/user)
var/list/data = list()
data["auth_id"] = auth_id
data["authenticated"] = authenticated
data["emagged"] = obj_flags & EMAGGED
data["logging"] = should_log
data["restoring"] = restoring
data["logs"] = list()
data["apcs"] = list()
for(var/entry in logs)
data["logs"] += list(list("entry" = entry))
for(var/apc in GLOB.apcs_list)
if(check_apc(apc))
var/obj/machinery/power/apc/A = apc
var/has_cell = (A.cell) ? TRUE : FALSE
data["apcs"] += list(list(
"name" = A.area.name,
"operating" = A.operating,
"charge" = (has_cell) ? A.cell.percent() : "NOCELL",
"load" = DisplayPower(A.lastused_total),
"charging" = A.charging,
"chargeMode" = A.chargemode,
"eqp" = A.equipment,
"lgt" = A.lighting,
"env" = A.environ,
"responds" = A.aidisabled || A.panel_open,
"ref" = REF(A)
)
)
return data
/obj/machinery/computer/apc_control/ui_act(action, params)
if(..())
return
if(!usr || !usr.canUseTopic(src) || stat || QDELETED(src))
return
if(href_list["authenticate"])
var/obj/item/card/id/ID = usr.get_idcard(TRUE)
if(ID && istype(ID))
if(check_access(ID))
switch(action)
if("log-in")
if(obj_flags & EMAGGED)
authenticated = TRUE
auth_id = "[ID.registered_name] ([ID.assignment])"
log_activity("logged in")
if(href_list["log_out"])
log_activity("logged out")
authenticated = FALSE
auth_id = "\[NULL\]"
if(href_list["restore_logging"])
to_chat(usr, "<span class='robot notice'>[icon2html(src, usr)] Logging functionality restored from backup data.</span>")
obj_flags &= ~EMAGGED
LAZYADD(logs, "<b>-=- Logging restored to full functionality at this point -=-</b>")
if(href_list["access_apc"])
playsound(src, "terminal_type", 50, 0)
var/obj/machinery/power/apc/APC = locate(href_list["access_apc"]) in GLOB.apcs_list
if(!APC || APC.aidisabled || APC.panel_open || QDELETED(APC))
to_chat(usr, "<span class='robot danger'>[icon2html(src, usr)] APC does not return interface request. Remote access may be disabled.</span>")
return
if(active_apc)
to_chat(usr, "<span class='robot danger'>[icon2html(src, usr)] Disconnected from [active_apc].</span>")
active_apc.say("Remote access canceled. Interface locked.")
playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, 0)
playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, 0)
active_apc.locked = TRUE
active_apc.update_icon()
active_apc.remote_control = null
active_apc = null
to_chat(usr, "<span class='robot notice'>[icon2html(src, usr)] Connected to APC in [get_area_name(APC.area, TRUE)]. Interface request sent.</span>")
log_activity("remotely accessed APC in [get_area_name(APC.area, TRUE)]")
APC.remote_control = src
APC.ui_interact(usr)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
message_admins("[ADMIN_LOOKUPFLW(usr)] remotely accessed [APC] from [src] at [AREACOORD(src)].")
log_game("[key_name(usr)] remotely accessed [APC] from [src] at [AREACOORD(src)].")
if(APC.locked)
APC.say("Remote access detected. Interface unlocked.")
playsound(APC, 'sound/machines/boltsup.ogg', 25, 0)
playsound(APC, 'sound/machines/terminal_alert.ogg', 50, 0)
APC.locked = FALSE
APC.update_icon()
active_apc = APC
if(href_list["name_filter"])
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
var/new_filter = stripped_input(usr, "What name are you looking for?", name)
if(!src || !usr || !usr.canUseTopic(src) || stat || QDELETED(src))
return
log_activity("changed name filter to \"[new_filter]\"")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Name"] = new_filter
if(href_list["above_filter"])
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
var/new_filter = input(usr, "Enter a percentage from 1-100 to sort by (greater than).", name) as null|num
if(!src || !usr || !usr.canUseTopic(src) || stat || QDELETED(src))
return
log_activity("changed greater than charge filter to \"[new_filter]\"")
if(new_filter)
new_filter = clamp(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Above"] = new_filter
if(href_list["below_filter"])
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
var/new_filter = input(usr, "Enter a percentage from 1-100 to sort by (lesser than).", name) as null|num
if(!src || !usr || !usr.canUseTopic(src) || stat || QDELETED(src))
return
log_activity("changed lesser than charge filter to \"[new_filter]\"")
if(new_filter)
new_filter = clamp(new_filter, 0, 100)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
result_filters["Charge Below"] = new_filter
if(href_list["access_filter"])
if(isnull(result_filters["Responsive"]))
result_filters["Responsive"] = 1
log_activity("sorted by non-responsive APCs only")
else
result_filters["Responsive"] = !result_filters["Responsive"]
log_activity("sorted by all APCs")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if(href_list["check_logs"])
checking_logs = TRUE
log_activity("checked logs")
if(href_list["check_apcs"])
checking_logs = FALSE
log_activity("checked APCs")
if(href_list["clear_logs"])
logs = list()
ui_interact(usr) //Refresh the UI after a filter changes
auth_id = "Unknown (Unknown):"
log_activity("[auth_id] logged in to the terminal")
return
var/obj/item/card/id/ID = operator.get_idcard(TRUE)
if(ID && istype(ID))
if(check_access(ID))
authenticated = TRUE
auth_id = "[ID.registered_name] ([ID.assignment]):"
log_activity("[auth_id] logged in to the terminal")
playsound(src, 'sound/machines/terminal_on.ogg', 50, FALSE)
else
auth_id = "[ID.registered_name] ([ID.assignment]):"
log_activity("[auth_id] attempted to log into the terminal")
return
auth_id = "Unknown (Unknown):"
log_activity("[auth_id] attempted to log into the terminal")
if("log-out")
log_activity("[auth_id] logged out of the terminal")
playsound(src, 'sound/machines/terminal_off.ogg', 50, FALSE)
authenticated = FALSE
auth_id = "\[NULL\]"
if("toggle-logs")
should_log = !should_log
log_game("[key_name(operator)] set the logs of [src] in [AREACOORD(src)] [should_log ? "On" : "Off"]")
if("restore-console")
restoring = TRUE
addtimer(CALLBACK(src, .proc/restore_comp), rand(3,5) * 9)
if("access-apc")
var/ref = params["ref"]
playsound(src, "terminal_type", 50, FALSE)
var/obj/machinery/power/apc/APC = locate(ref) in GLOB.apcs_list
if(!APC)
return
if(active_apc)
to_chat(operator, "<span class='robot danger'>[icon2html(src, auth_id)] Disconnected from [active_apc].</span>")
active_apc.say("Remote access canceled. Interface locked.")
playsound(active_apc, 'sound/machines/boltsdown.ogg', 25, FALSE)
playsound(active_apc, 'sound/machines/terminal_alert.ogg', 50, FALSE)
active_apc.locked = TRUE
active_apc.update_icon()
active_apc.remote_control = null
active_apc = null
APC.remote_control = src
APC.ui_interact(operator)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
log_game("[key_name(operator)] remotely accessed [APC] from [src] at [AREACOORD(src)].")
log_activity("[auth_id] remotely accessed APC in [get_area_name(APC.area, TRUE)]")
if(APC.locked)
APC.say("Remote access detected. Interface unlocked.")
playsound(APC, 'sound/machines/boltsup.ogg', 25, FALSE)
playsound(APC, 'sound/machines/terminal_alert.ogg', 50, FALSE)
APC.locked = FALSE
APC.update_icon()
active_apc = APC
if("check-logs")
log_activity("Checked Logs")
if("check-apcs")
log_activity("Checked APCs")
if("toggle-minor")
var/ref = params["ref"]
var/type = params["type"]
var/value = params["value"]
var/obj/machinery/power/apc/target = locate(ref) in GLOB.apcs_list
if(!target)
return
target.vars[type] = target.setsubsystem(text2num(value))
target.update_icon()
target.update()
var/setTo = ""
switch(target.vars[type])
if(0)
setTo = "Off"
if(1)
setTo = "Auto Off"
if(2)
setTo = "On"
if(3)
setTo = "Auto On"
log_activity("Set APC [target.area.name] [type] to [setTo]")
log_game("[key_name(operator)] Set APC [target.area.name] [type] to [setTo]]")
if("breaker")
var/ref = params["ref"]
var/obj/machinery/power/apc/target = locate(ref) in GLOB.apcs_list
target.toggle_breaker()
var/setTo = target.operating ? "On" : "Off"
log_activity("Turned APC [target.area.name]'s breaker [setTo]")
/obj/machinery/computer/apc_control/emag_act(mob/user)
. = ..()
if(!authenticated)
to_chat(user, "<span class='warning'>You bypass [src]'s access requirements using your emag.</span>")
authenticated = TRUE
log_activity("logged in")
else
if(obj_flags & EMAGGED)
return
user.visible_message("<span class='warning'>You emag [src], disabling precise logging and allowing you to clear logs.</span>")
log_game("[key_name(user)] emagged [src] at [AREACOORD(src)], disabling operator tracking.")
obj_flags |= EMAGGED
playsound(src, "sparks", 50, 1)
return TRUE
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
log_game("[key_name(user)] emagged [src] at [AREACOORD(src)]")
playsound(src, "sparks", 50, TRUE)
/obj/machinery/computer/apc_control/proc/log_activity(log_text)
var/op_string = operator && !(obj_flags & EMAGGED) ? operator : "\[NULL OPERATOR\]"
LAZYADD(logs, "<b>([STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)])</b> [op_string] [log_text]")
if(!should_log)
return
LAZYADD(logs, "([STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)]): [auth_id] [log_text]")
/obj/machinery/computer/apc_control/proc/restore_comp()
obj_flags &= ~EMAGGED
should_log = TRUE
log_game("[key_name(operator)] restored the logs of [src] in [AREACOORD(src)]")
log_activity("-=- Logging restored to full functionality at this point -=-")
restoring = FALSE
/mob/proc/using_power_flow_console()
for(var/obj/machinery/computer/apc_control/A in range(1, src))
@@ -49,7 +49,6 @@
dat += "</b></center>"
var/datum/browser/popup = new(user, "arcade", "Space Villain 2000")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/arcade/battle/Topic(href, href_list)
@@ -178,9 +178,12 @@
table[y1][x1] += 10
if(href_list["same_board"]) //Reset the board... kinda
if(game_status != MINESWEEPER_GAME_PLAYING)
mine_sound = TRUE
game_status = MINESWEEPER_GAME_PLAYING
if(table[y1][x1] >= 10) //If revealed, become unrevealed!
playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10)
if(mine_sound)
playsound(loc, 'sound/arcade/minesweeper_menuselect.ogg', 50, 0, extrarange = -3, falloff = 10)
mine_sound = FALSE
table[y1][x1] -= 10
if(table[y1][x1] > 10 && !reset_board)
safe_squares_revealed += 1
@@ -160,7 +160,6 @@
dat += "<P ALIGN=Right><a href='byond://?src=[REF(src)];close=1'>Close</a></P>"
var/datum/browser/popup = new(user, "arcade", "The Orion Trail",400,700)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
return
+5 -6
View File
@@ -19,11 +19,10 @@
SSradio.remove_object(src, receive_frequency)
return ..()
/obj/machinery/computer/atmos_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/atmos_alert/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "AtmosAlertConsole", name, 350, 300, master_ui, state)
ui = new(user, src, "AtmosAlertConsole", name)
ui.open()
/obj/machinery/computer/atmos_alert/ui_data(mob/user)
@@ -45,11 +44,11 @@
if("clear")
var/zone = params["zone"]
if(zone in priority_alarms)
to_chat(usr, "Priority alarm for [zone] cleared.")
to_chat(usr, "<span class='notice'>Priority alarm for [zone] cleared.</span>")
priority_alarms -= zone
. = TRUE
if(zone in minor_alarms)
to_chat(usr, "Minor alarm for [zone] cleared.")
to_chat(usr, "<span class='notice'>Minor alarm for [zone] cleared.</span>")
minor_alarms -= zone
. = TRUE
update_icon()
+3 -13
View File
@@ -91,8 +91,6 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers)
icon_screen = "tank"
icon_keyboard = "atmos_key"
circuit = /obj/item/circuitboard/computer/atmos_control
ui_x = 400
ui_y = 925
var/frequency = FREQ_ATMOS_STORAGE
var/list/sensors = list(
@@ -123,11 +121,10 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers)
SSradio.remove_object(src, frequency)
return ..()
/obj/machinery/computer/atmos_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/atmos_control/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "AtmosControlConsole", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "AtmosControlConsole", name)
ui.open()
/obj/machinery/computer/atmos_control/ui_data(mob/user)
@@ -265,13 +262,6 @@ GLOBAL_LIST_EMPTY(atmos_air_controllers)
for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in devices)
U.broadcast_status()
/obj/machinery/computer/atmos_control/tank/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "AtmosControlConsole", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/computer/atmos_control/tank/ui_data(mob/user)
var/list/data = ..()
data["tank"] = TRUE
+5 -8
View File
@@ -5,8 +5,6 @@
icon_keyboard = "security_key"
circuit = /obj/item/circuitboard/computer/security
light_color = LIGHT_COLOR_RED
ui_x = 870
ui_y = 708
var/list/network = list("ss13")
var/obj/machinery/camera/active_camera
@@ -55,11 +53,9 @@
network -= i
network += "[idnum][i]"
/obj/machinery/computer/security/ui_interact(\
mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
/obj/machinery/computer/security/ui_interact(mob/user, datum/tgui/ui)
// Update UI
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui)
// Show static if can't use the camera
if(!active_camera?.can_use())
show_camera_static()
@@ -76,10 +72,11 @@
use_power(active_power_usage)
// Register map objects
user.client.register_map_obj(cam_screen)
user.client.register_map_obj(cam_plane_master)
for(var/plane in cam_plane_master)
user.client.register_map_obj(plane)
user.client.register_map_obj(cam_background)
// Open UI
ui = new(user, src, ui_key, "CameraConsole", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "CameraConsole", name)
ui.open()
/obj/machinery/computer/security/ui_data()
-1
View File
@@ -353,7 +353,6 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0)
dat = list("<tt>", header.Join(), body, "<br></tt>")
var/datum/browser/popup = new(user, "id_com", src.name, 900, 620)
popup.set_content(dat.Join())
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/card/Topic(href, href_list)
-1
View File
@@ -276,7 +276,6 @@
var/datum/browser/popup = new(user, "cloning", "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/cloning/Topic(href, href_list)
+60 -30
View File
@@ -1,3 +1,15 @@
#define STATE_DEFAULT 1
#define STATE_CALLSHUTTLE 2
#define STATE_CANCELSHUTTLE 3
#define STATE_MESSAGELIST 4
#define STATE_VIEWMESSAGE 5
#define STATE_DELMESSAGE 6
#define STATE_STATUSDISPLAY 7
#define STATE_ALERT_LEVEL 8
#define STATE_CONFIRM_LEVEL 9
#define STATE_TOGGLE_EMERGENCY 10
#define STATE_PURCHASE 11
// The communications computer
/obj/machinery/computer/communications
name = "communications console"
@@ -6,6 +18,7 @@
icon_keyboard = "tech_key"
req_access = list(ACCESS_HEADS)
circuit = /obj/item/circuitboard/computer/communications
light_color = LIGHT_COLOR_BLUE
var/auth_id = "Unknown" //Who is currently logged in?
var/list/datum/comm_message/messages = list()
var/datum/comm_message/currmsg
@@ -16,22 +29,10 @@
var/ai_message_cooldown = 0
var/tmp_alertlevel = 0
var/static/security_level_cd // used to stop mass spam.
var/const/STATE_DEFAULT = 1
var/const/STATE_CALLSHUTTLE = 2
var/const/STATE_CANCELSHUTTLE = 3
var/const/STATE_MESSAGELIST = 4
var/const/STATE_VIEWMESSAGE = 5
var/const/STATE_DELMESSAGE = 6
var/const/STATE_STATUSDISPLAY = 7
var/const/STATE_ALERT_LEVEL = 8
var/const/STATE_CONFIRM_LEVEL = 9
var/const/STATE_TOGGLE_EMERGENCY = 10
var/const/STATE_PURCHASE = 11
var/stat_msg1
var/stat_msg2
light_color = LIGHT_COLOR_BLUE
/obj/machinery/computer/communications/proc/checkCCcooldown()
var/obj/item/circuitboard/computer/communications/CM = circuit
@@ -46,7 +47,7 @@
/obj/machinery/computer/communications/Topic(href, href_list)
if(..())
return
if(!usr.canUseTopic(src))
if(!usr.canUseTopic(src, !issilicon(usr)))
return
if(!is_station_level(z) && !is_reserved_level(z)) //Can only use in transit and on SS13
to_chat(usr, "<span class='boldannounce'>Unable to establish a connection</span>: \black You're too far away from the station!")
@@ -132,15 +133,20 @@
if("crossserver")
if(authenticated==2)
var/dest = href_list["cross_dest"]
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return
var/input = stripped_multiline_input(usr, "Please choose a message to transmit to allied stations. Please be aware that this process is very expensive, and abuse will lead to... termination.", "Send a message to an allied station.", "")
var/warning = dest == "all" ? "Please choose a message to transmit to allied stations." : "Please choose a message to transmit to [dest] sector station."
var/input = stripped_multiline_input(usr, "[warning] Please be aware that this process is very expensive, and abuse will lead to... termination.", "Send a message to an allied station.", "")
if(!input || !(usr in view(1,src)) || !checkCCcooldown())
return
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
send2otherserver("[station_name()]", input,"Comms_Console")
if(dest == "all")
send2otherserver("[station_name()]", input,"Comms_Console")
else
send2otherserver("[station_name()]", input,"Comms_Console", list(dest))
minor_announce(input, title = "Outgoing message to allied station")
usr.log_talk(input, LOG_SAY, tag="message to the other server")
message_admins("[ADMIN_LOOKUPFLW(usr)] has sent a message to the other server.")
@@ -156,12 +162,12 @@
var/datum/map_template/shuttle/S = locate(href_list["chosen_shuttle"]) in shuttles
if(S && istype(S))
if(SSshuttle.emergency.mode != SHUTTLE_RECALL && SSshuttle.emergency.mode != SHUTTLE_IDLE)
to_chat(usr, "It's a bit late to buy a new shuttle, don't you think?")
to_chat(usr, "<span class='alert'>It's a bit late to buy a new shuttle, don't you think?</span>")
return
if(SSshuttle.shuttle_purchased)
to_chat(usr, "A replacement shuttle has already been purchased.")
to_chat(usr, "<span class='alert'>A replacement shuttle has already been purchased.</span>")
else if(!S.prerequisites_met())
to_chat(usr, "You have not met the requirements for purchasing this shuttle.")
to_chat(usr, "<span class='alert'>You have not met the requirements for purchasing this shuttle.</span>")
else
var/points_to_check
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
@@ -183,7 +189,7 @@
if("callshuttle")
state = STATE_DEFAULT
if(authenticated)
if(authenticated && SSshuttle.canEvac(usr))
state = STATE_CALLSHUTTLE
if("callshuttle2")
if(authenticated)
@@ -284,12 +290,12 @@
if("MessageCentCom")
if(authenticated)
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
return
var/input = stripped_input(usr, "Please choose a message to transmit to CentCom via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "Send a message to CentCom.", "")
if(!input || !(usr in view(1,src)) || !checkCCcooldown())
return
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
CentCom_announce(input, usr)
to_chat(usr, "<span class='notice'>Message transmitted to Central Command.</span>")
for(var/client/X in GLOB.admins)
@@ -302,7 +308,7 @@
// OMG SYNDICATE ...LETTERHEAD
if("MessageSyndicate")
if((authenticated==2) && (obj_flags & EMAGGED))
if((authenticated) && (obj_flags & EMAGGED))
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
@@ -332,7 +338,7 @@
if(!checkCCcooldown())
to_chat(usr, "<span class='warning'>Arrays recycling. Please stand by.</span>")
return
var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self Destruct Code Request.","")
var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self-Destruct Code Request.","")
if(!input || !(usr in view(1,src)) || !checkCCcooldown())
return
Nuke_request(input, usr)
@@ -347,7 +353,9 @@
aicurrmsg = null
aistate = STATE_DEFAULT
if("ai-callshuttle")
aistate = STATE_CALLSHUTTLE
aistate = STATE_DEFAULT
if(SSshuttle.canEvac(usr))
aistate = STATE_CALLSHUTTLE
if("ai-callshuttle2")
SSshuttle.requestEvac(usr, href_list["call"])
aistate = STATE_DEFAULT
@@ -460,9 +468,8 @@
var/datum/browser/popup = new(user, "communications", "Communications Console", 400, 500)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
if(issilicon(user) || (hasSiliconAccessInArea(user) && !in_range(user,src)))
if(issilicon(user))
var/dat2 = interact_ai(user) // give the AI a different interact proc to limit its access
if(dat2)
dat += dat2
@@ -493,9 +500,15 @@
if (authenticated==2)
dat += "<BR><BR><B>Captain Functions</B>"
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=announce'>Make a Captain's Announcement</A> \]"
var/cross_servers_count = length(CONFIG_GET(keyed_list/cross_server))
if(cross_servers_count)
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=crossserver'>Send a message to [cross_servers_count == 1 ? "an " : ""]allied station[cross_servers_count > 1 ? "s" : ""]</A> \]"
var/list/cross_servers = CONFIG_GET(keyed_list/cross_server)
var/our_id = CONFIG_GET(string/cross_comms_name)
if(cross_servers.len)
for(var/server in cross_servers)
if(server == our_id)
continue
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=crossserver=all;cross_dest=[server]'>Send a message to station in [server] sector.</A> \]"
if(cross_servers.len > 2)
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=crossserver;cross_dest=all'>Send a message to all allied stations</A> \]"
if(SSmapping.config.allow_custom_shuttles)
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=purchase_menu'>Purchase Shuttle</A> \]"
dat += "<BR>\[ <A HREF='?src=[REF(src)];operation=changeseclevel'>Change Alert Level</A> \]"
@@ -721,8 +734,13 @@
to_chat(user, "<span class='alert'>Intercomms recharging. Please stand by.</span>")
return
var/input = stripped_input(user, "Please choose a message to announce to the station crew.", "What?")
if(!input || !user.canUseTopic(src))
if(!input || !user.canUseTopic(src, !issilicon(usr)))
return
if(!(user.can_speak())) //No more cheating, mime/random mute guy!
input = "..."
to_chat(user, "<span class='warning'>You find yourself unable to speak.</span>")
else
input = user.treat_message(input) //Adds slurs and so on. Someone should make this use languages too.
SScommunications.make_announcement(user, is_silicon, input)
deadchat_broadcast("<span class='deadsay'><span class='name'>[user.real_name]</span> made an priority announcement from <span class='name'>[get_area_name(usr, TRUE)]</span>.</span>", user)
@@ -771,3 +789,15 @@
content = new_content
if(new_possible_answers)
possible_answers = new_possible_answers
#undef STATE_DEFAULT
#undef STATE_CALLSHUTTLE
#undef STATE_CANCELSHUTTLE
#undef STATE_MESSAGELIST
#undef STATE_VIEWMESSAGE
#undef STATE_DELMESSAGE
#undef STATE_STATUSDISPLAY
#undef STATE_ALERT_LEVEL
#undef STATE_CONFIRM_LEVEL
#undef STATE_TOGGLE_EMERGENCY
#undef STATE_PURCHASE
+3 -4
View File
@@ -76,11 +76,10 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new)
/datum/crewmonitor/Destroy()
return ..()
/datum/crewmonitor/ui_interact(mob/user, ui_key = "crew", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/datum/crewmonitor/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
ui = new(user, src, ui_key, "CrewConsole", "crew monitor", 800, 600 , master_ui, state)
ui = new(user, src, "CrewConsole")
ui.open()
/datum/crewmonitor/proc/show(mob/M, source)
+9 -10
View File
@@ -217,12 +217,7 @@
// already discovered mutations
stored_research = SSresearch.science_tech
/obj/machinery/computer/scan_consolenew/examine(mob/user)
. = ..()
/obj/machinery/computer/scan_consolenew/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)
. = ..()
/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, datum/tgui/ui)
// Most of ui_interact is spent setting variables for passing to the tgui
// interface.
// We can also do some general state processing here too as it's a good
@@ -264,11 +259,14 @@
time_to_pulse = round((rad_pulse_timer - world.time)/10)
// Attempt to update tgui ui, open and update if needed.
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "DnaConsole", name, 539, 710, master_ui, state)
ui = new(user, src, "DnaConsole")
ui.open()
/obj/machinery/computer/scan_consolenew/ui_assets()
. = ..() || list()
. += get_asset_datum(/datum/asset/simple/genetics)
/obj/machinery/computer/scan_consolenew/ui_data(mob/user)
var/list/data = list()
@@ -360,7 +358,7 @@
return data
/obj/machinery/computer/scan_consolenew/ui_act(action, var/list/params)
/obj/machinery/computer/scan_consolenew/ui_act(action, list/params)
if(..())
return TRUE
@@ -485,6 +483,7 @@
// Resolve mutation's BYOND path from the alias
var/alias = params["alias"]
var/path = GET_MUTATION_TYPE_FROM_ALIAS(alias)
// Make sure the occupant still has this mutation
if(!(path in scanner_occupant.dna.mutation_index))
return
@@ -53,10 +53,10 @@
var/obj/machinery/launchpad/pad = launchpads[number]
return pad
/obj/machinery/computer/launchpad/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/launchpad/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "LaunchpadConsole", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "LaunchpadConsole", name)
ui.open()
/obj/machinery/computer/launchpad/ui_data(mob/user)
@@ -128,4 +128,4 @@
if("pull")
teleport(usr, current_pad, FALSE)
. = TRUE
. = TRUE
. = TRUE
-1
View File
@@ -178,7 +178,6 @@
dat += "<A href='?src=[REF(src)];login=1'>{Log In}</A>"
var/datum/browser/popup = new(user, "med_rec", "Medical Records Console", 600, 400)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/med_data/Topic(href, href_list)
-1
View File
@@ -67,7 +67,6 @@
add_fingerprint(usr)
var/datum/browser/popup = new(user, "computer", title, 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/pod/process()
@@ -6,8 +6,6 @@
icon_keyboard = "security_key"
req_access = list(ACCESS_ARMORY)
circuit = /obj/item/circuitboard/computer/gulag_teleporter_console
ui_x = 350
ui_y = 295
var/default_goal = 200
var/obj/machinery/gulag_teleporter/teleporter = null
@@ -21,11 +19,10 @@
. = ..()
scan_machinery()
/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "GulagTeleporterConsole", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "GulagTeleporterConsole", name)
ui.open()
/obj/machinery/computer/prisoner/gulag_teleporter_computer/ui_data(mob/user)
@@ -66,7 +66,6 @@
dat += "<HR><A href='?src=[REF(src)];lock=1'>{Log Out}</A>"
var/datum/browser/popup = new(user, "computer", "Prisoner Management Console", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
+4 -5
View File
@@ -23,11 +23,10 @@
return
return TRUE
/obj/machinery/computer/robotics/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/robotics/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "RoboticsControlConsole", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "RoboticsControlConsole", name)
ui.open()
/obj/machinery/computer/robotics/ui_data(mob/user)
@@ -123,5 +122,5 @@
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, TRUE, D)
s.start()
D.visible_message("<span class='danger'>\the [D] self destructs!</span>")
D.visible_message("<span class='danger'>\the [D] self-destructs!</span>")
D.gib()
-1
View File
@@ -250,7 +250,6 @@
dat += "<A href='?src=[REF(src)];choice=Log In'>{Log In}</A>"
var/datum/browser/popup = new(user, "secure_rec", "Security Records Console", 600, 400)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
@@ -16,11 +16,10 @@
GLOB.alert_consoles -= src
return ..()
/obj/machinery/computer/station_alert/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/station_alert/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "StationAlertConsole", name, 325, 500, master_ui, state)
ui = new(user, src, "StationAlertConsole", name)
ui.open()
/obj/machinery/computer/station_alert/ui_data(mob/user)
@@ -31,6 +30,7 @@
data["alarms"][class] = list()
for(var/area in alarms[class])
data["alarms"][class] += area
return data
/obj/machinery/computer/station_alert/proc/triggerAlarm(class, area/A, O, obj/source)
@@ -103,7 +103,6 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
var/datum/browser/popup = new(user, "computer", "Telecrystal Upload/Receive Station", 700, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/telecrystals/uplinker/Topic(href, href_list)
@@ -185,7 +184,6 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
var/datum/browser/popup = new(user, "computer", "Team Telecrystal Management Console", 700, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/telecrystals/boss/Topic(href, href_list)
+13 -13
View File
@@ -34,11 +34,10 @@
break
return power_station
obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/teleporter/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "Teleporter", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "Teleporter", name)
ui.open()
/obj/machinery/computer/teleporter/ui_data(mob/user)
@@ -56,7 +55,6 @@ obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/t
return data
/obj/machinery/computer/teleporter/ui_act(action, params)
if(..())
return
@@ -92,16 +90,18 @@ obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", datum/t
say("Processing hub calibration to target...")
calibrating = TRUE
power_station.update_icon()
spawn(50 * (3 - power_station.teleporter_hub.accuracy)) //Better parts mean faster calibration
calibrating = FALSE
if(check_hub_connection())
power_station.teleporter_hub.calibrated = TRUE
say("Calibration complete.")
else
say("Error: Unable to detect hub.")
power_station.update_icon()
addtimer(CALLBACK(src, .proc/finish_calibration), 50 * (3 - power_station.teleporter_hub.accuracy)) //Better parts mean faster calibration
. = TRUE
/obj/machinery/computer/teleporter/proc/finish_calibration()
calibrating = FALSE
if(check_hub_connection())
power_station.teleporter_hub.calibrated = TRUE
say("Calibration complete.")
else
say("Error: Unable to detect hub.")
power_station.update_icon()
/obj/machinery/computer/teleporter/proc/check_hub_connection()
if(!power_station)
return FALSE
+1 -2
View File
@@ -76,7 +76,6 @@
var/datum/browser/popup = new(user, "cryopod_console", "Cryogenic System Control")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/cryopod/Topic(href, href_list)
@@ -308,7 +307,7 @@
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
+64 -46
View File
@@ -9,6 +9,7 @@
var/active = FALSE
var/list/rangers = list()
var/stop = 0
var/volume = 70
var/datum/track/selection = null
/obj/machinery/jukebox/disco
@@ -51,74 +52,91 @@
else
icon_state = "[initial(icon_state)]"
/obj/machinery/jukebox/ui_interact(mob/user)
. = ..()
if(!user.canUseTopic(src, !hasSiliconAccessInArea(user)))
return
if (!anchored)
/obj/machinery/jukebox/ui_status(mob/user)
if(!anchored)
to_chat(user,"<span class='warning'>This device must be anchored by a wrench!</span>")
return
if(!allowed(user))
return UI_CLOSE
if(!allowed(user) && !isobserver(user))
to_chat(user,"<span class='warning'>Error: Access Denied.</span>")
user.playsound_local(src,'sound/misc/compiler-failure.ogg', 25, 1)
return
if(!SSjukeboxes.songs.len)
user.playsound_local(src, 'sound/misc/compiler-failure.ogg', 25, TRUE)
return UI_CLOSE
if(!SSjukeboxes.songs.len && !isobserver(user))
to_chat(user,"<span class='warning'>Error: No music tracks have been authorized for your station. Petition Central Command to resolve this issue.</span>")
playsound(src,'sound/misc/compiler-failure.ogg', 25, 1)
return
var/list/dat = list()
dat +="<div class='statusDisplay' style='text-align:center'>"
dat += "<b><A href='?src=[REF(src)];action=toggle'>[!active ? "BREAK IT DOWN" : "SHUT IT DOWN"]<b></A><br>"
dat += "</div><br>"
dat += "<A href='?src=[REF(src)];action=select'> Select Track</A><br>"
if(istype(selection))
dat += "Track Selected: [selection.song_name]<br>"
dat += "Track Length: [DisplayTimeText(selection.song_length)]<br><br>"
else
dat += "Track Selected: None!<br><br>"
var/datum/browser/popup = new(user, "vending", "[name]", 400, 350)
popup.set_content(dat.Join())
popup.open()
playsound(src, 'sound/misc/compiler-failure.ogg', 25, TRUE)
return UI_CLOSE
return ..()
/obj/machinery/jukebox/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Jukebox", name)
ui.open()
/obj/machinery/jukebox/Topic(href, href_list)
if(..())
/obj/machinery/jukebox/ui_data(mob/user)
var/list/data = list()
data["active"] = active
data["songs"] = list()
for(var/datum/track/S in SSjukeboxes.songs)
var/list/track_data = list(
name = S.song_name
)
data["songs"] += list(track_data)
data["track_selected"] = null
data["track_length"] = null
data["track_beat"] = null
if(selection)
data["track_selected"] = selection.song_name
data["track_length"] = DisplayTimeText(selection.song_length)
data["track_beat"] = selection.song_beat
data["volume"] = volume
return data
/obj/machinery/jukebox/ui_act(action, list/params)
. = ..()
if(.)
return
add_fingerprint(usr)
switch(href_list["action"])
switch(action)
if("toggle")
if (QDELETED(src))
if(QDELETED(src))
return
if(!active)
if(stop > world.time)
to_chat(usr, "<span class='warning'>Error: The device is still resetting from the last activation, it will be ready again in [DisplayTimeText(stop-world.time)].</span>")
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
playsound(src, 'sound/misc/compiler-failure.ogg', 50, TRUE)
return
if(!istype(selection))
to_chat(usr, "<span class='warning'>Error: Severe user incompetence detected.</span>")
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
return
if(!activate_music())
to_chat(usr, "<span class='warning'>Error: Generic hardware failure.</span>")
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
return
updateUsrDialog()
else if(active)
activate_music()
START_PROCESSING(SSobj, src)
return TRUE
else
stop = 0
updateUsrDialog()
if("select")
return TRUE
if("select_track")
if(active)
to_chat(usr, "<span class='warning'>Error: You cannot change the song until the current one is over.</span>")
return
var/list/available = list()
for(var/datum/track/S in SSjukeboxes.songs)
available[S.song_name] = S
var/selected = input(usr, "Choose your song", "Track:") as null|anything in available
var/selected = params["track"]
if(QDELETED(src) || !selected || !istype(available[selected], /datum/track))
return
selection = available[selected]
updateUsrDialog()
return TRUE
if("set_volume")
var/new_volume = params["volume"]
if(new_volume == "reset")
volume = initial(volume)
return TRUE
else if(new_volume == "min")
volume = 0
return TRUE
else if(new_volume == "max")
volume = 100
return TRUE
else if(text2num(new_volume) != null)
volume = text2num(new_volume)
return TRUE
/obj/machinery/jukebox/proc/activate_music()
var/jukeboxslottotake = SSjukeboxes.addjukebox(src, selection, 2)
+39 -30
View File
@@ -50,7 +50,7 @@
integrity_failure = 0.25
damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_N
autoclose = TRUE
secondsElectrified = 0 //How many seconds remain until the door is no longer electrified. -1 if it is permanently electrified until someone fixes it.
secondsElectrified = NOT_ELECTRIFIED //How many seconds remain until the door is no longer electrified. -1 if it is permanently electrified until someone fixes it.
assemblytype = /obj/structure/door_assembly
normalspeed = 1
explosion_block = 1
@@ -298,10 +298,10 @@
/obj/machinery/door/airlock/Destroy()
QDEL_NULL(wires)
QDEL_NULL(electronics)
if(charge)
qdel(charge)
charge = null
QDEL_NULL(electronics)
if (cyclelinkedairlock)
if (cyclelinkedairlock.cyclelinkedairlock == src)
cyclelinkedairlock.cyclelinkedairlock = null
@@ -309,7 +309,7 @@
if(id_tag)
for(var/obj/machinery/doorButtons/D in GLOB.machines)
D.removeMe(src)
qdel(note)
QDEL_NULL(note)
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.remove_from_hud(src)
return ..()
@@ -765,8 +765,8 @@
/obj/machinery/door/airlock/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!(issilicon(user) || IsAdminGhost(user)))
if(src.isElectrified())
if(src.shock(user, 100))
if(isElectrified())
if(shock(user, 100))
return
if(ishuman(user) && prob(40) && src.density)
@@ -790,15 +790,15 @@
return ..()
/obj/machinery/door/airlock/proc/electrified_loop()
while (secondsElectrified > 0)
while (secondsElectrified > NOT_ELECTRIFIED)
sleep(10)
if(QDELETED(src))
return
secondsElectrified -= 1
secondsElectrified--
updateDialog()
// This is to protect against changing to permanent, mid loop.
if(secondsElectrified==0)
if(secondsElectrified == NOT_ELECTRIFIED)
set_electrified(NOT_ELECTRIFIED)
else
set_electrified(ELECTRIFIED_PERMANENT)
@@ -825,8 +825,8 @@
/obj/machinery/door/airlock/attackby(obj/item/C, mob/user, params)
if(!issilicon(user) && !IsAdminGhost(user))
if(src.isElectrified())
if(src.shock(user, 75))
if(isElectrified())
if(shock(user, 75))
return
add_fingerprint(user)
@@ -839,7 +839,7 @@
to_chat(user, "<span class='warning'>You need at least 2 metal sheets to reinforce [src].</span>")
return
to_chat(user, "<span class='notice'>You start reinforcing [src].</span>")
if(do_after(user, 20, 1, target = src))
if(do_after(user, 20, TRUE, target = src))
if(!panel_open || !S.use(2))
return
user.visible_message("<span class='notice'>[user] reinforces \the [src] with metal.</span>",
@@ -1070,7 +1070,7 @@
INVOKE_ASYNC(src, (density ? .proc/open : .proc/close), 2)
if(istype(I, /obj/item/crowbar/power))
if(isElectrified())
if(hasPower() && isElectrified())
shock(user,100)//it's like sticking a forck in a power socket
return
@@ -1090,12 +1090,11 @@
time_to_open = 50
playsound(src, 'sound/machines/airlock_alien_prying.ogg',100,1) //is it aliens or just the CE being a dick?
prying_so_hard = TRUE
var/result = do_after(user, time_to_open,target = src)
prying_so_hard = FALSE
if(result)
if(do_after(user, time_to_open,target = src))
open(2)
if(density && !open(2))
to_chat(user, "<span class='warning'>Despite your attempts, [src] refuses to open.</span>")
prying_so_hard = FALSE
/obj/machinery/door/airlock/open(forced=0)
if( operating || welded || locked )
@@ -1112,7 +1111,6 @@
detonated = 1
charge = null
for(var/mob/living/carbon/human/H in orange(2,src))
H.Unconscious(160)
H.adjust_fire_stacks(20)
H.IgniteMob() //Guaranteed knockout and ignition for nearby people
H.apply_damage(40, BRUTE, BODY_ZONE_CHEST)
@@ -1360,12 +1358,25 @@
wires.cut_all()
update_icon()
/obj/machinery/door/airlock/proc/set_electrified(seconds)
/obj/machinery/door/airlock/proc/set_electrified(seconds, mob/user)
secondsElectrified = seconds
diag_hud_set_electrified()
if(secondsElectrified > 0)
if(secondsElectrified > NOT_ELECTRIFIED)
INVOKE_ASYNC(src, .proc/electrified_loop)
if(user)
var/message
switch(secondsElectrified)
if(ELECTRIFIED_PERMANENT)
message = "permanently shocked"
if(NOT_ELECTRIFIED)
message = "unshocked"
else
message = "temp shocked for [secondsElectrified] seconds"
LAZYADD(shockedby, text("\[[TIME_STAMP("hh:mm:ss", FALSE)]\] [key_name(user)] - ([uppertext(message)])"))
log_combat(user, src, message)
//add_hiddenprint(user)
/obj/machinery/door/airlock/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
if(obj_integrity < (0.75 * max_integrity))
@@ -1439,11 +1450,10 @@
else if(istype(note, /obj/item/photo))
return "photo"
/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/door/airlock/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "AiAirlock", name, 500, 390, master_ui, state)
ui = new(user, src, "AiAirlock", name)
ui.open()
return TRUE
@@ -1451,13 +1461,13 @@
var/list/data = list()
var/list/power = list()
power["main"] = src.secondsMainPowerLost ? 0 : 2 // boolean
power["main_timeleft"] = src.secondsMainPowerLost
power["backup"] = src.secondsBackupPowerLost ? 0 : 2 // boolean
power["backup_timeleft"] = src.secondsBackupPowerLost
power["main"] = secondsMainPowerLost ? 0 : 2 // boolean
power["main_timeleft"] = secondsMainPowerLost
power["backup"] = secondsBackupPowerLost ? 0 : 2 // boolean
power["backup_timeleft"] = secondsBackupPowerLost
data["power"] = power
data["shock"] = secondsElectrified == 0 ? 2 : 0
data["shock"] = secondsElectrified == NOT_ELECTRIFIED ? 2 : 0
data["shock_timeleft"] = secondsElectrified
data["id_scanner"] = !aiDisabledIdScanner
data["emergency"] = emergency // access
@@ -1494,14 +1504,14 @@
loseMainPower()
update_icon()
else
to_chat(usr, "Main power is already offline.")
to_chat(usr, "<span class='warning'>Main power is already offline.</span>")
. = TRUE
if("disrupt-backup")
if(!secondsBackupPowerLost)
loseBackupPower()
update_icon()
else
to_chat(usr, "Backup power is already offline.")
to_chat(usr, "<span class='warning'>Backup power is already offline.</span>")
. = TRUE
if("shock-restore")
shock_restore(usr)
@@ -1530,7 +1540,6 @@
. = TRUE
if("speed-toggle")
normalspeed = !normalspeed
. = TRUE
if("open-close")
user_toggle_open(usr)
@@ -15,11 +15,13 @@
. = ..()
. += "<span class='notice'>Has a neat <i>selection menu</i> for modifying airlock access levels.</span>"
/obj/item/electronics/airlock/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/electronics/airlock/ui_state(mob/user)
return GLOB.hands_state
/obj/item/electronics/airlock/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "AirlockElectronics", name, 420, 485, master_ui, state)
ui = new(user, src, "AirlockElectronics", name)
ui.open()
/obj/item/electronics/airlock/ui_static_data(mob/user)
@@ -310,6 +310,17 @@
opacity = 0
glass = TRUE
/obj/machinery/door/airlock/bronze
name = "bronze airlock"
icon = 'icons/obj/doors/airlocks/clockwork/pinion_airlock.dmi'
overlays_file = 'icons/obj/doors/airlocks/clockwork/overlays.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_bronze
/obj/machinery/door/airlock/bronze/seethru
assemblytype = /obj/structure/door_assembly/door_assembly_bronze/seethru
opacity = 0
glass = TRUE
//////////////////////////////////
/*
Station2 Airlocks
+4 -5
View File
@@ -140,11 +140,10 @@
. = new_time == timer_duration //return 1 on no change
timer_duration = new_time
/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/door_timer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "BrigTimer", name, 300, 138, master_ui, state)
ui = new(user, src, "BrigTimer", name)
ui.open()
//icon update function
@@ -235,7 +234,7 @@
preset_time = PRESET_LONG
. = set_timer(preset_time)
if(timing)
activation_time = REALTIMEOFDAY
activation_time = world.time
else
. = FALSE
+3 -2
View File
@@ -11,7 +11,7 @@
max_integrity = 350
armor = list("melee" = 30, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 70)
CanAtmosPass = ATMOS_PASS_DENSITY
flags_1 = PREVENT_CLICK_UNDER_1
flags_1 = PREVENT_CLICK_UNDER_1|DEFAULT_RICOCHET_1
ricochet_chance_mod = 0.8
interaction_flags_atom = INTERACT_ATOM_UI_INTERACT
@@ -342,7 +342,8 @@
L.visible_message("<span class='warning'>[src] closes on [L], crushing [L.p_them()]!</span>", "<span class='userdanger'>[src] closes on you and crushes you!</span>")
if(iscarbon(L))
var/mob/living/carbon/C = L
for(var/datum/wound/W in C.all_wounds)
for(var/i in C.all_wounds) // should probably replace with signal
var/datum/wound/W = i
W.crush(DOOR_CRUSH_DAMAGE)
if(isalien(L)) //For xenos
L.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 1.5) //Xenos go into crit after aproximately the same amount of crushes as humans.
+2 -16
View File
@@ -74,12 +74,6 @@
/obj/machinery/door/firedoor/Bumped(atom/movable/AM)
if(panel_open || operating || welded)
return
if(ismob(AM))
var/mob/user = AM
if(density && !welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user)))
add_fingerprint(user)
open()
return TRUE
return FALSE
/obj/machinery/door/firedoor/power_change()
@@ -90,14 +84,6 @@
stat |= NOPOWER
/obj/machinery/door/firedoor/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!welded && !operating && !(stat & NOPOWER) && (!density || allow_hand_open(user)))
add_fingerprint(user)
if(density)
emergency_close_timer = world.time + 30 // prevent it from instaclosing again if in space
open()
else
close()
return TRUE
if(operating || !density)
return
@@ -298,7 +284,7 @@
/obj/machinery/door/firedoor/border_only
icon = 'icons/obj/doors/edge_Doorfire.dmi'
flags_1 = ON_BORDER_1
flags_1 = ON_BORDER_1|DEFAULT_RICOCHET_1
CanAtmosPass = ATMOS_PASS_PROC
/obj/machinery/door/firedoor/border_only/closed
@@ -320,7 +306,7 @@
to_chat(M, "<span class='notice'>You pull [M.pulling] through [src] right as it closes</span>")
M.pulling.forceMove(T1)
M.start_pulling(M2)
for(var/mob/living/M in T2)
if(M.stat == CONSCIOUS && M.pulling && M.pulling.loc == T1 && !M.pulling.anchored && M.pulling.move_resist <= M.move_force)
var/mob/living/M2 = M.pulling
+1 -1
View File
@@ -11,7 +11,7 @@
integrity_failure = 0
armor = list("melee" = 20, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 70, "acid" = 100)
visible = FALSE
flags_1 = ON_BORDER_1
flags_1 = ON_BORDER_1|DEFAULT_RICOCHET_1
opacity = 0
CanAtmosPass = ATMOS_PASS_PROC
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN
@@ -260,7 +260,6 @@
/obj/machinery/doorButtons/airlock_controller/ui_interact(mob/user)
var/datum/browser/popup = new(user, "computer", name)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.set_content(returnText())
popup.open()
@@ -29,7 +29,6 @@
. = ..()
user.set_machine(src)
var/datum/browser/popup = new(user, "computer", name) // Set up the popup browser window
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.set_content(return_text())
popup.open()
+13 -14
View File
@@ -20,18 +20,15 @@
return ..()
/obj/machinery/gulag_item_reclaimer/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED) // emagging lets anyone reclaim all the items
return
req_access = list()
obj_flags |= EMAGGED
return TRUE
/obj/machinery/gulag_item_reclaimer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/gulag_item_reclaimer/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "GulagItemReclaimer", name, 300, 400, master_ui, state)
ui = new(user, src, "GulagItemReclaimer", name)
ui.open()
/obj/machinery/gulag_item_reclaimer/ui_data(mob/user)
@@ -60,20 +57,22 @@
mobs += list(mob_info)
data["mobs"] = mobs
data["can_reclaim"] = can_reclaim
return data
/obj/machinery/gulag_item_reclaimer/ui_act(action, list/params)
/obj/machinery/gulag_item_reclaimer/ui_act(action, params)
if(..())
return
switch(action)
if("release_items")
var/mob/M = locate(params["mobref"])
if(M == usr || allowed(usr))
drop_items(M)
else
to_chat(usr, "Access denied.")
var/mob/living/carbon/human/H = locate(params["mobref"]) in stored_items
if(H != usr && !allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return
drop_items(H)
. = TRUE
/obj/machinery/gulag_item_reclaimer/proc/drop_items(mob/user)
if(!stored_items[user])
+182 -187
View File
@@ -25,7 +25,6 @@ Possible to do for anyone motivated enough:
*/
GLOBAL_LIST_EMPTY(network_holopads)
#define HOLOPAD_PASSIVE_POWER_USAGE 1
#define HOLOGRAM_POWER_USAGE 2
@@ -34,34 +33,64 @@ GLOBAL_LIST_EMPTY(network_holopads)
desc = "It's a floor-mounted device for projecting holographic images."
icon_state = "holopad0"
layer = LOW_OBJ_LAYER
plane = ABOVE_WALL_PLANE
plane = FLOOR_PLANE
flags_1 = HEAR_1
req_access = list(ACCESS_KEYCARD_AUTH) //Used to allow for forced connecting to other (not secure) holopads. Anyone can make a call, though.
use_power = IDLE_POWER_USE
idle_power_usage = 5
active_power_usage = 100
max_integrity = 300
armor = list("melee" = 50, "bullet" = 20, "laser" = 20, "energy" = 20, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 0)
circuit = /obj/item/circuitboard/machine/holopad
var/list/masters //List of living mobs that use the holopad
var/list/holorays //Holoray-mob link.
var/last_request = 0 //to prevent request spam. ~Carn
var/holo_range = 5 // Change to change how far the AI can move away from the holopad before deactivating.
var/temp = ""
var/list/holo_calls //array of /datum/holocalls
var/datum/holocall/outgoing_call //do not modify the datums only check and call the public procs
var/obj/item/disk/holodisk/disk //Record disk
var/replay_mode = FALSE //currently replaying a recording
var/loop_mode = FALSE //currently looping a recording
var/record_mode = FALSE //currently recording
var/record_start = 0 //recording start time
var/record_user //user that inititiated the recording
var/obj/effect/overlay/holo_pad_hologram/replay_holo //replay hologram
var/static/force_answer_call = FALSE //Calls will be automatically answered after a couple rings, here for debugging
/// List of living mobs that use the holopad
var/list/masters
/// Holoray-mob link
var/list/holorays
/// To prevent request spam. ~Carn
var/last_request = 0
/// Change to change how far the AI can move away from the holopad before deactivating
var/holo_range = 5
/// Array of /datum/holocalls
var/list/holo_calls
/// Currently outgoing holocall, do not modify the datums only check and call the public procs
var/datum/holocall/outgoing_call
/// Record disk
var/obj/item/disk/holodisk/disk
/// Currently replaying a recording
var/replay_mode = FALSE
/// Currently looping a recording
var/loop_mode = FALSE
/// Currently recording
var/record_mode = FALSE
/// Recording start time
var/record_start = 0
/// User that inititiated the recording
var/record_user
/// Replay hologram
var/obj/effect/overlay/holo_pad_hologram/replay_holo
/// Calls will be automatically answered after a couple rings, here for debugging
var/static/force_answer_call = FALSE
// var/static/list/holopads = list()
var/obj/effect/overlay/holoray/ray
var/ringing = FALSE
var/offset = FALSE
var/on_network = TRUE
/// For pads in secure areas; do not allow forced connecting
var/secure = FALSE
/// If we are currently calling another holopad
var/calling = FALSE
/*
/obj/machinery/holopad/secure
name = "secure holopad"
desc = "It's a floor-mounted device for projecting holographic images. This one will refuse to auto-connect incoming calls."
secure = TRUE
/obj/machinery/holopad/secure/Initialize()
. = ..()
var/obj/item/circuitboard/machine/holopad/board = circuit
board.secure = TRUE
board.build_path = /obj/machinery/holopad/secure
*/
/obj/machinery/holopad/tutorial
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
flags_1 = NODECONSTRUCT_1
@@ -121,10 +150,8 @@ GLOBAL_LIST_EMPTY(network_holopads)
return ..()
/obj/machinery/holopad/power_change()
if (powered())
stat &= ~NOPOWER
else
stat |= NOPOWER
. = ..()
if (!powered())
if(replay_mode)
replay_stop()
if(record_mode)
@@ -163,171 +190,150 @@ GLOBAL_LIST_EMPTY(network_holopads)
if(istype(P,/obj/item/disk/holodisk))
if(disk)
to_chat(user,"<span class='notice'>There's already a disk inside [src]</span>")
to_chat(user,"<span class='warning'>There's already a disk inside [src]!</span>")
return
if (!user.transferItemToLoc(P,src))
return
to_chat(user,"<span class='notice'>You insert [P] into [src]</span>")
to_chat(user,"<span class='notice'>You insert [P] into [src].</span>")
disk = P
updateDialog()
return
return ..()
/obj/machinery/holopad/ui_status(mob/user)
if(!is_operational())
return UI_CLOSE
if(outgoing_call && !calling)
return UI_CLOSE
return ..()
/obj/machinery/holopad/ui_interact(mob/living/carbon/human/user) //Carn: Hologram requests.
/obj/machinery/holopad/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Holopad", name)
ui.open()
/obj/machinery/holopad/ui_data(mob/user)
var/list/data = list()
data["calling"] = calling
data["on_network"] = on_network
data["on_cooldown"] = last_request + 200 < world.time ? FALSE : TRUE
data["allowed"] = allowed(user)
data["disk"] = disk ? TRUE : FALSE
data["disk_record"] = disk?.record ? TRUE : FALSE
data["replay_mode"] = replay_mode
data["loop_mode"] = loop_mode
data["record_mode"] = record_mode
data["holo_calls"] = list()
for(var/I in holo_calls)
var/datum/holocall/HC = I
var/list/call_data = list(
caller = HC.user,
connected = HC.connected_holopad == src ? TRUE : FALSE,
ref = REF(HC)
)
data["holo_calls"] += list(call_data)
return data
/obj/machinery/holopad/ui_act(action, list/params)
. = ..()
if(!istype(user))
if(.)
return
if(outgoing_call || user.incapacitated() || !is_operational())
return
user.set_machine(src)
var/dat
if(temp)
dat = temp
else
if(on_network)
dat += "<a href='?src=[REF(src)];AIrequest=1'>Request an AI's presence</a><br>"
dat += "<a href='?src=[REF(src)];Holocall=1'>Call another holopad</a><br>"
if(disk)
if(disk.record)
//Replay
dat += "<a href='?src=[REF(src)];replay_start=1'>Replay disk recording</a><br>"
dat += "<a href='?src=[REF(src)];loop_start=1'>Loop disk recording</a><br>"
//Clear
dat += "<a href='?src=[REF(src)];record_clear=1'>Clear disk recording</a><br>"
switch(action)
if("AIrequest")
if(last_request + 200 < world.time)
last_request = world.time
to_chat(usr, "<span class='info'>You requested an AI's presence.</span>")
var/area/area = get_area(src)
for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs)
if(!AI.client)
continue
to_chat(AI, "<span class='info'>Your presence is requested at <a href='?src=[REF(AI)];jumptoholopad=[REF(src)]'>\the [area]</a>.</span>")
return TRUE
else
//Record
dat += "<a href='?src=[REF(src)];record_start=1'>Start new recording</a><br>"
//Eject
dat += "<a href='?src=[REF(src)];disk_eject=1'>Eject disk</a><br>"
to_chat(usr, "<span class='info'>A request for AI presence was already sent recently.</span>")
return
if("holocall")
if(outgoing_call)
return
if(usr.loc == loc)
var/list/callnames = list()
for(var/I in GLOB.network_holopads)
var/area/A = get_area(I)
if(A)
LAZYADD(callnames[A], I)
callnames -= get_area(src)
var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in sortNames(callnames)
if(QDELETED(usr) || !result || outgoing_call)
return
if(usr.loc == loc)
var/input = text2num(params["headcall"])
var/headcall = input == 1 ? TRUE : FALSE
new /datum/holocall(usr, src, callnames[result], headcall)
calling = TRUE
return TRUE
else
to_chat(usr, "<span class='warning'>You must stand on the holopad to make a call!</span>")
if("connectcall")
var/datum/holocall/call_to_connect = locate(params["holopad"]) in holo_calls
if(!QDELETED(call_to_connect))
call_to_connect.Answer(src)
return TRUE
if("disconnectcall")
var/datum/holocall/call_to_disconnect = locate(params["holopad"]) in holo_calls
if(!QDELETED(call_to_disconnect))
call_to_disconnect.Disconnect(src)
return TRUE
if("disk_eject")
if(disk && !replay_mode)
disk.forceMove(drop_location())
disk = null
return TRUE
if("replay_mode")
if(replay_mode)
replay_stop()
return TRUE
else
replay_start()
return TRUE
if("loop_mode")
loop_mode = !loop_mode
return TRUE
if("record_mode")
if(record_mode)
record_stop()
return TRUE
else
record_start(usr)
return TRUE
if("record_clear")
record_clear()
return TRUE
if("offset")
offset++
if(offset > 4)
offset = FALSE
var/turf/new_turf
if(!offset)
new_turf = get_turf(src)
else
new_turf = get_step(src, GLOB.cardinals[offset])
replay_holo.forceMove(new_turf)
return TRUE
if("hang_up")
if(outgoing_call)
outgoing_call.Disconnect(src)
return TRUE
if(LAZYLEN(holo_calls))
dat += "=====================================================<br>"
if(on_network)
var/one_answered_call = FALSE
var/one_unanswered_call = FALSE
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad != src)
dat += "<a href='?src=[REF(src)];connectcall=[REF(HC)]'>Answer call from [get_area(HC.calling_holopad)]</a><br>"
one_unanswered_call = TRUE
else
one_answered_call = TRUE
if(one_answered_call && one_unanswered_call)
dat += "=====================================================<br>"
//we loop twice for formatting
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad == src)
dat += "<a href='?src=[REF(src)];disconnectcall=[REF(HC)]'>Disconnect call from [HC.user]</a><br>"
var/datum/browser/popup = new(user, "holopad", name, 300, 175)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
//Stop ringing the AI!!
/**
* hangup_all_calls: Disconnects all current holocalls from the holopad
*/
/obj/machinery/holopad/proc/hangup_all_calls()
for(var/I in holo_calls)
var/datum/holocall/HC = I
HC.Disconnect(src)
/obj/machinery/holopad/Topic(href, href_list)
if(..() || isAI(usr))
return
add_fingerprint(usr)
if(!is_operational())
return
if (href_list["AIrequest"])
if(last_request + 200 < world.time)
last_request = world.time
temp = "You requested an AI's presence.<BR>"
temp += "<A href='?src=[REF(src)];mainmenu=1'>Main Menu</A>"
var/area/area = get_area(src)
for(var/mob/living/silicon/ai/AI in GLOB.silicon_mobs)
if(!AI.client)
continue
to_chat(AI, "<span class='info'>Your presence is requested at <a href='?src=[REF(AI)];jumptoholopad=[REF(src)]'>\the [area]</a>.</span>")
else
temp = "A request for AI presence was already sent recently.<BR>"
temp += "<A href='?src=[REF(src)];mainmenu=1'>Main Menu</A>"
else if(href_list["Holocall"])
if(outgoing_call)
return
temp = "You must stand on the holopad to make a call!<br>"
temp += "<A href='?src=[REF(src)];mainmenu=1'>Main Menu</A>"
if(usr.loc == loc)
var/list/callnames = list()
for(var/I in GLOB.network_holopads)
var/area/A = get_area(I)
if(A)
LAZYADD(callnames[A], I)
callnames -= get_area(src)
var/result = input(usr, "Choose an area to call", "Holocall") as null|anything in callnames
if(QDELETED(usr) || !result || outgoing_call)
return
if(usr.loc == loc)
temp = "Dialing...<br>"
temp += "<A href='?src=[REF(src)];mainmenu=1'>Main Menu</A>"
new /datum/holocall(usr, src, callnames[result])
else if(href_list["connectcall"])
var/datum/holocall/call_to_connect = locate(href_list["connectcall"])
if(!QDELETED(call_to_connect))
call_to_connect.Answer(src)
temp = ""
else if(href_list["disconnectcall"])
var/datum/holocall/call_to_disconnect = locate(href_list["disconnectcall"])
if(!QDELETED(call_to_disconnect))
call_to_disconnect.Disconnect(src)
temp = ""
else if(href_list["mainmenu"])
temp = ""
if(outgoing_call)
outgoing_call.Disconnect()
else if(href_list["disk_eject"])
if(disk && !replay_mode)
disk.forceMove(drop_location())
disk = null
else if(href_list["replay_stop"])
replay_stop()
else if(href_list["replay_start"])
replay_start()
else if(href_list["loop_start"])
loop_mode = TRUE
replay_start()
else if(href_list["record_start"])
record_start(usr)
else if(href_list["record_stop"])
record_stop()
else if(href_list["record_clear"])
record_clear()
else if(href_list["offset"])
offset++
if (offset > 4)
offset = FALSE
var/turf/new_turf
if (!offset)
new_turf = get_turf(src)
else
new_turf = get_step(src, GLOB.cardinals[offset])
replay_holo.forceMove(new_turf)
updateDialog()
//do not allow AIs to answer calls or people will use it to meta the AI sattelite
/obj/machinery/holopad/attack_ai(mob/living/silicon/ai/user)
if (!istype(user))
@@ -366,6 +372,9 @@ GLOBAL_LIST_EMPTY(network_holopads)
if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2)))
HC.Answer(src)
break
if(!secure) //HC.head_call &&
HC.Answer(src)
break
if(outgoing_call)
HC.Disconnect(src)//can't answer calls while calling
else
@@ -412,17 +421,17 @@ GLOBAL_LIST_EMPTY(network_holopads)
/*This is the proc for special two-way communication between AI and holopad/people talking near holopad.
For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
/obj/machinery/holopad/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list())
. = ..()
if(speaker && LAZYLEN(masters) && !radio_freq)//Master is mostly a safety in case lag hits or something. Radio_freq so AIs dont hear holopad stuff through radios.
for(var/mob/living/silicon/ai/master in masters)
if(masters[master] && speaker != master)
master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mode)
master.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
for(var/I in holo_calls)
var/datum/holocall/HC = I
if(HC.connected_holopad == src && speaker != HC.hologram)
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mode, source)
HC.user.Hear(message, speaker, message_language, raw_message, radio_freq, spans, message_mods)
if(outgoing_call && speaker == outgoing_call.user)
outgoing_call.hologram.say(raw_message)
@@ -449,7 +458,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
else
icon_state = "holopad0"
/obj/machinery/holopad/proc/set_holo(mob/living/user, var/obj/effect/overlay/holo_pad_hologram/h)
/obj/machinery/holopad/proc/set_holo(mob/living/user, obj/effect/overlay/holo_pad_hologram/h)
LAZYSET(masters, user, h)
LAZYSET(holorays, user, new /obj/effect/overlay/holoray(loc))
var/mob/living/silicon/ai/AI = user
@@ -504,7 +513,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
else
return FALSE
/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf, direction)
/obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf)
if(LAZYLEN(masters) && masters[user])
var/obj/effect/overlay/holo_pad_hologram/holo = masters[user]
var/transfered = FALSE
@@ -516,8 +525,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
transfered = TRUE
//All is good.
holo.forceMove(new_turf)
if(direction)
holo.setDir(direction)
if(!transfered)
update_holoray(user,new_turf)
return TRUE
@@ -568,22 +575,15 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(!replay_mode)
replay_mode = TRUE
replay_holo = setup_replay_holo(disk.record)
temp = "Replaying...<br>"
temp += "<A href='?src=[REF(src)];offset=1'>Change offset</A><br>"
temp += "<A href='?src=[REF(src)];replay_stop=1'>End replay</A>"
SetLightsAndPower()
replay_entry(1)
return
/obj/machinery/holopad/proc/replay_stop()
if(replay_mode)
replay_mode = FALSE
loop_mode = FALSE
offset = FALSE
temp = null
QDEL_NULL(replay_holo)
SetLightsAndPower()
updateDialog()
/obj/machinery/holopad/proc/record_start(mob/living/user)
if(!user || !disk || disk.record)
@@ -593,8 +593,6 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
record_start = world.time
record_user = user
disk.record.set_caller_image(user)
temp = "Recording...<br>"
temp += "<A href='?src=[REF(src)];record_stop=1'>End recording.</A>"
/obj/machinery/holopad/proc/record_message(mob/living/speaker,message,language)
if(!record_mode)
@@ -641,7 +639,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(replay_holo)
replay_holo.say(message)
if(HOLORECORD_SOUND)
playsound(src,entry[2],50,1)
playsound(src,entry[2],50,TRUE)
if(HOLORECORD_DELAY)
addtimer(CALLBACK(src,.proc/replay_entry,entry_number+1),entry[2])
return
@@ -660,14 +658,11 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
/obj/machinery/holopad/proc/record_stop()
if(record_mode)
record_mode = FALSE
temp = null
record_user = null
updateDialog()
/obj/machinery/holopad/proc/record_clear()
if(disk && disk.record)
QDEL_NULL(disk.record)
updateDialog()
/obj/effect/overlay/holo_pad_hologram
initial_language_holder = /datum/language_holder/universal
+9 -10
View File
@@ -6,14 +6,12 @@
circuit = /obj/item/circuitboard/machine/hypnochair
density = TRUE
opacity = 0
ui_x = 375
ui_y = 480
var/mob/living/carbon/victim = null ///Keeps track of the victim to apply effects if it teleports away
var/interrogating = FALSE ///Is the device currently interrogating someone?
var/start_time = 0 ///Time when the interrogation was started, to calculate effect in case of interruption
var/trigger_phrase = "" ///Trigger phrase to implant
var/timerid = 0 ///Timer ID for interrogations
var/message_cooldown = 0 ///Cooldown for breakout message
/obj/machinery/hypnochair/Initialize()
@@ -25,24 +23,24 @@
if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I))
update_icon()
return
if(default_pry_open(I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
/obj/machinery/hypnochair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/hypnochair/ui_state(mob/user)
return GLOB.notcontained_state
/obj/machinery/hypnochair/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "HypnoChair", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "HypnoChair", name)
ui.open()
/obj/machinery/hypnochair/ui_data()
var/list/data = list()
data["occupied"] = occupant ? TRUE : FALSE
data["occupied"] = occupant ? 1 : 0
data["open"] = state_open
data["interrogating"] = interrogating
@@ -201,3 +199,4 @@
if(!(L.mobility_flags & MOBILITY_STAND))
return
close_machine(target)
+16 -3
View File
@@ -3,13 +3,14 @@
/obj/machinery/iv_drip
name = "\improper IV drip"
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate."
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. Alt-Click to change the transfer rate."
icon = 'icons/obj/iv_drip.dmi'
icon_state = "iv_drip"
anchored = FALSE
mouse_drag_pointer = MOUSE_ACTIVE_POINTER
var/mob/living/carbon/attached
var/mode = IV_INJECTING
var/dripfeed = FALSE
var/obj/item/reagent_containers/beaker
var/static/list/drip_containers = typecacheof(list(/obj/item/reagent_containers/blood,
/obj/item/reagent_containers/food,
@@ -132,9 +133,11 @@
if(mode)
if(beaker.reagents.total_volume)
var/transfer_amount = 5
if (dripfeed)
transfer_amount = 1
if(istype(beaker, /obj/item/reagent_containers/blood))
// speed up transfer on blood packs
transfer_amount = 10
transfer_amount *= 2
var/fraction = min(transfer_amount/beaker.reagents.total_volume, 1) //the fraction that is transfered of the total volume
beaker.reagents.reaction(attached, INJECT, fraction, FALSE) //make reagents reacts, but don't spam messages
beaker.reagents.trans_to(attached, transfer_amount)
@@ -169,6 +172,16 @@
else
toggle_mode()
/obj/machinery/iv_drip/AltClick(mob/living/user)
if(!user.canUseTopic(src, be_close=TRUE))
return
if(dripfeed)
dripfeed = FALSE
to_chat(usr, "<span class='notice'>You loosen the valve to speed up the [src].</span>")
else
dripfeed = TRUE
to_chat(usr, "<span class='notice'>You tighten the valve to slowly drip-feed the contents of [src].</span>")
/obj/machinery/iv_drip/attack_robot(mob/user)
if(Adjacent(user))
attack_hand(user)
@@ -227,7 +240,7 @@
/obj/machinery/iv_drip/telescopic
name = "telescopic IV drip"
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down."
desc = "An IV drip with an advanced infusion pump that can both drain blood into and inject liquids from attached containers. Blood packs are processed at an accelerated rate. This one is telescopic, and can be picked up and put down.Alt-Click with a beaker attached to change the transfer rate."
icon_state = "iv_drip"
/obj/machinery/iv_drip/telescopic/update_icon_state()
+7 -5
View File
@@ -282,12 +282,14 @@
ui_interact(user)
to_chat(user, "<span class='notice'>[src] projects a display onto your retina.</span>")
/obj/item/launchpad_remote/ui_interact(mob/user, ui_key = "launchpad_remote", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "LaunchpadRemote", "Briefcase Launchpad Remote", 300, 240, master_ui, state) //width, height
ui.open()
/obj/item/launchpad_remote/ui_state(mob/user)
return GLOB.inventory_state
/obj/item/launchpad_remote/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "LaunchpadRemote")
ui.open()
ui.set_autoupdate(TRUE)
/obj/item/launchpad_remote/ui_data(mob/user)
+11
View File
@@ -38,3 +38,14 @@
if(stat & (BROKEN|NOPOWER))
return
drive()
/obj/machinery/mass_driver/pressure_plate
name = "pressure plated mass driver"
var/drive_delay = 10
/obj/machinery/mass_driver/pressure_plate/Crossed(atom/movable/O)
. = ..()
if(isliving(O))
var/mob/living/L = O
to_chat(L, "<span class='warning'>You feel something click beneath you!</span>")
addtimer(CALLBACK(src, .proc/drive), drive_delay)
@@ -4,6 +4,15 @@
#define POPUP_ANIM_TIME 5
#define POPDOWN_ANIM_TIME 5 //Be sure to change the icon animation at the same time or it'll look bad
#define TURRET_FLAG_SHOOT_ALL_REACT (1<<0) // The turret gets pissed off and shoots at people nearby (unless they have sec access!)
#define TURRET_FLAG_AUTH_WEAPONS (1<<1) // Checks if it can shoot people that have a weapon they aren't authorized to have
#define TURRET_FLAG_SHOOT_CRIMINALS (1<<2) // Checks if it can shoot people that are wanted
#define TURRET_FLAG_SHOOT_ALL (1<<3) // The turret gets pissed off and shoots at people nearby (unless they have sec access!)
#define TURRET_FLAG_SHOOT_ANOMALOUS (1<<4) // Checks if it can shoot at unidentified lifeforms (ie xenos)
#define TURRET_FLAG_SHOOT_UNSHIELDED (1<<5) // Checks if it can shoot people that aren't mindshielded and who arent heads
#define TURRET_FLAG_SHOOT_BORGS (1<<6) // checks if it can shoot cyborgs
#define TURRET_FLAG_SHOOT_HEADS (1<<7) // checks if it can shoot at heads of staff
/obj/machinery/porta_turret
name = "turret"
icon = 'icons/obj/turrets.dmi'
@@ -15,70 +24,79 @@
use_power = IDLE_POWER_USE //this turret uses and requires power
idle_power_usage = 50 //when inactive, this turret takes up constant 50 Equipment power
active_power_usage = 300 //when active, this turret takes up constant 300 Equipment power
req_access = list(ACCESS_SEC_DOORS)
req_access = list(ACCESS_SECURITY) /// Only people with Security access
power_channel = EQUIP //drains power from the EQUIPMENT channel
speed_process = TRUE
var/base_icon_state = "standard"
var/scan_range = 7
var/atom/base = null //for turrets inside other objects
var/raised = 0 //if the turret cover is "open" and the turret is raised
var/raising= 0 //if the turret is currently opening or closing its cover
max_integrity = 160 //the turret's health
integrity_failure = 0.5
armor = list("melee" = 50, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
var/locked = TRUE //if the turret's behaviour control access is locked
var/controllock = FALSE //if the turret responds to control panels
var/installation = /obj/item/gun/energy/e_gun/turret //the type of weapon installed by default
/// Base turret icon state
var/base_icon_state = "standard"
/// Scan range of the turret for locating targets
var/scan_range = 7
/// For turrets inside other objects
var/atom/base = null
/// If the turret cover is "open" and the turret is raised
var/raised = FALSE
/// If the turret is currently opening or closing its cover
var/raising = FALSE
/// If the turret's behaviour control access is locked
var/locked = TRUE
/// If the turret responds to control panels
var/controllock = FALSE
/// The type of weapon installed by default
var/installation = /obj/item/gun/energy/e_gun/turret
/// What stored gun is in the turret
var/obj/item/gun/stored_gun = null
var/gun_charge = 0 //the charge of the gun when retrieved from wreckage
/// The charge of the gun when retrieved from wreckage
var/gun_charge = 0
/// In which mode is turret in, stun or lethal
var/mode = TURRET_STUN
var/stun_projectile = null //stun mode projectile type
/// Stun mode projectile type
var/stun_projectile = null
/// Sound of stun projectile
var/stun_projectile_sound
var/nonlethal_projectile //projectile to use in stun mode when the target is resting, if any
/// Projectile to use in stun mode when the target is resting, if any
var/nonlethal_projectile
/// Sound of stun projectile wen the target is resting, optional
var/nonlethal_projectile_sound
var/lethal_projectile = null //lethal mode projectile type
/// Lethal mode projectile type
var/lethal_projectile = null
/// Sound of lethal projectile
var/lethal_projectile_sound
var/reqpower = 500 //power needed per shot
var/always_up = 0 //Will stay active
var/has_cover = 1 //Hides the cover
var/obj/machinery/porta_turret_cover/cover = null //the cover that is covering this turret
var/last_fired = 0 //world.time the turret last fired
var/shot_delay = 15 //ticks until next shot (1.5 ?)
var/shot_stagger = 0 // sleep() shots to stagger attacks
var/check_records = 1 //checks if it can use the security records
var/criminals = 1 //checks if it can shoot people on arrest
var/auth_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have
var/stun_all = 0 //if this is active, the turret shoots everything that isn't security or head of staff
var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos)
var/shoot_unloyal = 0 //checks if it can shoot people that aren't loyalty implantd
var/attacked = 0 //if set to 1, the turret gets pissed off and shoots at people nearby (unless they have sec access!)
var/on = TRUE //determines if the turret is on
var/list/faction = list("turret") // Same faction mobs will never be shot at, no matter the other settings
var/datum/effect_system/spark_spread/spark_system //the spark system, used for generating... sparks?
/// Power needed per shot
var/reqpower = 500
/// Will stay active
var/always_up = FALSE
/// Hides the cover
var/has_cover = TRUE
/// The cover that is covering this turret
var/obj/machinery/porta_turret_cover/cover = null
/// World.time the turret last fired
var/last_fired = 0
/// Ticks until next shot (1.5 ?)
var/shot_delay = 15
/// Turret flags about who is turret allowed to shoot
var/turret_flags = TURRET_FLAG_SHOOT_CRIMINALS | TURRET_FLAG_SHOOT_ANOMALOUS
/// Determines if the turret is on
var/on = TRUE
/// Same faction mobs will never be shot at, no matter the other settings
var/list/faction = list("turret")
/// The spark system, used for generating... sparks?
var/datum/effect_system/spark_spread/spark_system
/// Linked turret control panel of the turret
var/obj/machinery/turretid/cp = null
var/wall_turret_direction //The turret will try to shoot from a turf in that direction when in a wall
var/manual_control = FALSE //
/// The turret will try to shoot from a turf in that direction when in a wall
var/wall_turret_direction
/// If the turret is manually controlled
var/manual_control = FALSE
/// Action button holder for quitting manual control
var/datum/action/turret_quit/quit_action
/// Action button holder for switching between turret modes when manually controlling
var/datum/action/turret_toggle/toggle_action
/// Mob that is remotely controlling the turret
var/mob/remote_controller
/// MISSING:
var/shot_stagger = 0
/obj/machinery/porta_turret/Initialize()
. = ..()
@@ -100,6 +118,27 @@
if(!has_cover)
INVOKE_ASYNC(src, .proc/popUp)
/obj/machinery/porta_turret/proc/toggle_on(var/set_to)
var/current = on
if (!isnull(set_to))
on = set_to
else
on = !on
if (current != on)
check_should_process()
if (!on)
popDown()
/obj/machinery/porta_turret/proc/check_should_process()
if (datum_flags & DF_ISPROCESSING)
if (!on || !anchored || (stat & BROKEN) || !powered())
//end_processing()
STOP_PROCESSING(SSmachines, src)
else
if (on && anchored && !(stat & BROKEN) && powered())
START_PROCESSING(SSmachines, src)
//begin_processing()
/obj/machinery/porta_turret/update_icon_state()
if(!anchored)
icon_state = "turretCover"
@@ -119,7 +158,6 @@
else
icon_state = "[base_icon_state]_unpowered"
/obj/machinery/porta_turret/proc/setup(obj/item/gun/turret_gun)
if(stored_gun)
qdel(stored_gun)
@@ -160,83 +198,88 @@
remove_control()
return ..()
/obj/machinery/porta_turret/ui_interact(mob/user)
. = ..()
var/dat
dat += "Status: <a href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</a><br>"
dat += "Behaviour controls are [locked ? "locked" : "unlocked"]<br>"
/obj/machinery/porta_turret/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "PortableTurret", name)
ui.open()
if(!locked)
dat += "Check for Weapon Authorization: <A href='?src=[REF(src)];operation=authweapon'>[auth_weapons ? "Yes" : "No"]</A><BR>"
dat += "Check Security Records: <A href='?src=[REF(src)];operation=checkrecords'>[check_records ? "Yes" : "No"]</A><BR>"
dat += "Neutralize Identified Criminals: <A href='?src=[REF(src)];operation=shootcrooks'>[criminals ? "Yes" : "No"]</A><BR>"
dat += "Neutralize All Non-Security and Non-Command Personnel: <A href='?src=[REF(src)];operation=shootall'>[stun_all ? "Yes" : "No"]</A><BR>"
dat += "Neutralize All Unidentified Life Signs: <A href='?src=[REF(src)];operation=checkxenos'>[check_anomalies ? "Yes" : "No"]</A><BR>"
dat += "Neutralize All Non-Loyalty Implanted Personnel: <A href='?src=[REF(src)];operation=checkloyal'>[shoot_unloyal ? "Yes" : "No"]</A><BR>"
/obj/machinery/porta_turret/ui_data(mob/user)
var/list/data = list(
"locked" = locked,
"on" = on,
"check_weapons" = turret_flags & TURRET_FLAG_AUTH_WEAPONS,
"neutralize_criminals" = turret_flags & TURRET_FLAG_SHOOT_CRIMINALS,
"neutralize_all" = turret_flags & TURRET_FLAG_SHOOT_ALL,
"neutralize_unidentified" = turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS,
"neutralize_nonmindshielded" = turret_flags & TURRET_FLAG_SHOOT_UNSHIELDED,
"neutralize_cyborgs" = turret_flags & TURRET_FLAG_SHOOT_BORGS,
"ignore_heads" = turret_flags & TURRET_FLAG_SHOOT_HEADS,
"manual_control" = manual_control,
"silicon_user" = FALSE,
"allow_manual_control" = FALSE,
"lasertag_turret" = istype(src, /obj/machinery/porta_turret/lasertag),
)
if(issilicon(user))
data["silicon_user"] = TRUE
if(!manual_control)
var/mob/living/silicon/S = user
if(S.hack_software)
dat += "Assume direct control : <a href='?src=[REF(src)];operation=manual'>Manual Control</a><br>"
else
dat += "Warning! Remote control protocol enabled.<br>"
data["allow_manual_control"] = TRUE
return data
var/datum/browser/popup = new(user, "autosec", "Automatic Portable Turret Installation", 300, 300)
popup.set_content(dat)
popup.open()
/obj/machinery/porta_turret/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
add_fingerprint(usr)
if(href_list["power"] && !locked)
if(anchored) //you can't turn a turret on/off if it's not anchored/secured
on = !on //toggle on/off
else
to_chat(usr, "<span class='notice'>It has to be secured first!</span>")
interact(usr)
/obj/machinery/porta_turret/ui_act(action, list/params)
. = ..()
if(.)
return
if(href_list["operation"])
switch(href_list["operation"]) //toggles customizable behavioural protocols
if("authweapon")
auth_weapons = !auth_weapons
if("checkrecords")
check_records = !check_records
if("shootcrooks")
criminals = !criminals
if("shootall")
stun_all = !stun_all
if("checkxenos")
check_anomalies = !check_anomalies
if("checkloyal")
shoot_unloyal = !shoot_unloyal
if("manual")
if(issilicon(usr) && !manual_control)
give_control(usr)
interact(usr)
switch(action)
if("power")
if(anchored)
toggle_on()
return TRUE
else
to_chat(usr, "<span class='warning'>It has to be secured first!</span>")
if("authweapon")
turret_flags ^= TURRET_FLAG_AUTH_WEAPONS
return TRUE
if("shootcriminals")
turret_flags ^= TURRET_FLAG_SHOOT_CRIMINALS
return TRUE
if("shootall")
turret_flags ^= TURRET_FLAG_SHOOT_ALL
return TRUE
if("checkxenos")
turret_flags ^= TURRET_FLAG_SHOOT_ANOMALOUS
return TRUE
if("checkloyal")
turret_flags ^= TURRET_FLAG_SHOOT_UNSHIELDED
return TRUE
if("shootborgs")
turret_flags ^= TURRET_FLAG_SHOOT_BORGS
return TRUE
if("shootheads")
turret_flags ^= TURRET_FLAG_SHOOT_HEADS
return TRUE
if("manual")
if(!issilicon(usr))
return
give_control(usr)
return TRUE
/obj/machinery/porta_turret/ui_host(mob/user)
if(has_cover && cover)
return cover
if(base)
return base
return src
/obj/machinery/porta_turret/power_change()
if(!anchored)
. = ..()
if(!anchored || (stat & BROKEN) || !powered())
update_icon()
remove_control()
return
if(stat & BROKEN)
update_icon()
remove_control()
else
if( powered() )
stat &= ~NOPOWER
update_icon()
else
spawn(rand(0, 15))
stat |= NOPOWER
remove_control()
update_icon()
check_should_process()
/obj/machinery/porta_turret/attackby(obj/item/I, mob/user, params)
if(stat & BROKEN)
@@ -284,8 +327,10 @@
locked = !locked
to_chat(user, "<span class='notice'>Controls are now [locked ? "locked" : "unlocked"].</span>")
else
to_chat(user, "<span class='notice'>Access denied.</span>")
to_chat(user, "<span class='alert'>Access denied.</span>")
else if(istype(I, /obj/item/multitool) && !locked)
if(!multitool_check_buffer(user, I))
return
var/obj/item/multitool/M = I
M.buffer = src
to_chat(user, "<span class='notice'>You add [src] to multitool buffer.</span>")
@@ -293,19 +338,17 @@
return ..()
/obj/machinery/porta_turret/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "<span class='warning'>You short out [src]'s threat assessment circuits.</span>")
visible_message("[src] hums oddly...")
audible_message("<span class='hear'>[src] hums oddly...</span>")
obj_flags |= EMAGGED
controllock = TRUE
on = FALSE //turns off the turret temporarily
toggle_on(FALSE) //turns off the turret temporarily
update_icon()
sleep(60) //6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
on = TRUE //turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
return TRUE
//6 seconds for the traitor to gtfo of the area before the turret decides to ruin his shit
addtimer(CALLBACK(src, .proc/toggle_on, TRUE), 6 SECONDS)
//turns it back on. The cover popUp() popDown() are automatically called in process(), no need to define it here
/obj/machinery/porta_turret/emp_act(severity)
. = ..()
@@ -314,63 +357,41 @@
if(on)
//if the turret is on, the EMP no matter how severe disables the turret for a while
//and scrambles its settings, with a slight chance of having an emag effect
check_records = pick(0, 1)
criminals = pick(0, 1)
auth_weapons = pick(0, 1)
stun_all = pick(0, 0, 0, 0, 1) //stun_all is a pretty big deal, so it's least likely to get turned on
if(prob(50))
turret_flags |= TURRET_FLAG_SHOOT_CRIMINALS
if(prob(50))
turret_flags |= TURRET_FLAG_AUTH_WEAPONS
if(prob(20))
turret_flags |= TURRET_FLAG_SHOOT_ALL // Shooting everyone is a pretty big deal, so it's least likely to get turned on
on = FALSE
toggle_on(FALSE)
remove_control()
spawn(rand(60,600))
if(!on)
on = TRUE
addtimer(CALLBACK(src, .proc/toggle_on, TRUE), rand(60,600))
/obj/machinery/porta_turret/take_damage(damage, damage_type = BRUTE, damage_flag = 0, sound_effect = 1)
. = ..()
if(.) //damage received
if(. && obj_integrity > 0) //damage received
if(prob(30))
spark_system.start()
if(on && !attacked && !(obj_flags & EMAGGED))
attacked = TRUE
if(on && !(turret_flags & TURRET_FLAG_SHOOT_ALL_REACT) && !(obj_flags & EMAGGED))
turret_flags |= TURRET_FLAG_SHOOT_ALL_REACT
addtimer(CALLBACK(src, .proc/reset_attacked), 60)
/obj/machinery/porta_turret/proc/reset_attacked()
attacked = FALSE
turret_flags &= ~TURRET_FLAG_SHOOT_ALL_REACT
/obj/machinery/porta_turret/deconstruct(disassembled = TRUE)
qdel(src)
/obj/machinery/porta_turret/obj_break(damage_flag)
if(!(flags_1 & NODECONSTRUCT_1) && !(stat & BROKEN))
stat |= BROKEN //enables the BROKEN bit
. = ..()
if(.)
power_change()
invisibility = 0
spark_system.start() //creates some sparks because they look cool
qdel(cover) //deletes the cover - no need on keeping it there!
//turret healing
/obj/machinery/porta_turret/examine(mob/user)
. = ..()
if(obj_integrity < max_integrity)
. += "<span class='notice'>Use a welder to fix it.</span>"
/obj/machinery/porta_turret/welder_act(mob/living/user, obj/item/I)
. = TRUE
if(obj_integrity < max_integrity)
if(!I.tool_start_check(user, amount=0))
return
user.visible_message("[user] is welding the turret.", \
"<span class='notice'>You begin repairing the turret...</span>", \
"<span class='italics'>You hear welding.</span>")
if(I.use_tool(src, user, 40, volume=50))
obj_integrity = max_integrity
user.visible_message("[user.name] has repaired [src].", \
"<span class='notice'>You finish repairing the turret.</span>")
else
to_chat(user, "<span class='notice'>The turret doesn't need repairing.</span>")
/obj/machinery/porta_turret/process()
//the main machinery process
if(cover == null && anchored) //if it has no cover and is anchored
@@ -382,35 +403,43 @@
cover.parent_turret = src //assign the cover its parent_turret, which would be this (src)
if(!on || (stat & (NOPOWER|BROKEN)) || manual_control)
return
return PROCESS_KILL
var/list/targets = list()
for(var/mob/A in view(scan_range, base))
if(A.invisibility > SEE_INVISIBLE_LIVING)
continue
if(check_anomalies)//if it's set to check for simple animals
if(turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS)//if it's set to check for simple animals
if(isanimal(A))
var/mob/living/simple_animal/SA = A
if(SA.stat || in_faction(SA)) //don't target if dead or in faction
continue
targets += SA
if(issilicon(A))
var/mob/living/silicon/sillycone = A
if(sillycone.stat || in_faction(sillycone))
continue
if(issilicon(A))
var/mob/living/silicon/sillycone = A
if(ispAI(A))
continue
if((turret_flags & TURRET_FLAG_SHOOT_BORGS) && sillycone.stat != DEAD && iscyborg(sillycone))
targets += sillycone
continue
if(sillycone.stat || in_faction(sillycone))
continue
if(iscyborg(sillycone))
var/mob/living/silicon/robot/sillyconerobot = A
if(LAZYLEN(faction) && (ROLE_SYNDICATE in faction) && sillyconerobot.emagged == TRUE)
continue
if(iscyborg(sillycone))
var/mob/living/silicon/robot/sillyconerobot = A
if(LAZYLEN(faction) && (ROLE_SYNDICATE in faction) && sillyconerobot.emagged == TRUE)
continue
targets += sillycone
if(iscarbon(A))
else if(iscarbon(A))
var/mob/living/carbon/C = A
//If not emagged, only target non downed carbons
if(mode != TURRET_LETHAL && (C.stat || C.handcuffed || (C.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)))//CIT CHANGE - replaces check for lying with check for recoveringstam
//If not emagged, only target carbons that can use items
if(mode != TURRET_LETHAL && (C.stat || C.handcuffed || !(C.mobility_flags & MOBILITY_USE)))
continue
//If emagged, target all but dead carbons
@@ -419,12 +448,13 @@
//if the target is a human and not in our faction, analyze threat level
if(ishuman(C) && !in_faction(C))
if(assess_perp(C) >= 4)
targets += C
else if(check_anomalies) //non humans who are not simple animals (xenos etc)
else if(turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS) //non humans who are not simple animals (xenos etc)
if(!in_faction(C))
targets += C
for(var/A in GLOB.mechas_list)
if((get_dist(A, base) < scan_range) && can_see(base, A, scan_range))
var/obj/mecha/Mech = A
@@ -432,6 +462,10 @@
if(assess_perp(Mech.occupant) >= 4)
targets += Mech
if((turret_flags & TURRET_FLAG_SHOOT_ANOMALOUS) && GLOB.blobs.len && (mode == TURRET_LETHAL))
for(var/obj/structure/blob/B in view(scan_range, base))
targets += B
if(targets.len)
tryToShootAt(targets)
else if(!always_up)
@@ -488,36 +522,37 @@
if(obj_flags & EMAGGED)
return 10 //if emagged, always return 10.
if((stun_all || attacked) && !allowed(perp))
if((turret_flags & (TURRET_FLAG_SHOOT_ALL | TURRET_FLAG_SHOOT_ALL_REACT)) && !allowed(perp))
//if the turret has been attacked or is angry, target all non-sec people
if(!allowed(perp))
return 10
if(auth_weapons) //check for weapon authorization
if(turret_flags & TURRET_FLAG_AUTH_WEAPONS) //check for weapon authorization
if(isnull(perp.wear_id) || istype(perp.wear_id.GetID(), /obj/item/card/id/syndicate))
if(allowed(perp)) //if the perp has security access, return 0
return 0
if(perp.is_holding_item_of_type(/obj/item/gun) || perp.is_holding_item_of_type(/obj/item/melee/baton))
threatcount += 4
if(istype(perp.belt, /obj/item/gun) || istype(perp.belt, /obj/item/melee/baton))
threatcount += 2
if(check_records) //if the turret can check the records, check if they are set to *Arrest* on records
if(turret_flags & TURRET_FLAG_SHOOT_CRIMINALS) //if the turret can check the records, check if they are set to *Arrest* on records
var/perpname = perp.get_face_name(perp.get_id_name())
var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security)
if(!R || (R.fields["criminal"] == "*Arrest*"))
threatcount += 4
if(shoot_unloyal)
if (!HAS_TRAIT(perp, TRAIT_MINDSHIELD))
threatcount += 4
if((turret_flags & TURRET_FLAG_SHOOT_UNSHIELDED) && (!HAS_TRAIT(perp, TRAIT_MINDSHIELD)))
threatcount += 4
// If we aren't shooting heads then return a threatcount of 0
if (!(turret_flags & TURRET_FLAG_SHOOT_HEADS) && (perp.get_assignment() in GLOB.command_positions))
return 0
return threatcount
/obj/machinery/porta_turret/proc/in_faction(mob/target)
for(var/faction1 in faction)
if(faction1 in target.faction)
@@ -533,16 +568,16 @@
return
/obj/machinery/porta_turret/proc/shootAt(atom/movable/target, stagger_enabled = FALSE)
if(stagger_enabled)
randomize_shot_stagger()
sleep(shot_stagger)
if(!raised) //the turret has to be raised in order to fire - makes sense, right?
return
if(!(obj_flags & EMAGGED)) //if it hasn't been emagged, cooldown before shooting again
if(last_fired + shot_delay > world.time)
return
last_fired = world.time
if(last_fired + shot_delay > world.time)
return
last_fired = world.time
if(stagger_enabled)
randomize_shot_stagger()
sleep(shot_stagger)
var/turf/T = get_turf(src)
var/turf/U = get_turf(target)
@@ -563,15 +598,14 @@
T = closer
break
var/mob/living/carbon/C
if(iscarbon(target))
C = target
update_icon()
var/obj/item/projectile/A
//any emagged turrets drains 2x power and uses a different projectile?
if(mode == TURRET_STUN)
if(nonlethal_projectile && C && C.resting)
var/mob/living/carbon/C = null
if(iscarbon(target))
C = target
if(nonlethal_projectile && C?.resting)
use_power(reqpower*0.5)
A = new nonlethal_projectile(T)
playsound(loc, nonlethal_projectile_sound, 75, 1)
@@ -582,7 +616,7 @@
else
use_power(reqpower * 2)
A = new lethal_projectile(T)
playsound(loc, lethal_projectile_sound, 75, 1)
playsound(loc, lethal_projectile_sound, 75, TRUE)
//Shooting Code:
@@ -592,16 +626,15 @@
A.fire()
return A
/obj/machinery/porta_turret/proc/setState(on, mode)
/obj/machinery/porta_turret/proc/setState(on, mode, shoot_cyborgs)
if(controllock)
return
src.on = on
if(!on)
popDown()
shoot_cyborgs ? (turret_flags |= TURRET_FLAG_SHOOT_BORGS) : (turret_flags &= ~TURRET_FLAG_SHOOT_BORGS)
toggle_on(on)
src.mode = mode
power_change()
/datum/action/turret_toggle
name = "Toggle Mode"
icon_icon = 'icons/mob/actions/actions_mecha.dmi'
@@ -685,7 +718,15 @@
/obj/machinery/porta_turret/syndicate/ComponentInitialize()
. = ..()
AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES)
// AddComponent(/datum/component/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES)
AddElement(/datum/element/empprotection, EMP_PROTECT_SELF | EMP_PROTECT_WIRES) //this one or ^ one?
/obj/machinery/porta_turret/syndicate/setup()
return
/obj/machinery/porta_turret/syndicate/assess_perp(mob/living/carbon/human/perp)
return 10 //Syndicate turrets shoot everything not in their faction
/obj/machinery/porta_turret/syndicate/energy
icon_state = "standard_stun"
@@ -698,7 +739,6 @@
lethal_projectile_sound = 'sound/weapons/laser.ogg'
desc = "An energy blaster auto-turret."
/obj/machinery/porta_turret/syndicate/energy/heavy
icon_state = "standard_stun"
base_icon_state = "standard"
@@ -715,14 +755,13 @@
integrity_failure = 0.08
armor = list("melee" = 50, "bullet" = 30, "laser" = 30, "energy" = 30, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 90, "acid" = 90)
/obj/machinery/porta_turret/syndicate/setup()
return
/obj/machinery/porta_turret/syndicate/assess_perp(mob/living/carbon/human/perp)
return 10 //Syndicate turrets shoot everything not in their faction
/obj/machinery/porta_turret/syndicate/energy/raven
stun_projectile = /obj/item/projectile/beam/laser
stun_projectile_sound = 'sound/weapons/laser.ogg'
faction = list("neutral","silicon","turret")
/obj/machinery/porta_turret/syndicate/pod
integrity_failure = 0.5
max_integrity = 40
stun_projectile = /obj/item/projectile/bullet/syndicate_turret
lethal_projectile = /obj/item/projectile/bullet/syndicate_turret
@@ -749,6 +788,7 @@
faction = list("silicon")
nonlethal_projectile = /obj/item/projectile/beam/disabler
nonlethal_projectile_sound = 'sound/weapons/taser2.ogg'
turret_flags = TURRET_FLAG_SHOOT_CRIMINALS | TURRET_FLAG_SHOOT_ANOMALOUS | TURRET_FLAG_SHOOT_HEADS
/obj/machinery/porta_turret/ai/assess_perp(mob/living/carbon/human/perp)
return 10 //AI turrets shoot at everything not in their faction
@@ -804,6 +844,7 @@
/obj/machinery/porta_turret/centcom_shuttle/weak
max_integrity = 120
integrity_failure = 0.5
name = "Old Laser Turret"
desc = "A turret built with substandard parts and run down further with age. Still capable of delivering lethal lasers to the odd space carp, but not much else."
stun_projectile = /obj/item/projectile/beam/weak/penetrator
@@ -817,7 +858,6 @@
stun_projectile_sound = 'sound/weapons/gunshot.ogg'
desc = "A ballistic machine gun auto-turret."
////////////////////////
//Turret Control Panel//
////////////////////////
@@ -828,14 +868,22 @@
icon = 'icons/obj/machines/turret_control.dmi'
icon_state = "control_standby"
density = FALSE
var/enabled = 1
var/lethal = 0
var/locked = TRUE
var/control_area = null //can be area name, path or nothing.
var/ailock = 0 // AI cannot use this
req_access = list(ACCESS_AI_UPLOAD)
var/list/obj/machinery/porta_turret/turrets = list()
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/// Variable dictating if linked turrets are active and will shoot targets
var/enabled = TRUE
/// Variable dictating if linked turrets will shoot lethal projectiles
var/lethal = FALSE
/// Variable dictating if the panel is locked, preventing changes to turret settings
var/locked = TRUE
/// An area in which linked turrets are located, it can be an area name, path or nothing
var/control_area = null
/// AI is unable to use this machine if set to TRUE
var/ailock = FALSE
/// Variable dictating if linked turrets will shoot cyborgs
var/shoot_cyborgs = FALSE
/// List of all linked turrets
var/list/turrets = list()
/obj/machinery/turretid/Initialize(mapload, ndir = 0, built = 0)
. = ..()
@@ -868,112 +916,111 @@
T.cp = src
/obj/machinery/turretid/examine(mob/user)
. = ..()
if(hasSiliconAccessInArea(user) && (!stat & BROKEN))
. += "<span class='notice'>Ctrl-click [src] to [ enabled ? "disable" : "enable"] turrets.</span>"
. += "<span class='notice'>Alt-click [src] to set turrets to [ lethal ? "stun" : "kill"].</span>"
. += ..()
if(issilicon(user) && !(stat & BROKEN))
. += {"<span class='notice'>Ctrl-click [src] to [ enabled ? "disable" : "enable"] turrets.</span>
<span class='notice'>Alt-click [src] to set turrets to [ lethal ? "stun" : "kill"].</span>"}
/obj/machinery/turretid/attackby(obj/item/I, mob/user, params)
if(stat & BROKEN)
return
if (istype(I, /obj/item/multitool))
if(!multitool_check_buffer(user, I))
return
var/obj/item/multitool/M = I
if(M.buffer && istype(M.buffer, /obj/machinery/porta_turret))
turrets |= M.buffer
to_chat(user, "You link \the [M.buffer] with \the [src]")
to_chat(user, "<span class='notice'>You link \the [M.buffer] with \the [src].</span>")
return
if (hasSiliconAccessInArea(user))
if (issilicon(user))
return attack_hand(user)
if ( get_dist(src, user) == 0 ) // trying to unlock the interface
if (allowed(usr))
if(obj_flags & EMAGGED)
to_chat(user, "<span class='notice'>The turret control is unresponsive.</span>")
to_chat(user, "<span class='warning'>The turret control is unresponsive!</span>")
return
locked = !locked
to_chat(user, "<span class='notice'>You [ locked ? "lock" : "unlock"] the panel.</span>")
if (locked)
if (user.machine==src)
user.unset_machine()
user << browse(null, "window=turretid")
else
if (user.machine==src)
attack_hand(user)
else
to_chat(user, "<span class='warning'>Access denied.</span>")
to_chat(user, "<span class='alert'>Access denied.</span>")
/obj/machinery/turretid/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
to_chat(user, "<span class='danger'>You short out the turret controls' access analysis module.</span>")
to_chat(user, "<span class='notice'>You short out the turret controls' access analysis module.</span>")
obj_flags |= EMAGGED
locked = FALSE
if(user && user.machine == src)
attack_hand(user)
return TRUE
/obj/machinery/turretid/attack_ai(mob/user)
if(!ailock || IsAdminGhost(user))
return attack_hand(user)
else
to_chat(user, "<span class='notice'>There seems to be a firewall preventing you from accessing this device.</span>")
to_chat(user, "<span class='warning'>There seems to be a firewall preventing you from accessing this device!</span>")
/obj/machinery/turretid/ui_interact(mob/user)
/obj/machinery/turretid/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "TurretControl", name)
ui.open()
/obj/machinery/turretid/ui_data(mob/user)
var/list/data = list()
data["locked"] = locked
data["siliconUser"] = hasSiliconAccessInArea(user) || IsAdminGhost(user)
data["enabled"] = enabled
data["lethal"] = lethal
data["shootCyborgs"] = shoot_cyborgs
return data
/obj/machinery/turretid/ui_act(action, list/params)
. = ..()
if ( get_dist(src, user) > 0 )
if ( !(hasSiliconAccessInArea(user) || IsAdminGhost(user)) )
to_chat(user, "<span class='notice'>You are too far away.</span>")
user.unset_machine()
user << browse(null, "window=turretid")
return
var/t = ""
if(locked && !(hasSiliconAccessInArea(user) || IsAdminGhost(user)))
t += "<div class='notice icon'>Swipe ID card to unlock interface</div>"
else
if(!hasSiliconAccessInArea(user) && !IsAdminGhost(user))
t += "<div class='notice icon'>Swipe ID card to lock interface</div>"
t += "Turrets [enabled?"activated":"deactivated"] - <A href='?src=[REF(src)];toggleOn=1'>[enabled?"Disable":"Enable"]?</a><br>"
t += "Currently set for [lethal?"lethal":"stun repeatedly"] - <A href='?src=[REF(src)];toggleLethal=1'>Change to [lethal?"Stun repeatedly":"Lethal"]?</a><br>"
var/datum/browser/popup = new(user, "turretid", "Turret Control Panel ([get_area_name(src, TRUE)])")
popup.set_content(t)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/turretid/Topic(href, href_list)
if(..())
if(.)
return
if (locked)
if(!(hasSiliconAccessInArea(usr) || IsAdminGhost(usr)))
to_chat(usr, "Control panel is locked!")
return
if (href_list["toggleOn"])
toggle_on()
else if (href_list["toggleLethal"])
toggle_lethal()
attack_hand(usr)
/obj/machinery/turretid/proc/toggle_lethal()
switch(action)
if("lock")
if(!hasSiliconAccessInArea(usr) || IsAdminGhost(usr))
return
if((obj_flags & EMAGGED) || (stat & BROKEN))
to_chat(usr, "<span class='warning'>The turret control is unresponsive!</span>")
return
locked = !locked
return TRUE
if("power")
toggle_on(usr)
return TRUE
if("mode")
toggle_lethal(usr)
return TRUE
if("shoot_silicons")
shoot_silicons(usr)
return TRUE
/obj/machinery/turretid/proc/toggle_lethal(mob/user)
lethal = !lethal
add_hiddenprint(user)
log_combat(user, src, "[lethal ? "enabled" : "disabled"] lethals on")
updateTurrets()
/obj/machinery/turretid/proc/toggle_on()
/obj/machinery/turretid/proc/toggle_on(mob/user)
enabled = !enabled
add_hiddenprint(user)
log_combat(user, src, "[enabled ? "enabled" : "disabled"]")
updateTurrets()
/obj/machinery/turretid/proc/shoot_silicons(mob/user)
shoot_cyborgs = !shoot_cyborgs
add_hiddenprint(user)
log_combat(user, src, "[shoot_cyborgs ? "Shooting Borgs" : "Not Shooting Borgs"]")
updateTurrets()
/obj/machinery/turretid/proc/updateTurrets()
for (var/obj/machinery/porta_turret/aTurret in turrets)
aTurret.setState(enabled, lethal)
update_icon()
/obj/machinery/turretid/power_change()
..()
aTurret.setState(enabled, lethal, shoot_cyborgs)
update_icon()
/obj/machinery/turretid/update_icon_state()
@@ -1051,11 +1098,7 @@
/obj/machinery/porta_turret/lasertag
req_access = list(ACCESS_MAINT_TUNNELS, ACCESS_THEATRE)
check_records = 0
criminals = 0
auth_weapons = 1
stun_all = 0
check_anomalies = 0
turret_flags = TURRET_FLAG_AUTH_WEAPONS
var/team_color
/obj/machinery/porta_turret/lasertag/assess_perp(mob/living/carbon/human/perp)
@@ -1083,20 +1126,14 @@
if(properties["team_color"])
team_color = properties["team_color"]
/obj/machinery/porta_turret/lasertag/ui_interact(mob/user)
. = ..()
/obj/machinery/porta_turret/lasertag/ui_status(mob/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(team_color == "blue" && istype(H.wear_suit, /obj/item/clothing/suit/redtag))
return
return UI_CLOSE
if(team_color == "red" && istype(H.wear_suit, /obj/item/clothing/suit/bluetag))
return
var/dat = "Status: <a href='?src=[REF(src)];power=1'>[on ? "On" : "Off"]</a>"
var/datum/browser/popup = new(user, "autosec", "Automatic Portable Turret Installation", 300, 300)
popup.set_content(dat)
popup.open()
return UI_CLOSE
return ..()
//lasertag presets
/obj/machinery/porta_turret/lasertag/red
@@ -1112,11 +1149,9 @@
if(on)
if(team_color == "blue")
if(istype(P, /obj/item/projectile/beam/lasertag/redtag))
on = FALSE
spawn(100)
on = TRUE
toggle_on(FALSE)
addtimer(CALLBACK(src, .proc/toggle_on, TRUE), 10 SECONDS)
else if(team_color == "red")
if(istype(P, /obj/item/projectile/beam/lasertag/bluetag))
on = FALSE
spawn(100)
on = TRUE
toggle_on(FALSE)
addtimer(CALLBACK(src, .proc/toggle_on, TRUE), 10 SECONDS)
+3 -14
View File
@@ -126,17 +126,6 @@
update_icon()
/obj/machinery/recharge_station/proc/process_occupant()
if(occupant && iscyborg(occupant))
var/mob/living/silicon/robot/R = occupant
restock_modules()
if(repairs)
R.heal_bodypart_damage(repairs, repairs - 1)
if(R.cell)
R.cell.charge = min(R.cell.charge + recharge_speed, R.cell.maxcharge)
/obj/machinery/recharge_station/proc/restock_modules()
if(occupant)
var/mob/living/silicon/robot/R = occupant
if(R && R.module)
var/coeff = recharge_speed * 0.005
R.module.respawn_consumable(R, coeff)
if(!occupant)
return
SEND_SIGNAL(occupant, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, recharge_speed, repairs)
+5 -6
View File
@@ -218,10 +218,10 @@ GLOBAL_LIST_EMPTY(allConsoles)
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>"
@@ -271,7 +271,6 @@ GLOBAL_LIST_EMPTY(allConsoles)
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)
@@ -279,7 +278,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
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)
@@ -358,7 +357,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
workingServer = TRUE
if(!workingServer)
screen = 7
screen = 7
say("NOTICE: No server detected! Please contact your local engineering team.")
updateUsrDialog()
return
@@ -539,7 +538,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
to_chat(user, "<span class='warning'>You are not authorized to send announcements!</span>")
updateUsrDialog()
return
if(istype(O, /obj/item/stamp))
if(screen == 9)
var/obj/item/stamp/T = O
-1
View File
@@ -132,7 +132,6 @@
var/datum/browser/popup = new(user, "slotmachine", "Slot Machine")
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/slot_machine/Topic(href, href_list)
+5 -16
View File
@@ -170,12 +170,10 @@
..()
default_unfasten_wrench(user, I, 5)
return TRUE
/obj/machinery/space_heater/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/space_heater/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "SpaceHeater", name, 400, 305, master_ui, state)
ui = new(user, src, "SpaceHeater", name)
ui.open()
/obj/machinery/space_heater/ui_data()
@@ -210,7 +208,7 @@
if("power")
on = !on
mode = HEATER_MODE_STANDBY
usr.visible_message("[usr] switches [on ? "on" : "off"] \the [src].", "<span class='notice'>You switch [on ? "on" : "off"] \the [src].</span>")
usr.visible_message("<span class='notice'>[usr] switches [on ? "on" : "off"] \the [src].</span>", "<span class='notice'>You switch [on ? "on" : "off"] \the [src].</span>")
update_icon()
if (on)
START_PROCESSING(SSmachines, src)
@@ -222,16 +220,7 @@
if(!panel_open)
return
var/target = params["target"]
var/adjust = text2num(params["adjust"])
if(target == "input")
target = input("New target temperature:", name, round(targetTemperature - T0C, 1)) as num|null
if(!isnull(target) && !..())
target += T0C
. = TRUE
else if(adjust)
target = targetTemperature + adjust
. = TRUE
else if(text2num(target) != null)
if(text2num(target) != null)
target= text2num(target) + T0C
. = TRUE
if(.)
+6 -4
View File
@@ -377,11 +377,13 @@
return ..()
/obj/machinery/suit_storage_unit/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/suit_storage_unit/ui_state(mob/user)
return GLOB.notcontained_state
/obj/machinery/suit_storage_unit/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "SuitStorageUnit", name, 400, 305, master_ui, state)
ui = new(user, src, "SuitStorageUnit", name)
ui.open()
/obj/machinery/suit_storage_unit/ui_data()
@@ -17,11 +17,10 @@
var/notice = ""
var/universal_translate = FALSE // set to TRUE(1) if it can translate nonhuman speech
/obj/machinery/computer/telecomms/server/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/telecomms/server/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "TelecommsLogBrowser", "Telecomms Server Monitor", 575, 400, master_ui, state)
ui = new(user, src, "TelecommsLogBrowser", "Telecomms Server Monitor")
ui.open()
/obj/machinery/computer/telecomms/server/ui_data(mob/user)
@@ -36,12 +36,11 @@
light_color = LIGHT_COLOR_GREEN
/obj/machinery/computer/message_monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/message_monitor/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "TelecommsPDALog", name, 727, 510, master_ui, state)
ui = new(user, src, "TelecommsPDALog", name)
ui.open()
/obj/machinery/computer/message_monitor/ui_static_data(mob/user)
@@ -17,12 +17,11 @@
circuit = /obj/item/circuitboard/computer/comm_monitor
/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "TelecommsMonitor", name, 575, 400, master_ui, state)
ui = new(user, src, "TelecommsMonitor", name)
ui.open()
/obj/machinery/computer/telecomms/monitor/ui_data(mob/user)
@@ -27,16 +27,15 @@
else
return ..()
/obj/machinery/telecomms/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
/obj/machinery/telecomms/ui_interact(mob/user, datum/tgui/ui)
if(!canInteract(user))
if(ui)
ui.close() //haha no.
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "TelecommsInteraction", "[name] Access", 520, 500, master_ui, state)
ui = new(user, src, "TelecommsInteraction", "[name] Access")
ui.open()
/obj/machinery/telecomms/ui_data(mob/user)
+17 -9
View File
@@ -11,10 +11,15 @@
var/equip_ready = 1 //whether the equipment is ready for use. (or deactivated/activated for static stuff)
var/energy_drain = 0
var/obj/mecha/chassis = null
var/range = MELEE //bitFflags
/// Bitflag. Determines the range of the equipment.
var/range = MELEE
/// Bitflag. Used by exosuit fabricator to assign sub-categories based on which exosuits can equip this.
var/mech_flags = NONE
var/salvageable = 1
//var/detachable = TRUE // Set to FALSE for built-in equipment that cannot be removed
var/selectable = 1 // Set to 0 for passive equipment such as mining scanner or armor plates
var/harmful = FALSE //Controls if equipment can be used to attack by a pacifist.
//var/destroy_sound = 'sound/mecha/critdestr.ogg'
/obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page()
if(chassis)
@@ -35,9 +40,14 @@
if(chassis.selected == src)
chassis.selected = null
src.update_chassis_page()
chassis.occupant_message("<span class='danger'>[src] is destroyed!</span>")
//log_message("[src] is destroyed.", LOG_MECHA)
chassis.log_append_to_last("[src] is destroyed.",1)
SEND_SOUND(chassis.occupant, sound(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon) ? 'sound/mecha/weapdestr.ogg' : 'sound/mecha/critdestr.ogg', volume=50))
if(chassis.occupant)
chassis.occupant_message("<span class='danger'>[src] is destroyed!</span>")
SEND_SOUND(chassis.occupant, sound(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon) ? 'sound/mecha/weapdestr.ogg' : 'sound/mecha/critdestr.ogg', volume=50))
//chassis.occupant.playsound_local(chassis, destroy_sound, 50)
//if(!detachable) //If we're a built-in nondetachable equipment, let's lock up the slot that we were in.
// chassis.max_equip--
chassis = null
return ..()
@@ -59,7 +69,7 @@
return txt
/obj/item/mecha_parts/mecha_equipment/proc/is_ranged()//add a distance restricted equipment. Why not?
return range&RANGED
return range&RANGED //rename to MECHA_RANGE and MECHA_MELEE
/obj/item/mecha_parts/mecha_equipment/proc/is_melee()
return range&MELEE
@@ -72,10 +82,10 @@
return 0
if(!equip_ready)
return 0
if(crit_fail)
return 0
if(energy_drain && !chassis.has_charge(energy_drain))
return 0
if(crit_fail)
return 0
if(chassis.equipment_disabled)
to_chat(chassis.occupant, "<span=warn>Error -- Equipment control unit is unresponsive.</span>")
return 0
@@ -117,8 +127,6 @@
chassis = M
forceMove(M)
M.mecha_log_message("[src] initialized.")
if(!M.selected && selectable)
M.selected = src
src.update_chassis_page()
return
@@ -150,7 +158,7 @@
chassis.occupant_message("[icon2html(src, chassis.occupant)] [message]")
return
/obj/item/mecha_parts/mecha_equipment/proc/mecha_log_message(message, color)
/obj/item/mecha_parts/mecha_equipment/proc/mecha_log_message(message, color) //on tg this just overrides log_message
log_message(message, LOG_GAME, color) //pass to default admin logging too
if(chassis)
chassis.mecha_log_message(message, color) //and pass to our chassis
@@ -1,6 +1,7 @@
// Sleeper, Medical Beam, and Syringe gun
/obj/item/mecha_parts/mecha_equipment/medical
mech_flags = EXOSUIT_MODULE_MEDICAL
/obj/item/mecha_parts/mecha_equipment/medical/Initialize()
. = ..()
@@ -17,6 +17,7 @@
toolspeed = 0.9
var/drill_delay = 7
var/drill_level = DRILL_BASIC
mech_flags = EXOSUIT_MODULE_WORKING | EXOSUIT_MODULE_COMBAT
/obj/item/mecha_parts/mecha_equipment/drill/Initialize()
. = ..()
@@ -153,6 +154,7 @@
selectable = 0
equip_cooldown = 15
var/scanning_time = 0
mech_flags = EXOSUIT_MODULE_WORKING
/obj/item/mecha_parts/mecha_equipment/mining_scanner/Initialize()
. = ..()
@@ -8,11 +8,12 @@
icon_state = "mecha_clamp"
equip_cooldown = 15
energy_drain = 10
tool_behaviour = TOOL_RETRACTOR
toolspeed = 0.8
var/dam_force = 20
var/obj/mecha/working/ripley/cargo_holder
harmful = TRUE
tool_behaviour = TOOL_RETRACTOR
toolspeed = 0.8
mech_flags = EXOSUIT_MODULE_RIPLEY
/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/can_attach(obj/mecha/working/ripley/M as obj)
if(..())
@@ -180,6 +181,7 @@
equip_cooldown = 5
energy_drain = 0
range = MELEE|RANGED
mech_flags = EXOSUIT_MODULE_WORKING
/obj/item/mecha_parts/mecha_equipment/extinguisher/Initialize()
. = ..()
@@ -9,6 +9,7 @@
var/projectile_delay = 0
var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect //the visual effect appearing when the weapon is fired.
var/kickback = TRUE //Will using this weapon in no grav push mecha back.
mech_flags = EXOSUIT_MODULE_COMBAT
/obj/item/mecha_parts/mecha_equipment/weapon/can_attach(obj/mecha/combat/M)
if(..())
+3 -4
View File
@@ -81,10 +81,10 @@
var/obj/machinery/mech_bay_recharge_port/recharge_port
light_color = LIGHT_COLOR_PINK
/obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "MechBayPowerConsole", "Mech Bay Power Control Console", 400, 200, master_ui, state)
ui = new(user, src, "MechBayPowerConsole", name)
ui.open()
/obj/machinery/computer/mech_bay_power_console/ui_act(action, params)
@@ -104,7 +104,6 @@
data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mech.obj_integrity, "maxhealth" = recharge_port.recharging_mech.max_integrity, "cell" = null, "name" = recharge_port.recharging_mech.name,)
if(recharge_port.recharging_mech.cell && !QDELETED(recharge_port.recharging_mech.cell))
data["recharge_port"]["mech"]["cell"] = list(
"critfail" = recharge_port.recharging_mech.cell.crit_fail,
"charge" = recharge_port.recharging_mech.cell.charge,
"maxcharge" = recharge_port.recharging_mech.cell.maxcharge
)
+546 -335
View File
@@ -9,17 +9,41 @@
active_power_usage = 5000
req_access = list(ACCESS_ROBOTICS)
circuit = /obj/item/circuitboard/machine/mechfab
var/time_coeff = 1
var/component_coeff = 1
var/datum/techweb/specialized/autounlocking/exofab/stored_research
var/sync = 0
var/part_set
var/datum/design/being_built
// processing_flags = START_PROCESSING_MANUALLY
// subsystem_type = /datum/controller/subsystem/processing/fastprocess
/// Current items in the build queue.
var/list/queue = list()
var/processing_queue = 0
var/screen = "main"
var/temp
var/offstation_security_levels = TRUE
/// Whether or not the machine is building the entire queue automagically.
var/process_queue = FALSE
/// The current design datum that the machine is building.
var/datum/design/being_built
/// World time when the build will finish.
var/build_finish = 0
/// World time when the build started.
var/build_start = 0
/// Reference to all materials used in the creation of the item being_built.
var/list/build_materials
/// Part currently stored in the Exofab.
var/obj/item/stored_part
/// Coefficient for the speed of item building. Based on the installed parts.
var/time_coeff = 1
/// Coefficient for the efficiency of material usage in item building. Based on the installed parts.
var/component_coeff = 1
/// Copy of the currently synced techweb.
var/datum/techweb/specialized/autounlocking/exofab/stored_research
/// Whether the Exofab links to the ore silo on init. Special derelict or maintanance variants should set this to FALSE.
var/link_on_init = TRUE
/// Reference to a remote material inventory, such as an ore silo.
var/datum/component/remote_materials/rmat
/// A list of categories that valid MECHFAB design datums will broadly categorise themselves under.
var/list/part_sets = list(
"Cyborg",
"Ripley",
@@ -33,25 +57,17 @@
"Exosuit Equipment",
"Exosuit Ammunition",
"Cyborg Upgrade Modules",
"Cybernetics",
"Implants",
"Control Interfaces",
"Misc"
)
/obj/machinery/mecha_part_fabricator/Initialize()
var/static/list/allowed_types = list(
/datum/material/iron,
/datum/material/glass,
/datum/material/silver,
/datum/material/gold,
/datum/material/diamond,
/datum/material/plasma,
/datum/material/uranium,
/datum/material/bananium,
/datum/material/titanium,
/datum/material/bluespace
)
var/datum/component/material_container/materials = AddComponent(/datum/component/material_container, allowed_types, 0, TRUE, /obj/item/stack, CALLBACK(src, .proc/is_insertion_ready), CALLBACK(src, .proc/AfterMaterialInsert))
materials.precise_insertion = TRUE
/obj/machinery/mecha_part_fabricator/Initialize(mapload)
stored_research = new
rmat = AddComponent(/datum/component/remote_materials, "mechfab", mapload && link_on_init)
RefreshParts() //Recalculating local material sizes if the fab isn't linked
return ..()
/obj/machinery/mecha_part_fabricator/RefreshParts()
@@ -60,8 +76,7 @@
//maximum stocking amount (default 300000, 600000 at T4)
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
T += M.rating
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = (200000 + (T*50000))
rmat.set_local_size((200000 + (T*50000)))
//resources adjustment coefficient (1 -> 0.85 -> 0.7 -> 0.55)
T = 1.15
@@ -74,89 +89,157 @@
for(var/obj/item/stock_parts/manipulator/Ml in component_parts)
T += Ml.rating
time_coeff = round(initial(time_coeff) - (initial(time_coeff)*(T))/5,0.01)
var/obj/item/circuitboard/machine/mechfab/C = circuit
offstation_security_levels = C.offstation_security_levels
// Adjust the build time of any item currently being built.
if(being_built)
var/last_const_time = build_finish - build_start
var/new_const_time = get_construction_time_w_coeff(initial(being_built.construction_time))
var/const_time_left = build_finish - world.time
var/new_build_time = (new_const_time / last_const_time) * const_time_left
build_finish = world.time + new_build_time
update_static_data(usr)
/obj/machinery/mecha_part_fabricator/examine(mob/user)
. = ..()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
if(in_range(user, src) || isobserver(user))
. += "<span class='notice'>The status display reads: Storing up to <b>[materials.max_amount]</b> material units.<br>Material consumption at <b>[component_coeff*100]%</b>.<br>Build time reduced by <b>[100-time_coeff*100]%</b>.</span>"
. += "<span class='notice'>The status display reads: Storing up to <b>[rmat.local_size]</b> material units.<br>Material consumption at <b>[component_coeff*100]%</b>.<br>Build time reduced by <b>[100-time_coeff*100]%</b>.</span>"
/obj/machinery/mecha_part_fabricator/emag_act()
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
req_access = list()
INVOKE_ASYNC(src, .proc/error_action_sucessful)
return TRUE
/obj/machinery/mecha_part_fabricator/proc/error_action_sucessful()
say("DB error \[Code 0x00F1\]")
sleep(10)
say("Attempting auto-repair...")
sleep(15)
say("User DB corrupted \[Code 0x00FA\]. Truncating data structure...")
sleep(30)
say("User DB truncated. Please contact your Nanotrasen system operator for future assistance.")
/obj/machinery/mecha_part_fabricator/proc/output_parts_list(set_name)
var/output = ""
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(!(set_name in D.category))
continue
output += "<div class='part'>[output_part_info(D)]<br>\["
if(check_clearance(D) && check_resources(D))
output += "<a href='?src=[REF(src)];part=[D.id]'>Build</a> | "
output += "<a href='?src=[REF(src)];add_to_queue=[D.id]'>Add to queue</a>\]\[<a href='?src=[REF(src)];part_desc=[D.id]'>?</a>\]</div>"
return output
/obj/machinery/mecha_part_fabricator/proc/check_clearance(datum/design/D)
if(!(obj_flags & EMAGGED) && (offstation_security_levels || is_station_level(z)) && !ISINRANGE(GLOB.security_level, D.min_security_level, D.max_security_level))
return FALSE
return TRUE
/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D)
var/clearance = !(obj_flags & EMAGGED) && (offstation_security_levels || is_station_level(z))
var/sec_text = ""
if(clearance && (D.min_security_level > SEC_LEVEL_GREEN || D.max_security_level < SEC_LEVEL_DELTA))
sec_text = " (Allowed security levels: "
for(var/n in D.min_security_level to D.max_security_level)
sec_text += NUM2SECLEVEL(n)
if(n + 1 <= D.max_security_level)
sec_text += ", "
sec_text += ") "
var/output = "[initial(D.name)] (Cost: [output_part_cost(D)]) [sec_text][get_construction_time_w_coeff(D)/10]sec"
return output
/obj/machinery/mecha_part_fabricator/proc/output_part_cost(datum/design/D)
var/i = 0
var/output
/**
* Generates an info list for a given part.
*
* Returns a list of part information.
* * D - Design datum to get information on.
* * categories - Boolean, whether or not to parse snowflake categories into the part information list.
*/
/obj/machinery/mecha_part_fabricator/proc/output_part_info(datum/design/D, categories = FALSE)
var/cost = list()
for(var/c in D.materials)
var/datum/material/M = c
output += "[i?" | ":null][get_resource_cost_w_coeff(D, M)] [M.name]"
i++
return output
cost[M.name] = get_resource_cost_w_coeff(D, M)
var/obj/built_item = D.build_path
var/list/category_override = null
var/list/sub_category = null
if(categories)
// Handle some special cases to build up sub-categories for the fab interface.
// Start with checking if this design builds a cyborg module.
if(built_item in typesof(/obj/item/borg/upgrade))
var/obj/item/borg/upgrade/U = built_item
var/module_types = initial(U.module_flags)
sub_category = list()
if(module_types)
if(module_types & BORG_MODULE_SECURITY)
sub_category += "Security"
if(module_types & BORG_MODULE_MINER)
sub_category += "Mining"
if(module_types & BORG_MODULE_JANITOR)
sub_category += "Janitor"
if(module_types & BORG_MODULE_MEDICAL)
sub_category += "Medical"
if(module_types & BORG_MODULE_ENGINEERING)
sub_category += "Engineering"
else
sub_category += "All Cyborgs"
// Else check if this design builds a piece of exosuit equipment.
else if(built_item in typesof(/obj/item/mecha_parts/mecha_equipment))
var/obj/item/mecha_parts/mecha_equipment/E = built_item
var/mech_types = initial(E.mech_flags)
sub_category = "Equipment"
if(mech_types)
category_override = list()
if(mech_types & EXOSUIT_MODULE_RIPLEY)
category_override += "Ripley"
if(mech_types & EXOSUIT_MODULE_FIREFIGHTER)
category_override += "Firefighter"
if(mech_types & EXOSUIT_MODULE_ODYSSEUS)
category_override += "Odysseus"
// if(mech_types & EXOSUIT_MODULE_CLARKE)
// category_override += "Clarke"
if(mech_types & EXOSUIT_MODULE_GYGAX_MED)
category_override += "Medical-Spec Gygax"
if(mech_types & EXOSUIT_MODULE_GYGAX)
category_override += "Gygax"
if(mech_types & EXOSUIT_MODULE_DURAND)
category_override += "Durand"
if(mech_types & EXOSUIT_MODULE_HONK)
category_override += "H.O.N.K"
if(mech_types & EXOSUIT_MODULE_PHAZON)
category_override += "Phazon"
var/list/part = list(
"name" = D.name,
"desc" = initial(built_item.desc),
"printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10,
"cost" = cost,
"id" = D.id,
"subCategory" = sub_category,
"categoryOverride" = category_override,
"searchMeta" = "UNKNOWN"//D.search_metadata
)
return part
/**
* Generates a list of resources / materials available to this Exosuit Fab
*
* Returns null if there is no material container available.
* List format is list(material_name = list(amount = ..., ref = ..., etc.))
*/
/obj/machinery/mecha_part_fabricator/proc/output_available_resources()
var/output
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
for(var/mat_id in materials.materials)
var/datum/material/M = mat_id
var/amount = materials.materials[mat_id]
output += "<span class=\"res_name\">[M.name]: </span>[amount] cm&sup3;"
if(amount >= MINERAL_MATERIAL_AMOUNT)
output += "<span style='font-size:80%;'>- Remove \[<a href='?src=[REF(src)];remove_mat=1;material=[REF(mat_id)]'>1</a>\]"
if(amount >= (MINERAL_MATERIAL_AMOUNT * 10))
output += " | \[<a href='?src=[REF(src)];remove_mat=10;material=[REF(M)]'>10</a>\]"
output += " | \[<a href='?src=[REF(src)];remove_mat=50;material=[REF(M)]'>All</a>\]</span>"
output += "<br/>"
return output
var/datum/component/material_container/materials = rmat.mat_container
var/list/material_data = list()
if(materials)
for(var/mat_id in materials.materials)
var/datum/material/M = mat_id
var/list/material_info = list()
var/amount = materials.materials[mat_id]
material_info = list(
"name" = M.name,
"ref" = REF(M),
"amount" = amount,
"sheets" = round(amount / MINERAL_MATERIAL_AMOUNT),
"removable" = amount >= MINERAL_MATERIAL_AMOUNT
)
material_data += list(material_info)
return material_data
return null
/**
* Intended to be called when an item starts printing.
*
* Adds the overlay to show the fab working and sets active power usage settings.
*/
/obj/machinery/mecha_part_fabricator/proc/on_start_printing()
add_overlay("fab-active")
use_power = ACTIVE_POWER_USE
/**
* Intended to be called when the exofab has stopped working and is no longer printing items.
*
* Removes the overlay to show the fab working and sets idle power usage settings. Additionally resets the description and turns off queue processing.
*/
/obj/machinery/mecha_part_fabricator/proc/on_finish_printing()
cut_overlay("fab-active")
use_power = IDLE_POWER_USE
desc = initial(desc)
process_queue = FALSE
/**
* Calculates resource/material costs for printing an item based on the machine's resource coefficient.
*
* Returns a list of k,v resources with their amounts.
* * D - Design datum to calculate the modified resource cost of.
*/
/obj/machinery/mecha_part_fabricator/proc/get_resources_w_coeff(datum/design/D)
var/list/resources = list()
for(var/R in D.materials)
@@ -164,294 +247,419 @@
resources[M] = get_resource_cost_w_coeff(D, M)
return resources
/**
* Checks if the Exofab has enough resources to print a given item.
*
* Returns FALSE if the design has no reagents used in its construction (?) or if there are insufficient resources.
* Returns TRUE if there are sufficient resources to print the item.
* * D - Design datum to calculate the modified resource cost of.
*/
/obj/machinery/mecha_part_fabricator/proc/check_resources(datum/design/D)
if(D.reagents_list.len) // No reagents storage - no reagent designs.
if(length(D.reagents_list)) // No reagents storage - no reagent designs.
return FALSE
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/datum/component/material_container/materials = rmat.mat_container
if(materials.has_materials(get_resources_w_coeff(D)))
return TRUE
return FALSE
/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D)
/**
* Attempts to build the next item in the build queue.
*
* Returns FALSE if either there are no more parts to build or the next part is not buildable.
* Returns TRUE if the next part has started building.
* * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build.
*/
/obj/machinery/mecha_part_fabricator/proc/build_next_in_queue(verbose = TRUE)
if(!length(queue))
return FALSE
var/datum/design/D = queue[1]
if(build_part(D, verbose))
remove_from_queue(1)
return TRUE
return FALSE
/**
* Starts the build process for a given design datum.
*
* Returns FALSE if the procedure fails. Returns TRUE when being_built is set.
* Uses materials.
* * D - Design datum to attempt to print.
* * verbose - Whether the machine should use say() procs. Set to FALSE to disable the machine saying reasons for failure to build.
*/
/obj/machinery/mecha_part_fabricator/proc/build_part(datum/design/D, verbose = TRUE)
if(!D)
return FALSE
var/datum/component/material_container/materials = rmat.mat_container
if (!materials)
if(verbose)
say("No access to material storage, please contact the quartermaster.")
return FALSE
if (rmat.on_hold())
if(verbose)
say("Mineral access is on hold, please contact the quartermaster.")
return FALSE
if(!check_resources(D))
if(verbose)
say("Not enough resources. Processing stopped.")
return FALSE
build_materials = get_resources_w_coeff(D)
materials.use_materials(build_materials)
being_built = D
desc = "It's building \a [initial(D.name)]."
var/list/res_coef = get_resources_w_coeff(D)
build_finish = world.time + get_construction_time_w_coeff(initial(D.construction_time))
build_start = world.time
desc = "It's building \a [D.name]."
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.use_materials(res_coef)
add_overlay("fab-active")
use_power = ACTIVE_POWER_USE
updateUsrDialog()
sleep(get_construction_time_w_coeff(D))
use_power = IDLE_POWER_USE
cut_overlay("fab-active")
desc = initial(desc)
rmat.silo_log(src, "built", -1, "[D.name]", build_materials)
var/location = get_step(src,(dir))
var/obj/item/I = new D.build_path(location)
I.set_custom_materials(res_coef)
say("\The [I] is complete.")
being_built = null
updateUsrDialog()
return TRUE
/obj/machinery/mecha_part_fabricator/proc/update_queue_on_page()
send_byjax(usr,"mecha_fabricator.browser","queue",list_queue())
return
/obj/machinery/mecha_part_fabricator/process()
// If there's a stored part to dispense due to an obstruction, try to dispense it.
if(stored_part)
var/turf/exit = get_step(src,(dir))
if(exit.density)
return TRUE
/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(set_name)
if(set_name in part_sets)
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(set_name in D.category)
add_to_queue(D)
say("Obstruction cleared. \The [stored_part] is complete.")
stored_part.forceMove(exit)
stored_part = null
/obj/machinery/mecha_part_fabricator/proc/add_to_queue(D)
// If there's nothing being built, try to build something
if(!being_built)
// If we're not processing the queue anymore or there's nothing to build, end processing.
if(!process_queue || !build_next_in_queue())
on_finish_printing()
STOP_PROCESSING(SSfastprocess, src)
//end_processing()
return TRUE
on_start_printing()
// If there's an item being built, check if it is complete.
if(being_built && (build_finish < world.time))
// Then attempt to dispense it and if appropriate build the next item.
dispense_built_part(being_built)
if(process_queue)
build_next_in_queue(FALSE)
return TRUE
/**
* Dispenses a part to the tile infront of the Exosuit Fab.
*
* Returns FALSE is the machine cannot dispense the part on the appropriate turf.
* Return TRUE if the part was successfully dispensed.
* * D - Design datum to attempt to dispense.
*/
/obj/machinery/mecha_part_fabricator/proc/dispense_built_part(datum/design/D)
var/obj/item/I = new D.build_path(src)
// I.material_flags |= MATERIAL_NO_EFFECTS //Find a better way to do this.
I.set_custom_materials(build_materials)
being_built = null
var/turf/exit = get_step(src,(dir))
if(exit.density)
say("Error! Part outlet is obstructed.")
desc = "It's trying to dispense \a [D.name], but the part outlet is obstructed."
stored_part = I
return FALSE
say("\The [I] is complete.")
I.forceMove(exit)
return TRUE
/**
* Adds a list of datum designs to the build queue.
*
* Will only add designs that are in this machine's stored techweb.
* Does final checks for datum IDs and makes sure this machine can build the designs.
* * part_list - List of datum design ids for designs to add to the queue.
*/
/obj/machinery/mecha_part_fabricator/proc/add_part_set_to_queue(list/part_list)
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if((D.build_type & MECHFAB) && (D.id in part_list))
add_to_queue(D)
/**
* Adds a datum design to the build queue.
*
* Returns TRUE if successful and FALSE if the design was not added to the queue.
* * D - Datum design to add to the queue.
*/
/obj/machinery/mecha_part_fabricator/proc/add_to_queue(datum/design/D)
if(!istype(queue))
queue = list()
if(D)
queue[++queue.len] = D
return queue.len
return TRUE
return FALSE
/**
* Removes datum design from the build queue based on index.
*
* Returns TRUE if successful and FALSE if a design was not removed from the queue.
* * index - Index in the build queue of the element to remove.
*/
/obj/machinery/mecha_part_fabricator/proc/remove_from_queue(index)
if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>queue.len))
if(!isnum(index) || !ISINTEGER(index) || !istype(queue) || (index<1 || index>length(queue)))
return FALSE
queue.Cut(index,++index)
return TRUE
/obj/machinery/mecha_part_fabricator/proc/process_queue()
var/datum/design/D = queue[1]
if(!D)
remove_from_queue(1)
if(queue.len)
return process_queue()
else
return
temp = null
while(D)
if(stat&(NOPOWER|BROKEN))
return FALSE
if(!check_clearance(D))
say("Security level not met. Queue processing stopped.")
temp = {"<span class='alert'>Security level not met to build next part.</span><br>
<a href='?src=[REF(src)];process_queue=1'>Try again</a> | <a href='?src=[REF(src)];clear_temp=1'>Return</a><a>"}
return FALSE
if(!check_resources(D))
say("Not enough resources. Queue processing stopped.")
temp = {"<span class='alert'>Not enough resources to build next part.</span><br>
<a href='?src=[REF(src)];process_queue=1'>Try again</a> | <a href='?src=[REF(src)];clear_temp=1'>Return</a><a>"}
return FALSE
remove_from_queue(1)
build_part(D)
D = listgetindex(queue, 1)
say("Queue processing finished successfully.")
/**
* Generates a list of parts formatted for tgui based on the current build queue.
*
* Returns a formatted list of lists containing formatted part information for every part in the build queue.
*/
/obj/machinery/mecha_part_fabricator/proc/list_queue()
var/output = "<b>Queue contains:</b>"
if(!istype(queue) || !queue.len)
output += "<br>Nothing"
else
output += "<ol>"
var/i = 0
for(var/datum/design/D in queue)
i++
var/obj/part = D.build_path
output += "<li[(!check_clearance(D) ||!check_resources(D))?" style='color: #f00;'":null]>"
output += initial(part.name) + " - "
output += "[i>1?"<a href='?src=[REF(src)];queue_move=-1;index=[i]' class='arrow'>&uarr;</a>":null] "
output += "[i<queue.len?"<a href='?src=[REF(src)];queue_move=+1;index=[i]' class='arrow'>&darr;</a>":null] "
output += "<a href='?src=[REF(src)];remove_from_queue=[i]'>Remove</a></li>"
if(!istype(queue) || !length(queue))
return null
output += "</ol>"
output += "\[<a href='?src=[REF(src)];process_queue=1'>Process queue</a> | <a href='?src=[REF(src)];clear_queue=1'>Clear queue</a>\]"
return output
var/list/queued_parts = list()
for(var/datum/design/D in queue)
var/list/part = output_part_info(D)
queued_parts += list(part)
return queued_parts
/**
* Syncs machine with R&D servers.
*
* Requires an R&D Console visible within 7 tiles. Copies techweb research. Updates tgui's state data.
*/
/obj/machinery/mecha_part_fabricator/proc/sync()
temp = "Updating local R&D database..."
updateUsrDialog()
sleep(30) //only sleep if called by user
for(var/obj/machinery/computer/rdconsole/RDC in oview(7,src))
for(var/obj/machinery/computer/rdconsole/RDC in orange(7,src))
RDC.stored_research.copy_research_to(stored_research)
temp = "Processed equipment designs.<br>"
//check if the tech coefficients have changed
temp += "<a href='?src=[REF(src)];clear_temp=1'>Return</a>"
updateUsrDialog()
update_static_data(usr)
say("Successfully synchronized with R&D server.")
return
temp = "Unable to connect to local R&D Database.<br>Please check your connections and try again.<br><a href='?src=[REF(src)];clear_temp=1'>Return</a>"
updateUsrDialog()
say("Unable to connect to local R&D server.")
return
/**
* Calculates the coefficient-modified resource cost of a single material component of a design's recipe.
*
* Returns coefficient-modified resource cost for the given material component.
* * D - Design datum to pull the resource cost from.
* * resource - Material datum reference to the resource to calculate the cost of.
* * roundto - Rounding value for round() proc
*/
/obj/machinery/mecha_part_fabricator/proc/get_resource_cost_w_coeff(datum/design/D, var/datum/material/resource, roundto = 1)
return round(D.materials[resource]*component_coeff, roundto)
/obj/machinery/mecha_part_fabricator/proc/get_construction_time_w_coeff(datum/design/D, roundto = 1) //aran
return round(initial(D.construction_time)*time_coeff, roundto)
/**
* Calculates the coefficient-modified build time of a design.
*
* Returns coefficient-modified build time of a given design.
* * D - Design datum to calculate the modified build time of.
* * roundto - Rounding value for round() proc
*/
/obj/machinery/mecha_part_fabricator/proc/get_construction_time_w_coeff(construction_time, roundto = 1) //aran
return round(construction_time*time_coeff, roundto)
/obj/machinery/mecha_part_fabricator/ui_interact(mob/user as mob)
. = ..()
var/dat, left_part
user.set_machine(src)
var/turf/exit = get_step(src,(dir))
if(exit.density)
say("Error! Part outlet is obstructed.")
return
if(temp)
left_part = temp
else if(being_built)
var/obj/I = being_built.build_path
left_part = {"<TT>Building [initial(I.name)].<BR>
Please wait until completion...</TT>"}
/obj/machinery/mecha_part_fabricator/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet/sheetmaterials)
)
/obj/machinery/mecha_part_fabricator/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ExosuitFabricator")
ui.open()
/obj/machinery/mecha_part_fabricator/ui_static_data(mob/user)
var/list/data = list()
var/list/final_sets = list()
var/list/buildable_parts = list()
for(var/part_set in part_sets)
final_sets += part_set
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
// This is for us.
var/list/part = output_part_info(D, TRUE)
if(part["category_override"])
for(var/cat in part["category_override"])
buildable_parts[cat] += list(part)
if(!(cat in part_sets))
final_sets += cat
continue
for(var/cat in part_sets)
// Find all matching categories.
if(!(cat in D.category))
continue
buildable_parts[cat] += list(part)
data["partSets"] = final_sets
data["buildableParts"] = buildable_parts
return data
/obj/machinery/mecha_part_fabricator/ui_data(mob/user)
var/list/data = list()
data["materials"] = output_available_resources()
if(being_built)
var/list/part = list(
"name" = being_built.name,
"duration" = build_finish - world.time,
"printTime" = get_construction_time_w_coeff(initial(being_built.construction_time))
)
data["buildingPart"] = part
else
switch(screen)
if("main")
left_part = output_available_resources()+"<hr>"
left_part += "<a href='?src=[REF(src)];sync=1'>Sync with R&D servers</a><hr>"
for(var/part_set in part_sets)
left_part += "<a href='?src=[REF(src)];part_set=[part_set]'>[part_set]</a> - \[<a href='?src=[REF(src)];partset_to_queue=[part_set]'>Add all parts to queue</a>\]<br>"
if("parts")
left_part += output_parts_list(part_set)
left_part += "<hr><a href='?src=[REF(src)];screen=main'>Return</a>"
dat = {"<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<title>[name] data</title>
<style>
.res_name {font-weight: bold; text-transform: capitalize;}
.red {color: #f00;}
.part {margin-bottom: 10px;}
.arrow {text-decoration: none; font-size: 10px;}
body, table {height: 100%;}
td {vertical-align: top; padding: 5px;}
html, body {padding: 0px; margin: 0px;}
h1 {font-size: 18px; margin: 5px 0px;}
</style>
<script language='javascript' type='text/javascript'>
[js_byjax]
</script>
</head><body>
<body>
<table style='width: 100%;'>
<tr>
<td style='width: 65%; padding-right: 10px;'>
[left_part]
</td>
<td style='width: 35%; background: #ccc;' id='queue'>
[list_queue()]
</td>
<tr>
</table>
</body>
</html>"}
user << browse(dat, "window=mecha_fabricator;size=1000x430")
onclose(user, "mecha_fabricator")
return
data["buildingPart"] = null
/obj/machinery/mecha_part_fabricator/Topic(href, href_list)
data["queue"] = list_queue()
if(stored_part)
data["storedPart"] = stored_part.name
else
data["storedPart"] = null
data["isProcessingQueue"] = process_queue
return data
/obj/machinery/mecha_part_fabricator/ui_act(action, var/list/params)
if(..())
return
if(href_list["part_set"])
var/tpart_set = href_list["part_set"]
if(tpart_set)
if(tpart_set=="clear")
part_set = null
else
part_set = tpart_set
screen = "parts"
if(href_list["part"])
var/T = href_list["part"]
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(D.id == T)
if(!processing_queue)
build_part(D)
else
add_to_queue(D)
break
if(href_list["add_to_queue"])
var/T = href_list["add_to_queue"]
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(D.id == T)
return TRUE
. = TRUE
add_fingerprint(usr)
usr.set_machine(src)
switch(action)
if("sync_rnd")
// Sync with R&D Servers
sync()
return
if("add_queue_set")
// Add all parts of a set to queue
var/part_list = params["part_list"]
add_part_set_to_queue(part_list)
return
if("add_queue_part")
// Add a specific part to queue
var/T = params["id"]
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if((D.build_type & MECHFAB) && (D.id == T))
add_to_queue(D)
break
return update_queue_on_page()
if(href_list["remove_from_queue"])
remove_from_queue(text2num(href_list["remove_from_queue"]))
return update_queue_on_page()
if(href_list["partset_to_queue"])
add_part_set_to_queue(href_list["partset_to_queue"])
return update_queue_on_page()
if(href_list["process_queue"])
spawn(0)
if(processing_queue || being_built)
return FALSE
processing_queue = 1
process_queue()
processing_queue = 0
if(href_list["clear_temp"])
temp = null
if(href_list["screen"])
screen = href_list["screen"]
if(href_list["queue_move"] && href_list["index"])
var/index = text2num(href_list["index"])
var/new_index = index + text2num(href_list["queue_move"])
if(isnum(index) && isnum(new_index) && ISINTEGER(index) && ISINTEGER(new_index))
if(ISINRANGE(new_index,1,queue.len))
queue.Swap(index,new_index)
return update_queue_on_page()
if(href_list["clear_queue"])
queue = list()
return update_queue_on_page()
if(href_list["sync"])
sync()
if(href_list["part_desc"])
var/T = href_list["part_desc"]
for(var/v in stored_research.researched_designs)
var/datum/design/D = SSresearch.techweb_design_by_id(v)
if(D.build_type & MECHFAB)
if(D.id == T)
var/obj/part = D.build_path
temp = {"<h1>[initial(part.name)] description:</h1>
[initial(part.desc)]<br>
<a href='?src=[REF(src)];clear_temp=1'>Return</a>
"}
break
return
if("del_queue_part")
// Delete a specific from from the queue
var/index = text2num(params["index"])
remove_from_queue(index)
return
if("clear_queue")
// Delete everything from queue
queue.Cut()
return
if("build_queue")
// Build everything in queue
if(process_queue)
return
process_queue = TRUE
if(href_list["remove_mat"] && href_list["material"])
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/datum/material/Mat = locate(href_list["material"])
materials.retrieve_sheets(text2num(href_list["remove_mat"]), Mat)
if(!being_built)
START_PROCESSING(SSfastprocess, src)
//begin_processing()
return
if("stop_queue")
// Pause queue building. Also known as stop.
process_queue = FALSE
return
if("build_part")
// Build a single part
if(being_built || process_queue)
return
updateUsrDialog()
return
var/id = params["id"]
var/datum/design/D = SSresearch.techweb_design_by_id(id)
/obj/machinery/mecha_part_fabricator/on_deconstruction()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.retrieve_all()
..()
if(!(D.build_type & MECHFAB) || !(D.id == id))
return
if(build_part(D))
on_start_printing()
START_PROCESSING(SSfastprocess, src)
//begin_processing() teege has this as a helper proc. please port it!
return
if("move_queue_part")
// Moves a part up or down in the queue.
var/index = text2num(params["index"])
var/new_index = index + text2num(params["newindex"])
if(isnum(index) && isnum(new_index) && ISINTEGER(index) && ISINTEGER(new_index))
if(ISINRANGE(new_index,1,length(queue)))
queue.Swap(index,new_index)
return
if("remove_mat")
// Remove a material from the fab
var/mat_ref = params["ref"]
var/amount = text2num(params["amount"])
var/datum/material/mat = locate(mat_ref)
eject_sheets(mat, amount)
return
return FALSE
/**
* Eject material sheets.
*
* Returns the number of sheets successfully ejected.
* eject_sheet - Byond REF of the material to eject.
* eject_amt - Number of sheets to attempt to eject.
*/
/obj/machinery/mecha_part_fabricator/proc/eject_sheets(eject_sheet, eject_amt)
var/datum/component/material_container/mat_container = rmat.mat_container
if (!mat_container)
say("No access to material storage, please contact the quartermaster.")
return 0
if (rmat.on_hold())
say("Mineral access is on hold, please contact the quartermaster.")
return 0
var/count = mat_container.retrieve_sheets(text2num(eject_amt), eject_sheet, drop_location())
var/list/matlist = list()
matlist[eject_sheet] = text2num(eject_amt)
rmat.silo_log(src, "ejected", -count, "sheets", matlist)
return count
/obj/machinery/mecha_part_fabricator/proc/AfterMaterialInsert(item_inserted, id_inserted, amount_inserted)
var/datum/material/M = id_inserted
add_overlay("fab-load-[M.name]")
addtimer(CALLBACK(src, /atom/proc/cut_overlay, "fab-load-[M.name]"), 10)
updateUsrDialog()
/obj/machinery/mecha_part_fabricator/attackby(obj/item/W, mob/user, params)
if(default_deconstruction_screwdriver(user, "fab-o", "fab-idle", W))
/obj/machinery/mecha_part_fabricator/screwdriver_act(mob/living/user, obj/item/I)
if(..())
return TRUE
if(being_built)
to_chat(user, "<span class='warning'>\The [src] is currently processing! Please wait until completion.</span>")
return FALSE
return default_deconstruction_screwdriver(user, "fab-o", "fab-idle", I)
if(default_deconstruction_crowbar(W))
/obj/machinery/mecha_part_fabricator/crowbar_act(mob/living/user, obj/item/I)
if(..())
return TRUE
return ..()
if(being_built)
to_chat(user, "<span class='warning'>\The [src] is currently processing! Please wait until completion.</span>")
return FALSE
return default_deconstruction_crowbar(I)
/obj/machinery/mecha_part_fabricator/proc/is_insertion_ready(mob/user)
if(panel_open)
@@ -463,6 +671,9 @@
return TRUE
/obj/machinery/mecha_part_fabricator/maint
link_on_init = FALSE
/obj/machinery/mecha_part_fabricator/offstation
offstation_security_levels = FALSE
link_on_init = FALSE
circuit = /obj/item/circuitboard/machine/mechfab/offstation
+3
View File
@@ -153,6 +153,9 @@
/obj/mecha/get_cell()
return cell
/obj/mecha/rust_heretic_act()
take_damage(500, BRUTE)
/obj/mecha/Destroy()
go_out()
var/mob/living/silicon/ai/AI
+3 -6
View File
@@ -5,14 +5,11 @@
icon_keyboard = "tech_key"
req_access = list(ACCESS_ROBOTICS)
circuit = /obj/item/circuitboard/computer/mecha_control
ui_x = 500
ui_y = 500
/obj/machinery/computer/mecha/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/machinery/computer/mecha/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "ExosuitControlConsole", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "ExosuitControlConsole", name)
ui.open()
/obj/machinery/computer/mecha/ui_data(mob/user)
+4 -6
View File
@@ -1,12 +1,10 @@
/obj/mecha/proc/get_armour_facing(relative_dir)
switch(relative_dir)
if(0) // BACKSTAB!
if(180) // BACKSTAB!
return facing_modifiers[BACK_ARMOUR]
if(45, 90, 270, 315)
return facing_modifiers[SIDE_ARMOUR]
if(225, 180, 135)
if(0, 45) // direct or 45 degrees off
return facing_modifiers[FRONT_ARMOUR]
return 1 //always return non-0
return facing_modifiers[SIDE_ARMOUR] //if its not a front hit or back hit then assume its from the side
/obj/mecha/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
. = ..()
@@ -43,7 +41,7 @@
break
if(attack_dir)
var/facing_modifier = get_armour_facing(dir2angle(attack_dir) - dir2angle(src))
var/facing_modifier = get_armour_facing(abs(dir2angle(dir) - dir2angle(attack_dir)))
booster_damage_modifier /= facing_modifier
booster_deflection_modifier *= facing_modifier
if(prob(deflect_chance * booster_deflection_modifier))
+56 -34
View File
@@ -8,7 +8,7 @@
anchored = TRUE
light_range = 3
var/movechance = 70
var/obj/item/assembly/signaler/anomaly/aSignal
var/obj/item/assembly/signaler/anomaly/aSignal = /obj/item/assembly/signaler/anomaly
var/area/impact_area
var/lifespan = 990
@@ -17,14 +17,20 @@
var/countdown_colour
var/obj/effect/countdown/anomaly/countdown
/obj/effect/anomaly/Initialize(mapload, new_lifespan)
/// chance we drop a core when neutralized
var/core_drop_chance = 100
/obj/effect/anomaly/Initialize(mapload, new_lifespan, core_drop_chance = 100)
. = ..()
GLOB.poi_list |= src
START_PROCESSING(SSobj, src)
impact_area = get_area(src)
src.core_drop_chance = core_drop_chance
aSignal = new(src)
aSignal.name = "[name] core"
if (!impact_area)
return INITIALIZE_HINT_QDEL
aSignal = new aSignal(src)
aSignal.code = rand(1,100)
aSignal.anomaly_type = type
@@ -52,6 +58,8 @@
GLOB.poi_list.Remove(src)
STOP_PROCESSING(SSobj, src)
qdel(countdown)
if(aSignal)
QDEL_NULL(aSignal)
return ..()
/obj/effect/anomaly/proc/anomalyEffect()
@@ -68,14 +76,14 @@
/obj/effect/anomaly/proc/anomalyNeutralize()
new /obj/effect/particle_effect/smoke/bad(loc)
for(var/atom/movable/O in src)
O.forceMove(drop_location())
if(prob(core_drop_chance))
aSignal.forceMove(drop_location())
aSignal = null
qdel(src)
/obj/effect/anomaly/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/analyzer))
if(I.tool_behaviour == TOOL_ANALYZER) //revert if runtimed
to_chat(user, "<span class='notice'>Analyzing... [src]'s unstable field is fluctuating along frequency [format_frequency(aSignal.frequency)], code [aSignal.code].</span>")
///////////////////////
@@ -85,6 +93,7 @@
icon_state = "shield2"
density = FALSE
var/boing = 0
aSignal = /obj/item/assembly/signaler/anomaly/grav
/obj/effect/anomaly/grav/anomalyEffect()
..()
@@ -95,17 +104,23 @@
for(var/mob/living/M in range(0, src))
gravShock(M)
for(var/mob/living/M in orange(4, src))
step_towards(M,src)
if(!M.mob_negates_gravity()) //delete when runtimed
step_towards(M,src)
for(var/obj/O in range(0,src))
if(!O.anchored)
//if(isturf(O.loc))
// var/turf/T = O.loc
// if(T.intact && HAS_TRAIT(O, TRAIT_T_RAY_VISIBLE))
// continue
var/mob/living/target = locate() in view(4,src)
if(target && !target.stat)
O.throw_at(target, 5, 10)
/obj/effect/anomaly/grav/Crossed(mob/A)
gravShock(A)
/obj/effect/anomaly/grav/Crossed(atom/movable/AM)
. = ..()
gravShock(AM)
/obj/effect/anomaly/grav/Bump(mob/A)
/obj/effect/anomaly/grav/Bump(atom/A)
gravShock(A)
/obj/effect/anomaly/grav/Bumped(atom/movable/AM)
@@ -138,6 +153,7 @@
name = "flux wave anomaly"
icon_state = "electricity2"
density = TRUE
aSignal = /obj/item/assembly/signaler/anomaly/flux
var/canshock = FALSE
var/shockdamage = 20
var/explosive = TRUE
@@ -148,11 +164,12 @@
for(var/mob/living/M in range(0, src))
mobShock(M)
/obj/effect/anomaly/flux/Crossed(mob/living/M)
mobShock(M)
/obj/effect/anomaly/flux/Crossed(atom/movable/AM)
. = ..()
mobShock(AM)
/obj/effect/anomaly/flux/Bump(mob/living/M)
mobShock(M)
/obj/effect/anomaly/flux/Bump(atom/A)
mobShock(A)
/obj/effect/anomaly/flux/Bumped(atom/movable/AM)
mobShock(AM)
@@ -160,7 +177,7 @@
/obj/effect/anomaly/flux/proc/mobShock(mob/living/M)
if(canshock && istype(M))
canshock = FALSE //Just so you don't instakill yourself if you slam into the anomaly five times in a second.
M.electrocute_act(shockdamage, "[name]", flags = SHOCK_NOGLOVES)
M.electrocute_act(shockdamage, name, flags = SHOCK_NOGLOVES)
/obj/effect/anomaly/flux/detonate()
if(explosive)
@@ -176,6 +193,7 @@
icon = 'icons/obj/projectiles.dmi'
icon_state = "bluespace"
density = TRUE
aSignal = /obj/item/assembly/signaler/anomaly/bluespace
/obj/effect/anomaly/bluespace/anomalyEffect()
..()
@@ -187,7 +205,7 @@
do_teleport(AM, locate(AM.x, AM.y, AM.z), 8, channel = TELEPORT_CHANNEL_BLUESPACE)
/obj/effect/anomaly/bluespace/detonate()
var/turf/T = safepick(get_area_turfs(impact_area))
var/turf/T = pick(get_area_turfs(impact_area))
if(T)
// Calculate new position (searches through beacons in world)
var/obj/item/beacon/chosen
@@ -224,21 +242,23 @@
if(!A.Move(newloc) && newloc) // if the atom, for some reason, can't move, FORCE them to move! :) We try Move() first to invoke any movement-related checks the atom needs to perform after moving
A.forceMove(newloc)
spawn()
if(ismob(A) && !(A in flashers)) // don't flash if we're already doing an effect
var/mob/M = A
if(M.client)
var/obj/blueeffect = new /obj(src)
blueeffect.screen_loc = "WEST,SOUTH to EAST,NORTH"
blueeffect.icon = 'icons/effects/effects.dmi'
blueeffect.icon_state = "shieldsparkles"
blueeffect.layer = FLASH_LAYER
blueeffect.plane = FULLSCREEN_PLANE
blueeffect.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
M.client.screen += blueeffect
sleep(20)
M.client.screen -= blueeffect
qdel(blueeffect)
if(ismob(A) && !(A in flashers)) // don't flash if we're already doing an effect
var/mob/M = A
if(M.client)
INVOKE_ASYNC(src, .proc/blue_effect, M)
/obj/effect/anomaly/bluespace/proc/blue_effect(mob/M)
var/obj/blueeffect = new /obj(src)
blueeffect.screen_loc = "WEST,SOUTH to EAST,NORTH"
blueeffect.icon = 'icons/effects/effects.dmi'
blueeffect.icon_state = "shieldsparkles"
blueeffect.layer = FLASH_LAYER
blueeffect.plane = FULLSCREEN_PLANE
blueeffect.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
M.client.screen += blueeffect
sleep(20)
M.client.screen -= blueeffect
qdel(blueeffect)
/////////////////////
@@ -246,6 +266,7 @@
name = "pyroclastic anomaly"
icon_state = "mustard"
var/ticks = 0
aSignal = /obj/item/assembly/signaler/anomaly/pyro
/obj/effect/anomaly/pyro/anomalyEffect()
..()
@@ -270,7 +291,7 @@
S.rabid = TRUE
S.amount_grown = SLIME_EVOLUTION_THRESHOLD
S.Evolve()
offer_control(S)
offer_control(S,POLL_IGNORE_SENTIENCE_POTION)
/////////////////////
@@ -278,6 +299,7 @@
name = "vortex anomaly"
icon_state = "bhole3"
desc = "That's a nice station you have there. It'd be a shame if something happened to it."
aSignal = /obj/item/assembly/signaler/anomaly/vortex
/obj/effect/anomaly/bhole/anomalyEffect()
..()
+2 -1
View File
@@ -46,4 +46,5 @@
var/turf/T = loc
if(!istype(T)) //you know this will happen somehow
CRASH("Turf decal initialized in an object/nullspace")
T.AddElement(/datum/element/decal, icon, icon_state, turn(dir, -dir2angle(T.dir)), CLEAN_GOD, color, null, null, alpha)
var/turn_dir = 180 - dir2angle(T.dir) //Turning a dir by 0 results in a roulette of random dirs.
T.AddElement(/datum/element/decal, icon, icon_state, turn_dir ? turn(dir, turn_dir) : dir, CLEAN_GOD, color, null, null, alpha)
@@ -63,3 +63,23 @@
/datum/effect_system/lightning_spread
effect_type = /obj/effect/particle_effect/sparks/electricity
//fake sparks, not subtyped because we don't want light/heat, nor checks inside an often used proc for a rare subcase for saving like 10 lines of code
/obj/effect/particle_effect/fake_sparks
name = "lightning"
icon_state = "electricity"
/obj/effect/particle_effect/fake_sparks/Initialize()
. = ..()
flick(icon_state, src) // replay the animation
playsound(src, "sparks", 100, TRUE)
QDEL_IN(src, 20)
/datum/effect_system/fake_spark_spread
effect_type = /obj/effect/particle_effect/fake_sparks
/proc/do_fake_sparks(n, c, source)
var/datum/effect_system/fake_spark_spread/sparks = new
sparks.set_up(n, c, source)
sparks.autocleanup = TRUE
sparks.start()
+9 -13
View File
@@ -1,10 +1,10 @@
/proc/create_portal_pair(turf/source, turf/destination, _creator = null, _lifespan = 300, accuracy = 0, newtype = /obj/effect/portal, atmos_link_override)
/proc/create_portal_pair(turf/source, turf/destination, _lifespan = 300, accuracy = 0, newtype = /obj/effect/portal, atmos_link_override)
if(!istype(source) || !istype(destination))
return
var/turf/actual_destination = get_teleport_turf(destination, accuracy)
var/obj/effect/portal/P1 = new newtype(source, _creator, _lifespan, null, FALSE, null, atmos_link_override)
var/obj/effect/portal/P2 = new newtype(actual_destination, _creator, _lifespan, P1, TRUE, null, atmos_link_override)
var/obj/effect/portal/P1 = new newtype(source, _lifespan, null, FALSE, null, atmos_link_override)
var/obj/effect/portal/P2 = new newtype(actual_destination, _lifespan, P1, TRUE, null, atmos_link_override)
if(!istype(P1)||!istype(P2))
return
P1.link_portal(P2)
@@ -21,7 +21,6 @@
var/obj/effect/portal/linked
var/hardlinked = TRUE //Requires a linked portal at all times. Destroy if there's no linked portal, if there is destroy it when this one is deleted.
var/teleport_channel = TELEPORT_CHANNEL_BLUESPACE
var/creator
var/turf/hard_target //For when a portal needs a hard target and isn't to be linked.
var/atmos_link = FALSE //Link source/destination atmos.
var/turf/open/atmos_source //Atmos link source
@@ -35,6 +34,7 @@
name = "wormhole"
icon = 'icons/obj/objects.dmi'
icon_state = "anom"
layer = RIPPLE_LAYER
mech_sized = TRUE
teleport_channel = TELEPORT_CHANNEL_WORMHOLE
@@ -49,7 +49,9 @@
user.forceMove(get_turf(src))
return TRUE
/obj/effect/portal/Crossed(atom/movable/AM, oldloc)
/obj/effect/portal/Crossed(atom/movable/AM, oldloc, force_stop = 0)
if(force_stop)
return ..()
if(isobserver(AM))
return ..()
if(linked && (get_turf(oldloc) == get_turf(linked)))
@@ -66,7 +68,7 @@
if(Adjacent(user))
user.forceMove(get_turf(src))
/obj/effect/portal/Initialize(mapload, _creator, _lifespan = 0, obj/effect/portal/_linked, automatic_link = FALSE, turf/hard_target_override, atmos_link_override)
/obj/effect/portal/Initialize(mapload, _lifespan = 0, obj/effect/portal/_linked, automatic_link = FALSE, turf/hard_target_override, atmos_link_override)
. = ..()
GLOB.portals += src
if(!istype(_linked) && automatic_link)
@@ -78,7 +80,6 @@
atmos_link = atmos_link_override
link_portal(_linked)
hardlinked = automatic_link
creator = _creator
if(isturf(hard_target_override))
hard_target = hard_target_override
@@ -129,10 +130,7 @@
LAZYREMOVE(atmos_destination.atmos_adjacent_turfs, atmos_source)
atmos_destination = null
/obj/effect/portal/Destroy() //Calls on_portal_destroy(destroyed portal, location of destroyed portal) on creator if creator has such call.
if(creator && hascall(creator, "on_portal_destroy"))
call(creator, "on_portal_destroy")(src, src.loc)
creator = null
/obj/effect/portal/Destroy()
GLOB.portals -= src
unlink_atmos()
if(hardlinked && !QDELETED(linked))
@@ -153,8 +151,6 @@
return FALSE
if(!force && (!ismecha(M) && !istype(M, /obj/item/projectile) && M.anchored && !allow_anchored))
return
if(ismegafauna(M))
message_admins("[M] has used a portal at [ADMIN_VERBOSEJMP(src)] made by [usr].")
var/no_effect = FALSE
if(last_effect == world.time)
no_effect = TRUE
@@ -168,3 +168,26 @@
items = list(
/obj/item/clothing/mask/gas/sexymime,
/obj/item/clothing/under/rank/civilian/mime/sexy)
/obj/effect/spawner/bundle/crate/Initialize(mapload)
if(items && items.len)
var/turf/T = get_turf(src)
var/obj/structure/closet/LC = locate(/obj/structure/closet) in T
if(LC)
for(var/path in items)
new path(LC)
return INITIALIZE_HINT_QDEL
/obj/effect/spawner/bundle/crate/mosin
name = "Mosin-Nagant spawner"
items = list(
/obj/item/gun/ballistic/shotgun/boltaction,
/obj/item/ammo_box/a762
)
/obj/effect/spawner/bundle/crate/surplusrifle
name = "surplus rifle spawner"
items = list(
/obj/item/gun/ballistic/automatic/surplus,
/obj/item/ammo_box/magazine/m10mm/rifle
)
@@ -380,8 +380,6 @@
name = "random keg spawner"
lootcount = 1
loot = list(/obj/structure/reagent_dispensers/keg/mead = 5,
/obj/structure/reagent_dispensers/keg/aphro = 2,
/obj/structure/reagent_dispensers/keg/aphro/strong = 2,
/obj/structure/reagent_dispensers/keg/gargle = 1)
/obj/effect/spawner/lootdrop/coin
@@ -139,6 +139,23 @@
/obj/effect/temp_visual/dir_setting/curse/hand
icon_state = "cursehand"
/obj/effect/temp_visual/bsa_splash
name = "\improper Bluespace energy wave"
desc = "A massive, rippling wave of bluepace energy, all rapidly exhausting itself the moment it leaves the concentrated beam of light."
icon = 'icons/effects/beam_splash.dmi'
icon_state = "beam_splash_l"
layer = ABOVE_ALL_MOB_LAYER
pixel_y = -16
duration = 50
/obj/effect/temp_visual/bsa_splash/Initialize(mapload, dir)
. = ..()
switch(dir)
if(WEST)
icon_state = "beam_splash_w"
if(EAST)
icon_state = "beam_splash_e"
/obj/effect/temp_visual/wizard
name = "water"
icon = 'icons/mob/mob.dmi'
+5 -5
View File
@@ -103,12 +103,12 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
var/list/embedding = NONE
var/list/embedding
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
var/heat = 0
///All items with sharpness of IS_SHARP or higher will automatically get the butchering component.
var/sharpness = IS_BLUNT
///All items with sharpness of SHARP_EDGED or higher will automatically get the butchering component.
var/sharpness = SHARP_NONE
var/tool_behaviour = NONE
var/toolspeed = 1
@@ -206,7 +206,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
if(GLOB.rpg_loot_items)
AddComponent(/datum/component/fantasy)
if(sharpness) //give sharp objects butchering functionality, for consistency
if(sharpness && force > 5) //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)
@@ -1088,7 +1088,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
/obj/item/proc/updateEmbedding()
if(!islist(embedding) || !LAZYLEN(embedding))
if(!LAZYLEN(embedding))
return
AddElement(/datum/element/embed,\
+84 -8
View File
@@ -135,6 +135,14 @@ RLD
flick("[icon_state]_empty", src) //somewhat hacky thing to make RCDs with ammo counters actually have a blinking yellow light
return .
/obj/item/construction/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
if(user.incapacitated() || !user.Adjacent(src))
return FALSE
return TRUE
/obj/item/construction/proc/range_check(atom/A, mob/user)
if(!(A in range(custom_range, get_turf(user))))
to_chat(user, "<span class='warning'>The \'Out of Range\' light on [src] blinks red.</span>")
@@ -234,7 +242,6 @@ RLD
var/datum/browser/popup = new(user, "rcd_access", "Access Control", 900, 500, src)
popup.set_content(t1)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/item/construction/rcd/Topic(href, href_list)
@@ -276,13 +283,6 @@ RLD
//Not scaling these down to button size because they look horrible then, instead just bumping up radius.
return MA
/obj/item/construction/rcd/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
if(user.incapacitated() || !user.Adjacent(src))
return FALSE
return TRUE
/obj/item/construction/rcd/proc/change_computer_dir(mob/user)
if(!user)
return
@@ -856,6 +856,82 @@ RLD
desc = "It contains the design for firelock, air alarm, fire alarm, apc circuits and crap power cells."
upgrade = RCD_UPGRADE_SIMPLE_CIRCUITS
/obj/item/construction/plumbing
name = "Plumbing Constructor"
desc = "An expertly modified RCD outfitted to construct plumbing machinery. Reload with compressed matter cartridges."
icon = 'icons/obj/tools.dmi'
icon_state = "arcd"
item_state = "oldrcd"
has_ammobar = FALSE
matter = 200
max_matter = 200
///type of the plumbing machine
var/blueprint = null
///index, used in the attack self to get the type. stored here since it doesnt change
var/list/choices = list()
///index, used in the attack self to get the type. stored here since it doesnt change
var/list/name_to_type = list()
///
var/list/machinery_data = list("cost" = list(), "delay" = list())
/obj/item/construction/plumbing/attack_self(mob/user)
..()
if(!choices.len)
for(var/A in subtypesof(/obj/machinery/plumbing))
var/obj/machinery/plumbing/M = A
if(initial(M.rcd_constructable))
choices += list(initial(M.name) = image(icon = initial(M.icon), icon_state = initial(M.icon_state)))
name_to_type[initial(M.name)] = M
machinery_data["cost"][A] = initial(M.rcd_cost)
machinery_data["delay"][A] = initial(M.rcd_delay)
var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE)
if(!check_menu(user))
return
blueprint = name_to_type[choice]
playsound(src, 'sound/effects/pop.ogg', 50, FALSE)
to_chat(user, "<span class='notice'>You change [name]s blueprint to '[choice]'.</span>")
///pretty much rcd_create, but named differently to make myself feel less bad for copypasting from a sibling-type
/obj/item/construction/plumbing/proc/create_machine(atom/A, mob/user)
if(!machinery_data || !isopenturf(A))
return FALSE
if(checkResource(machinery_data["cost"][blueprint], user) && blueprint)
if(do_after(user, machinery_data["delay"][blueprint], target = A))
if(checkResource(machinery_data["cost"][blueprint], user) && canPlace(A))
useResource(machinery_data["cost"][blueprint], user)
activate()
playsound(src.loc, 'sound/machines/click.ogg', 50, TRUE)
new blueprint (A, FALSE, FALSE)
return TRUE
/obj/item/construction/plumbing/proc/canPlace(turf/T)
if(!isopenturf(T))
return FALSE
. = TRUE
for(var/obj/O in T.contents)
if(O.density) //let's not built ontop of dense stuff, like big machines and other obstacles, it kills my immershion
return FALSE
/obj/item/construction/plumbing/afterattack(atom/A, mob/user)
. = ..()
if(!range_check(A, user))
return
if(istype(A, /obj/machinery/plumbing))
var/obj/machinery/plumbing/P = A
if(P.anchored)
to_chat(user, "<span class='warning'>The [P.name] needs to be unanchored!</span>")
return
if(do_after(user, 20, target = P))
P.deconstruct() //Let's not substract matter
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) //this is just such a great sound effect
else
create_machine(A, user)
#undef GLOW_MODE
#undef LIGHT_MODE
#undef REMOVE_MODE
+84 -17
View File
@@ -6,6 +6,7 @@ RPD
#define ATMOS_CATEGORY 0
#define DISPOSALS_CATEGORY 1
#define TRANSIT_CATEGORY 2
#define PLUMBING_CATEGORY 3
#define BUILD_MODE (1<<0)
#define WRENCH_MODE (1<<1)
@@ -75,6 +76,13 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
)
))
GLOBAL_LIST_INIT(fluid_duct_recipes, list(
"Fluid Ducts" = list(
new /datum/pipe_info/plumbing("Duct", /obj/machinery/duct, PIPE_ONEDIR),
new /datum/pipe_info/plumbing/multilayer("Duct Layer-Manifold",/obj/machinery/duct/multilayered, PIPE_STRAIGHT)
)
))
/datum/pipe_info
var/name
var/icon_state
@@ -175,6 +183,15 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
if(dt == PIPE_UNARY_FLIPPABLE)
icon_state = "[icon_state]_preview"
/datum/pipe_info/plumbing/New(label, obj/path, dt=PIPE_UNARY)
name = label
id = path
icon_state = initial(path.icon_state)
dirtype = dt
/datum/pipe_info/plumbing/multilayer //exists as identifier so we can see the difference between multi_layer and just ducts properly later on
/obj/item/pipe_dispenser
name = "Rapid Piping Device (RPD)"
desc = "A device used to rapidly pipe things."
@@ -200,15 +217,19 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
var/atmos_build_speed = 5 //deciseconds (500ms)
var/disposal_build_speed = 5
var/transit_build_speed = 5
var/plumbing_build_speed = 5
var/destroy_speed = 5
var/paint_speed = 5
var/category = ATMOS_CATEGORY
var/piping_layer = PIPING_LAYER_DEFAULT
var/ducting_layer = DUCT_LAYER_DEFAULT
var/datum/pipe_info/recipe
var/static/datum/pipe_info/first_atmos
var/static/datum/pipe_info/first_disposal
var/static/datum/pipe_info/first_transit
var/mode = BUILD_MODE | DESTROY_MODE | WRENCH_MODE
var/static/datum/pipe_info/first_plumbing
var/locked = FALSE //wheter we can change categories. Useful for the plumber
/obj/item/pipe_dispenser/New()
. = ..()
@@ -238,29 +259,30 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
playsound(get_turf(user), 'sound/items/deconstruct.ogg', 50, 1)
return(BRUTELOSS)
/obj/item/pipe_dispenser/ui_base_html(html)
var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/pipes)
. = replacetext(html, "<!--customheadhtml-->", assets.css_tag())
/obj/item/pipe_dispenser/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet/pipes),
)
/obj/item/pipe_dispenser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/pipe_dispenser/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/pipes)
assets.send(user)
ui = new(user, src, ui_key, "RapidPipeDispenser", name, 425, 515, master_ui, state)
ui = new(user, src, "RapidPipeDispenser", name)
ui.open()
/obj/item/pipe_dispenser/ui_data(mob/user)
var/list/data = list(
"category" = category,
"piping_layer" = piping_layer,
"ducting_layer" = ducting_layer,
"preview_rows" = recipe.get_preview(p_dir),
"categories" = list(),
"selected_color" = paint_color,
"paint_colors" = GLOB.pipe_paint_colors,
"mode" = mode
"mode" = mode,
"locked" = locked
)
var/list/recipes
@@ -271,6 +293,8 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
recipes = GLOB.disposal_pipe_recipes
if(TRANSIT_CATEGORY)
recipes = GLOB.transit_tube_recipes
if(PLUMBING_CATEGORY)
recipes = GLOB.fluid_duct_recipes
for(var/c in recipes)
var/list/cat = recipes[c]
var/list/r = list()
@@ -284,7 +308,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
/obj/item/pipe_dispenser/ui_act(action, params)
if(..())
return
if(!usr.canUseTopic(src))
if(!usr.canUseTopic(src, BE_CLOSE))
return
var/playeffect = TRUE
switch(action)
@@ -299,11 +323,16 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
recipe = first_atmos
if(TRANSIT_CATEGORY)
recipe = first_transit
if(PLUMBING_CATEGORY)
recipe = first_plumbing
p_dir = NORTH
playeffect = FALSE
if("piping_layer")
piping_layer = text2num(params["piping_layer"])
playeffect = FALSE
// if("ducting_layer")
// ducting_layer = text2num(params["ducting_layer"])
// playeffect = FALSE
if("pipe_type")
var/static/list/recipes
if(!recipes)
@@ -320,11 +349,9 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
mode &= ~n
else
mode |= n
if(playeffect && world.time >= effectcooldown)
if(playeffect)
spark_system.start()
effectcooldown = world.time + 100
playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0)
playsound(get_turf(src), 'sound/effects/pop.ogg', 50, FALSE)
return TRUE
/obj/item/pipe_dispenser/pre_attack(atom/A, mob/user)
@@ -469,16 +496,56 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
if(mode & WRENCH_MODE)
tube.wrench_act(user, src)
return
if(PLUMBING_CATEGORY) //Plumbing.
if(!can_make_pipe)
return ..()
A = get_turf(A)
if(isclosedturf(A))
to_chat(user, "<span class='warning'>[src]'s error light flickers; there's something in the way!</span>")
return
to_chat(user, "<span class='notice'>You start building a fluid duct...</span>")
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
if(do_after(user, plumbing_build_speed, target = A))
var/obj/machinery/duct/D
if(recipe.type == /datum/pipe_info/plumbing/multilayer)
var/temp_connects = NORTH + SOUTH
if(queued_p_dir == EAST)
temp_connects = EAST + WEST
D = new queued_p_type (A, TRUE, GLOB.pipe_paint_colors[paint_color], ducting_layer, temp_connects)
else
D = new queued_p_type (A, TRUE, GLOB.pipe_paint_colors[paint_color], ducting_layer)
D.add_fingerprint(usr)
if(mode & WRENCH_MODE)
D.wrench_act(user, src)
else
return ..()
/obj/item/pipe_dispenser/proc/activate()
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
/* unneeded, you can craft ducts from plastic
/obj/item/pipe_dispenser/plumbing
name = "Plumberinator"
desc = "A crude device to rapidly plumb things."
icon_state = "plumberer"
category = PLUMBING_CATEGORY
locked = TRUE
/obj/item/pipe_dispenser/plumbing/Initialize()
. = ..()
spark_system = new
spark_system.set_up(5, 0, src)
spark_system.attach(src)
if(!first_plumbing)
first_plumbing = GLOB.fluid_duct_recipes[GLOB.fluid_duct_recipes[1]][1]
recipe = first_plumbing
*/
#undef ATMOS_CATEGORY
#undef DISPOSALS_CATEGORY
#undef TRANSIT_CATEGORY
#undef PLUMBING_CATEGORY
#undef BUILD_MODE
#undef DESTROY_MODE
+3 -3
View File
@@ -180,10 +180,10 @@
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)
/obj/item/airlock_painter/decal/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "DecalPainter", name, 500, 400, master_ui, state)
ui = new(user, src, "DecalPainter", name)
ui.open()
/obj/item/airlock_painter/decal/ui_data(mob/user)
+16 -18
View File
@@ -28,39 +28,37 @@
/// 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)
RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, .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)
UnregisterSignal(user, COMSIG_MOVABLE_PRE_MOVE)
/obj/item/broom/afterattack(atom/A, mob/user, proximity)
. = ..()
if(!proximity)
return
sweep(user, A, FALSE)
sweep(user, A)
/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))
/obj/item/broom/proc/sweep(datum/source, atom/newLoc)
if(!ismob(source) || !isturf(newLoc) || (get_dist(source, newLoc) > 1))
return
if (locate(/obj/structure/table) in target.contents)
var/turf/target = newLoc
var/atom/movable/AM
var/sweep_dir = get_dir(source, target)
if(!sweep_dir)
return
for(var/i in target.contents)
AM = i
if(AM.density) // eh good enough heuristic check
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)
step(garbage, sweep_dir)
if(++i > 20)
break
if(i >= 1)
if(i)
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
+1 -5
View File
@@ -16,7 +16,7 @@
custom_materials = list(/datum/material/iron=13000)
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = "swing_hit"
sharpness = IS_SHARP
sharpness = SHARP_EDGED
actions_types = list(/datum/action/item_action/startchainsaw)
tool_behaviour = TOOL_SAW
toolspeed = 0.5
@@ -71,10 +71,6 @@
/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>"
+4
View File
@@ -13,6 +13,7 @@
var/ignores_timeout = FALSE
var/response_timer_id = null
var/approval_time = 600
var/allow_unicode = FALSE
var/static/regex/standard_station_regex
@@ -48,6 +49,9 @@
if(!new_name)
return
if(!allow_unicode && (length(new_name) != length_char(new_name)))
to_chat(user, "Unicode is not allowed. Adminhelp if you want to use it so badly.")
return
log_game("[key_name(user)] has proposed to name the station as \
[new_name]")
@@ -48,6 +48,13 @@
/obj/item/stack/cable_coil = 5,
/obj/item/stack/sheet/glass = 1)
/obj/item/circuitboard/machine/medipen_refiller
name = "Medipen Refiller (Machine Board)"
icon_state = "medical"
build_path = /obj/machinery/medipen_refiller
req_components = list(
/obj/item/stock_parts/matter_bin = 1)
/obj/item/circuitboard/machine/clonepod
name = "Clone Pod (Machine Board)"
build_path = /obj/machinery/clonepod
@@ -383,7 +390,7 @@
/obj/item/circuitboard/machine/thermomachine/examine()
. = ..()
. += "<span class='notice'>It is set to layer [pipe_layer].</span>"
. += "<span class='notice'>It is set to layer [pipe_layer]. Use a Multitool on the circuit to change this.</span>"
/obj/item/circuitboard/machine/thermomachine/heater
name = "Heater (Machine Board)"
@@ -512,6 +519,10 @@
/obj/item/stack/sheet/glass = 1)
needs_anchored = FALSE
/obj/item/circuitboard/machine/hydroponics/automagic
name = "Automatic Hydroponics Tray (Machine Board)"
build_path = /obj/machinery/hydroponics/constructable/automagic
/obj/item/circuitboard/machine/seed_extractor
name = "Seed Extractor (Machine Board)"
build_path = /obj/machinery/seed_extractor
@@ -1135,3 +1146,8 @@
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)
/obj/item/circuitboard/machine/explosive_compressor
name = "Explosive Compressor (Machine Board)"
build_path = /obj/machinery/research/explosive_compressor
req_components = list(/obj/item/stock_parts/matter_bin = 3)
+12 -8
View File
@@ -147,23 +147,23 @@
to_chat(user, "<span class='warning'>There is not enough of [src] left!</span>")
. = TRUE
/obj/item/toy/crayon/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
// tgui is a plague upon this codebase
/obj/item/toy/crayon/ui_state(mob/user)
return GLOB.hands_state
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/toy/crayon/ui_interact(mob/user, datum/tgui/ui)
// tgui is a plague upon this codebase
// no u
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "Crayon", name, 600, 600,
master_ui, state)
ui = new(user, src, "Crayon", name)
ui.open()
/obj/item/toy/crayon/spraycan/AltClick(mob/user)
. = ..()
if(user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
if(has_cap)
is_capped = !is_capped
to_chat(user, "<span class='notice'>The cap on [src] is now [is_capped ? "on" : "off"].</span>")
update_icon()
return TRUE
/obj/item/toy/crayon/CtrlClick(mob/user)
if(can_change_colour && !isturf(loc) && user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
@@ -735,7 +735,11 @@
if(isobj(target))
if(actually_paints)
var/list/hsl = rgb2hsl(hex2num(copytext(paint_color,2,4)),hex2num(copytext(paint_color,4,6)),hex2num(copytext(paint_color,6,8)))
if(hsl[3] < 0.25 && !istype(target, /obj/structure/window) && !istype(target, /obj/effect/decal/cleanable/crayon)) //Colors too dark are rejected
var/static/whitelisted = typecacheof(list(/obj/structure/window,
/obj/effect/decal/cleanable/crayon,
/obj/machinery/door/window)
)
if(hsl[3] < 0.25 && !whitelisted[target]) //Colors too dark are rejected
to_chat(usr, "<span class='warning'>A color that dark on an object like this? Surely not...</span>")
return FALSE
+1 -4
View File
@@ -394,8 +394,6 @@
to_chat(user, "<span class='warning'>[src] are recharging!</span>")
return
user.stop_pulling() //User has hands full, and we don't care about anyone else pulling on it, their problem. CLEAR!!
if(user.a_intent == INTENT_DISARM)
do_disarm(M, user)
return
@@ -447,8 +445,7 @@
if(do_after(user, isnull(defib?.disarm_shock_time)? disarm_shock_time : defib.disarm_shock_time, target = M))
M.visible_message("<span class='danger'>[user] zaps [M] with [src]!</span>", \
"<span class='userdanger'>[user] zaps [M] with [src]!</span>")
M.adjustStaminaLoss(50)
M.DefaultCombatKnockdown(100)
M.DefaultCombatKnockdown(140)
M.updatehealth() //forces health update before next life tick
playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1)
M.emote("gasp")
+2 -1
View File
@@ -266,7 +266,7 @@ GLOBAL_LIST_EMPTY(PDAs)
var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/simple/pda)
assets.send(user)
var/datum/asset/spritesheet/emoji_s = get_asset_datum(/datum/asset/spritesheet/goonchat)
var/datum/asset/spritesheet/emoji_s = get_asset_datum(/datum/asset/spritesheet/chat)
emoji_s.send(user) //Already sent by chat but no harm doing this
user.set_machine(src)
@@ -1027,6 +1027,7 @@ GLOBAL_LIST_EMPTY(PDAs)
else if(is_type_in_list(C, contained_item)) //Checks if there is a pen
if(inserted_item)
to_chat(user, "<span class='warning'>There is already \a [inserted_item] in \the [src]!</span>")
return ..()
else
if(!user.transferItemToLoc(C, src))
return
+1 -1
View File
@@ -590,7 +590,7 @@ Code:
var/static/list/emoji_icon_states
var/static/emoji_table
if(!emoji_table)
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/goonchat)
var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
var/list/collate = list("<br><table>")
for(var/emoji in sortList(icon_states(icon('icons/emoji.dmi'))))
var/tag = sheet.icon_tag("emoji-[emoji]")
+11 -9
View File
@@ -54,18 +54,20 @@
name = initial(name)
icon_state = initial(icon_state)
/obj/item/aicard/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/aicard/ui_state(mob/user)
return GLOB.hands_state
/obj/item/aicard/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "Intellicard", name, 500, 500, master_ui, state)
ui = new(user, src, "Intellicard", name)
ui.open()
/obj/item/aicard/ui_data()
var/list/data = list()
if(AI)
data["name"] = AI.name
data["laws"] = AI.laws.get_law_list(include_zeroth = 1)
data["laws"] = AI.laws.get_law_list(include_zeroth = TRUE, render_html = FALSE)
data["health"] = (AI.health + 100) / 2
data["wireless"] = !AI.control_disabled //todo disabled->enabled
data["radio"] = AI.radio_enabled
@@ -86,19 +88,19 @@
if(confirm == "Yes" && !..())
flush = TRUE
if(AI && AI.loc == src)
to_chat(AI, "Your core files are being wiped!")
to_chat(AI, "<span class='userdanger'>Your core files are being wiped!</span>")
while(AI.stat != DEAD && flush)
AI.adjustOxyLoss(1)
AI.adjustOxyLoss(5)
AI.updatehealth()
sleep(5)
flush = FALSE
. = TRUE
if("wireless")
AI.control_disabled = !AI.control_disabled
to_chat(AI, "[src]'s wireless port has been [AI.control_disabled ? "disabled" : "enabled"]!")
to_chat(AI, "<span class='warning'>[src]'s wireless port has been [AI.control_disabled ? "disabled" : "enabled"]!</span>")
. = TRUE
if("radio")
AI.radio_enabled = !AI.radio_enabled
to_chat(AI, "Your Subspace Transceiver has been [AI.radio_enabled ? "enabled" : "disabled"]!")
to_chat(AI, "<span class='warning'>Your Subspace Transceiver has been [AI.radio_enabled ? "enabled" : "disabled"]!</span>")
. = TRUE
update_icon()
@@ -163,12 +163,13 @@
return
ui_interact(user)
/obj/item/dogborg/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
/obj/item/dogborg/sleeper/ui_state(mob/user)
return GLOB.notcontained_state
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/dogborg/sleeper/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "dogborg_sleeper", name, 375, 550, master_ui, state)
ui = new(user, src, "dogborg_sleeper", name, 375, 550) //UI DOES NOT EXIST
ui.open()
/obj/item/dogborg/sleeper/ui_data()

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