diff --git a/baystation12.dme b/baystation12.dme
index 2068f9ff37c..eced0f72410 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -157,7 +157,6 @@
#include "code\datums\spells\turf_teleport.dm"
#include "code\datums\spells\wizard.dm"
#include "code\defines\obj.dm"
-#include "code\defines\obj\hydro.dm"
#include "code\defines\obj\weapon.dm"
#include "code\defines\procs\AStar.dm"
#include "code\defines\procs\captain_announce.dm"
@@ -230,6 +229,21 @@
#include "code\game\gamemodes\malfunction\malfunction.dm"
#include "code\game\gamemodes\meteor\meteor.dm"
#include "code\game\gamemodes\meteor\meteors.dm"
+#include "code\game\gamemodes\mutiny\auth_key.dm"
+#include "code\game\gamemodes\mutiny\directive.dm"
+#include "code\game\gamemodes\mutiny\emergency_authentication_device.dm"
+#include "code\game\gamemodes\mutiny\key_pinpointer.dm"
+#include "code\game\gamemodes\mutiny\mutiny.dm"
+#include "code\game\gamemodes\mutiny\mutiny_admin.dm"
+#include "code\game\gamemodes\mutiny\mutiny_fluff.dm"
+#include "code\game\gamemodes\mutiny\mutiny_hooks.dm"
+#include "code\game\gamemodes\mutiny\directives\alien_fraud_directive.dm"
+#include "code\game\gamemodes\mutiny\directives\bluespace_contagion_directive.dm"
+#include "code\game\gamemodes\mutiny\directives\financial_crisis_directive.dm"
+#include "code\game\gamemodes\mutiny\directives\ipc_virus_directive.dm"
+#include "code\game\gamemodes\mutiny\directives\research_to_ripleys_directive.dm"
+#include "code\game\gamemodes\mutiny\directives\tau_ceti_needs_women_directive.dm"
+#include "code\game\gamemodes\mutiny\directives\terminations_directive.dm"
#include "code\game\gamemodes\ninja\ninja.dm"
#include "code\game\gamemodes\nuclear\nuclear.dm"
#include "code\game\gamemodes\nuclear\nuclearbomb.dm"
@@ -259,14 +273,13 @@
#include "code\game\jobs\job\silicon.dm"
#include "code\game\machinery\adv_med.dm"
#include "code\game\machinery\ai_slipper.dm"
-#include "code\game\machinery\airlock_control.dm"
#include "code\game\machinery\alarm.dm"
#include "code\game\machinery\atmo_control.dm"
#include "code\game\machinery\autolathe.dm"
+#include "code\game\machinery\autolathe_datums.dm"
#include "code\game\machinery\Beacon.dm"
#include "code\game\machinery\bees_apiary.dm"
#include "code\game\machinery\bees_items.dm"
-#include "code\game\machinery\biogenerator.dm"
#include "code\game\machinery\buttons.dm"
#include "code\game\machinery\cell_charger.dm"
#include "code\game\machinery\cloning.dm"
@@ -281,7 +294,6 @@
#include "code\game\machinery\Freezer.dm"
#include "code\game\machinery\hologram.dm"
#include "code\game\machinery\holosign.dm"
-#include "code\game\machinery\hydroponics.dm"
#include "code\game\machinery\igniter.dm"
#include "code\game\machinery\iv_drip.dm"
#include "code\game\machinery\lightswitch.dm"
@@ -357,10 +369,9 @@
#include "code\game\machinery\computer\skills.dm"
#include "code\game\machinery\computer\specops_shuttle.dm"
#include "code\game\machinery\computer\station_alert.dm"
-#include "code\game\machinery\computer\syndicate_shuttle.dm"
#include "code\game\machinery\computer\syndicate_specops_shuttle.dm"
-#include "code\game\machinery\computer\vox_shuttle.dm"
#include "code\game\machinery\doors\airlock.dm"
+#include "code\game\machinery\doors\airlock_control.dm"
#include "code\game\machinery\doors\airlock_electronics.dm"
#include "code\game\machinery\doors\alarmlock.dm"
#include "code\game\machinery\doors\brigdoors.dm"
@@ -373,8 +384,12 @@
#include "code\game\machinery\doors\unpowered.dm"
#include "code\game\machinery\doors\windowdoor.dm"
#include "code\game\machinery\embedded_controller\airlock_controllers.dm"
+#include "code\game\machinery\embedded_controller\airlock_docking_controller.dm"
#include "code\game\machinery\embedded_controller\airlock_program.dm"
+#include "code\game\machinery\embedded_controller\docking_program.dm"
#include "code\game\machinery\embedded_controller\embedded_controller_base.dm"
+#include "code\game\machinery\embedded_controller\embedded_program_base.dm"
+#include "code\game\machinery\embedded_controller\simple_docking_controller.dm"
#include "code\game\machinery\kitchen\gibber.dm"
#include "code\game\machinery\kitchen\juicer.dm"
#include "code\game\machinery\kitchen\microwave.dm"
@@ -400,7 +415,6 @@
#include "code\game\mecha\combat\combat.dm"
#include "code\game\mecha\combat\durand.dm"
#include "code\game\mecha\combat\gygax.dm"
-#include "code\game\mecha\combat\honker.dm"
#include "code\game\mecha\combat\marauder.dm"
#include "code\game\mecha\combat\phazon.dm"
#include "code\game\mecha\equipment\mecha_equipment.dm"
@@ -472,6 +486,7 @@
#include "code\game\objects\items\devices\pipe_painter.dm"
#include "code\game\objects\items\devices\powersink.dm"
#include "code\game\objects\items\devices\scanners.dm"
+#include "code\game\objects\items\devices\suit_cooling.dm"
#include "code\game\objects\items\devices\taperecorder.dm"
#include "code\game\objects\items\devices\traitordevices.dm"
#include "code\game\objects\items\devices\transfer_valve.dm"
@@ -516,7 +531,6 @@
#include "code\game\objects\items\weapons\flamethrower.dm"
#include "code\game\objects\items\weapons\gift_wrappaper.dm"
#include "code\game\objects\items\weapons\handcuffs.dm"
-#include "code\game\objects\items\weapons\hydroponics.dm"
#include "code\game\objects\items\weapons\kitchen.dm"
#include "code\game\objects\items\weapons\manuals.dm"
#include "code\game\objects\items\weapons\mop.dm"
@@ -632,6 +646,7 @@
#include "code\game\objects\structures\stool_bed_chair_nest\bed.dm"
#include "code\game\objects\structures\stool_bed_chair_nest\chairs.dm"
#include "code\game\objects\structures\stool_bed_chair_nest\stools.dm"
+#include "code\game\objects\structures\stool_bed_chair_nest\wheelchair.dm"
#include "code\game\turfs\simulated.dm"
#include "code\game\turfs\turf.dm"
#include "code\game\turfs\unsimulated.dm"
@@ -747,6 +762,7 @@
#include "code\modules\clothing\shoes\magboots.dm"
#include "code\modules\clothing\shoes\miscellaneous.dm"
#include "code\modules\clothing\spacesuits\alien.dm"
+#include "code\modules\clothing\spacesuits\breaches.dm"
#include "code\modules\clothing\spacesuits\captain.dm"
#include "code\modules\clothing\spacesuits\ert.dm"
#include "code\modules\clothing\spacesuits\miscellaneous.dm"
@@ -825,7 +841,13 @@
#include "code\modules\flufftext\Hallucination.dm"
#include "code\modules\flufftext\TextFilters.dm"
#include "code\modules\food\recipes_microwave.dm"
+#include "code\modules\games\cards.dm"
#include "code\modules\genetics\side_effects.dm"
+#include "code\modules\hydroponics\biogenerator.dm"
+#include "code\modules\hydroponics\grown_inedible.dm"
+#include "code\modules\hydroponics\hydro_tools.dm"
+#include "code\modules\hydroponics\hydro_tray.dm"
+#include "code\modules\hydroponics\seeds.dm"
#include "code\modules\library\lib_items.dm"
#include "code\modules\library\lib_machines.dm"
#include "code\modules\library\lib_readme.dm"
@@ -835,6 +857,8 @@
#include "code\modules\maps\swapmaps.dm"
#include "code\modules\maps\writer.dm"
#include "code\modules\mining\abandonedcrates.dm"
+#include "code\modules\mining\alloys.dm"
+#include "code\modules\mining\coins.dm"
#include "code\modules\mining\machine_input_output_plates.dm"
#include "code\modules\mining\machine_processing.dm"
#include "code\modules\mining\machine_stacking.dm"
@@ -845,8 +869,11 @@
#include "code\modules\mining\minerals.dm"
#include "code\modules\mining\mint.dm"
#include "code\modules\mining\money_bag.dm"
-#include "code\modules\mining\ores_coins.dm"
+#include "code\modules\mining\ore.dm"
+#include "code\modules\mining\ore_datum.dm"
#include "code\modules\mining\satchel_ore_boxdm.dm"
+#include "code\modules\mining\drilling\distribution.dm"
+#include "code\modules\mining\drilling\drill.dm"
#include "code\modules\mob\abilities.dm"
#include "code\modules\mob\death.dm"
#include "code\modules\mob\emote.dm"
@@ -1071,6 +1098,7 @@
#include "code\modules\paperwork\photography.dm"
#include "code\modules\paperwork\stamps.dm"
#include "code\modules\power\apc.dm"
+#include "code\modules\power\batteryrack.dm"
#include "code\modules\power\cable.dm"
#include "code\modules\power\cable_heavyduty.dm"
#include "code\modules\power\cable_logic.dm"
@@ -1181,12 +1209,12 @@
#include "code\modules\research\rdconsole.dm"
#include "code\modules\research\rdmachines.dm"
#include "code\modules\research\research.dm"
-#include "code\modules\research\research_shuttle.dm"
#include "code\modules\research\server.dm"
#include "code\modules\research\xenoarchaeology\areas.dm"
#include "code\modules\research\xenoarchaeology\chemistry.dm"
#include "code\modules\research\xenoarchaeology\geosample.dm"
#include "code\modules\research\xenoarchaeology\manuals.dm"
+#include "code\modules\research\xenoarchaeology\master_controller.dm"
#include "code\modules\research\xenoarchaeology\misc.dm"
#include "code\modules\research\xenoarchaeology\artifact\artifact.dm"
#include "code\modules\research\xenoarchaeology\artifact\artifact_autocloner.dm"
@@ -1222,7 +1250,11 @@
#include "code\modules\research\xenoarchaeology\finds\finds_defines.dm"
#include "code\modules\research\xenoarchaeology\finds\finds_fossils.dm"
#include "code\modules\research\xenoarchaeology\finds\finds_misc.dm"
+#include "code\modules\research\xenoarchaeology\finds\finds_special.dm"
#include "code\modules\research\xenoarchaeology\finds\finds_talkingitem.dm"
+#include "code\modules\research\xenoarchaeology\genetics\prehistoric_animals.dm"
+#include "code\modules\research\xenoarchaeology\genetics\prehistoric_plants.dm"
+#include "code\modules\research\xenoarchaeology\genetics\reconstitutor.dm"
#include "code\modules\research\xenoarchaeology\machinery\artifact_analyser.dm"
#include "code\modules\research\xenoarchaeology\machinery\artifact_harvester.dm"
#include "code\modules\research\xenoarchaeology\machinery\artifact_scanner.dm"
@@ -1261,6 +1293,13 @@
#include "code\modules\scripting\Scanner\Tokens.dm"
#include "code\modules\security levels\keycard authentication.dm"
#include "code\modules\security levels\security levels.dm"
+#include "code\modules\shuttles\antagonist.dm"
+#include "code\modules\shuttles\departmental.dm"
+#include "code\modules\shuttles\shuttle.dm"
+#include "code\modules\shuttles\shuttle_console.dm"
+#include "code\modules\shuttles\shuttle_specops.dm"
+#include "code\modules\shuttles\shuttle_supply.dm"
+#include "code\modules\shuttles\shuttles_multi.dm"
#include "code\modules\supermatter\supermatter.dm"
#include "code\modules\surgery\appendix.dm"
#include "code\modules\surgery\bones.dm"
@@ -1274,6 +1313,9 @@
#include "code\modules\surgery\ribcage.dm"
#include "code\modules\surgery\robolimbs.dm"
#include "code\modules\surgery\surgery.dm"
+#include "code\modules\vehicles\cargo_train.dm"
+#include "code\modules\vehicles\train.dm"
+#include "code\modules\vehicles\vehicle.dm"
#include "code\modules\virus2\analyser.dm"
#include "code\modules\virus2\antibodies.dm"
#include "code\modules\virus2\centrifuge.dm"
diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
index ef0f656781e..16a863a2e1f 100755
--- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
@@ -1,7 +1,7 @@
obj/machinery/atmospherics/trinary/filter
icon = 'icons/obj/atmospherics/filter.dmi'
icon_state = "intact_off"
- density = 1
+ density = 0
name = "Gas filter"
diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
index 3b16042fca6..4d94acbfba3 100644
--- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
@@ -1,7 +1,7 @@
obj/machinery/atmospherics/trinary/mixer
icon = 'icons/obj/atmospherics/mixer.dmi'
icon_state = "intact_off"
- density = 1
+ density = 0
name = "Gas mixer"
diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm
index 61d7a48d5ff..b7444d00df8 100644
--- a/code/ATMOSPHERICS/datum_pipeline.dm
+++ b/code/ATMOSPHERICS/datum_pipeline.dm
@@ -1,3 +1,5 @@
+#define STEFAN_BOLTZMANN_CONSTANT 0.0000000567
+
datum/pipeline
var/datum/gas_mixture/air
@@ -209,5 +211,12 @@ datum/pipeline
(partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
air.temperature -= heat/total_heat_capacity
+ if(network)
+ network.update = 1
+
+ proc/radiate_heat(surface, thermal_conductivity)
+ var/total_heat_capacity = air.heat_capacity()
+ var/heat = STEFAN_BOLTZMANN_CONSTANT * surface * air.temperature ** 4 * thermal_conductivity
+ air.temperature = max(0, air.temperature - heat / total_heat_capacity)
if(network)
network.update = 1
\ No newline at end of file
diff --git a/code/ATMOSPHERICS/he_pipes.dm b/code/ATMOSPHERICS/he_pipes.dm
index 3fe69c855d4..a8e7e06bad6 100644
--- a/code/ATMOSPHERICS/he_pipes.dm
+++ b/code/ATMOSPHERICS/he_pipes.dm
@@ -4,6 +4,7 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging
icon_state = "intact"
level = 2
var/initialize_directions_he
+ var/surface = 2
minimum_temperature_difference = 20
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
@@ -49,12 +50,11 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging
else
var/datum/gas_mixture/environment = loc.return_air()
environment_temperature = environment.temperature
+ var/datum/gas_mixture/pipe_air = return_air()
+ if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
+ parent.temperature_interact(loc, volume, thermal_conductivity)
else
- environment_temperature = loc:temperature
- var/datum/gas_mixture/pipe_air = return_air()
- if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
- parent.temperature_interact(loc, volume, thermal_conductivity)
-
+ parent.radiate_heat(surface, 1)
obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
diff --git a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi
index 13cd5e77396..f27897881ce 100644
Binary files a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi and b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi differ
diff --git a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm
index 30750d64fea..d36671e49fa 100644
--- a/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm
+++ b/code/WorkInProgress/Cael_Aislinn/Jungle/jungle_temple.dm
@@ -86,9 +86,6 @@
for(var/coin_type in typesof(/obj/item/weapon/coin))
possible_spawns += coin_type
- //no icon_state for mythril coins
- possible_spawns -= /obj/item/weapon/coin/mythril
-
var/coin_type = pick(possible_spawns)
for(var/i=0,i
+ NanoTrasen's reasons for the following directives are classified.
+
+ An extensive conspiracy network aimed at defrauding NanoTrasen of large amounts of funds has been uncovered
+ operating within [system_name()]. Human personnel are not suspected to be involved. Further information is classified.
+
+ A manufactured and near-undetectable virus is spreading on NanoTrasen stations.
+ The pathogen travels by bluespace after maturing for one day.
+ No treatment has yet been discovered. Personnel onboard [station_name()] have been infected. Further information is classified.
+
+ [system_name()] system banks in financial crisis. Local emergency situation ongoing.
+ NT Funds redistributed, impact upon civilian department expected.
+ Further information is classified.
+
+ IPC units have been found to be infected with a violent and undesired virus in Virgus Ferrorus system.
+ Risk to [station_name()] IPC units has not been assessed. Further information is classified.
+
+ The NanoTrasen [system_name()] Manufactory faces an ore deficit. Financial crisis imminent. [station_name()] has been reassigned as a mining platform.
+ The Research Director is to assist the Head of Personnel in coordinating assets.
+ Weapons department reports solid sales. Further information is classified.
+
+ Recent evidence suggests [get_target_gender()] aptitudes may be effected by radiation from [system_name()].
+ Effects were measured under laboratory and station conditions. Humans remain more trusted than Xeno. Further information is classified.
+
+ Wow. Much ugly. So painful.
+ Many terminations. Very classified.
+
+ [current_directive.get_description()]
+
+ TO: Captain [mode.head_loyalist], Commanding Officer, [station_name()]
+ A member of your Command Staff is this shift's designated Emergency Secondary Authenticator.
+ Captain [mode.head_loyalist], you are to immediately initiate the following procedure; codenamed Directive X:
+ \"You must read this! NanoTrasen Chain of Command COMPROMISED. Command Encryptions BROKEN. [station_name()] Captain [mode.head_loyalist] will receive orders that must NOT BE BROUGHT TO FRUITION!
+
+They don't care about us they only care about WEALTH and POWER... Share this message with people you trust.
+
+Be safe, friend.\" (Unable to Reply) The presence of [pick(
+ "political instability",
+ "quantum fluctuations",
+ "hostile raiders",
+ "derelict station debris",
+ "REDACTED",
+ "ancient alien artillery",
+ "solar magnetic storms",
+ "sentient time-travelling killbots",
+ "gravitational anomalies",
+ "wormholes to another dimension",
+ "a telescience mishap",
+ "radiation flares",
+ "supermatter dust",
+ "leaks into a negative reality",
+ "antiparticle clouds",
+ "residual bluespace energy",
+ "suspected syndicate operatives",
+ "malfunctioning von Neumann probe swarms",
+ "shadowy interlopers",
+ "a stranded Vox arkship",
+ "haywire IPC constructs",
+ "rogue Unathi exiles",
+ "artifacts of eldritch horror",
+ "a brain slug infestation",
+ "killer bugs that lay eggs in the husks of the living",
+ "a deserted transport carrying xenomorph specimens",
+ "an emissary for the gestalt requesting a security detail",
+ "a Tajaran slave rebellion",
+ "radical Skrellian transevolutionaries",
+ "classified security operations",
+ "science-defying raw elemental chaos")]
+in the region is tying up all available local emergency resources;
+emergency response teams can not be called at this time. The crew will be divided by their sense of ethics when a morally turbulent emergency directive arrives with an incomplete command validation code.
+Loyalists - Follow the Head Loyalist in carrying out [loyalist_tag("NanoTrasen's directives")] then activate the EAD. NanoTrasen's image will forever be haunted by the fact that a mutiny took place on one of its own stations. NanoTrasen's image will forever be haunted by the fact that a mutiny took place on one of its own stations. NanoTrasen's image will forever be haunted by the fact that a mutiny took place on one of its own stations. Even though the directive was not successfully implemented, NanoTrasen's image will forever be haunted by the fact that its authentication protocol was breached with such magnitude and that a mutiny was the result. Even though the directive was not successfully implemented, NanoTrasen's image will forever be haunted by the fact that its authentication protocol was breached with such magnitude and that a mutiny was the result.Breaking News
"
+ if (was_bloodbath())
+ world << fluff.no_victory()
+ return
+
+ var/directives_completed = current_directive.directives_complete()
+ var/ead_activated = ead.activated
+ if (directives_completed && ead_activated)
+ world << fluff.loyalist_major_victory()
+ else if (directives_completed && !ead_activated)
+ world << fluff.loyalist_minor_victory()
+ else if (!directives_completed && ead_activated)
+ world << fluff.mutineer_minor_victory()
+ else if (!directives_completed && !ead_activated)
+ world << fluff.mutineer_major_victory()
+
+ world << sound('sound/machines/twobeep.ogg')
+
+ proc/update_all_icons()
+ spawn(0)
+ for(var/datum/mind/M in mutineers)
+ update_icon(M)
+
+ for(var/datum/mind/M in loyalists)
+ update_icon(M)
+ return 1
+
+ proc/update_icon(datum/mind/M)
+ if(!M.current || !M.current.client)
+ return 0
+
+ for(var/image/I in head_loyalist.current.client.images)
+ if(I.loc == M.current && (I.icon_state == "loyalist" || I.icon_state == "mutineer"))
+ del(I)
+
+ for(var/image/I in head_mutineer.current.client.images)
+ if(I.loc == M.current && (I.icon_state == "loyalist" || I.icon_state == "mutineer"))
+ del(I)
+
+ if(M in loyalists)
+ var/I = image('icons/mob/mob.dmi', loc=M.current, icon_state = "loyalist")
+ head_loyalist.current.client.images += I
+
+ if(M in mutineers)
+ var/I = image('icons/mob/mob.dmi', loc=M.current, icon_state = "mutineer")
+ head_mutineer.current.client.images += I
+
+ return 1
+
+/datum/game_mode/mutiny/announce()
+ fluff.announce()
+
+/datum/game_mode/mutiny/pre_setup()
+ var/list/loyalist_candidates = get_head_loyalist_candidates()
+ if(!loyalist_candidates || loyalist_candidates.len == 0)
+ world << "\red Mutiny mode aborted: no valid candidates for head loyalist."
+ return 0
+
+ var/list/mutineer_candidates = get_head_mutineer_candidates()
+ if(!mutineer_candidates || mutineer_candidates.len == 0)
+ world << "\red Mutiny mode aborted: no valid candidates for head mutineer."
+ return 0
+
+ var/list/directive_candidates = get_directive_candidates()
+ if(!directive_candidates || directive_candidates.len == 0)
+ world << "\red Mutiny mode aborted: no valid candidates for Directive X."
+ return 0
+
+ head_loyalist = pick(loyalist_candidates)
+ head_mutineer = pick(mutineer_candidates)
+ current_directive = pick(directive_candidates)
+
+ return 1
+
+/datum/game_mode/mutiny/post_setup()
+ equip_head_loyalist()
+ equip_head_mutineer()
+
+ loyalists.Add(head_loyalist)
+ mutineers.Add(head_mutineer)
+
+ replace_nuke_with_ead()
+ current_directive.initialize()
+ unbolt_vault_door()
+ make_secret_transcript()
+
+ update_all_icons()
+ spawn(0)
+ reveal_directives()
+ ..()
+
+/mob/living/carbon/human/proc/recruit_loyalist()
+ set name = "Recruit Loyalist"
+ set category = "Mutiny"
+
+ var/datum/game_mode/mutiny/mode = get_mutiny_mode()
+ if (!mode || src != mode.head_loyalist.current)
+ return
+
+ var/list/candidates = list()
+ for (var/mob/living/carbon/human/P in oview(src))
+ if(!stat && P.client && mode.can_be_recruited(P.mind, "loyalist"))
+ candidates += P
+
+ if(!candidates.len)
+ src << "\red You aren't close enough to anybody that can be recruited."
+ return
+
+ if(world.time < mode.recruit_loyalist_cooldown)
+ src << "\red Wait [MUTINY_RECRUITMENT_COOLDOWN] seconds before recruiting again."
+ return
+
+ mode.recruit_loyalist_cooldown = world.time + (MUTINY_RECRUITMENT_COOLDOWN SECONDS)
+
+ var/mob/living/carbon/human/M = input("Select a person to recruit", "Loyalist recruitment", null) as mob in candidates
+
+ if (M)
+ src << "Attempting to recruit [M]..."
+ log_admin("[src]([src.ckey]) attempted to recruit [M] as a loyalist.")
+ message_admins("\red [src]([src.ckey]) attempted to recruit [M] as a loyalist.")
+
+ var/choice = alert(M, "Asked by [src]: Will you help me complete Directive X?", "Loyalist recruitment", "No", "Yes")
+ if(choice == "Yes")
+ mode.add_loyalist(M.mind)
+ else if(choice == "No")
+ M << "\red You declined to join the loyalists."
+ mode.head_loyalist.current << "\red [M] declined to support the loyalists."
+
+/mob/living/carbon/human/proc/recruit_mutineer()
+ set name = "Recruit Mutineer"
+ set category = "Mutiny"
+
+ var/datum/game_mode/mutiny/mode = get_mutiny_mode()
+ if (!mode || src != mode.head_mutineer.current)
+ return
+
+ var/list/candidates = list()
+ for (var/mob/living/carbon/human/P in oview(src))
+ if(!stat && P.client && mode.can_be_recruited(P.mind, "mutineer"))
+ candidates += P
+
+ if(!candidates.len)
+ src << "\red You aren't close enough to anybody that can be recruited."
+ return
+
+ if(world.time < mode.recruit_mutineer_cooldown)
+ src << "\red Wait [MUTINY_RECRUITMENT_COOLDOWN] seconds before recruiting again."
+ return
+
+ mode.recruit_mutineer_cooldown = world.time + (MUTINY_RECRUITMENT_COOLDOWN SECONDS)
+
+ var/mob/living/carbon/human/M = input("Select a person to recruit", "Mutineer recruitment", null) as mob in candidates
+
+ if (M)
+ src << "Attempting to recruit [M]..."
+ log_admin("[src]([src.ckey]) attempted to recruit [M] as a mutineer.")
+ message_admins("\red [src]([src.ckey]) attempted to recruit [M] as a mutineer.")
+
+ var/choice = alert(M, "Asked by [src]: Will you help me stop Directive X?", "Mutineer recruitment", "No", "Yes")
+ if(choice == "Yes")
+ mode.add_mutineer(M.mind)
+ else if(choice == "No")
+ M << "\red You declined to join the mutineers."
+ mode.head_mutineer.current << "\red [M] declined to support the mutineers."
+
+/proc/get_mutiny_mode()
+ if(!ticker || !istype(ticker.mode, /datum/game_mode/mutiny))
+ return null
+
+ return ticker.mode
diff --git a/code/game/gamemodes/mutiny/mutiny_admin.dm b/code/game/gamemodes/mutiny/mutiny_admin.dm
new file mode 100644
index 00000000000..2ba08def2d9
--- /dev/null
+++ b/code/game/gamemodes/mutiny/mutiny_admin.dm
@@ -0,0 +1,83 @@
+/datum/game_mode/mutiny/proc/check_antagonists_ui(admins)
+ var/turf/captains_key_loc = captains_key ? captains_key.get_loc_turf() : "Lost or Destroyed"
+ var/turf/secondary_key_loc = secondary_key ? secondary_key.get_loc_turf() : "Lost or Destroyed"
+ var/remaining_objectives = current_directive.get_remaining_orders()
+ var/txt = {"
+ Context:
+ Orders:
+
+ [fluff.get_orders()]
+
+
+ Remaining Objectives
+
+ [remaining_objectives ? remaining_objectives : "
+
+ Authentication:
+ Captain's Key: [captains_key_loc]
+ Activate
+ Secondary Key: [secondary_key_loc]
+ Activate
+ EAD: [ead ? ead.get_status() : "Lost or Destroyed"]
+ Activate
+
+ "}
+
+ txt += "Reassign Head Loyalist
"
+ if(head_loyalist)
+ txt += check_role_table("Head Loyalist", list(head_loyalist), admins, 0)
+
+ var/list/loyal_crew = loyalists - head_loyalist
+ if(loyal_crew.len)
+ txt += check_role_table("Loyalists", loyal_crew, admins, 0)
+
+ txt += "Reassign Head Mutineer
"
+ if(head_mutineer)
+ txt += check_role_table("Head Mutineer", list(head_mutineer), admins, 0)
+
+ var/list/mutiny_crew = mutineers - head_mutineer
+ if(mutiny_crew.len)
+ txt += check_role_table("Mutineers", mutiny_crew, admins, 0)
+
+ if(body_count.len)
+ txt += check_role_table("Casualties", body_count, admins, 0)
+
+ return txt
+
+/datum/game_mode/mutiny/check_antagonists_topic(href, href_list[])
+ switch(href_list["choice"])
+ if("activate_captains_key")
+ ead.captains_key = 1
+ return 1
+ if("activate_secondary_key")
+ ead.secondary_key = 1
+ return 1
+ if("activate_ead")
+ ead.activated = 1
+ return 1
+ if("reassign_head_loyalist")
+ var/mob/M = get_reassignment_candidate("Loyalist")
+ if(M)
+ head_loyalist = M.mind
+ equip_head_loyalist()
+ return 1
+ if("reassign_head_mutineer")
+ var/mob/M = get_reassignment_candidate("Mutineer")
+ if(M)
+ head_mutineer = M.mind
+ equip_head_mutineer()
+ return 1
+ else
+ return 0
+
+/datum/game_mode/mutiny/proc/get_reassignment_candidate(faction)
+ var/list/targets[0]
+ for(var/mob/living/carbon/human/H in player_list)
+ if(H.is_ready() && !H.is_dead())
+ targets.Add(H)
+
+ return input("Select a player to lead the [faction] faction.", "Head [faction] reassignment", null) as mob in targets
diff --git a/code/game/gamemodes/mutiny/mutiny_fluff.dm b/code/game/gamemodes/mutiny/mutiny_fluff.dm
new file mode 100644
index 00000000000..c93a7d67194
--- /dev/null
+++ b/code/game/gamemodes/mutiny/mutiny_fluff.dm
@@ -0,0 +1,251 @@
+/datum/mutiny_fluff
+ var/datum/game_mode/mutiny/mode
+
+ New(datum/game_mode/mutiny/M)
+ mode = M
+
+ proc/centcom_announce(text)
+ world << {"
+
+[text]
+ "}
+ world << sound('sound/AI/commandreport.ogg')
+
+ proc/announce_incoming_fax()
+ centcom_announce({"
+Incoming Emergency Directive:
+Captain's Office Fax Machine, [station_name()]
+ "})
+
+ proc/announce_directives()
+ for (var/obj/machinery/faxmachine/fax in world)
+ if (fax.department == "Captain's Office")
+ var/obj/item/weapon/paper/directive_x = new(fax.loc)
+ directive_x.name = "emergency action message"
+ directive_x.info = get_fax_body()
+
+ proc/get_fax_body()
+ return {"
+ NOT A DRILL . . . EMERGENCY DIRECTIVE . . . NOT A DRILL
+ FROM: NanoTrasen Emergency Messaging Relay
+ DATE: [time2text(world.realtime, "MM/DD")]/[game_year]
+ SUBJECT: Directive X
+
+ Emergency Authentication Protocol
+
+ This Emergency Secondary Authenticator is uniquely aware of their role and possesses the Emergency Secondary Authentication Key.
+ As Captain, you possess the Captain's Authentication Key.
+ The Emergency Authentication Device is located in the vault of your station, and requires simultaneous activation of the Authentication Keys.
+ An Authentication Key Pinpointer can be delivered via Cargo Bay to assist recovery of the Authentication Keys should they be lost aboard the station.
+ A key's destruction or removal from the station's perimeter will automatically and irreversibly activate the Emergency Authentication Device.
+
+
+ Orders
+
+ [get_orders()]
+
+
+
+ Authentication
+
+ Encoded Authentication String: T0JCJUwoIVFDQA==
+ Emergency Action Code: O B B _ L _ _ Q C _
+ ERROR: DECODING INCOMPLETE (40% LOSS)
+
+
+
+
+ NOT A DRILL . . . EMERGENCY DIRECTIVE . . . NOT A DRILL
+The [loyalist_tag("Head Loyalist")] is the Captain, who carries the [loyalist_tag("Captain's Authentication Key")] at all times.
+The [mutineer_tag("Head Mutineer")] is a random Head of Staff who carries the [mutineer_tag("Emergency Secondary Authentication Key")].
+
+Mutineers - Prevent the completion of the [mutineer_tag("improperly validated directives")] and the activation of the EAD.
+Corporate Rival Threat Assessment
+Time: 16:11, May 24, 2558 (Sol Reckoning)
+
+
+
+
+D: Mr. Mitchell, first you send cryptic messages to my office and then you request to have me come personally to this barely lit closet you call a workstation; all of this to talk about a computer glitch?
+
+D: Who?
+TM: It's not who, it's what. The computer program we planted in the [system_name()] communications satellite.
+D: What is so important about this computer program?
+TM: We call her an eavesdropper. Captures network traffic, records it, and forwards the stream to the receiver autonomously.
+D: Speak English goddamnit.
+TM: Standard intelligence acquisition package, sir; we bug their satellite and listen. It's like we have their playbook and we know what their moves are going to be on the market before they make them.
+D: So Mallory doesn't work?
+TM: She worked, sir. We've had an ear on NanoTrasen's regional communications for weeks.
+D: Any news about their Phoron refinement process?
+TM: No sir. Our analysts believe they are using a separate channel for their most sensitive data.
+D: So what's the problem?
+TM: The intelligence hasn't been doing us any good. Anything that appears actionable, I send it to the analysts and they make a plan. Thing is, NanoTrasen always sees us coming.
+D: Tim...
+TM: I think they discovered the hack, sir. Case in point, Energine Consolidated Solutions. That subsidiary of ours that was awarded a lease on NanoTrasen's mining platform in Nyx? NanoTrasen acquired them a week before we made the announcement.
+D: They know about they have a bug. They left her on and fed her the information for us to hear, those sneaks. How did they find it?
+TM: Top secret communique came through. I'm not sure what happened. Either Mallory couldn't replicate the encryption scheme and garbled it going out or the transmission was already corrupted to begin with.
+D: Either way the transmission caused NanoTrasen to look at the satellite. They found out about Mallory.
+TM: Precisely sir. There's only so much I can do to cover our tracks from here.
+D: I'm pulling the plug. We have assets in the sector that are capable of a job like this. Thank you for bringing this to my attention.
+
+TM: Just the subject, 'Directive X'.
+D: Directive X... Now what do you suppose that means?
+"
- dat += " "
dat += ""
if(occupant.sdisabilities & BLIND)
diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm
index c84f6b137a1..33592d0bdf2 100644
--- a/code/game/machinery/alarm.dm
+++ b/code/game/machinery/alarm.dm
@@ -646,18 +646,6 @@
updateDialog()
return
-/obj/machinery/alarm/proc/shock(mob/user, prb)
- if((stat & (NOPOWER))) // unpowered, no shock
- return 0
- if(!prob(prb))
- return 0 //you lucked out, no shock for you
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, src)
- s.start() //sparks always.
- if (electrocute_mob(user, get_area(src), src))
- return 1
- else
- return 0
///////////////
//END HACKING//
///////////////
@@ -994,11 +982,11 @@ table tr:first-child th:first-child { border: none;}
add_fingerprint(usr)
usr.set_machine(src)
-
+
// hrefs that can always be called -walter0o
if(href_list["rcon"])
var/attempted_rcon_setting = text2num(href_list["rcon"])
-
+
switch(attempted_rcon_setting)
if(RCON_NO)
rcon_setting = RCON_NO
@@ -1008,7 +996,7 @@ table tr:first-child th:first-child { border: none;}
rcon_setting = RCON_YES
else
return
-
+
if(href_list["temperature"])
var/list/selected = TLV["temperature"]
var/max_temperature = min(selected[3] - T0C, MAX_TEMPERATURE)
@@ -1021,7 +1009,7 @@ table tr:first-child th:first-child { border: none;}
// hrefs that need the AA unlocked -walter0o
if(!locked || istype(usr, /mob/living/silicon))
-
+
if(href_list["command"])
var/device_id = href_list["id_tag"]
switch(href_list["command"])
@@ -1034,9 +1022,9 @@ table tr:first-child th:first-child { border: none;}
"n2o_scrub",
"panic_siphon",
"scrubbing")
-
+
send_signal(device_id, list(href_list["command"] = text2num(href_list["val"]) ) )
-
+
if("set_threshold")
var/env = href_list["env"]
var/threshold = text2num(href_list["var"])
@@ -1084,36 +1072,36 @@ table tr:first-child th:first-child { border: none;}
selected[2] = selected[4]
if(selected[3] > selected[4])
selected[3] = selected[4]
-
+
apply_mode()
-
+
if(href_list["screen"])
screen = text2num(href_list["screen"])
-
+
if(href_list["atmos_unlock"])
switch(href_list["atmos_unlock"])
if("0")
air_doors_close(1)
if("1")
air_doors_open(1)
-
+
if(href_list["atmos_alarm"])
if (alarm_area.atmosalert(2))
apply_danger_level(2)
update_icon()
-
+
if(href_list["atmos_reset"])
if (alarm_area.atmosalert(0))
apply_danger_level(0)
update_icon()
-
+
if(href_list["mode"])
mode = text2num(href_list["mode"])
apply_mode()
-
+
// hrefs that need the AA wires exposed, note that borgs should be in range here too -walter0o
if(wiresexposed && Adjacent(usr))
-
+
if (href_list["AAlarmwires"])
var/t1 = text2num(href_list["AAlarmwires"])
if (!( istype(usr.equipped(), /obj/item/weapon/wirecutters) ))
@@ -1128,7 +1116,7 @@ table tr:first-child th:first-child { border: none;}
update_icon()
buildstage = 1
return
-
+
else if (href_list["pulse"])
var/t1 = text2num(href_list["pulse"])
if (!istype(usr.equipped(), /obj/item/device/multitool))
@@ -1247,8 +1235,7 @@ Just a object used in constructing air alarms
icon_state = "door_electronics"
desc = "Looks like a circuit. Probably is."
w_class = 2.0
- m_amt = 50
- g_amt = 50
+ matter = list("metal" = 50, "glass" = 50)
/*
@@ -1278,7 +1265,7 @@ Code shamelessly copied from apc_frame
if (!(ndir in cardinal))
return
- var/turf/loc = get_turf_loc(usr)
+ var/turf/loc = get_turf(usr)
var/area/A = loc.loc
if (!istype(loc, /turf/simulated/floor))
usr << "\red Air Alarm cannot be placed on this spot."
@@ -1575,8 +1562,7 @@ Just a object used in constructing fire alarms
icon_state = "door_electronics"
desc = "A circuit. It has a label on it, it says \"Can handle heat levels up to 40 degrees celsius!\""
w_class = 2.0
- m_amt = 50
- g_amt = 50
+ matter = list("metal" = 50, "glass" = 50)
/*
@@ -1606,7 +1592,7 @@ Code shamelessly copied from apc_frame
if (!(ndir in cardinal))
return
- var/turf/loc = get_turf_loc(usr)
+ var/turf/loc = get_turf(usr)
var/area/A = loc.loc
if (!istype(loc, /turf/simulated/floor))
usr << "\red Fire Alarm cannot be placed on this spot."
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index 107f67ee01e..64dcbe0c2fb 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -299,6 +299,9 @@ update_flag
if (href_list["remove_tank"])
if(holding)
+ if (valve_open)
+ valve_open = 0
+ release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding][i.name] N/A [i.damage] None:[mech] "
+ dat += " [i.name] N/A [i.damage] [infection]:[mech] "
dat += "
"
if(istype(holding, /obj/item/weapon/tank))
holding.manipulated_by = usr.real_name
holding.loc = loc
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 6a65e4812a5..080faf4b892 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -1,401 +1,371 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
-
-var/global/list/autolathe_recipes = list( \
- /* screwdriver removed*/ \
- new /obj/item/weapon/reagent_containers/glass/bucket(), \
- new /obj/item/weapon/crowbar(), \
- new /obj/item/device/flashlight(), \
- new /obj/item/weapon/extinguisher(), \
- new /obj/item/device/multitool(), \
- new /obj/item/device/t_scanner(), \
- new /obj/item/weapon/weldingtool(), \
- new /obj/item/weapon/screwdriver(), \
- new /obj/item/weapon/wirecutters(), \
- new /obj/item/weapon/wrench(), \
- new /obj/item/clothing/head/welding(), \
- new /obj/item/weapon/stock_parts/console_screen(), \
- new /obj/item/weapon/airlock_electronics(), \
- new /obj/item/weapon/airalarm_electronics(), \
- new /obj/item/weapon/firealarm_electronics(), \
- new /obj/item/weapon/module/power_control(), \
- new /obj/item/stack/sheet/metal(), \
- new /obj/item/stack/sheet/glass(), \
- new /obj/item/stack/sheet/rglass(), \
- new /obj/item/stack/rods(), \
- new /obj/item/weapon/rcd_ammo(), \
- new /obj/item/weapon/kitchenknife(), \
- new /obj/item/weapon/scalpel(), \
- new /obj/item/weapon/circular_saw(), \
- new /obj/item/weapon/surgicaldrill(),\
- new /obj/item/weapon/retractor(),\
- new /obj/item/weapon/cautery(),\
- new /obj/item/weapon/hemostat(),\
- new /obj/item/weapon/reagent_containers/glass/beaker(), \
- new /obj/item/weapon/reagent_containers/glass/beaker/large(), \
- new /obj/item/weapon/reagent_containers/glass/beaker/vial(), \
- new /obj/item/weapon/reagent_containers/syringe(), \
- new /obj/item/ammo_casing/shotgun/blank(), \
- new /obj/item/ammo_casing/shotgun/beanbag(), \
- new /obj/item/ammo_magazine/c45r(), \
- new /obj/item/device/taperecorder(), \
- new /obj/item/device/assembly/igniter(), \
- new /obj/item/device/assembly/signaler(), \
- new /obj/item/device/radio/headset(), \
- new /obj/item/device/radio/off(), \
- new /obj/item/device/assembly/infra(), \
- new /obj/item/device/assembly/timer(), \
- new /obj/item/device/assembly/prox_sensor(), \
- new /obj/item/weapon/light/tube(), \
- new /obj/item/weapon/light/bulb(), \
- new /obj/item/ashtray/glass(), \
- new /obj/item/weapon/camera_assembly(), \
- )
-
-var/global/list/autolathe_recipes_hidden = list( \
- new /obj/item/weapon/flamethrower/full(), \
- new /obj/item/weapon/rcd(), \
- new /obj/item/device/radio/electropack(), \
- new /obj/item/weapon/weldingtool/largetank(), \
- new /obj/item/weapon/handcuffs(), \
- new /obj/item/ammo_magazine/a357(), \
- new /obj/item/ammo_magazine/c45m(), \
- new /obj/item/ammo_casing/shotgun(), \
- new /obj/item/ammo_casing/shotgun/dart(), \
- /* new /obj/item/weapon/shield/riot(), */ \
- )
-
/obj/machinery/autolathe
- name = "\improper Autolathe"
+ name = "\improper autolathe"
desc = "It produces items using metal and glass."
icon_state = "autolathe"
density = 1
+ anchored = 1
+ use_power = 1
+ idle_power_usage = 10
+ active_power_usage = 100
- var/m_amount = 0.0
- var/max_m_amount = 150000.0
+ var/list/stored_material = list("metal" = 0, "glass" = 0)
+ var/list/storage_capacity = list("metal" = 0, "glass" = 0)
+ var/show_category = "All"
- var/g_amount = 0.0
- var/max_g_amount = 75000.0
-
- var/operating = 0.0
- var/opened = 0.0
- anchored = 1.0
- var/list/L = list()
- var/list/LL = list()
+ var/opened = 0
var/hacked = 0
var/disabled = 0
var/shocked = 0
+ var/busy = 0
+
var/list/wires = list()
var/hack_wire
var/disable_wire
var/shock_wire
- use_power = 1
- idle_power_usage = 10
- active_power_usage = 100
- var/busy = 0
- proc
- wires_win(mob/user as mob)
- var/dat as text
- dat += "Autolathe Wires:
"
- for(var/wire in src.wires)
- dat += text("[wire] Wire: [src.wires[wire] ? "Mend" : "Cut"] Pulse
")
+/obj/machinery/autolathe/interact(mob/user as mob)
- dat += text("The red light is [src.disabled ? "off" : "on"].
")
- dat += text("The green light is [src.shocked ? "off" : "on"].
")
- dat += text("The blue light is [src.hacked ? "off" : "on"].
")
- user << browse("
\nGlass Amount: [src.g_amount] cm3 (MAX: [max_g_amount])
")
- var/list/objs = list()
- objs += src.L
- if (src.hacked)
- objs += src.LL
- for(var/obj/t in objs)
- var/title = "[t.name] ([t.m_amt] m /[t.g_amt] g)"
- if (m_amount
"
- user << browse("Autolathe Control Panel
"
- var/amount = 1
- var/obj/item/stack/stack
- var/m_amt = O.m_amt
- var/g_amt = O.g_amt
- if (istype(O, /obj/item/stack))
- stack = O
- amount = stack.amount
- if (m_amt)
- amount = min(amount, round((max_m_amount-src.m_amount)/m_amt))
- flick("autolathe_o",src)//plays metal insertion animation
- if (g_amt)
- amount = min(amount, round((max_g_amount-src.g_amount)/g_amt))
- flick("autolathe_r",src)//plays glass insertion animation
- stack.use(amount)
+ dat += ""
+ var/material_top = "
"
+ var/material_bottom = " "
+
+ for(var/material in stored_material)
+ material_top += " [material_bottom][material] "
+ material_bottom += "[stored_material[material]]/[storage_capacity[material]] "
+
+ dat += "[material_top]
"
+ dat += "Printable Designs
Showing: [show_category].
"
+
+ var/index = 0
+ for(var/datum/autolathe/recipe/R in autolathe_recipes)
+ index++
+ if(R.hidden && !hacked || (show_category != "All" && show_category != R.category))
+ continue
+
+ var/can_make = 1
+ var/material_string = ""
+ var/multiplier_string = ""
+ var/max_sheets
+
+ var/comma
+ if(!R.resources || !R.resources.len)
+ material_string = "No resources required."
else
- usr.before_take_item(O)
- O.loc = src
- icon_state = "autolathe"
+
+ //Make sure it's buildable and list requires resources.
+ for(var/material in R.resources)
+ var/sheets = round(stored_material[material]/R.resources[material])
+ if(isnull(max_sheets) || max_sheets > sheets)
+ max_sheets = sheets
+
+ if(!isnull(stored_material[material]) && stored_material[material] < R.resources[material])
+ can_make = 0
+ if(!comma)
+ comma = 1
+ else
+ material_string += ", "
+ material_string += "[R.resources[material]] [material]"
+ material_string += ".
"
+
+ //Build list of multipliers for sheets.
+ if(R.is_stack)
+ if(max_sheets && max_sheets > 0)
+ multiplier_string += "
"
+ for(var/i = 5;i "
+
+ dat += "[R.hidden ? "*" : ""][can_make ? "" : ""][R.name][can_make ? "" : ""][R.hidden ? "*" : ""][multiplier_string] [material_string]
"
+
+ //Hacking.
+ if(opened)
+ dat += "Maintenance Panel
"
+ for(var/wire in wires)
+ dat += "[wire] Wire: [wires[wire] ? "Mend" : "Cut"] Pulse
"
+ dat += "
"
+ dat += "The red light is [disabled ? "off" : "on"].
"
+ dat += "The green light is [shocked ? "off" : "on"].
"
+ dat += "The blue light is [hacked ? "off" : "on"].
"
+
+ dat += "
"
+
+ user << browse(dat, "window=autolathe")
+ onclose(user, "autolathe")
+
+/obj/machinery/autolathe/attackby(var/obj/item/O as obj, var/mob/user as mob)
+
+ if (stat)
+ return
+
+ if (busy)
+ user << "\red \The [src] is busy. Please wait for completion of previous operation."
+ return
+
+ if(istype(O, /obj/item/weapon/screwdriver))
+ opened = !opened
+ icon_state = (opened ? "autolathe_t": "autolathe")
+ user << "You [opened ? "open" : "close"] the maintenance hatch of [src]."
+ updateUsrDialog()
+ return
+
+ if (opened)
+ //Dismantle the frame.
+ if(istype(O, /obj/item/weapon/crowbar))
+ dismantle()
+ return
+
+ //Resources are being loaded.
+ var/obj/item/eating = O
+ if(!eating.matter)
+ user << "\The [eating] does not contain significant amounts of useful materials and cannot be accepted."
+ return
+
+ var/filltype = 0 // Used to determine message.
+ var/total_used = 0 // Amount of material used.
+ var/mass_per_sheet = 0 // Amount of material constituting one sheet.
+
+ for(var/material in eating.matter)
+
+ if(isnull(stored_material[material]) || isnull(storage_capacity[material]))
+ continue
+
+ if(stored_material[material] >= storage_capacity[material])
+ continue
+
+ var/total_material = eating.matter[material]
+
+ //If it's a stack, we eat multiple sheets.
+ if(istype(eating,/obj/item/stack))
+ var/obj/item/stack/stack = eating
+ total_material *= stack.amount
+
+ if(stored_material[material] + total_material > storage_capacity[material])
+ total_material = storage_capacity[material] - stored_material[material]
+ filltype = 1
+ else
+ filltype = 2
+
+ stored_material[material] += total_material
+ total_used += total_material
+ mass_per_sheet += eating.matter[material]
+
+ if(!filltype)
+ user << "\red \The [src] is full. Please remove material from the autolathe in order to insert more."
+ return
+ else if(filltype == 1)
+ user << "You fill \the [src] to capacity with \the [eating]."
+ else
+ user << "You fill \the [src] with \the [eating]."
+
+ flick("autolathe_o",src) // Plays metal insertion animation. Work out a good way to work out a fitting animation. ~Z
+
+ if(istype(eating,/obj/item/stack))
+ var/obj/item/stack/stack = eating
+ stack.use(max(1,round(total_used/mass_per_sheet))) // Always use at least 1 to prevent infinite materials.
+ else
+ user.drop_item(O)
+ del(O)
+
+ updateUsrDialog()
+ return
+
+/obj/machinery/autolathe/attack_paw(mob/user as mob)
+ return attack_hand(user)
+
+/obj/machinery/autolathe/attack_hand(mob/user as mob)
+ user.set_machine(src)
+ interact(user)
+
+/obj/machinery/autolathe/Topic(href, href_list)
+
+ if(..())
+ return
+
+ usr.set_machine(src)
+ add_fingerprint(usr)
+
+ if(busy)
+ usr << "\red The autolathe is busy. Please wait for completion of previous operation."
+ return
+
+ if(href_list["change_category"])
+
+ var/choice = input("Which category do you wish to display?") as null|anything in autolathe_categories+"All"
+ if(!choice) return
+ show_category = choice
+
+ if(href_list["make"] && autolathe_recipes)
+
+ var/index = text2num(href_list["make"])
+ var/multiplier = text2num(href_list["multiplier"])
+ var/datum/autolathe/recipe/making
+
+ if(index > 0 && index <= autolathe_recipes.len)
+ making = autolathe_recipes[index]
+
+ //Exploit detection, not sure if necessary after rewrite.
+ if(!making || multiplier < 0 || multiplier > 100)
+ var/turf/exploit_loc = get_turf(usr)
+ message_admins("[key_name_admin(usr)] tried to exploit an autolathe to duplicate an item! ([exploit_loc ? "JMP" : "null"])", 0)
+ log_admin("EXPLOIT : [key_name(usr)] tried to exploit an autolathe to duplicate an item!")
+ return
+
busy = 1
- use_power(max(1000, (m_amt+g_amt)*amount/10))
- src.m_amount += m_amt * amount
- src.g_amount += g_amt * amount
- user << "You insert [amount] sheet[amount>1 ? "s" : ""] to the autolathe."
- if (O && O.loc == src)
- del(O)
+ //This needs some work.
+ use_power(max(2000, (making.power_use*multiplier)))
+
+ //Check if we still have the materials.
+ for(var/material in making.resources)
+ if(!isnull(stored_material[material]))
+ if(stored_material[material] < (making.resources[material]*multiplier))
+ return
+
+ //Consume materials.
+ for(var/material in making.resources)
+ if(!isnull(stored_material[material]))
+ stored_material[material] = max(0,stored_material[material]-(making.resources[material]*multiplier))
+
+ //Fancy autolathe animation.
+ flick("autolathe_n",src)
+
+ sleep(50)
+
busy = 0
- src.updateUsrDialog()
- attack_paw(mob/user as mob)
- return src.attack_hand(user)
+ //Sanity check.
+ if(!making || !src) return
- attack_hand(mob/user as mob)
- user.set_machine(src)
- interact(user)
+ //Create the desired item.
+ var/obj/item/I = new making.path(get_step(loc, get_dir(src,usr)))
+ if(multiplier>1 && istype(I,/obj/item/stack))
+ var/obj/item/stack/S = I
+ S.amount = multiplier
+
+ if(href_list["act"])
+
+ var/temp_wire = href_list["wire"]
+ if(href_list["act"] == "pulse")
+
+ if (!istype(usr.get_active_hand(), /obj/item/device/multitool))
+ usr << "You need a multitool!"
+ return
+
+ if(wires[temp_wire])
+ usr << "You can't pulse a cut wire."
+ return
+
+ if(hack_wire == temp_wire)
+ hacked = !hacked
+
+ spawn(100)
+ hacked = !hacked
+
+ if(disable_wire == temp_wire)
+ disabled = !disabled
+ shock(usr,50)
+
+ spawn(100)
+ disabled = !disabled
+
+ if(shock_wire == temp_wire)
+ shocked = !shocked
+ shock(usr,50)
+
+ spawn(100)
+ shocked = !shocked
+
+ else if(href_list["act"] == "wire")
+
+ if (!istype(usr.get_active_hand(), /obj/item/weapon/wirecutters))
+ usr << "You need wirecutters!"
+ return
+
+ wires[temp_wire] = !wires[temp_wire]
+
+ if(hack_wire == temp_wire)
+ hacked = !hacked
+
+ if(disable_wire == temp_wire)
+ disabled = !disabled
+ shock(usr,50)
+
+ if(shock_wire == temp_wire)
+ shocked = !shocked
+ shock(usr,50)
+
+ updateUsrDialog()
- Topic(href, href_list)
- if(..())
- return
- usr.set_machine(src)
- src.add_fingerprint(usr)
- if (!busy)
- if(href_list["make"])
- var/turf/T = get_step(src.loc, get_dir(src,usr))
-
- // critical exploit fix start -walter0o
- var/obj/item/template = null
- var/attempting_to_build = locate(href_list["make"])
+/obj/machinery/autolathe/New()
- if(!attempting_to_build)
- return
+ ..()
- if(locate(attempting_to_build, src.L) || locate(attempting_to_build, src.LL)) // see if the requested object is in one of the construction lists, if so, it is legit -walter0o
- template = attempting_to_build
-
- else // somebody is trying to exploit, alert admins -walter0o
-
- var/turf/LOC = get_turf(usr)
- message_admins("[key_name_admin(usr)] tried to exploit an autolathe to duplicate [attempting_to_build] ! ([LOC ? "JMP" : "null"])", 0)
- log_admin("EXPLOIT : [key_name(usr)] tried to exploit an autolathe to duplicate [attempting_to_build] !")
- return
-
- // now check for legit multiplier, also only stacks should pass with one to prevent raw-materials-manipulation -walter0o
-
- var/multiplier = text2num(href_list["multiplier"])
-
- if (!multiplier) multiplier = 1
- var/max_multiplier = 1
-
- if(istype(template, /obj/item/stack)) // stacks are the only items which can have a multiplier higher than 1 -walter0o
- var/obj/item/stack/S = template
- max_multiplier = min(S.max_amount, S.m_amt?round(m_amount/S.m_amt):INFINITY, S.g_amt?round(g_amount/S.g_amt):INFINITY) // pasta from regular_win() to make sure the numbers match -walter0o
-
- if( (multiplier > max_multiplier) || (multiplier <= 0) ) // somebody is trying to exploit, alert admins-walter0o
-
- var/turf/LOC = get_turf(usr)
- message_admins("[key_name_admin(usr)] tried to exploit an autolathe with multiplier set to [multiplier] on [template] ! ([LOC ? "JMP" : "null"])" , 0)
- log_admin("EXPLOIT : [key_name(usr)] tried to exploit an autolathe with multiplier set to [multiplier] on [template] !")
- return
-
- var/power = max(2000, (template.m_amt+template.g_amt)*multiplier/5)
- if(src.m_amount >= template.m_amt*multiplier && src.g_amount >= template.g_amt*multiplier)
- busy = 1
- use_power(power)
- icon_state = "autolathe"
- flick("autolathe_n",src)
- spawn(16)
- use_power(power)
- spawn(16)
- use_power(power)
- spawn(16)
- src.m_amount -= template.m_amt*multiplier
- src.g_amount -= template.g_amt*multiplier
- if(src.m_amount < 0)
- src.m_amount = 0
- if(src.g_amount < 0)
- src.g_amount = 0
- var/obj/new_item = new template.type(T)
- if (multiplier>1)
- var/obj/item/stack/S = new_item
- S.amount = multiplier
- busy = 0
- src.updateUsrDialog()
- if(href_list["act"])
- var/temp_wire = href_list["wire"]
- if(href_list["act"] == "pulse")
- if (!istype(usr.get_active_hand(), /obj/item/device/multitool))
- usr << "You need a multitool!"
- else
- if(src.wires[temp_wire])
- usr << "You can't pulse a cut wire."
- else
- if(src.hack_wire == temp_wire)
- src.hacked = !src.hacked
- spawn(100) src.hacked = !src.hacked
- if(src.disable_wire == temp_wire)
- src.disabled = !src.disabled
- src.shock(usr,50)
- spawn(100) src.disabled = !src.disabled
- if(src.shock_wire == temp_wire)
- src.shocked = !src.shocked
- src.shock(usr,50)
- spawn(100) src.shocked = !src.shocked
- if(href_list["act"] == "wire")
- if (!istype(usr.get_active_hand(), /obj/item/weapon/wirecutters))
- usr << "You need wirecutters!"
- else
- wires[temp_wire] = !wires[temp_wire]
- if(src.hack_wire == temp_wire)
- src.hacked = !src.hacked
- if(src.disable_wire == temp_wire)
- src.disabled = !src.disabled
- src.shock(usr,50)
- if(src.shock_wire == temp_wire)
- src.shocked = !src.shocked
- src.shock(usr,50)
- else
- usr << "\red The autolathe is busy. Please wait for completion of previous operation."
- src.updateUsrDialog()
- return
+ //Create global autolathe recipe list if it hasn't been made already.
+ if(isnull(autolathe_recipes))
+ autolathe_recipes = list()
+ autolathe_categories = list()
+ for(var/R in typesof(/datum/autolathe/recipe)-/datum/autolathe/recipe)
+ var/datum/autolathe/recipe/recipe = new R
+ autolathe_recipes += recipe
+ autolathe_categories |= recipe.category
+ var/obj/item/I = new recipe.path
+ if(I.matter && !recipe.resources) //This can be overidden in the datums.
+ recipe.resources = list()
+ for(var/material in I.matter)
+ if(!isnull(storage_capacity[material]))
+ recipe.resources[material] = round(I.matter[material]*1.25) // More expensive to produce than they are to recycle.
+ del(I)
+ //Create parts for lathe.
+ component_parts = list()
+ component_parts += new /obj/item/weapon/circuitboard/autolathe(src)
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
+ component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
+ component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
+ component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
RefreshParts()
- ..()
- var/tot_rating = 0
- for(var/obj/item/weapon/stock_parts/matter_bin/MB in component_parts)
- tot_rating += MB.rating
- tot_rating *= 25000
- max_m_amount = tot_rating * 2
- max_g_amount = tot_rating
- New()
- ..()
- component_parts = list()
- component_parts += new /obj/item/weapon/circuitboard/autolathe(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
- component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
- component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
- RefreshParts()
+ //Init wires.
+ wires = list(
+ "Light Red" = 0,
+ "Dark Red" = 0,
+ "Blue" = 0,
+ "Green" = 0,
+ "Yellow" = 0,
+ "Black" = 0,
+ "White" = 0,
+ "Gray" = 0,
+ "Orange" = 0,
+ "Pink" = 0
+ )
- src.L = autolathe_recipes
- src.LL = autolathe_recipes_hidden
- src.wires["Light Red"] = 0
- src.wires["Dark Red"] = 0
- src.wires["Blue"] = 0
- src.wires["Green"] = 0
- src.wires["Yellow"] = 0
- src.wires["Black"] = 0
- src.wires["White"] = 0
- src.wires["Gray"] = 0
- src.wires["Orange"] = 0
- src.wires["Pink"] = 0
- var/list/w = list("Light Red","Dark Red","Blue","Green","Yellow","Black","White","Gray","Orange","Pink")
- src.hack_wire = pick(w)
- w -= src.hack_wire
- src.shock_wire = pick(w)
- w -= src.shock_wire
- src.disable_wire = pick(w)
- w -= src.disable_wire
+ //Randomize wires.
+ var/list/w = list("Light Red","Dark Red","Blue","Green","Yellow","Black","White","Gray","Orange","Pink")
+ hack_wire = pick(w)
+ w -= hack_wire
+ shock_wire = pick(w)
+ w -= shock_wire
+ disable_wire = pick(w)
+ w -= disable_wire
+
+//Updates overall lathe storage size.
+/obj/machinery/autolathe/RefreshParts()
+ ..()
+ var/tot_rating = 0
+ for(var/obj/item/weapon/stock_parts/matter_bin/MB in component_parts)
+ tot_rating += MB.rating
+
+ storage_capacity["metal"] = tot_rating * 25000
+ storage_capacity["glass"] = tot_rating * 12500
\ No newline at end of file
diff --git a/code/game/machinery/autolathe_datums.dm b/code/game/machinery/autolathe_datums.dm
new file mode 100644
index 00000000000..04ce0401628
--- /dev/null
+++ b/code/game/machinery/autolathe_datums.dm
@@ -0,0 +1,304 @@
+/var/global/list/autolathe_recipes
+/var/global/list/autolathe_categories
+
+/datum/autolathe/recipe
+ var/name = "object"
+ var/path
+ var/list/resources
+ var/hidden
+ var/category
+ var/power_use = 0
+ var/is_stack
+
+/datum/autolathe/recipe/bucket
+ name = "bucket"
+ path = /obj/item/weapon/reagent_containers/glass/bucket
+ category = "General"
+
+/datum/autolathe/recipe/flashlight
+ name = "flashlight"
+ path = /obj/item/device/flashlight
+ category = "General"
+
+/datum/autolathe/recipe/extinguisher
+ name = "extinguisher"
+ path = /obj/item/weapon/extinguisher
+ category = "General"
+
+/datum/autolathe/recipe/crowbar
+ name = "crowbar"
+ path = /obj/item/weapon/crowbar
+ category = "Tools"
+
+/datum/autolathe/recipe/multitool
+ name = "multitool"
+ path = /obj/item/device/multitool
+ category = "Tools"
+
+/datum/autolathe/recipe/t_scanner
+ name = "T-ray scanner"
+ path = /obj/item/device/t_scanner
+ category = "Tools"
+
+/datum/autolathe/recipe/weldertool
+ name = "welding tool"
+ path = /obj/item/weapon/weldingtool
+ category = "Tools"
+
+/datum/autolathe/recipe/screwdriver
+ name = "screwdriver"
+ path = /obj/item/weapon/screwdriver
+ category = "Tools"
+
+/datum/autolathe/recipe/wirecutters
+ name = "wirecutters"
+ path = /obj/item/weapon/wirecutters
+ category = "Tools"
+
+/datum/autolathe/recipe/wrench
+ name = "wrench"
+ path = /obj/item/weapon/wrench
+ category = "Tools"
+
+/datum/autolathe/recipe/radio_headset
+ name = "radio headset"
+ path = /obj/item/device/radio/headset
+ category = "General"
+
+/datum/autolathe/recipe/radio_bounced
+ name = "station bounced radio"
+ path = /obj/item/device/radio/off
+ category = "General"
+
+/datum/autolathe/recipe/weldermask
+ name = "welding mask"
+ path = /obj/item/clothing/head/welding
+ category = "General"
+
+/datum/autolathe/recipe/metal
+ name = "steel sheets"
+ path = /obj/item/stack/sheet/metal
+ category = "General"
+ is_stack = 1
+
+/datum/autolathe/recipe/glass
+ name = "glass sheets"
+ path = /obj/item/stack/sheet/glass
+ category = "General"
+ is_stack = 1
+
+/datum/autolathe/recipe/rglass
+ name = "reinforced glass sheets"
+ path = /obj/item/stack/sheet/rglass
+ category = "General"
+ is_stack = 1
+
+/datum/autolathe/recipe/rods
+ name = "metal rods"
+ path = /obj/item/stack/rods
+ category = "General"
+ is_stack = 1
+
+/datum/autolathe/recipe/knife
+ name = "kitchen knife"
+ path = /obj/item/weapon/kitchenknife
+ category = "General"
+
+/datum/autolathe/recipe/taperecorder
+ name = "tape recorder"
+ path = /obj/item/device/taperecorder
+ category = "General"
+
+/datum/autolathe/recipe/airlockmodule
+ name = "airlock electronics"
+ path = /obj/item/weapon/airlock_electronics
+ category = "Engineering"
+
+/datum/autolathe/recipe/airalarm
+ name = "air alarm electronics"
+ path = /obj/item/weapon/airalarm_electronics
+ category = "Engineering"
+
+/datum/autolathe/recipe/firealarm
+ name = "fire alarm electronics"
+ path = /obj/item/weapon/firealarm_electronics
+ category = "Engineering"
+
+/datum/autolathe/recipe/powermodule
+ name = "power control module"
+ path = /obj/item/weapon/module/power_control
+ category = "Engineering"
+
+/datum/autolathe/recipe/rcd_ammo
+ name = "matter cartridge"
+ path = /obj/item/weapon/rcd_ammo
+ category = "Engineering"
+
+/datum/autolathe/recipe/scalpel
+ name = "scalpel"
+ path = /obj/item/weapon/scalpel
+ category = "Medical"
+
+/datum/autolathe/recipe/circularsaw
+ name = "circular saw"
+ path = /obj/item/weapon/circular_saw
+ category = "Medical"
+
+/datum/autolathe/recipe/surgicaldrill
+ name = "surgical drill"
+ path = /obj/item/weapon/surgicaldrill
+ category = "Medical"
+
+/datum/autolathe/recipe/retractor
+ name = "retractor"
+ path = /obj/item/weapon/retractor
+ category = "Medical"
+
+/datum/autolathe/recipe/cautery
+ name = "cautery"
+ path = /obj/item/weapon/cautery
+ category = "Medical"
+
+/datum/autolathe/recipe/hemostat
+ name = "hemostat"
+ path = /obj/item/weapon/hemostat
+ category = "Medical"
+
+/datum/autolathe/recipe/beaker
+ name = "glass beaker"
+ path = /obj/item/weapon/reagent_containers/glass/beaker
+ category = "Medical"
+
+/datum/autolathe/recipe/beaker_large
+ name = "large glass beaker"
+ path = /obj/item/weapon/reagent_containers/glass/beaker/large
+ category = "Medical"
+
+/datum/autolathe/recipe/vial
+ name = "glass vial"
+ path = /obj/item/weapon/reagent_containers/glass/beaker/vial
+ category = "Medical"
+
+/datum/autolathe/recipe/syringe
+ name = "syringe"
+ path = /obj/item/weapon/reagent_containers/syringe
+ category = "Medical"
+
+/datum/autolathe/recipe/shotgun_blanks
+ name = "ammunition (shotgun, blanks)"
+ path = /obj/item/ammo_casing/shotgun/blank
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/shotgun_beanbag
+ name = "ammunition (shotgun, beanbag)"
+ path = /obj/item/ammo_casing/shotgun/beanbag
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/magazine_rubber
+ name = "ammunition (rubber)"
+ path = /obj/item/ammo_magazine/c45r
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/consolescreen
+ name = "console screen"
+ path = /obj/item/weapon/stock_parts/console_screen
+ category = "Devices and Components"
+
+/datum/autolathe/recipe/igniter
+ name = "igniter"
+ path = /obj/item/device/assembly/igniter
+ category = "Devices and Components"
+
+/datum/autolathe/recipe/signaler
+ name = "signaler"
+ path = /obj/item/device/assembly/signaler
+ category = "Devices and Components"
+
+/datum/autolathe/recipe/sensor_infra
+ name = "infrared sensor"
+ path = /obj/item/device/assembly/infra
+ category = "Devices and Components"
+
+/datum/autolathe/recipe/timer
+ name = "timer"
+ path = /obj/item/device/assembly/timer
+ category = "Devices and Components"
+
+/datum/autolathe/recipe/sensor_prox
+ name = "proximity sensor"
+ path = /obj/item/device/assembly/prox_sensor
+ category = "Devices and Components"
+
+/datum/autolathe/recipe/tube
+ name = "light tube"
+ path = /obj/item/weapon/light/tube
+ category = "General"
+
+/datum/autolathe/recipe/bulb
+ name = "light bulb"
+ path = /obj/item/weapon/light/bulb
+ category = "General"
+
+/datum/autolathe/recipe/ashtray_glass
+ name = "glass ashtray"
+ path = /obj/item/ashtray/glass
+ category = "General"
+
+/datum/autolathe/recipe/camera_assembly
+ name = "camera assembly"
+ path = /obj/item/weapon/camera_assembly
+ category = "Engineering"
+
+/datum/autolathe/recipe/flamethrower
+ name = "flamethrower"
+ path = /obj/item/weapon/flamethrower/full
+ hidden = 1
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/magazine_revolver_1
+ name = "ammunition (.357)"
+ path = /obj/item/ammo_magazine/a357
+ hidden = 1
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/magazine_revolver_2
+ name = "ammunition (.45)"
+ path = /obj/item/ammo_magazine/c45m
+ hidden = 1
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/shotgun
+ name = "ammunition (shell, shotgun)"
+ path = /obj/item/ammo_casing/shotgun
+ hidden = 1
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/shotgun_dart
+ name = "ammunition (dart, shotgun)"
+ path = /obj/item/ammo_casing/shotgun/dart
+ hidden = 1
+ category = "Arms and Ammunition"
+
+/datum/autolathe/recipe/rcd
+ name = "rapid construction device"
+ path = /obj/item/weapon/rcd
+ hidden = 1
+ category = "Engineering"
+
+/datum/autolathe/recipe/electropack
+ name = "electropack"
+ path = /obj/item/device/radio/electropack
+ hidden = 1
+ category = "Devices and Components"
+
+/datum/autolathe/recipe/welder_industrial
+ name = "industrial welding tool"
+ path = /obj/item/weapon/weldingtool/largetank
+ hidden = 1
+ category = "Tools"
+
+/datum/autolathe/recipe/handcuffs
+ name = "handcuffs"
+ path = /obj/item/weapon/handcuffs
+ hidden = 1
+ category = "General"
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 5d206b9f94b..b50d38dcb6a 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -94,11 +94,6 @@
src.view_range = num
cameranet.updateVisibility(src, 0)
-/obj/machinery/camera/proc/shock(var/mob/living/user)
- if(!istype(user))
- return
- user.electrocute_act(10, src)
-
/obj/machinery/camera/attack_paw(mob/living/carbon/alien/humanoid/user as mob)
if(!istype(user))
return
diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm
index a57140b6e39..8f0739b13ea 100644
--- a/code/game/machinery/camera/camera_assembly.dm
+++ b/code/game/machinery/camera/camera_assembly.dm
@@ -6,8 +6,7 @@
w_class = 2
anchored = 0
- m_amt = 700
- g_amt = 300
+ matter = list("metal" = 700,"glass" = 300)
// Motion, EMP-Proof, X-Ray
var/list/obj/item/possible_upgrades = list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/sheet/mineral/phoron, /obj/item/weapon/reagent_containers/food/snacks/grown/carrot)
diff --git a/code/game/machinery/camera/wires.dm b/code/game/machinery/camera/wires.dm
index 13f0a858616..785b33368a2 100644
--- a/code/game/machinery/camera/wires.dm
+++ b/code/game/machinery/camera/wires.dm
@@ -50,7 +50,6 @@
if(CAMERA_WIRE_POWER)
deactivate(usr, 1)
- //shock(usr)
if(CAMERA_WIRE_LIGHT)
light_disabled = 1
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 69a8dba4780..ee06823cae1 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -183,6 +183,7 @@
H << "Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?"
// -- Mode/mind specific stuff goes here
+ callHook("clone", list(H))
switch(ticker.mode.name)
if("revolution")
@@ -303,6 +304,21 @@
user.drop_item()
del(W)
return
+ else if (istype(W, /obj/item/weapon/wrench))
+ if(src.locked && (src.anchored || src.occupant))
+ user << "\red Can not do that while [src] is in use."
+ else
+ if(src.anchored)
+ src.anchored = 0
+ connected.pod1 = null
+ connected = null
+ else
+ src.anchored = 1
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1)
+ if(anchored)
+ user.visible_message("[user] secures [src] to the floor.", "You secure [src] to the floor.")
+ else
+ user.visible_message("[user] unsecures [src] from the floor.", "You unsecure [src] from the floor.")
else
..()
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index 3c6fbd991a3..03ae77614f8 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -169,10 +169,7 @@
build_path = "/obj/machinery/computer/supplycomp"
origin_tech = "programming=3"
var/contraband_enabled = 0
-/obj/item/weapon/circuitboard/research_shuttle
- name = "Circuit board (Research Shuttle)"
- build_path = "/obj/machinery/computer/research_shuttle"
- origin_tech = "programming=2"
+
/obj/item/weapon/circuitboard/operating
name = "Circuit board (Operating Computer)"
build_path = "/obj/machinery/computer/operating"
@@ -196,14 +193,17 @@
/obj/item/weapon/circuitboard/splicer
name = "Circuit board (Disease Splicer)"
build_path = "/obj/machinery/computer/diseasesplicer"
-
/obj/item/weapon/circuitboard/mining_shuttle
name = "Circuit board (Mining Shuttle)"
- build_path = "/obj/machinery/computer/mining_shuttle"
+ build_path = "/obj/machinery/computer/shuttle_control/mining"
+ origin_tech = "programming=2"
+/obj/item/weapon/circuitboard/engineering_shuttle
+ name = "Circuit board (Engineering Shuttle)"
+ build_path = "/obj/machinery/computer/shuttle_control/engineering"
origin_tech = "programming=2"
/obj/item/weapon/circuitboard/research_shuttle
name = "Circuit board (Research Shuttle)"
- build_path = "/obj/machinery/computer/research_shuttle"
+ build_path = "/obj/machinery/computer/shuttle_control/research"
origin_tech = "programming=2"
/obj/item/weapon/circuitboard/HolodeckControl // Not going to let people get this, but it's just here for future
name = "Circuit board (Holodeck Control)"
diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm
index 8c86629de36..78e0b16c641 100644
--- a/code/game/machinery/computer/card.dm
+++ b/code/game/machinery/computer/card.dm
@@ -2,256 +2,124 @@
/obj/machinery/computer/card
name = "Identification Computer"
- desc = "You can use this to change ID's."
+ desc = "Terminal for programming NanoTrasen employee ID cards to access parts of the station."
icon_state = "id"
req_access = list(access_change_ids)
circuit = "/obj/item/weapon/circuitboard/card"
var/obj/item/weapon/card/id/scan = null
var/obj/item/weapon/card/id/modify = null
- var/authenticated = 0.0
var/mode = 0.0
var/printing = null
+ proc/is_centcom()
+ return istype(src, /obj/machinery/computer/card/centcom)
-/obj/machinery/computer/card/attackby(O as obj, user as mob)//TODO:SANITY
- if(istype(O, /obj/item/weapon/card/id))
- var/obj/item/weapon/card/id/idcard = O
- if(access_change_ids in idcard.access)
- if(!scan)
- usr.drop_item()
- idcard.loc = src
- scan = idcard
- else if(!modify)
- usr.drop_item()
- idcard.loc = src
- modify = idcard
- else
- if(!modify)
- usr.drop_item()
- idcard.loc = src
- modify = idcard
- else
- ..()
+ proc/is_authenticated()
+ return scan ? check_access(scan) : 0
+ proc/get_target_rank()
+ return modify && modify.assignment ? modify.assignment : "Unassigned"
+
+ proc/format_jobs(list/jobs)
+ var/list/formatted = list()
+ for(var/job in jobs)
+ formatted.Add(list(list(
+ "display_name" = replacetext(job, " ", " "),
+ "target_rank" = get_target_rank(),
+ "job" = job)))
+
+ return formatted
+
+/obj/machinery/computer/card/attackby(obj/item/weapon/card/id/id_card, mob/user)
+ if(!istype(id_card))
+ return ..()
+
+ if(!scan && access_change_ids in id_card.access)
+ user.drop_item()
+ id_card.loc = src
+ scan = id_card
+ else if(!modify)
+ user.drop_item()
+ id_card.loc = src
+ modify = id_card
+
+ nanomanager.update_uis(src)
+ attack_hand(user)
/obj/machinery/computer/card/attack_ai(var/mob/user as mob)
return attack_hand(user)
-
/obj/machinery/computer/card/attack_paw(var/mob/user as mob)
return attack_hand(user)
+/obj/machinery/computer/card/attack_hand(mob/user as mob)
+ if(..()) return
+ if(stat & (NOPOWER|BROKEN)) return
+ ui_interact(user)
-/obj/machinery/computer/card/attack_hand(var/mob/user as mob)
- if(..())
- return
-
+/obj/machinery/computer/card/ui_interact(mob/user, ui_key="main", datum/nanoui/ui=null)
user.set_machine(src)
- var/dat
- if (!( ticker ))
- return
- if (mode) // accessing crew manifest
- dat += "Crew Manifest
"
- dat += "Entries cannot be modified from this terminal.
"
- if(data_core)
- dat += data_core.get_manifest(0) // make it monochrome
- dat += "
"
- dat += "Print
"
- dat += "
"
- dat += "Access ID modification console.
"
+ var/data[0]
+ data["src"] = "\ref[src]"
+ data["station_name"] = station_name()
+ data["mode"] = mode
+ data["printing"] = printing
+ data["manifest"] = data_core ? data_core.get_manifest(0) : null
+ data["target_name"] = modify ? modify.name : "-----"
+ data["target_owner"] = modify && modify.registered_name ? modify.registered_name : "-----"
+ data["target_rank"] = get_target_rank()
+ data["scan_name"] = scan ? scan.name : "-----"
+ data["authenticated"] = is_authenticated()
+ data["has_modify"] = !!modify
+ data["account_number"] = modify ? modify.associated_account_number : null
+ data["centcom_access"] = is_centcom()
+ data["all_centcom_access"] = null
+ data["regions"] = null
- /*var/crew = ""
- var/list/L = list()
- for (var/datum/data/record/t in data_core.general)
- var/R = t.fields["name"] + " - " + t.fields["rank"]
- L += R
- for(var/R in sortList(L))
- crew += "[R]
"*/
- //dat = "Crew Manifest:
Please use security record computer to modify entries.
[crew]Print
Access ID modification console.
"
- else
- var/header = "
Please insert the cards into the slots
"
- header += "Target: [target_name]
"
- header += "Confirm Identity: [scan_name]
"
- else
- header += "
"
- header += "Remove [target_name] || "
- header += "Remove [scan_name]
"
- header += "Access Crew Manifest || "
- header += "Log Out
"
-
- var/jobs_all = ""
- var/counter = 0
- jobs_all += "
"
+ //Spam filter modification
+ if(5)
+ dat += "Command "
-
- jobs_all += "Special "//Captain in special because he is head of heads ~Intercross21
- jobs_all += "Captain "
- jobs_all += "Custom "
-
- counter = 0
- jobs_all += "Security "//Red
- for(var/job in security_positions)
- counter++
- if(counter >= 6)
- jobs_all += ""
- counter = 0
- jobs_all += " [replacetext(job, " ", " ")] "
-
- counter = 0
- jobs_all += "Engineering "//Orange
- for(var/job in engineering_positions)
- counter++
- if(counter >= 6)
- jobs_all += ""
- counter = 0
- jobs_all += " [replacetext(job, " ", " ")] "
-
- counter = 0
- jobs_all += "Medical "//Green
- for(var/job in medical_positions)
- counter++
- if(counter >= 6)
- jobs_all += ""
- counter = 0
- jobs_all += " [replacetext(job, " ", " ")] "
-
- counter = 0
- jobs_all += "Science "//Purple
- for(var/job in science_positions)
- counter++
- if(counter >= 6)
- jobs_all += ""
- counter = 0
- jobs_all += " [replacetext(job, " ", " ")] "
-
- counter = 0
- jobs_all += "Civilian "//Grey
- for(var/job in civilian_positions)
- counter++
- if(counter >= 6)
- jobs_all += ""
- counter = 0
- jobs_all += " [replacetext(job, " ", " ")] "
-
- if(istype(src,/obj/machinery/computer/card/centcom))
- counter = 0
- jobs_all += "CentComm "//Brown
- for(var/job in get_all_centcom_jobs())
- if(counter >= 6)
- jobs_all += " "}
dat += ""
- counter = 0
- jobs_all += " [replacetext(job, " ", " ")] "
-
- var/body
- if (authenticated && modify)
- var/carddesc = {""}
- carddesc += ""
-
- carddesc += ""
-
- carddesc += "Assignment: "
- var/jobs = "[target_rank]" //CHECK THIS
- var/accesses = ""
- if(istype(src,/obj/machinery/computer/card/centcom))
- accesses += "Central Command:
"
- for(var/A in get_all_centcom_access())
- if(A in modify.access)
- accesses += "[replacetext(get_centcom_access_desc(A), " ", " ")] "
- else
- accesses += "[replacetext(get_centcom_access_desc(A), " ", " ")] "
- else
- accesses += ""
- accesses += "
"
- body = "[carddesc]"
- for(var/i = 1; i <= 7; i++)
- accesses += " [get_region_accesses_name(i)]: "
- accesses += ""
- for(var/i = 1; i <= 7; i++)
- accesses += " "
- for(var/A in get_region_accesses(i))
- if(A in modify.access)
- accesses += "[replacetext(get_access_desc(A), " ", " ")] "
- else
- accesses += "[replacetext(get_access_desc(A), " ", " ")] "
- accesses += " "
- accesses += "
"
- accesses += "
[jobs]
[accesses]" //CHECK THIS
- else
- body = "{Log in}
"
- body += "Access Crew Manifest"
- dat = "[header][body]
"
- user << browse(dat, "window=id_com;size=900x520")
- onclose(user, "id_com")
- return
+ data["regions"] = regions
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
+ if (!ui)
+ ui = new(user, src, ui_key, "identification_computer.tmpl", src.name, 600, 700)
+ ui.set_initial_data(data)
+ ui.open()
/obj/machinery/computer/card/Topic(href, href_list)
if(..())
- return
- usr.set_machine(src)
+ return 1
+
switch(href_list["choice"])
if ("modify")
if (modify)
@@ -271,7 +139,6 @@
usr.drop_item()
I.loc = src
modify = I
- authenticated = 0
if ("scan")
if (scan)
@@ -289,26 +156,19 @@
usr.drop_item()
I.loc = src
scan = I
- authenticated = 0
- if ("auth")
- if ((!( authenticated ) && (scan || (istype(usr, /mob/living/silicon))) && (modify || mode)))
- if (check_access(scan))
- authenticated = 1
- else if ((!( authenticated ) && (istype(usr, /mob/living/silicon))) && (!modify))
- usr << "You can't modify an ID without an ID inserted to modify. Once one is in the modify slot on the computer, you can log in."
- if ("logout")
- authenticated = 0
+
if("access")
if(href_list["allowed"])
- if(authenticated)
+ if(is_authenticated())
var/access_type = text2num(href_list["access_target"])
var/access_allowed = text2num(href_list["allowed"])
- if(access_type in (istype(src,/obj/machinery/computer/card/centcom)?get_all_centcom_access() : get_all_accesses()))
+ if(access_type in (is_centcom() ? get_all_centcom_access() : get_all_accesses()))
modify.access -= access_type
- if(access_allowed == 1)
+ if(!access_allowed)
modify.access += access_type
+
if ("assign")
- if (authenticated)
+ if (is_authenticated() && modify)
var/t1 = href_list["assign_target"]
if(t1 == "Custom")
var/temp_t = copytext(sanitize(input("Enter a custom job assignment.","Assignment")),1,45)
@@ -316,69 +176,92 @@
if(temp_t && modify)
modify.assignment = temp_t
else
- var/datum/job/jobdatum
- for(var/jobtype in typesof(/datum/job))
- var/datum/job/J = new jobtype
- if(ckey(J.title) == ckey(t1))
- jobdatum = J
- break
- if(!jobdatum)
- usr << "\red No log exists for this job."
- return
+ var/list/access = list()
+ if(is_centcom())
+ access = get_centcom_access(t1)
+ else
+ var/datum/job/jobdatum
+ for(var/jobtype in typesof(/datum/job))
+ var/datum/job/J = new jobtype
+ if(ckey(J.title) == ckey(t1))
+ jobdatum = J
+ break
+ if(!jobdatum)
+ usr << "\red No log exists for this job: [t1]"
+ return
+
+ access = jobdatum.get_access()
+
+ modify.access = access
+ modify.assignment = t1
+ modify.rank = t1
+
+ callHook("reassign_employee", list(modify))
- modify.access = ( istype(src,/obj/machinery/computer/card/centcom) ? get_centcom_access(t1) : jobdatum.get_access() )
- if (modify)
- modify.assignment = t1
- modify.rank = t1
if ("reg")
- if (authenticated)
+ if (is_authenticated())
var/t2 = modify
- //var/t1 = input(usr, "What name?", "ID computer", null) as text
- if ((authenticated && modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf)))
+ if ((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf)))
var/temp_name = reject_bad_name(href_list["reg"])
if(temp_name)
modify.registered_name = temp_name
else
src.visible_message("[src] buzzes rudely.")
+ nanomanager.update_uis(src)
+
if ("account")
- if (authenticated)
+ if (is_authenticated())
var/t2 = modify
- //var/t1 = input(usr, "What name?", "ID computer", null) as text
- if ((authenticated && modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf)))
+ if ((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf)))
var/account_num = text2num(href_list["account"])
modify.associated_account_number = account_num
+ nanomanager.update_uis(src)
+
if ("mode")
mode = text2num(href_list["mode_target"])
+
if ("print")
- if (!( printing ))
+ if (!printing)
printing = 1
- sleep(50)
- var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( loc )
- /*var/t1 = "Crew Manifest:
"
- var/list/L = list()
- for (var/datum/data/record/t in data_core.general)
- var/R = t.fields["name"] + " - " + t.fields["rank"]
- L += R
- for(var/R in sortList(L))
- t1 += "[R]
"*/
+ spawn(50)
+ printing = null
+ nanomanager.update_uis(src)
- var/t1 = "Crew Manifest
"
- t1 += "
"
- if(data_core)
- t1 += data_core.get_manifest(0) // make it monochrome
+ var/obj/item/weapon/paper/P = new(loc)
+ if (mode)
+ P.name = text("crew manifest ([])", worldtime2text())
+ P.info = {"Crew Manifest
+
+ [data_core ? data_core.get_manifest(0) : ""]
+ "}
+ else if (modify)
+ P.name = "access report"
+ P.info = {"Access Report
+ Prepared By: [scan.registered_name ? scan.registered_name : "Unknown"]
+ For: [modify.registered_name ? modify.registered_name : "Unregistered"]
+
+ Assignment: [modify.assignment]
+ Account Number: #[modify.associated_account_number]
+ Blood Type: [modify.blood_type]
+ Access:
+ "}
+
+ for(var/A in modify.access)
+ P.info += " [get_access_desc(A)]"
+
+ if ("terminate")
+ if (is_authenticated())
+ modify.assignment = "Terminated"
+ modify.access = list()
+
+ callHook("terminate_employee", list(modify))
- P.info = t1
- P.name = text("Crew Manifest ([])", worldtime2text())
- printing = null
if (modify)
modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])")
- updateUsrDialog()
- return
-
+ return 1
/obj/machinery/computer/card/centcom
name = "CentCom Identification Computer"
circuit = "/obj/item/weapon/circuitboard/card/centcom"
req_access = list(access_cent_captain)
-
diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm
index 49d12a48478..bb8d5fd997d 100644
--- a/code/game/machinery/computer/crew.dm
+++ b/code/game/machinery/computer/crew.dm
@@ -16,14 +16,14 @@
/obj/machinery/computer/crew/attack_ai(mob/user)
attack_hand(user)
- interact(user)
+ ui_interact(user)
/obj/machinery/computer/crew/attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
- interact(user)
+ ui_interact(user)
/obj/machinery/computer/crew/update_icon()
@@ -43,67 +43,68 @@
if(..()) return
if (src.z > 6)
usr << "\red Unable to establish a connection: \black You're too far away from the station!"
- return
+ return 0
if( href_list["close"] )
- usr << browse(null, "window=crewcomp")
+ var/mob/user = usr
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main")
usr.unset_machine()
- return
+ ui.close()
+ return 0
if(href_list["update"])
src.updateDialog()
- return
-
+ return 1
/obj/machinery/computer/crew/interact(mob/user)
+ ui_interact(user)
+
+/obj/machinery/computer/crew/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
if(stat & (BROKEN|NOPOWER))
return
- if(!istype(user, /mob/living/silicon) && get_dist(src, user) > 1)
- user.unset_machine()
- user << browse(null, "window=powcomp")
- return
user.set_machine(src)
src.scan()
- var/t = "Crew Monitoring
"
- t += "
Refresh "
- t += "Close
"
- t += "
"
- t += ""
- user << browse(t, "window=crewcomp;size=900x600")
- onclose(user, "crewcomp")
+ crewmembers = sortByKey(crewmembers, "name")
+
+ data["crewmembers"] = crewmembers
+
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
+ if(!ui)
+ ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 600)
+ ui.set_initial_data(data)
+ ui.open()
+
+ // should make the UI auto-update; doesn't seem to?
+ ui.set_auto_update(1)
/obj/machinery/computer/crew/proc/scan()
diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm
index 0cfc5fe3622..60e7ac0484d 100644
--- a/code/game/machinery/computer/message.dm
+++ b/code/game/machinery/computer/message.dm
@@ -26,7 +26,7 @@
var/emag = 0 // When it is emagged.
var/message = "System bootup complete. Please select an option." // The message that shows on the main menu.
var/auth = 0 // Are they authenticated?
- var/optioncount = 7
+ var/optioncount = 8
// Custom Message Properties
var/customsender = "System Administrator"
var/obj/item/device/pda/customrecepient = null
@@ -122,6 +122,7 @@
dat += " "
- var/list/logs = list()
+
+ var/data[0]
+ var/list/crewmembers = list()
+
for(var/obj/item/clothing/under/C in src.tracked)
- var/log = ""
+
+
var/turf/pos = get_turf(C)
+
if((C) && (C.has_sensor) && (pos) && (pos.z == src.z) && C.sensor_mode)
if(istype(C.loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = C.loc
- var/dam1 = round(H.getOxyLoss(),1)
- var/dam2 = round(H.getToxLoss(),1)
- var/dam3 = round(H.getFireLoss(),1)
- var/dam4 = round(H.getBruteLoss(),1)
+ var/list/crewmemberData = list()
- var/life_status = "[H.stat > 1 ? "Deceased" : "Living"]"
- var/damage_report = "([dam1]/[dam2]/[dam3]/[dam4])"
+ crewmemberData["sensor_type"] = C.sensor_mode
+ crewmemberData["dead"] = H.stat > 1
+ crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
+ crewmemberData["tox"] = round(H.getToxLoss(), 1)
+ crewmemberData["fire"] = round(H.getFireLoss(), 1)
+ crewmemberData["brute"] = round(H.getBruteLoss(), 1)
+ crewmemberData["name"] = (H.wear_id ? H.wear_id.name : "Unknown")
+ crewmemberData["area"] = get_area(H)
+ crewmemberData["x"] = pos.x
+ crewmemberData["y"] = pos.y
- if(H.wear_id)
- log += "Name Vitals Position [H.wear_id.name] "
- else
- log += " "
- if(2)
- log += "Unknown "
+ // Works around list += list2 merging lists; it's not pretty but it works
+ crewmembers += "temporary item"
+ crewmembers[crewmembers.len] = crewmemberData
- switch(C.sensor_mode)
- if(1)
- log += "[life_status] Not Available [life_status] [damage_report] Not Available "
- if(3)
- var/area/player_area = get_area(H)
- log += "[life_status] [damage_report] [player_area.name] ([pos.x], [pos.y]) "
- logs += log
- logs = sortList(logs)
- for(var/log in logs)
- t += log
- t += "[rc.rec_dpt] [rc.message] [rc.stamp] [rc.id_auth] [rc.priority]
"
+ var/index = 0
+ for(var/token in src.linkedServer.spamfilter)
+ index++
+ if(index > 3000)
+ break
+ dat += "
"
+ if (linkedServer.spamfilter.len < linkedServer.spamfilter_limit)
+ dat += "Add token
"
+
dat += "
"
message = defaultmsg
@@ -485,6 +499,26 @@
//usr << href_list["select"]
+ if(href_list["spam"])
+ if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN)))
+ message = noserver
+ else
+ if(auth)
+ src.screen = 5
+
+ if(href_list["addtoken"])
+ if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN)))
+ message = noserver
+ else
+ src.linkedServer.spamfilter += input(usr,"Enter text you want to be filtered out","Token creation") as text|null
+
+ if(href_list["deltoken"])
+ if(src.linkedServer == null || (src.linkedServer.stat & (NOPOWER|BROKEN)))
+ message = noserver
+ else
+ var/tokennum = text2num(href_list["deltoken"])
+ src.linkedServer.spamfilter.Cut(tokennum,tokennum+1)
+
if (href_list["back"])
src.screen = 0
diff --git a/code/game/machinery/computer/prisoner.dm b/code/game/machinery/computer/prisoner.dm
index ca0512e2cbd..cb3e0f8f11b 100644
--- a/code/game/machinery/computer/prisoner.dm
+++ b/code/game/machinery/computer/prisoner.dm
@@ -50,7 +50,7 @@
var/loc_display = "Unknown"
var/mob/living/carbon/M = T.imp_in
if(M.z == 1 && !istype(M.loc, /turf/space))
- var/turf/mob_loc = get_turf_loc(M)
+ var/turf/mob_loc = get_turf(M)
loc_display = mob_loc.loc
if(T.malfunction)
loc_display = pick(teleportlocs)
diff --git a/code/game/machinery/computer/syndicate_shuttle.dm b/code/game/machinery/computer/syndicate_shuttle.dm
deleted file mode 100644
index 681fc65fe97..00000000000
--- a/code/game/machinery/computer/syndicate_shuttle.dm
+++ /dev/null
@@ -1,104 +0,0 @@
-#define SYNDICATE_SHUTTLE_MOVE_TIME 240
-#define SYNDICATE_SHUTTLE_COOLDOWN 200
-
-/obj/machinery/computer/syndicate_station
- name = "syndicate shuttle terminal"
- icon = 'icons/obj/computer.dmi'
- icon_state = "syndishuttle"
- req_access = list(access_syndicate)
- var/area/curr_location
- var/moving = 0
- var/lastMove = 0
-
-
-/obj/machinery/computer/syndicate_station/New()
- curr_location= locate(/area/syndicate_station/start)
-
-
-/obj/machinery/computer/syndicate_station/proc/syndicate_move_to(area/destination as area)
- if(moving) return
- if(lastMove + SYNDICATE_SHUTTLE_COOLDOWN > world.time) return
- var/area/dest_location = locate(destination)
- if(curr_location == dest_location) return
-
- moving = 1
- lastMove = world.time
-
- if(curr_location.z != dest_location.z)
- var/area/transit_location = locate(/area/syndicate_station/transit)
- curr_location.move_contents_to(transit_location)
- curr_location = transit_location
- sleep(SYNDICATE_SHUTTLE_MOVE_TIME)
-
- curr_location.move_contents_to(dest_location)
- curr_location = dest_location
- moving = 0
- return 1
-
-
-/obj/machinery/computer/syndicate_station/attackby(obj/item/I as obj, mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/syndicate_station/attack_ai(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/syndicate_station/attack_paw(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/syndicate_station/attack_hand(mob/user as mob)
- if(!allowed(user))
- user << "\red Access Denied"
- return
-
- user.set_machine(src)
-
- var/dat = {"Location: [curr_location]
- Ready to move[max(lastMove + SYNDICATE_SHUTTLE_COOLDOWN - world.time, 0) ? " in [max(round((lastMove + SYNDICATE_SHUTTLE_COOLDOWN - world.time) * 0.1), 0)] seconds" : ": now"]
- Syndicate Space
- North West of SS13 |
- North of SS13 |
- North East of SS13
- South West of SS13 |
- South of SS13 |
- South East of SS13
- South of the Communication Satellite |
- North East of the Mining Asteroid
- Close"}
-
- user << browse(dat, "window=computer;size=575x450")
- onclose(user, "computer")
- return
-
-
-/obj/machinery/computer/syndicate_station/Topic(href, href_list)
- if(!isliving(usr)) return
- var/mob/living/user = usr
-
- if(in_range(src, user) || istype(user, /mob/living/silicon))
- user.set_machine(src)
-
- if(href_list["syndicate"])
- syndicate_move_to(/area/syndicate_station/start)
- else if(href_list["station_nw"])
- syndicate_move_to(/area/syndicate_station/northwest)
- else if(href_list["station_n"])
- syndicate_move_to(/area/syndicate_station/north)
- else if(href_list["station_ne"])
- syndicate_move_to(/area/syndicate_station/northeast)
- else if(href_list["station_sw"])
- syndicate_move_to(/area/syndicate_station/southwest)
- else if(href_list["station_s"])
- syndicate_move_to(/area/syndicate_station/south)
- else if(href_list["station_se"])
- syndicate_move_to(/area/syndicate_station/southeast)
- else if(href_list["commssat"])
- syndicate_move_to(/area/syndicate_station/commssat)
- else if(href_list["mining"])
- syndicate_move_to(/area/syndicate_station/mining)
-
- add_fingerprint(usr)
- updateUsrDialog()
- return
-
-/obj/machinery/computer/syndicate_station/bullet_act(var/obj/item/projectile/Proj)
- visible_message("[Proj] ricochets off [src]!") //let's not let them fuck themselves in the rear
\ No newline at end of file
diff --git a/code/game/machinery/computer/vox_shuttle.dm b/code/game/machinery/computer/vox_shuttle.dm
deleted file mode 100644
index 6854949cd28..00000000000
--- a/code/game/machinery/computer/vox_shuttle.dm
+++ /dev/null
@@ -1,141 +0,0 @@
-#define VOX_SHUTTLE_MOVE_TIME 400
-#define VOX_SHUTTLE_COOLDOWN 1200
-
-//Copied from Syndicate shuttle.
-var/global/vox_shuttle_location
-var/global/announce_vox_departure = 1 //Stealth systems - give an announcement or not.
-
-/obj/machinery/computer/vox_stealth
- name = "skipjack cloaking field terminal"
- icon = 'icons/obj/computer.dmi'
- icon_state = "syndishuttle"
- req_access = list(access_syndicate)
-
-/obj/machinery/computer/vox_stealth/attackby(obj/item/I as obj, mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/vox_stealth/attack_ai(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/vox_stealth/attack_paw(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/vox_stealth/attack_hand(mob/user as mob)
- if(!allowed(user))
- user << "\red Access Denied"
- return
-
- if(announce_vox_departure)
- user << "\red Shuttle stealth systems have been activated. The Exodus will not be warned of our arrival."
- announce_vox_departure = 0
- else
- user << "\red Shuttle stealth systems have been deactivated. The Exodus will be warned of our arrival."
- announce_vox_departure = 1
-
-
-/obj/machinery/computer/vox_station
- name = "vox skipjack terminal"
- icon = 'icons/obj/computer.dmi'
- icon_state = "syndishuttle"
- req_access = list(access_syndicate)
- var/area/curr_location
- var/moving = 0
- var/lastMove = 0
- var/warning //Warning about the end of the round.
-
-/obj/machinery/computer/vox_station/New()
- curr_location= locate(/area/shuttle/vox/station)
-
-
-/obj/machinery/computer/vox_station/proc/vox_move_to(area/destination as area)
- if(moving) return
- if(lastMove + VOX_SHUTTLE_COOLDOWN > world.time) return
- var/area/dest_location = locate(destination)
- if(curr_location == dest_location) return
-
- if(announce_vox_departure)
- if(curr_location == locate(/area/shuttle/vox/station))
- command_alert("Attention, Exodus, we just tracked a small target bypassing our defensive perimeter. Can't fire on it without hitting the station - you've got incoming visitors, like it or not.", "NSV Icarus")
- else if(dest_location == locate(/area/shuttle/vox/station))
- command_alert("Your guests are pulling away, Exodus - moving too fast for us to draw a bead on them. Looks like they're heading out of Tau Ceti at a rapid clip.", "NSV Icarus")
-
- moving = 1
- lastMove = world.time
-
- if(curr_location.z != dest_location.z)
- var/area/transit_location = locate(/area/vox_station/transit)
- curr_location.move_contents_to(transit_location)
- curr_location = transit_location
- sleep(VOX_SHUTTLE_MOVE_TIME)
-
- curr_location.move_contents_to(dest_location)
- curr_location = dest_location
- moving = 0
-
- return 1
-
-
-/obj/machinery/computer/vox_station/attackby(obj/item/I as obj, mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/vox_station/attack_ai(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/vox_station/attack_paw(mob/user as mob)
- return attack_hand(user)
-
-/obj/machinery/computer/vox_station/attack_hand(mob/user as mob)
- if(!allowed(user))
- user << "\red Access Denied"
- return
-
- user.set_machine(src)
-
- var/dat = {"Location: [curr_location]
- Ready to move[max(lastMove + VOX_SHUTTLE_COOLDOWN - world.time, 0) ? " in [max(round((lastMove + VOX_SHUTTLE_COOLDOWN - world.time) * 0.1), 0)] seconds" : ": now"]
- Return to dark space
- Fore port solar |
- Aft port solar |
- Fore starboard solar
- Aft starboard solar |
- Mining Asteroid
- Close"}
-
- user << browse(dat, "window=computer;size=575x450")
- onclose(user, "computer")
- return
-
-
-/obj/machinery/computer/vox_station/Topic(href, href_list)
- if(!isliving(usr)) return
- var/mob/living/user = usr
-
- if(in_range(src, user) || istype(user, /mob/living/silicon))
- user.set_machine(src)
-
- vox_shuttle_location = "station"
- if(href_list["start"])
- if(ticker && (istype(ticker.mode,/datum/game_mode/heist)))
- if(!warning)
- user << "\red Returning to dark space will end your raid and report your success or failure. If you are sure, press the button again."
- warning = 1
- return
- vox_move_to(/area/shuttle/vox/station)
- vox_shuttle_location = "start"
- else if(href_list["solars_fore_starboard"])
- vox_move_to(/area/vox_station/northeast_solars)
- else if(href_list["solars_fore_port"])
- vox_move_to(/area/vox_station/northwest_solars)
- else if(href_list["solars_aft_starboard"])
- vox_move_to(/area/vox_station/southeast_solars)
- else if(href_list["solars_aft_port"])
- vox_move_to(/area/vox_station/southwest_solars)
- else if(href_list["mining"])
- vox_move_to(/area/vox_station/mining)
-
- add_fingerprint(usr)
- updateUsrDialog()
- return
-
-/obj/machinery/computer/vox_station/bullet_act(var/obj/item/projectile/Proj)
- visible_message("[Proj] ricochets off [src]!")
\ No newline at end of file
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 9232ff019b1..340ee6da8ca 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -160,7 +160,7 @@
//Machine Frame Circuit Boards
/*Common Parts: Parts List: Ignitor, Timer, Infra-red laser, Infra-red sensor, t_scanner, Capacitor, Valve, sensor unit,
micro-manipulator, console screen, beaker, Microlaser, matter bin, power cells.
-Note: Once everything is added to the public areas, will add m_amt and g_amt to circuit boards since autolathe won't be able
+Note: Once everything is added to the public areas, will add materials to circuit boards since autolathe won't be able
to destroy them and players will be able to make replacements.
*/
/obj/item/weapon/circuitboard/destructive_analyzer
diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm
index 63251c2b688..2dcb0c0b2e0 100644
--- a/code/game/machinery/door_control.dm
+++ b/code/game/machinery/door_control.dm
@@ -93,8 +93,7 @@
if(specialfunctions & IDSCAN)
D.aiDisabledIdScanner = 1
if(specialfunctions & BOLTS)
- D.locked = 1
- D.update_icon()
+ D.lock()
if(specialfunctions & SHOCK)
D.secondsElectrified = -1
if(specialfunctions & SAFE)
@@ -104,8 +103,7 @@
D.aiDisabledIdScanner = 0
if(specialfunctions & BOLTS)
if(!D.isWireCut(4) && D.arePowerSystemsOn())
- D.locked = 0
- D.update_icon()
+ D.unlock()
if(specialfunctions & SHOCK)
D.secondsElectrified = 0
if(specialfunctions & SAFE)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 39b5ec9a538..37a57e7a991 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -32,11 +32,19 @@
//This generates the randomized airlock wire assignments for the game.
/proc/RandomAirlockWires()
+ var/list/wire_assignments = CreateRandomAirlockWires()
+
+ globalAirlockIndexToFlag = wire_assignments[2]
+ globalAirlockIndexToWireColor = wire_assignments[3]
+ globalAirlockWireColorToIndex = wire_assignments[4]
+ return wire_assignments[1]
+
+/proc/CreateRandomAirlockWires()
//to make this not randomize the wires, just set index to 1 and increment it in the flag for loop (after doing everything else).
var/list/wires = list(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
- airlockIndexToFlag = list(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
- airlockIndexToWireColor = list(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
- airlockWireColorToIndex = list(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ var/airlockIndexToFlag = list(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ var/airlockIndexToWireColor = list(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ var/airlockWireColorToIndex = list(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
var/flagIndex = 1
for (var/flag=1, flag<4096, flag+=flag)
var/valid = 0
@@ -54,7 +62,7 @@
airlockWireColorToIndex[colorIndex] = flagIndex
colorList -= colorIndex
flagIndex+=1
- return wires
+ return list(wires, airlockIndexToFlag, airlockIndexToWireColor, airlockWireColorToIndex)
/* Example:
Airlock wires color -> flag are { 64, 128, 256, 2, 16, 4, 8, 32, 1 }.
@@ -93,6 +101,11 @@ Airlock index -> wire color are { 9, 4, 6, 7, 5, 8, 1, 2, 3 }.
normalspeed = 1
var/obj/item/weapon/airlock_electronics/electronics = null
var/hasShocked = 0 //Prevents multiple shocks from happening
+ var/secured_wires = 0 //for mapping use
+ var/list/airlockIndexToFlag
+ var/list/airlockWireColorToFlag
+ var/list/airlockIndexToWireColor
+ var/list/airlockWireColorToIndex
/obj/machinery/door/airlock/command
name = "Airlock"
@@ -293,11 +306,6 @@ Airlock index -> wire color are { 9, 4, 6, 7, 5, 8, 1, 2, 3 }.
new/obj/structure/door_assembly( src.loc )
del (src)
-/obj/machinery/door/airlock/clown
- name = "Bananium Airlock"
- icon = 'icons/obj/doors/Doorbananium.dmi'
- mineral = "clown"
-
/obj/machinery/door/airlock/sandstone
name = "Sandstone Airlock"
icon = 'icons/obj/doors/Doorsand.dmi'
@@ -373,17 +381,10 @@ About the new airlock wires panel:
//one wire for door bolts. Sending a pulse through this drops door bolts if they're not down (whether power's on or not),
//raises them if they are down (only if power's on)
if(!src.locked)
- src.locked = 1
- for(var/mob/M in range(1,src))
- M << "You hear a click from the bottom of the door."
- src.updateUsrDialog()
+ src.lock()
else
- if(src.arePowerSystemsOn()) //only can raise bolts if power's on
- src.locked = 0
- for(var/mob/M in range(1,src))
- M << "You hear a click from the bottom of the door."
- src.updateUsrDialog()
- update_icon()
+ src.unlock()
+ src.updateUsrDialog()
if(AIRLOCK_WIRE_BACKUP_POWER1 || AIRLOCK_WIRE_BACKUP_POWER2)
//two wires for backup power. Sending a pulse through either one causes a breaker to trip, but this does not disable it unless main power is down too (in which case it is disabled for 1 minute or however long it takes main power to come back, whichever is shorter).
@@ -447,9 +448,7 @@ About the new airlock wires panel:
src.updateUsrDialog()
if(AIRLOCK_WIRE_DOOR_BOLTS)
//Cutting this wire also drops the door bolts, and mending it does not raise them. (This is what happens now, except there are a lot more wires going to door bolts at present)
- if(src.locked!=1)
- src.locked = 1
- update_icon()
+ src.lock()
src.updateUsrDialog()
if(AIRLOCK_WIRE_BACKUP_POWER1 || AIRLOCK_WIRE_BACKUP_POWER2)
//Cutting either one disables the backup door power (allowing it to be crowbarred open, but disabling bolts-raising), but may electocute the user.
@@ -597,17 +596,12 @@ About the new airlock wires panel:
// shock user with probability prb (if all connections & power are working)
// returns 1 if shocked, 0 otherwise
// The preceding comment was borrowed from the grille's shock script
-/obj/machinery/door/airlock/proc/shock(mob/user, prb)
- if((stat & (NOPOWER)) || !src.arePowerSystemsOn()) // unpowered, no shock
+/obj/machinery/door/airlock/shock(mob/user, prb)
+ if(!arePowerSystemsOn())
return 0
if(hasShocked)
return 0 //Already shocked someone recently?
- if(!prob(prb))
- return 0 //you lucked out, no shock for you
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, src)
- s.start() //sparks always.
- if(electrocute_mob(user, get_area(src), src))
+ if(..())
hasShocked = 1
sleep(10)
hasShocked = 0
@@ -707,7 +701,7 @@ About the new airlock wires panel:
t1 += text("Backup Power Output wire is cut.
\n")
if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS))
- t1 += text("Door bolt drop wire is cut.
\n")
+ t1 += text("Door bolt control wire is cut.
\n")
else if(!src.locked)
t1 += text("Door bolts are up. Drop them?
\n", src)
else
@@ -818,7 +812,7 @@ About the new airlock wires panel:
if (src.isElectrified())
if (istype(mover, /obj/item))
var/obj/item/i = mover
- if (i.m_amt)
+ if (i.matter["metal"])
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(5, 1, src)
s.start()
@@ -986,10 +980,9 @@ About the new airlock wires panel:
if(4)
//drop door bolts
if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS))
- usr << "You can't drop the door bolts - The door bolt dropping wire has been cut."
- else if(src.locked!=1)
- src.locked = 1
- update_icon()
+ usr << "You can't drop the door bolts - The door bolt control wire has been cut."
+ else
+ src.lock()
if(5)
//un-electrify door
if(src.isWireCut(AIRLOCK_WIRE_ELECTRIFY))
@@ -1055,15 +1048,11 @@ About the new airlock wires panel:
if(4)
//raise door bolts
if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS))
- usr << text("The door bolt drop wire is cut - you can't raise the door bolts.
\n")
+ usr << text("The door bolt control wire is cut - you can't raise the door bolts.
\n")
else if(!src.locked)
usr << text("The door bolts are already up.
\n")
else
- if(src.arePowerSystemsOn())
- src.locked = 0
- update_icon()
- else
- usr << text("Cannot raise door bolts due to power failure.
\n")
+ src.unlock()
if(5)
//electrify door for 30 seconds
@@ -1262,8 +1251,6 @@ About the new airlock wires panel:
use_power(50)
if(istype(src, /obj/machinery/door/airlock/glass))
playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1)
- if(istype(src, /obj/machinery/door/airlock/clown))
- playsound(src.loc, 'sound/items/bikehorn.ogg', 30, 1)
else
playsound(src.loc, 'sound/machines/airlock.ogg', 30, 1)
if(src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density)
@@ -1306,8 +1293,6 @@ About the new airlock wires panel:
use_power(50)
if(istype(src, /obj/machinery/door/airlock/glass))
playsound(src.loc, 'sound/machines/windowdoor.ogg', 30, 1)
- if(istype(src, /obj/machinery/door/airlock/clown))
- playsound(src.loc, 'sound/items/bikehorn.ogg', 30, 1)
else
playsound(src.loc, 'sound/machines/airlock.ogg', 30, 1)
for(var/turf/turf in locs)
@@ -1317,8 +1302,35 @@ About the new airlock wires panel:
..()
return
+/obj/machinery/door/airlock/proc/lock(var/forced=0)
+ if (src.locked) return
+
+ src.locked = 1
+ for(var/mob/M in range(1,src))
+ M.show_message("You hear a click from the bottom of the door.", 2)
+ update_icon()
+
+/obj/machinery/door/airlock/proc/unlock(var/forced=0)
+ if (!src.locked) return
+
+ if(forced || src.arePowerSystemsOn()) //only can raise bolts if power's on
+ src.locked = 0
+ for(var/mob/M in range(1,src))
+ M.show_message("You hear a click from the bottom of the door.", 2)
+ update_icon()
+
/obj/machinery/door/airlock/New()
..()
+
+ //wires
+ if (!secured_wires)
+ airlockWireColorToFlag = globalAirlockWireColorToFlag
+ airlockIndexToFlag = globalAirlockIndexToFlag
+ airlockIndexToWireColor = globalAirlockIndexToWireColor
+ airlockWireColorToIndex = globalAirlockWireColorToIndex
+ else
+ randomize_wires()
+
if(src.closeOtherId != null)
spawn (5)
for (var/obj/machinery/door/airlock/A in world)
@@ -1326,9 +1338,15 @@ About the new airlock wires panel:
src.closeOther = A
break
+/obj/machinery/door/airlock/proc/randomize_wires()
+ var/wire_assignments = CreateRandomAirlockWires()
+ airlockWireColorToFlag = wire_assignments[1]
+ airlockIndexToFlag = wire_assignments[2]
+ airlockIndexToWireColor = wire_assignments[3]
+ airlockWireColorToIndex = wire_assignments[4]
/obj/machinery/door/airlock/proc/prison_open()
- src.locked = 0
+ src.unlock()
src.open()
- src.locked = 1
+ src.lock()
return
\ No newline at end of file
diff --git a/code/game/machinery/airlock_control.dm b/code/game/machinery/doors/airlock_control.dm
similarity index 91%
rename from code/game/machinery/airlock_control.dm
rename to code/game/machinery/doors/airlock_control.dm
index a5de183a921..59ed905a0ad 100644
--- a/code/game/machinery/airlock_control.dm
+++ b/code/game/machinery/doors/airlock_control.dm
@@ -1,255 +1,257 @@
-#define AIRLOCK_CONTROL_RANGE 5
-
-// This code allows for airlocks to be controlled externally by setting an id_tag and comm frequency (disables ID access)
-obj/machinery/door/airlock
- var/id_tag
- var/frequency
- var/shockedby = list()
- var/datum/radio_frequency/radio_connection
- explosion_resistance = 15
-
-
-obj/machinery/door/airlock/receive_signal(datum/signal/signal)
- if(!signal || signal.encryption) return
-
- if(id_tag != signal.data["tag"] || !signal.data["command"]) return
-
- switch(signal.data["command"])
- if("open")
- open(1)
-
- if("close")
- close(1)
-
- if("unlock")
- locked = 0
- update_icon()
-
- if("lock")
- locked = 1
- update_icon()
-
- if("secure_open")
- locked = 0
- update_icon()
-
- sleep(2)
- open(1)
-
- locked = 1
- update_icon()
-
- if("secure_close")
- locked = 0
- close(1)
-
- locked = 1
- sleep(2)
- update_icon()
-
- send_status()
-
-
-obj/machinery/door/airlock/proc/send_status()
- if(radio_connection)
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.data["tag"] = id_tag
- signal.data["timestamp"] = world.time
-
- signal.data["door_status"] = density?("closed"):("open")
- signal.data["lock_status"] = locked?("locked"):("unlocked")
-
- radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
-
-
-obj/machinery/door/airlock/open(surpress_send)
- . = ..()
- if(!surpress_send) send_status()
-
-
-obj/machinery/door/airlock/close(surpress_send)
- . = ..()
- if(!surpress_send) send_status()
-
-
-obj/machinery/door/airlock/Bumped(atom/AM)
- ..(AM)
- if(istype(AM, /obj/mecha))
- var/obj/mecha/mecha = AM
- if(density && radio_connection && mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access)))
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.data["tag"] = id_tag
- signal.data["timestamp"] = world.time
-
- signal.data["door_status"] = density?("closed"):("open")
- signal.data["lock_status"] = locked?("locked"):("unlocked")
-
- signal.data["bumped_with_access"] = 1
-
- radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
- return
-
-obj/machinery/door/airlock/proc/set_frequency(new_frequency)
- radio_controller.remove_object(src, frequency)
- if(new_frequency)
- frequency = new_frequency
- radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK)
-
-
-obj/machinery/door/airlock/initialize()
- if(frequency)
- set_frequency(frequency)
-
- update_icon()
-
-
-obj/machinery/door/airlock/New()
- ..()
-
- if(radio_controller)
- set_frequency(frequency)
-
-
-
-
-obj/machinery/airlock_sensor
- icon = 'icons/obj/airlock_machines.dmi'
- icon_state = "airlock_sensor_off"
- name = "airlock sensor"
-
- anchored = 1
- power_channel = ENVIRON
-
- var/id_tag
- var/master_tag
- var/frequency = 1379
- var/command = "cycle"
-
- var/datum/radio_frequency/radio_connection
-
- var/on = 1
- var/alert = 0
- var/previousPressure
-
-obj/machinery/airlock_sensor/update_icon()
- if(on)
- if(alert)
- icon_state = "airlock_sensor_alert"
- else
- icon_state = "airlock_sensor_standby"
- else
- icon_state = "airlock_sensor_off"
-
-obj/machinery/airlock_sensor/attack_hand(mob/user)
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.data["tag"] = master_tag
- signal.data["command"] = command
-
- radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
- flick("airlock_sensor_cycle", src)
-
-obj/machinery/airlock_sensor/process()
- if(on)
- var/datum/gas_mixture/air_sample = return_air()
- var/pressure = round(air_sample.return_pressure(),0.1)
-
- if(abs(pressure - previousPressure) > 0.001 || previousPressure == null)
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.data["tag"] = id_tag
- signal.data["timestamp"] = world.time
- signal.data["pressure"] = num2text(pressure)
-
- radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
-
- previousPressure = pressure
-
- alert = (pressure < ONE_ATMOSPHERE*0.8)
-
- update_icon()
-
-obj/machinery/airlock_sensor/proc/set_frequency(new_frequency)
- radio_controller.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK)
-
-obj/machinery/airlock_sensor/initialize()
- set_frequency(frequency)
-
-obj/machinery/airlock_sensor/New()
- ..()
- if(radio_controller)
- set_frequency(frequency)
-
-
-obj/machinery/airlock_sensor/airlock_interior
- command = "cycle_interior"
-
-obj/machinery/airlock_sensor/airlock_exterior
- command = "cycle_exterior"
-
-obj/machinery/access_button
- icon = 'icons/obj/airlock_machines.dmi'
- icon_state = "access_button_standby"
- name = "access button"
-
- anchored = 1
- power_channel = ENVIRON
-
- var/master_tag
- var/frequency = 1449
- var/command = "cycle"
-
- var/datum/radio_frequency/radio_connection
-
- var/on = 1
-
-
-obj/machinery/access_button/update_icon()
- if(on)
- icon_state = "access_button_standby"
- else
- icon_state = "access_button_off"
-
-
-obj/machinery/access_button/attack_hand(mob/user)
- add_fingerprint(usr)
- if(!allowed(user))
- user << "\red Access Denied"
-
- else if(radio_connection)
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.data["tag"] = master_tag
- signal.data["command"] = command
-
- radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
- flick("access_button_cycle", src)
-
-
-obj/machinery/access_button/proc/set_frequency(new_frequency)
- radio_controller.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK)
-
-
-obj/machinery/access_button/initialize()
- set_frequency(frequency)
-
-
-obj/machinery/access_button/New()
- ..()
-
- if(radio_controller)
- set_frequency(frequency)
-
-obj/machinery/access_button/airlock_interior
- frequency = 1379
- command = "cycle_interior"
-
-obj/machinery/access_button/airlock_exterior
- frequency = 1379
+#define AIRLOCK_CONTROL_RANGE 22
+
+// This code allows for airlocks to be controlled externally by setting an id_tag and comm frequency (disables ID access)
+obj/machinery/door/airlock
+ var/id_tag
+ var/frequency
+ var/shockedby = list()
+ var/datum/radio_frequency/radio_connection
+ explosion_resistance = 15
+
+obj/machinery/door/airlock/proc/can_radio()
+ if( !arePowerSystemsOn() || (stat & NOPOWER) || isWireCut(AIRLOCK_WIRE_AI_CONTROL) )
+ return 0
+ return 1
+
+
+obj/machinery/door/airlock/receive_signal(datum/signal/signal)
+ if (!can_radio()) return
+
+ if(!signal || signal.encryption) return
+
+ if(id_tag != signal.data["tag"] || !signal.data["command"]) return
+
+ switch(signal.data["command"])
+ if("open")
+ open()
+
+ if("close")
+ close()
+
+ if("unlock")
+ unlock()
+
+ if("lock")
+ lock()
+
+ if("secure_open")
+ unlock()
+
+ sleep(2)
+ open()
+
+ lock()
+
+ if("secure_close")
+ unlock()
+ close()
+
+ lock()
+ sleep(2)
+
+ send_status()
+
+
+obj/machinery/door/airlock/proc/send_status()
+ if(radio_connection)
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.data["tag"] = id_tag
+ signal.data["timestamp"] = world.time
+
+ signal.data["door_status"] = density?("closed"):("open")
+ signal.data["lock_status"] = locked?("locked"):("unlocked")
+
+ radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
+
+
+obj/machinery/door/airlock/open(surpress_send)
+ . = ..()
+ if(!surpress_send) send_status()
+
+
+obj/machinery/door/airlock/close(surpress_send)
+ . = ..()
+ if(!surpress_send) send_status()
+
+
+obj/machinery/door/airlock/Bumped(atom/AM)
+ ..(AM)
+ if(istype(AM, /obj/mecha))
+ var/obj/mecha/mecha = AM
+ if(density && radio_connection && mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access)))
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.data["tag"] = id_tag
+ signal.data["timestamp"] = world.time
+
+ signal.data["door_status"] = density?("closed"):("open")
+ signal.data["lock_status"] = locked?("locked"):("unlocked")
+
+ signal.data["bumped_with_access"] = 1
+
+ radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
+ return
+
+obj/machinery/door/airlock/proc/set_frequency(new_frequency)
+ radio_controller.remove_object(src, frequency)
+ if(new_frequency)
+ frequency = new_frequency
+ radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK)
+
+
+obj/machinery/door/airlock/initialize()
+ if(frequency)
+ set_frequency(frequency)
+
+ update_icon()
+
+
+obj/machinery/door/airlock/New()
+ ..()
+
+ if(radio_controller)
+ set_frequency(frequency)
+
+
+
+
+obj/machinery/airlock_sensor
+ icon = 'icons/obj/airlock_machines.dmi'
+ icon_state = "airlock_sensor_off"
+ name = "airlock sensor"
+
+ anchored = 1
+ power_channel = ENVIRON
+
+ var/id_tag
+ var/master_tag
+ var/frequency = 1379
+ var/command = "cycle"
+
+ var/datum/radio_frequency/radio_connection
+
+ var/on = 1
+ var/alert = 0
+ var/previousPressure
+
+obj/machinery/airlock_sensor/update_icon()
+ if(on)
+ if(alert)
+ icon_state = "airlock_sensor_alert"
+ else
+ icon_state = "airlock_sensor_standby"
+ else
+ icon_state = "airlock_sensor_off"
+
+obj/machinery/airlock_sensor/attack_hand(mob/user)
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.data["tag"] = master_tag
+ signal.data["command"] = command
+
+ radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
+ flick("airlock_sensor_cycle", src)
+
+obj/machinery/airlock_sensor/process()
+ if(on)
+ var/datum/gas_mixture/air_sample = return_air()
+ var/pressure = round(air_sample.return_pressure(),0.1)
+
+ if(abs(pressure - previousPressure) > 0.001 || previousPressure == null)
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.data["tag"] = id_tag
+ signal.data["timestamp"] = world.time
+ signal.data["pressure"] = num2text(pressure)
+
+ radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
+
+ previousPressure = pressure
+
+ alert = (pressure < ONE_ATMOSPHERE*0.8)
+
+ update_icon()
+
+obj/machinery/airlock_sensor/proc/set_frequency(new_frequency)
+ radio_controller.remove_object(src, frequency)
+ frequency = new_frequency
+ radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK)
+
+obj/machinery/airlock_sensor/initialize()
+ set_frequency(frequency)
+
+obj/machinery/airlock_sensor/New()
+ ..()
+ if(radio_controller)
+ set_frequency(frequency)
+
+
+obj/machinery/airlock_sensor/airlock_interior
+ command = "cycle_interior"
+
+obj/machinery/airlock_sensor/airlock_exterior
+ command = "cycle_exterior"
+
+obj/machinery/access_button
+ icon = 'icons/obj/airlock_machines.dmi'
+ icon_state = "access_button_standby"
+ name = "access button"
+
+ anchored = 1
+ power_channel = ENVIRON
+
+ var/master_tag
+ var/frequency = 1449
+ var/command = "cycle"
+
+ var/datum/radio_frequency/radio_connection
+
+ var/on = 1
+
+
+obj/machinery/access_button/update_icon()
+ if(on)
+ icon_state = "access_button_standby"
+ else
+ icon_state = "access_button_off"
+
+
+obj/machinery/access_button/attack_hand(mob/user)
+ add_fingerprint(usr)
+ if(!allowed(user))
+ user << "\red Access Denied"
+
+ else if(radio_connection)
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.data["tag"] = master_tag
+ signal.data["command"] = command
+
+ radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
+ flick("access_button_cycle", src)
+
+
+obj/machinery/access_button/proc/set_frequency(new_frequency)
+ radio_controller.remove_object(src, frequency)
+ frequency = new_frequency
+ radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK)
+
+
+obj/machinery/access_button/initialize()
+ set_frequency(frequency)
+
+
+obj/machinery/access_button/New()
+ ..()
+
+ if(radio_controller)
+ set_frequency(frequency)
+
+obj/machinery/access_button/airlock_interior
+ frequency = 1379
+ command = "cycle_interior"
+
+obj/machinery/access_button/airlock_exterior
+ frequency = 1379
command = "cycle_exterior"
\ No newline at end of file
diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm
index 33621a301f3..d9a3efe9594 100644
--- a/code/game/machinery/doors/airlock_electronics.dm
+++ b/code/game/machinery/doors/airlock_electronics.dm
@@ -5,8 +5,8 @@
icon = 'icons/obj/doors/door_assembly.dmi'
icon_state = "door_electronics"
w_class = 2.0 //It should be tiny! -Agouri
- m_amt = 50
- g_amt = 50
+
+ matter = list("metal" = 50,"glass" = 50)
req_access = list(access_engine)
@@ -109,3 +109,8 @@
if (!conf_access.len)
conf_access = null
+
+/obj/item/weapon/airlock_electronics/secure
+ name = "secure airlock electronics"
+ desc = "designed to be somewhat more resistant to hacking than standard electronics."
+ origin_tech = "programming=3"
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 950871d983e..12f224ac527 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -81,6 +81,14 @@
else
flick("door_deny", src)
return
+ if(istype(AM, /obj/structure/stool/bed/chair/wheelchair))
+ var/obj/structure/stool/bed/chair/wheelchair/wheel = AM
+ if(density)
+ if(wheel.pulling && (src.allowed(wheel.pulling)))
+ open()
+ else
+ flick("door_deny", src)
+ return
return
diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm
index 017796b5931..aeccacd45ce 100644
--- a/code/game/machinery/doors/poddoor.dm
+++ b/code/game/machinery/doors/poddoor.dm
@@ -1,6 +1,6 @@
/obj/machinery/door/poddoor
name = "Podlock"
- desc = "Why it no open!!!"
+ desc = "That looks like it doesn't open easily."
icon = 'icons/obj/doors/rapid_pdoor.dmi'
icon_state = "pdoor1"
var/id = 1.0
diff --git a/code/game/machinery/embedded_controller/airlock_controllers.dm b/code/game/machinery/embedded_controller/airlock_controllers.dm
index 4ace634295e..4a48558f875 100644
--- a/code/game/machinery/embedded_controller/airlock_controllers.dm
+++ b/code/game/machinery/embedded_controller/airlock_controllers.dm
@@ -1,8 +1,23 @@
+//base type for controllers of two-door systems
+/obj/machinery/embedded_controller/radio/airlock
+ // Setup parameters only
+ var/tag_exterior_door
+ var/tag_interior_door
+ var/tag_airpump
+ var/tag_chamber_sensor
+ var/tag_exterior_sensor
+ var/tag_interior_sensor
+ var/tag_secure = 0
+
+/obj/machinery/embedded_controller/radio/airlock/initialize()
+ ..()
+ program = new/datum/computer/file/embedded_program/airlock(src)
+
//Advanced airlock controller for when you want a more versatile airlock controller - useful for turning simple access control rooms into airlocks
-/obj/machinery/embedded_controller/radio/advanced_airlock_controller
+/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller
name = "Advanced Airlock Controller"
-/obj/machinery/embedded_controller/radio/advanced_airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
+/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
var/data[0]
data = list(
@@ -25,7 +40,13 @@
ui.set_auto_update(1)
-/obj/machinery/embedded_controller/radio/advanced_airlock_controller/Topic(href, href_list)
+/obj/machinery/embedded_controller/radio/airlock/advanced_airlock_controller/Topic(href, href_list)
+ if(..())
+ return
+
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+
var/clean = 0
switch(href_list["command"]) //anti-HTML-hacking checks
if("cycle_ext")
@@ -50,11 +71,11 @@
//Airlock controller for airlock control - most airlocks on the station use this
-/obj/machinery/embedded_controller/radio/airlock_controller
+/obj/machinery/embedded_controller/radio/airlock/airlock_controller
name = "Airlock Controller"
tag_secure = 1
-/obj/machinery/embedded_controller/radio/airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
+/obj/machinery/embedded_controller/radio/airlock/airlock_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
var/data[0]
data = list(
@@ -75,7 +96,13 @@
ui.set_auto_update(1)
-/obj/machinery/embedded_controller/radio/airlock_controller/Topic(href, href_list)
+/obj/machinery/embedded_controller/radio/airlock/airlock_controller/Topic(href, href_list)
+ if(..())
+ return
+
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+
var/clean = 0
switch(href_list["command"]) //anti-HTML-hacking checks
if("cycle_ext")
@@ -96,7 +123,7 @@
//Access controller for door control - used in virology and the like
-/obj/machinery/embedded_controller/radio/access_controller
+/obj/machinery/embedded_controller/radio/airlock/access_controller
icon = 'icons/obj/airlock_machines.dmi'
icon_state = "access_control_standby"
@@ -104,7 +131,7 @@
tag_secure = 1
-/obj/machinery/embedded_controller/radio/access_controller/update_icon()
+/obj/machinery/embedded_controller/radio/airlock/access_controller/update_icon()
if(on && program)
if(program.memory["processing"])
icon_state = "access_control_process"
@@ -113,7 +140,7 @@
else
icon_state = "access_control_off"
-/obj/machinery/embedded_controller/radio/access_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
+/obj/machinery/embedded_controller/radio/airlock/access_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
var/data[0]
data = list(
@@ -133,7 +160,13 @@
ui.set_auto_update(1)
-/obj/machinery/embedded_controller/radio/access_controller/Topic(href, href_list)
+/obj/machinery/embedded_controller/radio/airlock/access_controller/Topic(href, href_list)
+ if(..())
+ return
+
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+
var/clean = 0
switch(href_list["command"]) //anti-HTML-hacking checks
if("cycle_ext_door")
diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller.dm b/code/game/machinery/embedded_controller/airlock_docking_controller.dm
new file mode 100644
index 00000000000..69db042b7ed
--- /dev/null
+++ b/code/game/machinery/embedded_controller/airlock_docking_controller.dm
@@ -0,0 +1,170 @@
+//a docking port based on an airlock
+/obj/machinery/embedded_controller/radio/airlock/docking_port
+ name = "docking port controller"
+ var/datum/computer/file/embedded_program/airlock/docking/airlock_program
+ var/datum/computer/file/embedded_program/docking/airlock/docking_program
+ tag_secure = 1
+
+/obj/machinery/embedded_controller/radio/airlock/docking_port/initialize()
+ ..()
+ airlock_program = new/datum/computer/file/embedded_program/airlock/docking(src)
+ docking_program = new/datum/computer/file/embedded_program/docking/airlock(src, airlock_program)
+ program = docking_program
+
+/obj/machinery/embedded_controller/radio/airlock/docking_port/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
+ var/data[0]
+
+ data = list(
+ "chamber_pressure" = round(airlock_program.memory["chamber_sensor_pressure"]),
+ "exterior_status" = airlock_program.memory["exterior_status"],
+ "interior_status" = airlock_program.memory["interior_status"],
+ "processing" = airlock_program.memory["processing"],
+ "docking_status" = docking_program.get_docking_status(),
+ "airlock_disabled" = !(docking_program.undocked() || docking_program.override_enabled),
+ )
+
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
+
+ if (!ui)
+ ui = new(user, src, ui_key, "docking_airlock_console.tmpl", name, 470, 290)
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(1)
+
+/obj/machinery/embedded_controller/radio/airlock/docking_port/Topic(href, href_list)
+ if(..())
+ return
+
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+
+ var/clean = 0
+ switch(href_list["command"]) //anti-HTML-hacking checks
+ if("cycle_ext")
+ clean = 1
+ if("cycle_int")
+ clean = 1
+ if("force_ext")
+ clean = 1
+ if("force_int")
+ clean = 1
+ if("abort")
+ clean = 1
+ if("toggle_override")
+ clean = 1
+
+ if(clean)
+ program.receive_user_command(href_list["command"])
+
+ return 1
+
+
+
+//A docking controller for an airlock based docking port
+/datum/computer/file/embedded_program/docking/airlock
+ var/datum/computer/file/embedded_program/airlock/docking/airlock_program
+
+/datum/computer/file/embedded_program/docking/airlock/New(var/obj/machinery/embedded_controller/M, var/datum/computer/file/embedded_program/airlock/docking/A)
+ ..(M)
+ airlock_program = A
+ airlock_program.master_prog = src
+
+/datum/computer/file/embedded_program/docking/airlock/receive_user_command(command)
+ if (command == "toggle_override")
+ if (override_enabled)
+ disable_override()
+ else
+ enable_override()
+ return
+
+ ..(command)
+ airlock_program.receive_user_command(command) //pass along to subprograms
+
+/datum/computer/file/embedded_program/docking/airlock/process()
+ airlock_program.process()
+ ..()
+
+/datum/computer/file/embedded_program/docking/airlock/receive_signal(datum/signal/signal, receive_method, receive_param)
+ airlock_program.receive_signal(signal, receive_method, receive_param) //pass along to subprograms
+ ..(signal, receive_method, receive_param)
+
+//tell the docking port to start getting ready for docking - e.g. pressurize
+/datum/computer/file/embedded_program/docking/airlock/prepare_for_docking()
+ airlock_program.begin_cycle_in()
+
+//are we ready for docking?
+/datum/computer/file/embedded_program/docking/airlock/ready_for_docking()
+ return airlock_program.done_cycling()
+
+//we are docked, open the doors or whatever.
+/datum/computer/file/embedded_program/docking/airlock/finish_docking()
+ airlock_program.open_doors()
+
+//tell the docking port to start getting ready for undocking - e.g. close those doors.
+/datum/computer/file/embedded_program/docking/airlock/prepare_for_undocking()
+ airlock_program.stop_cycling()
+ airlock_program.close_doors()
+
+//are we ready for undocking?
+/datum/computer/file/embedded_program/docking/airlock/ready_for_undocking()
+ return airlock_program.check_doors_secured()
+
+//An airlock controller to be used by the airlock-based docking port controller.
+//Same as a regular airlock controller but allows disabling of the regular airlock functions when docking
+/datum/computer/file/embedded_program/airlock/docking
+
+ var/datum/computer/file/embedded_program/docking/airlock/master_prog
+
+/datum/computer/file/embedded_program/airlock/docking/receive_user_command(command)
+ if (master_prog.undocked() || master_prog.override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled
+ ..(command)
+
+/datum/computer/file/embedded_program/airlock/docking/proc/open_doors()
+ toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "open")
+ toggleDoor(memory["exterior_status"], tag_exterior_door, memory["secure"], "open")
+
+/datum/computer/file/embedded_program/airlock/docking/cycleDoors(var/target)
+ if (master_prog.undocked() || master_prog.override_enabled) //only allow the port to be used as an airlock if nothing is docked here or the override is enabled
+ ..(target)
+
+/*** DEBUG VERBS ***
+
+/datum/computer/file/embedded_program/docking/proc/print_state()
+ world << "id_tag: [id_tag]"
+ world << "dock_state: [dock_state]"
+ world << "control_mode: [control_mode]"
+ world << "tag_target: [tag_target]"
+ world << "response_sent: [response_sent]"
+
+/datum/computer/file/embedded_program/docking/post_signal(datum/signal/signal, comm_line)
+ world << "Program [id_tag] sent a message!"
+ print_state()
+ world << "[id_tag] sent command \"[signal.data["command"]]\" to \"[signal.data["recipient"]]\""
+ ..(signal)
+
+/obj/machinery/embedded_controller/radio/airlock/docking_port/verb/view_state()
+ set category = "Debug"
+ set src in view(1)
+ src.program:print_state()
+
+/obj/machinery/embedded_controller/radio/airlock/docking_port/verb/spoof_signal(var/command as text, var/sender as text)
+ set category = "Debug"
+ set src in view(1)
+ var/datum/signal/signal = new
+ signal.data["tag"] = sender
+ signal.data["command"] = command
+ signal.data["recipient"] = id_tag
+
+ src.program:receive_signal(signal)
+
+/obj/machinery/embedded_controller/radio/airlock/docking_port/verb/debug_init_dock(var/target as text)
+ set category = "Debug"
+ set src in view(1)
+ src.program:initiate_docking(target)
+
+/obj/machinery/embedded_controller/radio/airlock/docking_port/verb/debug_init_undock()
+ set category = "Debug"
+ set src in view(1)
+ src.program:initiate_undocking()
+
+*/
\ No newline at end of file
diff --git a/code/game/machinery/embedded_controller/airlock_program.dm b/code/game/machinery/embedded_controller/airlock_program.dm
index 8ce0256a962..72c2427cf05 100644
--- a/code/game/machinery/embedded_controller/airlock_program.dm
+++ b/code/game/machinery/embedded_controller/airlock_program.dm
@@ -8,11 +8,8 @@
#define TARGET_INOPEN -1
#define TARGET_OUTOPEN -2
-/datum/computer/file/embedded_program
- var/list/memory = list()
- var/obj/machinery/embedded_controller/master
- var/id_tag
+/datum/computer/file/embedded_program/airlock
var/tag_exterior_door
var/tag_interior_door
var/tag_airpump
@@ -23,9 +20,9 @@
var/state = STATE_WAIT
var/target_state = TARGET_NONE
-
-/datum/computer/file/embedded_program/New()
- ..()
+/datum/computer/file/embedded_program/airlock/New(var/obj/machinery/embedded_controller/M)
+ ..(M)
+
memory["chamber_sensor_pressure"] = ONE_ATMOSPHERE
memory["external_sensor_pressure"] = 0 //assume vacuum for simple airlock controller
memory["internal_sensor_pressure"] = ONE_ATMOSPHERE
@@ -35,11 +32,22 @@
memory["target_pressure"] = ONE_ATMOSPHERE
memory["purge"] = 0
memory["secure"] = 0
+
+ if (istype(M, /obj/machinery/embedded_controller/radio/airlock)) //if our controller is an airlock controller than we can auto-init our tags
+ var/obj/machinery/embedded_controller/radio/airlock/controller = M
+ tag_exterior_door = controller.tag_exterior_door
+ tag_interior_door = controller.tag_interior_door
+ tag_airpump = controller.tag_airpump
+ tag_chamber_sensor = controller.tag_chamber_sensor
+ tag_exterior_sensor = controller.tag_exterior_sensor
+ tag_interior_sensor = controller.tag_interior_sensor
+ memory["secure"] = controller.tag_secure
+
+ spawn(10)
+ signalDoor(tag_exterior_door, "update") //signals connected doors to update their status
+ signalDoor(tag_interior_door, "update")
-
-
-
-/datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
+/datum/computer/file/embedded_program/airlock/receive_signal(datum/signal/signal, receive_method, receive_param)
var/receive_tag = signal.data["tag"]
if(!receive_tag) return
@@ -68,7 +76,7 @@
memory["pump_status"] = "off"
else if(receive_tag==id_tag)
- if(istype(master, /obj/machinery/embedded_controller/radio/access_controller))
+ if(istype(master, /obj/machinery/embedded_controller/radio/airlock/access_controller))
switch(signal.data["command"])
if("cycle_exterior")
receive_user_command("cycle_ext_door")
@@ -92,16 +100,14 @@
receive_user_command("cycle_int")
-/datum/computer/file/embedded_program/proc/receive_user_command(command)
+/datum/computer/file/embedded_program/airlock/receive_user_command(command)
var/shutdown_pump = 0
switch(command)
if("cycle_ext")
- state = STATE_WAIT
- target_state = TARGET_OUTOPEN
+ begin_cycle_out()
if("cycle_int")
- state = STATE_WAIT
- target_state = TARGET_INOPEN
+ begin_cycle_in()
if("cycle_ext_door")
cycleDoors(TARGET_OUTOPEN)
@@ -144,37 +150,44 @@
signalPump(tag_airpump, 0) //send a signal to stop pressurizing
-/datum/computer/file/embedded_program/proc/process()
- if(!state && target_state)
- switch(target_state)
- if(TARGET_INOPEN)
- memory["target_pressure"] = memory["internal_sensor_pressure"]
- if(TARGET_OUTOPEN)
- memory["target_pressure"] = memory["external_sensor_pressure"]
+/datum/computer/file/embedded_program/airlock/process()
+ if(!state)
+ if(target_state)
+ switch(target_state)
+ if(TARGET_INOPEN)
+ memory["target_pressure"] = memory["internal_sensor_pressure"]
+ if(TARGET_OUTOPEN)
+ memory["target_pressure"] = memory["external_sensor_pressure"]
- //lock down the airlock before activating pumps
- toggleDoor(memory["exterior_status"], tag_exterior_door, 1, "close")
- toggleDoor(memory["interior_status"], tag_interior_door, 1, "close")
+ //lock down the airlock before activating pumps
+ close_doors()
- var/chamber_pressure = memory["chamber_sensor_pressure"]
- var/target_pressure = memory["target_pressure"]
+ var/chamber_pressure = memory["chamber_sensor_pressure"]
+ var/target_pressure = memory["target_pressure"]
- if(memory["purge"])
- target_pressure = 0
+ if(memory["purge"])
+ target_pressure = 0
- if(chamber_pressure <= target_pressure)
- state = STATE_PRESSURIZE
- signalPump(tag_airpump, 1, 1, target_pressure) //send a signal to start pressurizing
-
- else if(chamber_pressure > target_pressure)
- state = STATE_DEPRESSURIZE
- signalPump(tag_airpump, 1, 0, target_pressure) //send a signal to start depressurizing
-
- //Check for vacuum - this is set after the pumps so the pumps are aiming for 0
- if(!memory["target_pressure"])
- memory["target_pressure"] = ONE_ATMOSPHERE * 0.05
+ if(chamber_pressure <= target_pressure)
+ state = STATE_PRESSURIZE
+ signalPump(tag_airpump, 1, 1, target_pressure) //send a signal to start pressurizing
+ else if(chamber_pressure > target_pressure)
+ state = STATE_DEPRESSURIZE
+ signalPump(tag_airpump, 1, 0, target_pressure) //send a signal to start depressurizing
+ //Check for vacuum - this is set after the pumps so the pumps are aiming for 0
+ if(!memory["target_pressure"])
+ memory["target_pressure"] = ONE_ATMOSPHERE * 0.05
+ else
+ //make sure to return to a sane idle state
+ if(memory["pump_status"] != "off") //send a signal to stop pumping
+ signalPump(tag_airpump, 0)
+
+ //the airlock will not allow itself to continue to cycle when any of the doors are forced open.
+ if (state && !check_doors_secured())
+ stop_cycling()
+
switch(state)
if(STATE_PRESSURIZE)
if(memory["chamber_sensor_pressure"] >= memory["target_pressure"] * 0.95)
@@ -209,22 +222,40 @@
return 1
+//these are here so that other types don't have to make so many assuptions about our implementation
-/datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line)
- if(master)
- master.post_signal(signal, comm_line)
- else
- del(signal)
+/datum/computer/file/embedded_program/airlock/proc/begin_cycle_in()
+ state = STATE_WAIT
+ target_state = TARGET_INOPEN
+/datum/computer/file/embedded_program/airlock/proc/begin_cycle_out()
+ state = STATE_WAIT
+ target_state = TARGET_OUTOPEN
-/datum/computer/file/embedded_program/proc/signalDoor(var/tag, var/command)
+/datum/computer/file/embedded_program/airlock/proc/close_doors()
+ toggleDoor(memory["interior_status"], tag_interior_door, 1, "close")
+ toggleDoor(memory["exterior_status"], tag_exterior_door, 1, "close")
+
+/datum/computer/file/embedded_program/airlock/proc/stop_cycling()
+ state = STATE_WAIT
+ target_state = TARGET_NONE
+
+/datum/computer/file/embedded_program/airlock/proc/done_cycling()
+ return (state == STATE_WAIT && target_state == TARGET_NONE)
+
+//are the doors closed and locked?
+/datum/computer/file/embedded_program/airlock/proc/check_doors_secured()
+ var/ext_closed = (memory["exterior_status"]["state"] == "closed" && memory["exterior_status"]["lock"] == "locked")
+ var/int_closed = (memory["interior_status"]["state"] == "closed" && memory["interior_status"]["lock"] == "locked")
+ return (ext_closed && int_closed)
+
+/datum/computer/file/embedded_program/airlock/proc/signalDoor(var/tag, var/command)
var/datum/signal/signal = new
signal.data["tag"] = tag
signal.data["command"] = command
post_signal(signal)
-
-/datum/computer/file/embedded_program/proc/signalPump(var/tag, var/power, var/direction, var/pressure)
+/datum/computer/file/embedded_program/airlock/proc/signalPump(var/tag, var/power, var/direction, var/pressure)
var/datum/signal/signal = new
signal.data = list(
"tag" = tag,
@@ -235,8 +266,8 @@
)
post_signal(signal)
-
-/datum/computer/file/embedded_program/proc/cycleDoors(var/target)
+//this is called to set the appropriate door state at the end of a cycling process, or for the exterior buttons
+/datum/computer/file/embedded_program/airlock/proc/cycleDoors(var/target)
switch(target)
if(TARGET_OUTOPEN)
toggleDoor(memory["interior_status"], tag_interior_door, memory["secure"], "close")
@@ -265,7 +296,7 @@ Only sends a command if it is needed, i.e. if the door is
already open, passing an open command to this proc will not
send an additional command to open the door again.
----------------------------------------------------------*/
-/datum/computer/file/embedded_program/proc/toggleDoor(var/list/doorStatus, var/doorTag, var/secure, var/command)
+/datum/computer/file/embedded_program/airlock/proc/toggleDoor(var/list/doorStatus, var/doorTag, var/secure, var/command)
var/doorCommand = null
if(command == "toggle")
diff --git a/code/game/machinery/embedded_controller/docking_program.dm b/code/game/machinery/embedded_controller/docking_program.dm
new file mode 100644
index 00000000000..a96850acfe3
--- /dev/null
+++ b/code/game/machinery/embedded_controller/docking_program.dm
@@ -0,0 +1,262 @@
+
+#define STATE_UNDOCKED 0
+#define STATE_DOCKING 1
+#define STATE_UNDOCKING 2
+#define STATE_DOCKED 3
+
+#define MODE_NONE 0
+#define MODE_SERVER 1
+#define MODE_CLIENT 2 //The one who initiated the docking, and who can initiate the undocking. The server cannot initiate undocking. (Think server == station, client == shuttle)
+
+/*
+ *** STATE TABLE ***
+
+ MODE_CLIENT|STATE_UNDOCKED sent a request for docking and now waiting for a reply.
+ MODE_CLIENT|STATE_DOCKING server told us they are OK to dock, waiting for our docking port to be ready.
+ MODE_CLIENT|STATE_DOCKED idle - docked as client.
+ MODE_CLIENT|STATE_UNDOCKING we are either waiting for our docking port to be ready or for the server to give us the OK to finish undocking.
+
+ MODE_SERVER|STATE_UNDOCKED should never happen.
+ MODE_SERVER|STATE_DOCKING someone requested docking, we are waiting for our docking port to be ready.
+ MODE_SERVER|STATE_DOCKED idle - docked as server
+ MODE_SERVER|STATE_UNDOCKING client requested undocking, we are waiting for our docking port to be ready.
+
+ MODE_NONE|STATE_UNDOCKED idle - not docked.
+ MODE_NONE|anything else should never happen.
+
+ *** Docking Signals ***
+
+ Docking
+ Client sends request_dock
+ Server sends confirm_dock to say that yes, we will serve your request
+ When client is ready, sends confirm_dock
+ Server sends confirm_dock back to indicate that docking is complete
+
+ Undocking
+ Client sends request_undock
+ When client is ready, sends confirm_undock
+ Server sends confirm_undock back to indicate that docking is complete
+
+ Note that in both cases each side exchanges confirm_dock before the docking operation is considered done.
+ The client first sends a confirm message to indicate it is ready, and then finally the server will send it's
+ confirm message to indicate that the operation is complete.
+
+ Note also that when docking, the server sends an additional confirm message. This is because before docking,
+ the server and client do not have a defined relationship. Before undocking, the server and client are already
+ related to each other, thus the extra confirm message is not needed.
+
+ *** Override, what is it? ***
+
+ The purpose of enabling the override is to prevent the docking program from automatically doing things with the docking port when docking or undocking.
+ Maybe the shuttle is full of plamsa/phoron for some reason, and you don't want the door to automatically open, or the airlock to cycle.
+ This means that the prepare_for_docking/undocking and finish_docking/undocking procs don't get called.
+
+ The docking controller will still check the state of the docking port, and thus prevent the shuttle from launching unless they force the launch (handling forced
+ launches is not the docking controller's responsibility). In this case it is up to the players to manually get the docking port into a good state to undock
+ (which usually just means closing and locking the doors).
+
+ In line with this, docking controllers should prevent players from manually doing things when the override is NOT enabled.
+*/
+
+
+/datum/computer/file/embedded_program/docking
+ var/tag_target //the tag of the docking controller that we are trying to dock with
+ var/dock_state = STATE_UNDOCKED
+ var/control_mode = MODE_NONE
+ var/response_sent = 0 //so we don't spam confirmation messages
+
+ var/override_enabled = 0 //skips checks for the docking port being ready
+ var/received_confirm = 0 //for undocking, whether the client has recieved a confirmation from the server
+
+/datum/computer/file/embedded_program/docking/receive_signal(datum/signal/signal, receive_method, receive_param)
+ var/receive_tag = signal.data["tag"] //for docking signals, this is the sender id
+ var/command = signal.data["command"]
+ var/recipient = signal.data["recipient"] //the intended recipient of the docking signal
+
+ if (recipient != id_tag)
+ return //this signal is not for us
+
+ switch (command)
+ if ("confirm_dock")
+ if (control_mode == MODE_CLIENT && dock_state == STATE_UNDOCKED && receive_tag == tag_target)
+ dock_state = STATE_DOCKING
+ if (!override_enabled)
+ prepare_for_docking()
+
+ else if (control_mode == MODE_CLIENT && dock_state == STATE_DOCKING && receive_tag == tag_target)
+ dock_state = STATE_DOCKED
+ if (!override_enabled)
+ finish_docking() //client done docking!
+ response_sent = 0
+ else if (control_mode == MODE_SERVER && dock_state == STATE_DOCKING && receive_tag == tag_target) //client just sent us the confirmation back, we're done with the docking process
+ received_confirm = 1
+
+ if ("request_dock")
+ if (control_mode == MODE_NONE && dock_state == STATE_UNDOCKED)
+ control_mode = MODE_SERVER
+ dock_state = STATE_DOCKING
+ tag_target = receive_tag
+ if (!override_enabled)
+ prepare_for_docking()
+ send_docking_command(tag_target, "confirm_dock") //acknowledge the request
+
+ if ("confirm_undock")
+ if (control_mode == MODE_CLIENT && dock_state == STATE_UNDOCKING && receive_tag == tag_target)
+ if (!override_enabled)
+ finish_undocking()
+ reset() //client is done undocking!
+ else if (control_mode == MODE_SERVER && dock_state == STATE_UNDOCKING && receive_tag == tag_target)
+ received_confirm = 1
+
+ if ("request_undock")
+ if (control_mode == MODE_SERVER && dock_state == STATE_DOCKED && receive_tag == tag_target)
+ dock_state = STATE_UNDOCKING
+ if (!override_enabled)
+ prepare_for_undocking()
+
+ if ("dock_error")
+ if (receive_tag == tag_target)
+ reset()
+
+/datum/computer/file/embedded_program/docking/process()
+ switch(dock_state)
+ if (STATE_DOCKING) //waiting for our docking port to be ready for docking
+ if (ready_for_docking())
+ if (control_mode == MODE_CLIENT)
+ if (!response_sent)
+ send_docking_command(tag_target, "confirm_dock") //tell the server we're ready
+ response_sent = 1
+
+ else if (control_mode == MODE_SERVER && received_confirm)
+ send_docking_command(tag_target, "confirm_dock") //tell the client we are done docking.
+ dock_state = STATE_DOCKED
+ if (!override_enabled)
+ finish_docking() //server done docking!
+ response_sent = 0
+ received_confirm = 0
+
+ if (STATE_UNDOCKING)
+ if (ready_for_undocking())
+ if (control_mode == MODE_CLIENT)
+ if (!response_sent)
+ send_docking_command(tag_target, "confirm_undock") //tell the server we are OK to undock.
+ response_sent = 1
+
+ else if (control_mode == MODE_SERVER && received_confirm)
+ send_docking_command(tag_target, "confirm_undock") //tell the client we are done undocking.
+ if (!override_enabled)
+ finish_undocking()
+ reset() //server is done undocking!
+
+
+
+ if (dock_state != STATE_DOCKING && dock_state != STATE_UNDOCKING)
+ response_sent = 0
+
+ //handle invalid states
+ if (control_mode == MODE_NONE && dock_state != STATE_UNDOCKED)
+ if (tag_target)
+ send_docking_command(tag_target, "dock_error")
+ reset()
+ if (control_mode == MODE_SERVER && dock_state == STATE_UNDOCKED)
+ control_mode = MODE_NONE
+
+
+/datum/computer/file/embedded_program/docking/proc/initiate_docking(var/target)
+ if (dock_state != STATE_UNDOCKED || control_mode == MODE_SERVER) //must be undocked and not serving another request to begin a new docking handshake
+ return
+
+ tag_target = target
+ control_mode = MODE_CLIENT
+
+ send_docking_command(tag_target, "request_dock")
+
+/datum/computer/file/embedded_program/docking/proc/initiate_undocking()
+ if (dock_state != STATE_DOCKED || control_mode != MODE_CLIENT) //must be docked and must be client to start undocking
+ return
+
+ dock_state = STATE_UNDOCKING
+ if (!override_enabled)
+ prepare_for_undocking()
+
+ send_docking_command(tag_target, "request_undock")
+
+//tell the docking port to start getting ready for docking - e.g. pressurize
+/datum/computer/file/embedded_program/docking/proc/prepare_for_docking()
+ return
+
+//are we ready for docking?
+/datum/computer/file/embedded_program/docking/proc/ready_for_docking()
+ return 1
+
+//we are docked, open the doors or whatever.
+/datum/computer/file/embedded_program/docking/proc/finish_docking()
+ return
+
+//tell the docking port to start getting ready for undocking - e.g. close those doors.
+/datum/computer/file/embedded_program/docking/proc/prepare_for_undocking()
+ return
+
+//we are docked, open the doors or whatever.
+/datum/computer/file/embedded_program/docking/proc/finish_undocking()
+ return
+
+//are we ready for undocking?
+/datum/computer/file/embedded_program/docking/proc/ready_for_undocking()
+ return 1
+
+/datum/computer/file/embedded_program/docking/proc/enable_override()
+ override_enabled = 1
+
+/datum/computer/file/embedded_program/docking/proc/disable_override()
+ override_enabled = 0
+
+/datum/computer/file/embedded_program/docking/proc/reset()
+ dock_state = STATE_UNDOCKED
+ control_mode = MODE_NONE
+ tag_target = null
+ response_sent = 0
+ received_confirm = 0
+
+/datum/computer/file/embedded_program/docking/proc/force_undock()
+ //world << "[id_tag]: forcing undock"
+ if (tag_target)
+ send_docking_command(tag_target, "dock_error")
+ reset()
+
+/datum/computer/file/embedded_program/docking/proc/docked()
+ return (dock_state == STATE_DOCKED)
+
+/datum/computer/file/embedded_program/docking/proc/undocked()
+ return (dock_state == STATE_UNDOCKED)
+
+//returns 1 if we are saftely undocked (and the shuttle can leave)
+/datum/computer/file/embedded_program/docking/proc/can_launch()
+ return undocked()
+
+/datum/computer/file/embedded_program/docking/proc/send_docking_command(var/recipient, var/command)
+ var/datum/signal/signal = new
+ signal.data["tag"] = id_tag
+ signal.data["command"] = command
+ signal.data["recipient"] = recipient
+ post_signal(signal)
+
+//this is mostly for NanoUI
+/datum/computer/file/embedded_program/docking/proc/get_docking_status()
+ switch (dock_state)
+ if (STATE_UNDOCKED) return "undocked"
+ if (STATE_DOCKING) return "docking"
+ if (STATE_UNDOCKING) return "undocking"
+ if (STATE_DOCKED) return "docked"
+
+
+
+
+#undef STATE_UNDOCKED
+#undef STATE_DOCKING
+#undef STATE_UNDOCKING
+#undef STATE_DOCKED
+
+#undef MODE_NONE
+#undef MODE_SERVER
+#undef MODE_CLIENT
\ No newline at end of file
diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm
index 2f2c6029160..0d6241211e5 100644
--- a/code/game/machinery/embedded_controller/embedded_controller_base.dm
+++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm
@@ -41,16 +41,8 @@
icon_state = "airlock_control_standby"
power_channel = ENVIRON
density = 0
-
- // Setup parameters only
+
var/id_tag
- var/tag_exterior_door
- var/tag_interior_door
- var/tag_airpump
- var/tag_chamber_sensor
- var/tag_exterior_sensor
- var/tag_interior_sensor
- var/tag_secure = 0
var/frequency = 1379
var/datum/radio_frequency/radio_connection
@@ -58,23 +50,6 @@
/obj/machinery/embedded_controller/radio/initialize()
set_frequency(frequency)
- var/datum/computer/file/embedded_program/new_prog = new
-
- new_prog.id_tag = id_tag
- new_prog.tag_exterior_door = tag_exterior_door
- new_prog.tag_interior_door = tag_interior_door
- new_prog.tag_airpump = tag_airpump
- new_prog.tag_chamber_sensor = tag_chamber_sensor
- new_prog.tag_exterior_sensor = tag_exterior_sensor
- new_prog.tag_interior_sensor = tag_interior_sensor
- new_prog.memory["secure"] = tag_secure
-
- new_prog.master = src
- program = new_prog
-
- spawn(10)
- program.signalDoor(tag_exterior_door, "update") //signals connected doors to update their status
- program.signalDoor(tag_interior_door, "update")
/obj/machinery/embedded_controller/radio/update_icon()
if(on && program)
diff --git a/code/game/machinery/embedded_controller/embedded_program_base.dm b/code/game/machinery/embedded_controller/embedded_program_base.dm
new file mode 100644
index 00000000000..611fcfc52e5
--- /dev/null
+++ b/code/game/machinery/embedded_controller/embedded_program_base.dm
@@ -0,0 +1,27 @@
+
+/datum/computer/file/embedded_program
+ var/list/memory = list()
+ var/obj/machinery/embedded_controller/master
+
+ var/id_tag
+
+/datum/computer/file/embedded_program/New(var/obj/machinery/embedded_controller/M)
+ master = M
+ if (istype(M, /obj/machinery/embedded_controller/radio))
+ var/obj/machinery/embedded_controller/radio/R = M
+ id_tag = R.id_tag
+
+/datum/computer/file/embedded_program/proc/receive_user_command(command)
+ return
+
+/datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
+ return
+
+/datum/computer/file/embedded_program/proc/process()
+ return
+
+/datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line)
+ if(master)
+ master.post_signal(signal, comm_line)
+ else
+ del(signal)
diff --git a/code/game/machinery/embedded_controller/simple_docking_controller.dm b/code/game/machinery/embedded_controller/simple_docking_controller.dm
new file mode 100644
index 00000000000..bf200b85eb1
--- /dev/null
+++ b/code/game/machinery/embedded_controller/simple_docking_controller.dm
@@ -0,0 +1,157 @@
+//a docking port that uses a single door
+/obj/machinery/embedded_controller/radio/simple_docking_controller
+ name = "docking hatch controller"
+ var/tag_door
+ var/datum/computer/file/embedded_program/docking/simple/docking_program
+
+/obj/machinery/embedded_controller/radio/simple_docking_controller/initialize()
+ ..()
+ docking_program = new/datum/computer/file/embedded_program/docking/simple(src)
+ program = docking_program
+
+/obj/machinery/embedded_controller/radio/simple_docking_controller/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
+ var/data[0]
+
+ data = list(
+ "docking_status" = docking_program.get_docking_status(),
+ "override_enabled" = docking_program.override_enabled,
+ )
+
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
+
+ if (!ui)
+ ui = new(user, src, ui_key, "simple_docking_console.tmpl", name, 470, 290)
+ ui.set_initial_data(data)
+ ui.open()
+ ui.set_auto_update(1)
+
+/obj/machinery/embedded_controller/radio/simple_docking_controller/Topic(href, href_list)
+ if(..())
+ return
+
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+
+ var/clean = 0
+ switch(href_list["command"]) //anti-HTML-hacking checks
+ if("force_door")
+ clean = 1
+ if("toggle_override")
+ clean = 1
+
+ if(clean)
+ program.receive_user_command(href_list["command"])
+
+ return 1
+
+
+//A docking controller program for a simple door based docking port
+/datum/computer/file/embedded_program/docking/simple
+ var/tag_door
+
+/datum/computer/file/embedded_program/docking/simple/New(var/obj/machinery/embedded_controller/M)
+ ..(M)
+ memory["door_status"] = list(state = "closed", lock = "locked") //assume closed and locked in case the doors dont report in
+ memory["door_status"] = list(state = "closed", lock = "locked")
+
+ if (istype(M, /obj/machinery/embedded_controller/radio/simple_docking_controller))
+ var/obj/machinery/embedded_controller/radio/simple_docking_controller/controller = M
+
+ tag_door = controller.tag_door
+
+ spawn(10)
+ signal_door("update") //signals connected doors to update their status
+
+
+/datum/computer/file/embedded_program/docking/simple/receive_signal(datum/signal/signal, receive_method, receive_param)
+ var/receive_tag = signal.data["tag"]
+
+ if(!receive_tag) return
+
+ if(receive_tag==tag_door)
+ memory["door_status"]["state"] = signal.data["door_status"]
+ memory["door_status"]["lock"] = signal.data["lock_status"]
+
+ ..(signal, receive_method, receive_param)
+
+/datum/computer/file/embedded_program/docking/simple/receive_user_command(command)
+ switch(command)
+ if("force_door")
+ if (override_enabled)
+ if(memory["door_status"]["state"] == "open")
+ close_door()
+ else
+ open_door()
+ if("toggle_override")
+ if (override_enabled)
+ disable_override()
+ else
+ enable_override()
+
+
+/datum/computer/file/embedded_program/docking/simple/proc/signal_door(var/command)
+ var/datum/signal/signal = new
+ signal.data["tag"] = tag_door
+ signal.data["command"] = command
+ post_signal(signal)
+
+/datum/computer/file/embedded_program/docking/simple/proc/open_door()
+ if(memory["door_status"]["state"] == "closed")
+ signal_door("secure_open")
+ else if(memory["door_status"]["lock"] == "unlocked")
+ signal_door("lock")
+
+/datum/computer/file/embedded_program/docking/simple/proc/close_door()
+ if(memory["door_status"]["state"] == "open")
+ signal_door("secure_close")
+ else if(memory["door_status"]["lock"] == "unlocked")
+ signal_door("lock")
+
+//tell the docking port to start getting ready for docking - e.g. pressurize
+/datum/computer/file/embedded_program/docking/simple/prepare_for_docking()
+ return //don't need to do anything
+
+//are we ready for docking?
+/datum/computer/file/embedded_program/docking/simple/ready_for_docking()
+ return 1 //don't need to do anything
+
+//we are docked, open the doors or whatever.
+/datum/computer/file/embedded_program/docking/simple/finish_docking()
+ open_door()
+
+//tell the docking port to start getting ready for undocking - e.g. close those doors.
+/datum/computer/file/embedded_program/docking/simple/prepare_for_undocking()
+ close_door()
+
+//are we ready for undocking?
+/datum/computer/file/embedded_program/docking/simple/ready_for_undocking()
+ return (memory["door_status"]["state"] == "closed" && memory["door_status"]["lock"] == "locked")
+
+/*** DEBUG VERBS ***
+
+/obj/machinery/embedded_controller/radio/simple_docking_controller/verb/view_state()
+ set category = "Debug"
+ set src in view(1)
+ src.program:print_state()
+
+/obj/machinery/embedded_controller/radio/simple_docking_controller/verb/spoof_signal(var/command as text, var/sender as text)
+ set category = "Debug"
+ set src in view(1)
+ var/datum/signal/signal = new
+ signal.data["tag"] = sender
+ signal.data["command"] = command
+ signal.data["recipient"] = id_tag
+
+ src.program:receive_signal(signal)
+
+/obj/machinery/embedded_controller/radio/simple_docking_controller/verb/debug_init_dock(var/target as text)
+ set category = "Debug"
+ set src in view(1)
+ src.program:initiate_docking(target)
+
+/obj/machinery/embedded_controller/radio/simple_docking_controller/verb/debug_init_undock()
+ set category = "Debug"
+ set src in view(1)
+ src.program:initiate_undocking()
+
+*/
\ No newline at end of file
diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm
index 841ac36d9bc..6242626bc79 100644
--- a/code/game/machinery/kitchen/smartfridge.dm
+++ b/code/game/machinery/kitchen/smartfridge.dm
@@ -407,16 +407,6 @@
src.visible_message("\red [src] launches [throw_item.name] at [target.name]!")
return 1
-/obj/machinery/smartfridge/proc/shock(mob/user, prb)
- if(!ispowered) return 0
- if(!prob(prb)) return 0
-
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, src)
- s.start()
-
- return electrocute_mob(user, get_area(src), src, 0.7)
-
/************************
* Secure SmartFridges
*************************/
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 0b16a5aee2d..495bb452464 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -258,3 +258,28 @@ Class Procs:
state(text, "blue")
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
+
+/obj/machinery/proc/shock(mob/user, prb)
+ if(stat & (BROKEN|NOPOWER))
+ return 0
+ if(!prob(prb))
+ return 0
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ if (electrocute_mob(user, get_area(src), src, 0.7))
+ return 1
+ else
+ return 0
+
+/obj/machinery/proc/dismantle()
+ playsound(loc, 'sound/items/Crowbar.ogg', 50, 1)
+ var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(loc)
+ M.state = 2
+ M.icon_state = "box_1"
+ for(var/obj/I in component_parts)
+ if(I.reliability != 100 && crit_fail)
+ I.crit_fail = 1
+ I.loc = loc
+ del(src)
+ return 1
\ No newline at end of file
diff --git a/code/game/machinery/podmen.dm b/code/game/machinery/podmen.dm
index 980596e91bd..5acd792942d 100644
--- a/code/game/machinery/podmen.dm
+++ b/code/game/machinery/podmen.dm
@@ -126,6 +126,8 @@ Growing it to term with nothing injected will grab a ghost from the observers. *
podman.dna.real_name = podman.real_name
// Update mode specific HUD icons.
+ callHook("harvest_podman", list(podman))
+
switch(ticker.mode.name)
if ("revolution")
if (podman.mind in ticker.mode:revolutionaries)
diff --git a/code/game/machinery/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm
index 3d185e47d7c..73aacd3a9b0 100644
--- a/code/game/machinery/robot_fabricator.dm
+++ b/code/game/machinery/robot_fabricator.dm
@@ -21,7 +21,7 @@
if(!O:amount)
return
while(metal_amount < 150000 && O:amount)
- src.metal_amount += O:m_amt /*O:height * O:width * O:length * 100000.0*/
+ src.metal_amount += O.matter["metal"] /*O:height * O:width * O:length * 100000.0*/
O:amount--
count++
diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm
index c62f1a236aa..404c2d54ca4 100644
--- a/code/game/machinery/status_display.dm
+++ b/code/game/machinery/status_display.dm
@@ -110,13 +110,22 @@
update_display(line1, line2)
if(4) // supply shuttle timer
var/line1 = "SUPPLY"
- var/line2
- if(supply_shuttle.moving)
+ var/line2 = ""
+
+ var/datum/shuttle/ferry/supply/shuttle = supply_controller.get_shuttle()
+ if (!shuttle)
+ line2 = "Error"
+ else if(shuttle.has_eta())
line2 = get_supply_shuttle_timer()
if(lentext(line2) > CHARS_PER_LINE)
line2 = "Error"
+ else if (shuttle.moving_status == SHUTTLE_WARMUP)
+ if (shuttle.at_station())
+ line2 = "Launch"
+ else
+ line2 = "ETA"
else
- if(supply_shuttle.at_station)
+ if(shuttle.at_station())
line2 = "Docked"
else
line1 = ""
@@ -162,8 +171,12 @@
return ""
proc/get_supply_shuttle_timer()
- if(supply_shuttle.moving)
- var/timeleft = round((supply_shuttle.eta_timeofday - world.timeofday) / 10,1)
+ var/datum/shuttle/ferry/supply/shuttle = supply_controller.get_shuttle()
+ if (!shuttle)
+ return "Error"
+
+ if(shuttle.has_eta())
+ var/timeleft = round((shuttle.arrive_time - world.time) / 10,1)
if(timeleft < 0)
return "Late"
return "[add_zero(num2text((timeleft / 60) % 60),2)]:[add_zero(num2text(timeleft % 60), 2)]"
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 1d8fd6a36b7..f939e24a6b8 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -567,4 +567,541 @@
return
-//////////////////////////////REMINDER: Make it lock once you place some fucker inside.
\ No newline at end of file
+//////////////////////////////REMINDER: Make it lock once you place some fucker inside.
+
+//God this entire file is fucking awful
+//Suit painter for Bay's special snowflake aliums.
+
+/obj/machinery/suit_cycler
+
+ name = "suit cycler"
+ desc = "An industrial machine for repairing, painting and equipping hardsuits."
+ anchored = 1
+ density = 1
+
+ icon = 'icons/obj/suitstorage.dmi'
+ icon_state = "suitstorage000000100"
+
+ req_access = list(access_captain,access_heads)
+
+ var/active = 0 // PLEASE HOLD.
+ var/safeties = 1 // The cycler won't start with a living thing inside it unless safeties are off.
+ var/irradiating = 0 // If this is > 0, the cycler is decontaminating whatever is inside it.
+ var/radiation_level = 2 // 1 is removing germs, 2 is removing blood, 3 is removing phoron.
+ var/model_text = "" // Some flavour text for the topic box.
+ var/locked = 1 // If locked, nothing can be taken from or added to the cycler.
+ var/panel_open = 0 // Hacking!
+
+ // Wiring bollocks.
+ var/wires = 15
+ var/electrified = 0
+ var/const/WIRE_EXTEND = 1 // Safeties
+ var/const/WIRE_SCANID = 2 // Locked status
+ var/const/WIRE_SHOCK = 3 // What it says on the tin.
+
+ //Departments that the cycler can paint suits to look like.
+ var/list/departments = list("Engineering","Mining","Medical","Security","Atmos")
+ //Species that the suits can be configured to fit.
+ var/list/species = list("Human","Skrell","Unathi","Tajaran")
+
+ var/target_department = "Engineering"
+ var/target_species = "Human"
+
+ var/mob/living/carbon/human/occupant = null
+ var/obj/item/clothing/suit/space/rig/suit = null
+ var/obj/item/clothing/head/helmet/space/helmet = null
+
+/obj/machinery/suit_cycler/engineering
+ name = "Engineering suit cycler"
+ model_text = "Engineering"
+ req_access = list(access_construction)
+ departments = list("Engineering","Atmos")
+ species = list("Human","Unathi","Tajaran")
+
+/obj/machinery/suit_cycler/mining
+ name = "Mining suit cycler"
+ model_text = "Mining"
+ req_access = list(access_mining)
+ departments = list("Mining")
+ species = list("Human","Unathi","Tajaran")
+
+/obj/machinery/suit_cycler/attack_ai(mob/user as mob)
+ return src.attack_hand(user)
+
+/obj/machinery/suit_cycler/attack_paw(mob/user as mob)
+ user << "\blue The console controls are far too complicated for your tiny brain!"
+ return
+
+/obj/machinery/suit_cycler/attackby(obj/item/I as obj, mob/user as mob)
+
+ if(electrified != 0)
+ if(src.shock(user, 100))
+ return
+
+ //Hacking init.
+ if(istype(I, /obj/item/device/multitool) || istype(I, /obj/item/weapon/wirecutters))
+ if(panel_open)
+ attack_hand(user)
+ return
+ //Other interface stuff.
+ if(istype(I, /obj/item/weapon/grab))
+ var/obj/item/weapon/grab/G = I
+
+ if(!(ismob(G.affecting)))
+ return
+
+ if(locked)
+ user << "\red The suit cycler is locked."
+ return
+
+ if(src.contents.len > 0)
+ user << "\red There is no room inside the cycler for [G.affecting.name]."
+ return
+
+ visible_message("[user] starts putting [G.affecting.name] into the suit cycler.", 3)
+
+ if(do_after(user, 20))
+ if(!G || !G.affecting) return
+ var/mob/M = G.affecting
+ if (M.client)
+ M.client.perspective = EYE_PERSPECTIVE
+ M.client.eye = src
+ M.loc = src
+ src.occupant = M
+
+ src.add_fingerprint(user)
+ del(G)
+
+ src.updateUsrDialog()
+
+ return
+ else if(istype(I,/obj/item/weapon/screwdriver))
+
+ panel_open = !panel_open
+ user << "You [panel_open ? "open" : "close"] the maintenance panel."
+ src.updateUsrDialog()
+ return
+
+ else if(istype(I,/obj/item/weapon/card/emag))
+
+ if(emagged)
+ user << "\red The cycler has already been subverted."
+ return
+
+ var/obj/item/weapon/card/emag/E = I
+ src.updateUsrDialog()
+ E.uses--
+
+ //Clear the access reqs, disable the safeties, and open up all paintjobs.
+ user << "\red You run the sequencer across the interface, corrupting the operating protocols."
+ departments = list("Engineering","Mining","Medical","Security","Atmos","^%###^%$")
+ emagged = 1
+ safeties = 0
+ req_access = list()
+ return
+
+ else if(istype(I,/obj/item/clothing/head/helmet/space))
+
+ if(locked)
+ user << "\red The suit cycler is locked."
+ return
+
+ if(helmet)
+ user << "The cycler already contains a helmet."
+ return
+
+ user << "You fit \the [I] into the suit cycler."
+ user.drop_item()
+ I.loc = src
+ helmet = I
+
+ src.update_icon()
+ src.updateUsrDialog()
+ return
+
+ else if(istype(I,/obj/item/clothing/suit/space/rig))
+
+ if(locked)
+ user << "\red The suit cycler is locked."
+ return
+
+ if(suit)
+ user << "The cycler already contains a hardsuit."
+ return
+
+ var/obj/item/clothing/suit/space/rig/S = I
+
+ if(S.helmet)
+ user << "\The [S] will not fit into the cycler with a helmet attached."
+ return
+
+ if(S.boots)
+ user << "\The [S] will not fit into the cycler with boots attached."
+ return
+
+ user << "You fit \the [I] into the suit cycler."
+ user.drop_item()
+ I.loc = src
+ suit = I
+
+ src.update_icon()
+ src.updateUsrDialog()
+ return
+
+ ..()
+
+/obj/machinery/suit_cycler/attack_hand(mob/user as mob)
+
+ add_fingerprint(user)
+
+ if(..() || stat & (BROKEN|NOPOWER))
+ return
+
+ if(electrified != 0)
+ if(src.shock(user, 100))
+ return
+
+ usr.set_machine(src)
+
+ var/dat = "
"
+
+ if(src.active)
+ dat+= "
The [model_text ? "[model_text] " : ""]suit cycler is currently in use. Please wait..."
+
+ else if(locked)
+ dat += "
The [model_text ? "[model_text] " : ""]suit cycler is currently locked. Please contact your system administrator."
+ if(src.allowed(usr))
+ dat += "
\[unlock unit\]"
+ else
+ dat += "
" + dat += "Welcome to the [model_text ? "[model_text] " : ""]suit cycler control panel. \[lock unit\]
" + + dat += "
"
+ dat += "Helmet: [helmet ? "\the [helmet]" : "no helmet stored" ]. \[eject\]
"
+ dat += "Suit: [suit ? "\the [suit]" : "no suit stored" ]. \[eject\]"
+
+ if(suit && istype(suit))
+ dat += "[(suit.damage ? " \[repair\]" : "")]"
+
+ dat += "
UV decontamination systems: SYSTEM ERROR" : "green'>READY"]
"
+ dat += "Output level: [radiation_level]
"
+ dat += "\[select power level\] \[begin decontamination cycle\]
" + + dat += "
"
+ dat += "Target product: [target_department], [target_species]."
+ dat += "
\[apply customisation routine\]
"
+
+ if(panel_open)
+ var/list/vendwires = list(
+ "Violet" = 1,
+ "Orange" = 2,
+ "Goldenrod" = 3,
+ )
+ dat += "Access Panel
"
+ for(var/wiredesc in vendwires)
+ var/is_uncut = src.wires & APCWireColorToFlag[vendwires[wiredesc]]
+ dat += "[wiredesc] wire: "
+ if(!is_uncut)
+ dat += "Mend"
+ else
+ dat += "Cut "
+ dat += "Pulse "
+ dat += "
"
+
+ dat += "
"
+ dat += "The orange light is [(electrified == 0) ? "off" : "on"].
"
+ dat += "The red light is [safeties ? "blinking" : "off"].
"
+ dat += "The yellow light is [locked ? "on" : "off"].
"
+
+ user << browse(dat, "window=suit_cycler")
+ onclose(user, "suit_cycler")
+ return
+
+/obj/machinery/suit_cycler/Topic(href, href_list)
+ if(href_list["eject_suit"])
+ if(!suit) return
+ suit.loc = get_turf(src)
+ suit = null
+ else if(href_list["eject_helmet"])
+ if(!helmet) return
+ helmet.loc = get_turf(src)
+ helmet = null
+ else if(href_list["select_department"])
+ target_department = input("Please select the target department paintjob.","Suit cycler",null) as null|anything in departments
+ else if(href_list["select_species"])
+ target_species = input("Please select the target species configuration.","Suit cycler",null) as null|anything in species
+ else if(href_list["select_rad_level"])
+ var/choices = list(1,2,3)
+ if(emagged)
+ choices = list(1,2,3,4,5)
+ radiation_level = input("Please select the desired radiation level.","Suit cycler",null) as null|anything in choices
+ else if(href_list["repair_suit"])
+
+ if(!suit) return
+ active = 1
+ spawn(100)
+ repair_suit()
+ finished_job()
+
+ else if(href_list["apply_paintjob"])
+
+ if(!suit && !helmet) return
+ active = 1
+ spawn(100)
+ apply_paintjob()
+ finished_job()
+
+ else if(href_list["toggle_safties"])
+ safeties = !safeties
+
+ else if(href_list["toggle_lock"])
+
+ if(src.allowed(usr))
+ locked = !locked
+ usr << "You [locked ? "" : "un"]lock \the [src]."
+ else
+ usr << "\red Access denied."
+
+ else if(href_list["begin_decontamination"])
+
+ if(safeties && occupant)
+ usr << "\red The cycler has detected an occupant. Please remove the occupant before commencing the decontamination cycle."
+ return
+
+ active = 1
+ irradiating = 10
+ src.updateUsrDialog()
+
+ sleep(10)
+
+ if(helmet)
+ if(radiation_level > 2)
+ helmet.decontaminate()
+ if(radiation_level > 1)
+ helmet.clean_blood()
+
+ if(suit)
+ if(radiation_level > 2)
+ suit.decontaminate()
+ if(radiation_level > 1)
+ suit.clean_blood()
+
+ else if ((href_list["cutwire"]) && (src.panel_open))
+ var/twire = text2num(href_list["cutwire"])
+ if (!( istype(usr.get_active_hand(), /obj/item/weapon/wirecutters) ))
+ usr << "You need wirecutters!"
+ return
+ if (src.isWireColorCut(twire))
+ src.mend(twire)
+ else
+ src.cut(twire)
+
+ else if ((href_list["pulsewire"]) && (src.panel_open))
+ var/twire = text2num(href_list["pulsewire"])
+ if (!istype(usr.get_active_hand(), /obj/item/device/multitool))
+ usr << "You need a multitool!"
+ return
+ if (src.isWireColorCut(twire))
+ usr << "You can't pulse a cut wire."
+ return
+ else
+ src.pulse(twire)
+
+ src.updateUsrDialog()
+ return
+
+/obj/machinery/suit_cycler/process()
+
+ if(electrified > 0)
+ electrified--
+
+ if(!active)
+ return
+
+ if(active && stat & (BROKEN|NOPOWER))
+ active = 0
+ irradiating = 0
+ electrified = 0
+ return
+
+ if(irradiating == 1)
+ finished_job()
+ irradiating = 0
+ return
+
+ irradiating--
+
+ if(occupant)
+ if(prob(radiation_level*2)) occupant.emote("scream")
+ if(radiation_level > 2)
+ occupant.take_organ_damage(0,radiation_level*2 + rand(1,3))
+ if(radiation_level > 1)
+ occupant.take_organ_damage(0,radiation_level + rand(1,3))
+ occupant.radiation += radiation_level*10
+
+/obj/machinery/suit_cycler/proc/finished_job()
+ var/turf/T = get_turf(src)
+ T.visible_message("\The [src] pings loudly.")
+ icon_state = initial(icon_state)
+ active = 0
+ src.updateUsrDialog()
+
+/obj/machinery/suit_cycler/proc/repair_suit()
+ if(!suit || !suit.damage || !suit.can_breach)
+ return
+
+ suit.breaches = list()
+ suit.calc_breach_damage()
+
+ return
+
+/obj/machinery/suit_cycler/verb/leave()
+ set name = "Eject Cycler"
+ set category = "Object"
+ set src in oview(1)
+
+ if (usr.stat != 0)
+ return
+
+ eject_occupant(usr)
+
+/obj/machinery/suit_cycler/proc/eject_occupant(mob/user as mob)
+
+ if(locked || active)
+ user << "\red The cycler is locked."
+ return
+
+ if (!occupant)
+ return
+
+ if (occupant.client)
+ occupant.client.eye = occupant.client.mob
+ occupant.client.perspective = MOB_PERSPECTIVE
+
+ occupant.loc = get_turf(occupant)
+ occupant = null
+
+ add_fingerprint(usr)
+ src.updateUsrDialog()
+ src.update_icon()
+
+ return
+
+//HACKING PROCS, MOSTLY COPIED FROM VENDING MACHINES
+/obj/machinery/suit_cycler/proc/isWireColorCut(var/wireColor)
+ var/wireFlag = APCWireColorToFlag[wireColor]
+ return ((src.wires & wireFlag) == 0)
+
+/obj/machinery/suit_cycler/proc/isWireCut(var/wireIndex)
+ var/wireFlag = APCIndexToFlag[wireIndex]
+ return ((src.wires & wireFlag) == 0)
+
+/obj/machinery/suit_cycler/proc/cut(var/wireColor)
+ var/wireFlag = APCWireColorToFlag[wireColor]
+ var/wireIndex = APCWireColorToIndex[wireColor]
+ src.wires &= ~wireFlag
+ switch(wireIndex)
+
+ if(WIRE_EXTEND)
+ safeties = 0
+ if(WIRE_SHOCK)
+ electrified = -1
+ if (WIRE_SCANID)
+ locked = 0
+
+/obj/machinery/suit_cycler/proc/mend(var/wireColor)
+ var/wireFlag = APCWireColorToFlag[wireColor]
+ var/wireIndex = APCWireColorToIndex[wireColor] //not used in this function
+ src.wires |= wireFlag
+ switch(wireIndex)
+ if(WIRE_SHOCK)
+ src.electrified = 0
+
+/obj/machinery/suit_cycler/proc/pulse(var/wireColor)
+ var/wireIndex = APCWireColorToIndex[wireColor]
+ switch(wireIndex)
+ if(WIRE_EXTEND)
+ safeties = !locked
+ if(WIRE_SHOCK)
+ electrified = 30
+ if (WIRE_SCANID)
+ locked = !locked
+
+//There HAS to be a less bloated way to do this. TODO: some kind of table/icon name coding? ~Z
+/obj/machinery/suit_cycler/proc/apply_paintjob()
+
+ if(!target_species || !target_department)
+ return
+
+ switch(target_species)
+ if("Human" || "Skrell")
+ if(helmet) helmet.species_restricted = list("exclude","Unathi","Tajaran","Diona","Vox")
+ if(suit) suit.species_restricted = list("exclude","Unathi","Tajaran","Diona","Vox")
+ if("Unathi")
+ if(helmet) helmet.species_restricted = list("Unathi")
+ if(suit) suit.species_restricted = list("Unathi")
+ if("Tajaran")
+ if(helmet) helmet.species_restricted = list("Tajaran")
+ if(suit) suit.species_restricted = list("Tajaran")
+
+ switch(target_department)
+ if("Engineering")
+ if(helmet)
+ helmet.name = "engineering hardsuit helmet"
+ helmet.icon_state = "rig0-engineering"
+ helmet.item_state = "eng_helm"
+ helmet.item_color = "engineering"
+ if(suit)
+ suit.name = "engineering hardsuit"
+ suit.icon_state = "rig-engineering"
+ suit.item_state = "eng_hardsuit"
+ if("Mining")
+ if(helmet)
+ helmet.name = "mining hardsuit helmet"
+ helmet.icon_state = "rig0-mining"
+ helmet.item_state = "mining_helm"
+ helmet.item_color = "mining"
+ if(suit)
+ suit.name = "mining hardsuit"
+ suit.icon_state = "rig-mining"
+ suit.item_state = "mining_hardsuit"
+ if("Medical")
+ if(helmet)
+ helmet.name = "medical hardsuit helmet"
+ helmet.icon_state = "rig0-medical"
+ helmet.item_state = "medical_helm"
+ helmet.item_color = "medical"
+ if(suit)
+ suit.name = "medical hardsuit"
+ suit.icon_state = "rig-medical"
+ suit.item_state = "medical_hardsuit"
+ if("Security")
+ if(helmet)
+ helmet.name = "security hardsuit helmet"
+ helmet.icon_state = "rig0-sec"
+ helmet.item_state = "sec_helm"
+ helmet.item_color = "sec"
+ if(suit)
+ suit.name = "security hardsuit"
+ suit.icon_state = "rig-sec"
+ suit.item_state = "sec_hardsuit"
+ if("Atmos")
+ if(helmet)
+ helmet.name = "atmospherics hardsuit helmet"
+ helmet.icon_state = "rig0-atmos"
+ helmet.item_state = "atmos_helm"
+ helmet.item_color = "atmos"
+ if(suit)
+ suit.name = "atmospherics hardsuit"
+ suit.icon_state = "rig-atmos"
+ suit.item_state = "atmos_hardsuit"
+ if("^%###^%$")
+ if(helmet)
+ helmet.name = "blood-red hardsuit helmet"
+ helmet.icon_state = "rig0-syndie"
+ helmet.item_state = "syndie_helm"
+ helmet.item_color = "syndie"
+ if(suit)
+ suit.name = "blood-red hardsuit"
+ suit.item_state = "syndie_hardsuit"
+ suit.icon_state = "rig-syndie"
\ No newline at end of file
diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm
index 916c7450212..d8272453c92 100644
--- a/code/game/machinery/teleporter.dm
+++ b/code/game/machinery/teleporter.dm
@@ -3,6 +3,7 @@
desc = "Used to control a linked teleportation Hub and Station."
icon_state = "teleport"
circuit = "/obj/item/weapon/circuitboard/teleporter"
+ dir = 4
var/obj/item/locked = null
var/id = null
var/one_time_use = 0 //Used for one-time-use teleport cards (such as clown planet coordinates.)
@@ -11,8 +12,23 @@
/obj/machinery/computer/teleporter/New()
src.id = "[rand(1000, 9999)]"
..()
+ underlays.Cut()
+ underlays += image('icons/obj/stationobjs.dmi', icon_state = "telecomp-wires")
return
+/obj/machinery/computer/teleporter/initialize()
+ var/obj/machinery/teleport/station/station = locate(/obj/machinery/teleport/station, get_step(src, dir))
+ var/obj/machinery/teleport/hub/hub
+ if(station)
+ hub = locate(/obj/machinery/teleport/hub, get_step(station, dir))
+
+ if(istype(station))
+ station.com = hub
+ station.dir = dir
+
+ if(istype(hub))
+ hub.com = src
+ hub.dir = dir
/obj/machinery/computer/teleporter/attackby(I as obj, mob/living/user as mob)
if(istype(I, /obj/item/weapon/card/data/))
@@ -143,10 +159,17 @@
name = "teleporter hub"
desc = "It's the hub of a teleporting machine."
icon_state = "tele0"
+ dir = 4
var/accurate = 0
use_power = 1
idle_power_usage = 10
active_power_usage = 2000
+ var/obj/machinery/computer/teleporter/com
+
+/obj/machinery/teleport/hub/New()
+ ..()
+ underlays.Cut()
+ underlays += image('icons/obj/stationobjs.dmi', icon_state = "tele-wires")
/obj/machinery/teleport/hub/Bumped(M as mob|obj)
spawn()
@@ -156,8 +179,6 @@
return
/obj/machinery/teleport/hub/proc/teleport(atom/movable/M as mob|obj)
- var/atom/l = src.loc
- var/obj/machinery/computer/teleporter/com = locate(/obj/machinery/computer/teleporter, locate(l.x - 2, l.y, l.z))
if (!com)
return
if (!com.locked)
@@ -271,11 +292,18 @@
name = "station"
desc = "It's the station thingy of a teleport thingy." //seriously, wtf.
icon_state = "controller"
+ dir = 4
var/active = 0
var/engaged = 0
use_power = 1
idle_power_usage = 10
active_power_usage = 2000
+ var/obj/machinery/teleport/hub/com
+
+/obj/machinery/teleport/station/New()
+ ..()
+ overlays.Cut()
+ overlays += image('icons/obj/stationobjs.dmi', icon_state = "controller-wires")
/obj/machinery/teleport/station/attackby(var/obj/item/weapon/W)
src.attack_hand()
@@ -296,8 +324,6 @@
if(stat & (BROKEN|NOPOWER))
return
- var/atom/l = src.loc
- var/atom/com = locate(/obj/machinery/teleport/hub, locate(l.x + 1, l.y, l.z))
if (com)
com.icon_state = "tele1"
use_power(5000)
@@ -311,8 +337,6 @@
if(stat & (BROKEN|NOPOWER))
return
- var/atom/l = src.loc
- var/atom/com = locate(/obj/machinery/teleport/hub, locate(l.x + 1, l.y, l.z))
if (com)
com.icon_state = "tele0"
for(var/mob/O in hearers(src, null))
@@ -329,8 +353,6 @@
if(stat & (BROKEN|NOPOWER) || !istype(usr,/mob/living))
return
- var/atom/l = src.loc
- var/obj/machinery/teleport/hub/com = locate(/obj/machinery/teleport/hub, locate(l.x + 1, l.y, l.z))
if (com && !active)
active = 1
for(var/mob/O in hearers(src, null))
@@ -348,7 +370,7 @@
..()
if(stat & NOPOWER)
icon_state = "controller-p"
- var/obj/machinery/teleport/hub/com = locate(/obj/machinery/teleport/hub, locate(x + 1, y, z))
+
if(com)
com.icon_state = "tele0"
else
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 1c130d252b7..5dd31a036ea 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -158,6 +158,20 @@
ewallet = W
user << "\blue You insert the [W] into the [src]"
+ else if(istype(W, /obj/item/weapon/wrench))
+
+ if(do_after(user, 20))
+ if(!src) return
+ playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1)
+ switch (anchored)
+ if (0)
+ anchored = 1
+ user.visible_message("[user] tightens the bolts securing \the [src] to the floor.", "You tighten the bolts securing \the [src] to the floor.")
+ if (1)
+ user.visible_message("[user] unfastens the bolts securing \the [src] to the floor.", "You unfasten the bolts securing \the [src] to the floor.")
+ anchored = 0
+ return
+
else if(src.panel_open)
for(var/datum/data/vending_product/R in product_records)
@@ -587,19 +601,6 @@
src.shoot_inventory = !src.shoot_inventory
-/obj/machinery/vending/proc/shock(mob/user, prb)
- if(stat & (BROKEN|NOPOWER)) // unpowered, no shock
- return 0
- if(!prob(prb))
- return 0
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(5, 1, src)
- s.start()
- if (electrocute_mob(user, get_area(src), src, 0.7))
- return 1
- else
- return 0
-
/*
* Vending machine types
*/
@@ -806,7 +807,7 @@
products = list(/obj/item/seeds/bananaseed = 3,/obj/item/seeds/berryseed = 3,/obj/item/seeds/carrotseed = 3,/obj/item/seeds/chantermycelium = 3,/obj/item/seeds/chiliseed = 3,
/obj/item/seeds/cornseed = 3, /obj/item/seeds/eggplantseed = 3, /obj/item/seeds/potatoseed = 3, /obj/item/seeds/replicapod = 3,/obj/item/seeds/soyaseed = 3,
/obj/item/seeds/sunflowerseed = 3,/obj/item/seeds/tomatoseed = 3,/obj/item/seeds/towermycelium = 3,/obj/item/seeds/wheatseed = 3,/obj/item/seeds/appleseed = 3,
- /obj/item/seeds/poppyseed = 3,/obj/item/seeds/sugarcaneseed = 3,/obj/item/seeds/ambrosiavulgarisseed = 3,/obj/item/seeds/whitebeetseed = 3,/obj/item/seeds/watermelonseed = 3,/obj/item/seeds/limeseed = 3,
+ /obj/item/seeds/poppyseed = 3,/obj/item/seeds/sugarcaneseed = 3,/obj/item/seeds/ambrosiavulgarisseed = 3,/obj/item/seeds/peanutseed = 3,/obj/item/seeds/whitebeetseed = 3,/obj/item/seeds/watermelonseed = 3,/obj/item/seeds/limeseed = 3,
/obj/item/seeds/lemonseed = 3,/obj/item/seeds/orangeseed = 3,/obj/item/seeds/grassseed = 3,/obj/item/seeds/cocoapodseed = 3,/obj/item/seeds/plumpmycelium = 2,
/obj/item/seeds/cabbageseed = 3,/obj/item/seeds/grapeseed = 3,/obj/item/seeds/pumpkinseed = 3,/obj/item/seeds/cherryseed = 3,/obj/item/seeds/plastiseed = 3,/obj/item/seeds/riceseed = 3)
contraband = list(/obj/item/seeds/amanitamycelium = 2,/obj/item/seeds/glowshroom = 2,/obj/item/seeds/libertymycelium = 2,/obj/item/seeds/mtearseed = 2,
diff --git a/code/game/mecha/combat/honker.dm b/code/game/mecha/combat/honker.dm
deleted file mode 100644
index 45159458a90..00000000000
--- a/code/game/mecha/combat/honker.dm
+++ /dev/null
@@ -1,164 +0,0 @@
-/obj/mecha/combat/honker
- desc = "Produced by \"Tyranny of Honk, INC\", this exosuit is designed as heavy clown-support. Used to spread the fun and joy of life. HONK!"
- name = "H.O.N.K"
- icon_state = "honker"
- initial_icon = "honker"
- step_in = 2
- health = 140
- deflect_chance = 60
- internal_damage_threshold = 60
- damage_absorption = list("brute"=1.2,"fire"=1.5,"bullet"=1,"laser"=1,"energy"=1,"bomb"=1)
- max_temperature = 25000
- infra_luminosity = 5
- operation_req_access = list(access_clown)
- wreckage = /obj/effect/decal/mecha_wreckage/honker
- add_req_access = 0
- max_equip = 3
- var/squeak = 0
-
-/*
-/obj/mecha/combat/honker/New()
- ..()
-
- weapons += new /datum/mecha_weapon/honker(src)
- weapons += new /datum/mecha_weapon/missile_rack/banana_mortar(src)
- weapons += new /datum/mecha_weapon/missile_rack/banana_mortar/mousetrap_mortar(src)
- selected_weapon = weapons[1]
- return
-*/
-
-
-/obj/mecha/combat/honker/melee_action(target)
- if(!melee_can_hit)
- return
- else if(istype(target, /mob))
- step_away(target,src,15)
- return
-
-/obj/mecha/combat/honker/get_stats_part()
- var/integrity = health/initial(health)*100
- var/cell_charge = get_charge()
- var/tank_pressure = internal_tank ? round(internal_tank.return_pressure(),0.01) : "None"
- var/tank_temperature = internal_tank ? internal_tank.return_temperature() : "Unknown"
- var/cabin_pressure = round(return_pressure(),0.01)
- var/output = {"[report_internal_damage()]
- [integrity<30?"DAMAGE LEVEL CRITICAL
":null]
- [internal_damage&MECHA_INT_TEMP_CONTROL?"CLOWN SUPPORT SYSTEM MALFUNCTION
":null]
- [internal_damage&MECHA_INT_TANK_BREACH?"GAS TANK HONK
":null]
- [internal_damage&MECHA_INT_CONTROL_LOST?"HONK-A-DOODLE - Recalibrate
":null]
- IntegriHONK: [integrity]%
- PowerHONK charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
- Air source: [use_internal_tank?"Internal Airtank":"Environment"]
- AirHONK pressure: [tank_pressure]kPa
- AirHONK temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
- HONK pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
- HONK temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
- Lights: [lights?"on":"off"]
- [src.dna?"DNA-locked:
[src.dna] \[Reset\]
":null]
- "}
- return output
-
-/obj/mecha/combat/honker/get_stats_html()
- var/output = {"
-
-