diff --git a/code/__DEFINES/_flags/_flags.dm b/code/__DEFINES/_flags/_flags.dm index 2f07afa95a4..b4144ee28bc 100644 --- a/code/__DEFINES/_flags/_flags.dm +++ b/code/__DEFINES/_flags/_flags.dm @@ -3,6 +3,10 @@ #define ALL (~0) // For convenience. #define NONE 0 +/* Directions */ +///All the cardinal direction bitflags. +#define ALL_CARDINALS (NORTH|SOUTH|EAST|WEST) + // For convenience #define ENABLE_BITFIELD(variable, flag) (variable |= (flag)) #define DISABLE_BITFIELD(variable, flag) (variable &= ~(flag)) diff --git a/code/__DEFINES/_flags/obj_flags.dm b/code/__DEFINES/_flags/obj_flags.dm index 6081c31bd39..fdccffaae69 100644 --- a/code/__DEFINES/_flags/obj_flags.dm +++ b/code/__DEFINES/_flags/obj_flags.dm @@ -9,7 +9,9 @@ /* #define BEING_SHOCKED (1<<3) //Whether this thing is currently (already) being shocked by a tesla #define DANGEROUS_POSSESSION (1<<4) //Admin possession yes/no +*/ #define ON_BLUEPRINTS (1<<5) //Are we visible on the station blueprints at roundstart? +/* #define UNIQUE_RENAME (1<<6) //can you customize the description/name of the thing? #define USES_TGUI (1<<7) //put on things that use tgui on ui_interact instead of custom/old UI. #define FROZEN (1<<8) diff --git a/code/__DEFINES/atmos.dm b/code/__DEFINES/atmospherics/atmos.dm similarity index 95% rename from code/__DEFINES/atmos.dm rename to code/__DEFINES/atmospherics/atmos.dm index 1c6a07c7ce7..32e2362a0f8 100644 --- a/code/__DEFINES/atmos.dm +++ b/code/__DEFINES/atmospherics/atmos.dm @@ -87,11 +87,6 @@ //How many moles of fuel are contained within one solid/liquid fuel volume unit #define LIQUIDFUEL_AMOUNT_TO_MOL 0.45 //mol/volume unit -#define TANK_LEAK_PRESSURE (30.*ONE_ATMOSPHERE) // Tank starts leaking. -#define TANK_RUPTURE_PRESSURE (40.*ONE_ATMOSPHERE) // Tank spills all contents into atmosphere. -#define TANK_FRAGMENT_PRESSURE (50.*ONE_ATMOSPHERE) // Boom 3x3 base explosion. -#define TANK_FRAGMENT_SCALE (10.*ONE_ATMOSPHERE) // +1 for each SCALE kPa above threshold. Was 2 atm. - #define NORMPIPERATE 30 // Pipe-insulation rate divisor. #define HEATPIPERATE 8 // Heat-exchange pipe insulation. #define FLOWFRAC 0.99 // Fraction of gas transfered per process. diff --git a/code/__DEFINES/atmospherics/pipes.dm b/code/__DEFINES/atmospherics/pipes.dm index a4b38e99454..7f259b53361 100644 --- a/code/__DEFINES/atmospherics/pipes.dm +++ b/code/__DEFINES/atmospherics/pipes.dm @@ -1,9 +1,84 @@ -// Pipe colors -#define PIPE_COLOR_GREY "#ffffff" //yes white is grey -#define PIPE_COLOR_RED "#ff0000" -#define PIPE_COLOR_BLUE "#0000ff" -#define PIPE_COLOR_CYAN "#00ffff" -#define PIPE_COLOR_GREEN "#00ff00" -#define PIPE_COLOR_YELLOW "#ffcc00" -#define PIPE_COLOR_BLACK "#444444" -#define PIPE_COLOR_PURPLE "#5c1ec0" +//PIPES +//Defines for pipe bitmasking +#define NORTH_FULLPIPE (1<<0) //also just NORTH +#define SOUTH_FULLPIPE (1<<1) //also just SOUTH +#define EAST_FULLPIPE (1<<2) //also just EAST +#define WEST_FULLPIPE (1<<3) //also just WEST +#define NORTH_SHORTPIPE (1<<4) +#define SOUTH_SHORTPIPE (1<<5) +#define EAST_SHORTPIPE (1<<6) +#define WEST_SHORTPIPE (1<<7) +// Helpers to convert cardinals to and from pipe bitfields +// Assumes X_FULLPIPE = X, X_SHORTPIPE >> 4 = X as above +#define FULLPIPE_TO_CARDINALS(bitfield) ((bitfield) & ALL_CARDINALS) +#define SHORTPIPE_TO_CARDINALS(bitfield) (((bitfield) >> 4) & ALL_CARDINALS) +#define CARDINAL_TO_FULLPIPES(cardinals) (cardinals) +#define CARDINAL_TO_SHORTPIPES(cardinals) ((cardinals) << 4) +// A pipe is a stub if it only has zero or one permitted direction. For a regular pipe this is nonsensical, and there are no pipe sprites for this, so it is not allowed. +#define ISSTUB(bits) !((bits) & (bits - 1)) +#define ISNOTSTUB(bits) ((bits) & (bits - 1)) +//Atmos pipe limits +/// (kPa) What pressure pumps and powered equipment max out at. +#define MAX_OUTPUT_PRESSURE 4500 +/// (L/s) Maximum speed powered equipment can work at. +#define MAX_TRANSFER_RATE 200 +/// How many percent of the contents that an overclocked volume pumps leak into the air +#define VOLUME_PUMP_LEAK_AMOUNT 0.1 +//used for device_type vars +#define UNARY 1 +#define BINARY 2 +#define TRINARY 3 +#define QUATERNARY 4 + +//TANKS +/// The volume of the standard handheld gas tanks on the station. +#define TANK_STANDARD_VOLUME 70 +/// The minimum pressure an gas tanks release valve can be set to. +#define TANK_MIN_RELEASE_PRESSURE 0 +/// The maximum pressure an gas tanks release valve can be set to. +#define TANK_MAX_RELEASE_PRESSURE (ONE_ATMOSPHERE*3) +/// The default initial value gas tanks release valves are set to. (At least the ones containing pure plasma/oxygen.) +#define TANK_DEFAULT_RELEASE_PRESSURE ONE_ATMOSPHERE +/// The default initial value gas plasmamen tanks releases valves are set to. +#define TANK_PLASMAMAN_RELEASE_PRESSURE 4 +/// The internal temperature in kelvins at which a handheld gas tank begins to take damage. +#define TANK_MELT_TEMPERATURE 1000000 +/// The internal pressure in kPa at which a handheld gas tank begins to take damage. +#define TANK_LEAK_PRESSURE (30.*ONE_ATMOSPHERE) +/// The internal pressure in kPa at which a handheld gas tank almost immediately ruptures and leaks. +#define TANK_RUPTURE_PRESSURE (40.*ONE_ATMOSPHERE) +/// The internal pressure in kPa at which an gas tank that breaks will cause an explosion. Will cause a 3x3 explosion. +#define TANK_FRAGMENT_PRESSURE (50.*ONE_ATMOSPHERE) +/// Range scaling constant for tank explosions. Calibrated so +1 for each SCALE kPa above threshold. +#define TANK_FRAGMENT_SCALE (10.*ONE_ATMOSPHERE) +///Arbitrary. I don't even know honestly. -Zan +#define TANK_IDEAL_PRESSURE 1015 +/// Denotes that our tank is overpressurized simply from gas merging. +#define TANK_MERGE_OVERPRESSURE "tank_overpressure" +// Indices for the reaction_results returned by explosion_information() +/// Reactions that have happened in the tank. +#define TANK_RESULTS_REACTION 1 +/// Additional information of the tank. +#define TANK_RESULTS_MISC 2 + +//PIPE FLAGS +/// intended to connect with all layers, check for all instead of just one. +#define PIPING_ALL_LAYER (1<<0) +/// can only be built if nothing else with this flag is on the tile already. +#define PIPING_ONE_PER_TURF (1<<1) +/// can only exist at PIPING_LAYER_DEFAULT +#define PIPING_DEFAULT_LAYER_ONLY (1<<2) +/// north/south east/west doesn't matter, auto normalize on build. +#define PIPING_CARDINAL_AUTONORMALIZE (1<<3) +/// intended to connect with everything, both layers and colors +//#define PIPING_ALL_COLORS (1<<4) +/// can bridge over pipenets +//#define PIPING_BRIDGE (1<<5) + +// Ventcrawling bitflags, handled in var/vent_movement +///Allows for ventcrawling to occur. All atmospheric machines have this flag on by default. Cryo is the exception +#define VENTCRAWL_ALLOWED (1<<0) +///Allows mobs to enter or leave from atmospheric machines. On for passive, unary, and scrubber vents. +#define VENTCRAWL_ENTRANCE_ALLOWED (1<<1) +///Used to check if a machinery is visible. Called by update_pipe_vision(). On by default for all except cryo. +#define VENTCRAWL_CAN_SEE (1<<2) diff --git a/code/__DEFINES/chat.dm b/code/__DEFINES/chat.dm new file mode 100644 index 00000000000..78a3c993b2c --- /dev/null +++ b/code/__DEFINES/chat.dm @@ -0,0 +1,36 @@ +/*! + * Copyright (c) 2020 Aleksej Komarov + * SPDX-License-Identifier: MIT + */ + +#define MESSAGE_TYPE_SYSTEM "system" +#define MESSAGE_TYPE_LOCALCHAT "localchat" +#define MESSAGE_TYPE_RADIO "radio" +#define MESSAGE_TYPE_INFO "info" +#define MESSAGE_TYPE_WARNING "warning" +#define MESSAGE_TYPE_DEADCHAT "deadchat" +#define MESSAGE_TYPE_OOC "ooc" +#define MESSAGE_TYPE_ADMINPM "adminpm" +#define MESSAGE_TYPE_COMBAT "combat" +#define MESSAGE_TYPE_ADMINCHAT "adminchat" +#define MESSAGE_TYPE_MODCHAT "modchat" +#define MESSAGE_TYPE_EVENTCHAT "eventchat" +#define MESSAGE_TYPE_ADMINLOG "adminlog" +#define MESSAGE_TYPE_ATTACKLOG "attacklog" +#define MESSAGE_TYPE_DEBUG "debug" + +//debug printing macros (for development and testing) +/// Used for debug messages to the world +#define debug_world(msg) if (GLOB.Debug2) to_chat(world, \ + type = MESSAGE_TYPE_DEBUG, \ + text = "DEBUG: [msg]") +/// Used for debug messages to the player +#define debug_usr(msg) if (GLOB.Debug2&&usr) to_chat(usr, \ + type = MESSAGE_TYPE_DEBUG, \ + text = "DEBUG: [msg]") +/// Used for debug messages to the admins +#define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.admins, \ + type = MESSAGE_TYPE_DEBUG, \ + text = "DEBUG: [msg]") +/// Used for debug messages to the server +#define debug_world_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]") diff --git a/code/__DEFINES/construction.dm b/code/__DEFINES/construction.dm index ac194c0a8cd..10e30f31376 100644 --- a/code/__DEFINES/construction.dm +++ b/code/__DEFINES/construction.dm @@ -42,27 +42,30 @@ #define CONNECT_TYPE_AUX 32 // Aux pipes for 'other' things (airlocks, etc) // We are based on the three named layers of supply, regular, and scrubber. -#define PIPING_LAYER_SUPPLY 1 -#define PIPING_LAYER_REGULAR 2 -#define PIPING_LAYER_SCRUBBER 3 -#define PIPING_LAYER_FUEL 4 +#define PIPING_LAYER_FUEL 1 +#define PIPING_LAYER_SUPPLY 2 +#define PIPING_LAYER_REGULAR 3 +#define PIPING_LAYER_SCRUBBER 4 #define PIPING_LAYER_AUX 5 -#define PIPING_LAYER_DEFAULT PIPING_LAYER_REGULAR // We offset the layer values of the different pipe types to ensure they look nice -#define PIPES_SCRUBBER_LAYER (PIPES_LAYER - 0.05) -#define PIPES_AUX_LAYER (PIPES_LAYER - 0.04) -#define PIPES_FUEL_LAYER (PIPES_LAYER - 0.03) -#define PIPES_SUPPLY_LAYER (PIPES_LAYER - 0.01) +#define PIPES_FUEL_LAYER (PIPES_LAYER - 0.04) +#define PIPES_SUPPLY_LAYER (PIPES_LAYER - 0.03) +#define PIPES_SCRUBBER_LAYER (PIPES_LAYER - 0.02) +#define PIPES_AUX_LAYER (PIPES_LAYER - 0.01) #define PIPES_HE_LAYER (PIPES_LAYER + 0.01) -// Pipe flags -#define PIPING_ALL_LAYER 1 // Intended to connect with all layers, check for all instead of just one. -#define PIPING_ONE_PER_TURF 2 // Can only be built if nothing else with this flag is on the tile already. -#define PIPING_DEFAULT_LAYER_ONLY 4 // Can only exist at PIPING_LAYER_DEFAULT -#define PIPING_CARDINAL_AUTONORMALIZE 8 // North/South East/West doesn't matter, auto normalize on build. +//MULTIPIPES //Ignore warning below until we update pipes +//IF YOU EVER CHANGE THESE CHANGE SPRITES TO MATCH. +//layer = initial(layer) + piping_layer / 1000 in atmospherics/update_icon() to determine order of pipe overlap +#define PIPING_LAYER_MIN 1 +#define PIPING_LAYER_MAX 5 +#define PIPING_LAYER_DEFAULT PIPING_LAYER_REGULAR +#define PIPING_LAYER_P_X 5 +#define PIPING_LAYER_P_Y 5 +#define PIPING_LAYER_LCHANGE 0.05 -// Macro for easy use of boilerplate code for searching for a valid node connection. +/// Macro for easy use of boilerplate code for searching for a valid node connection. #define STANDARD_ATMOS_CHOOSE_NODE(node_num, direction) \ for(var/obj/machinery/atmospherics/target in get_step(src, direction)) { \ if(can_be_node(target, node_num)) { \ diff --git a/code/__DEFINES/controllers/_subsystems.dm b/code/__DEFINES/controllers/_subsystems.dm index 542b47f644f..7ec148d9c6f 100644 --- a/code/__DEFINES/controllers/_subsystems.dm +++ b/code/__DEFINES/controllers/_subsystems.dm @@ -108,6 +108,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_SKYBOX 30 #define INIT_ORDER_MAPPING 25 #define INIT_ORDER_DECALS 20 +#define INIT_ORDER_PLANTS 19 #define INIT_ORDER_ALARMS 18 #define INIT_ORDER_ATOMS 15 #define INIT_ORDER_MACHINES 10 @@ -128,13 +129,14 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define INIT_ORDER_AI -22 #define INIT_ORDER_OPENSPACE -50 #define INIT_ORDER_PERSISTENCE -95 -#define INIT_ORDER_ICON_SMOOTHING -99 +#define INIT_ORDER_ICON_SMOOTHING -99 #define INIT_ORDER_CHAT -100 //Should be last to ensure chat remains smooth during init. // Subsystem fire priority, from lowest to highest priority // If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child) #define FIRE_PRIORITY_SHUTTLES 5 #define FIRE_PRIORITY_NIGHTSHIFT 6 +#define FIRE_PRIORITY_PLANTS 5 #define FIRE_PRIORITY_ORBIT 8 #define FIRE_PRIORITY_VOTE 9 #define FIRE_PRIORITY_AI 10 @@ -142,6 +144,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define FIRE_PRIORITY_VIS 10 #define FIRE_PRIORITY_SERVER_MAINT 10 #define FIRE_PRIORITY_GARBAGE 15 +#define FIRE_PRIORITY_ALARMS 20 #define FIRE_PRIORITY_CHARSETUP 25 #define FIRE_PRIORITY_SPACEDRIFT 25 #define FIRE_PRIORITY_AIRFLOW 30 diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 65d057b32a6..d84117cca6a 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -121,19 +121,28 @@ /// Called from orbit component: (atom/movable/orbiter, refreshing) #define COMSIG_ATOM_ORBIT_END "atom_orbit_end" -#define COMSIG_ENTER_AREA "enter_area" //from base of area/Entered(): (/area) -#define COMSIG_EXIT_AREA "exit_area" //from base of area/Exited(): (/area) - -#define COMSIG_CLICK "atom_click" //from base of atom/Click(): (location, control, params, mob/user) -/* -#define COMSIG_CLICK_SHIFT "shift_click" //from base of atom/ShiftClick(): (/mob) -#define COMSIG_CLICK_CTRL "ctrl_click" //from base of atom/CtrlClickOn(): (/mob) -#define COMSIG_CLICK_ALT "alt_click" //from base of atom/AltClick(): (/mob) -#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click" //from base of atom/CtrlShiftClick(/mob) -#define COMSIG_MOUSEDROP_ONTO "mousedrop_onto" //from base of atom/MouseDrop(): (/atom/over, /mob/user) - #define COMPONENT_NO_MOUSEDROP 1 -#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto" //from base of atom/MouseDrop_T: (/atom/from, /mob/user) -*/ +///from base of area/Entered(): (/area) +#define COMSIG_ENTER_AREA "enter_area" +///from base of area/Exited(): (/area) +#define COMSIG_EXIT_AREA "exit_area" +///from base of atom/Click(): (location, control, params, mob/user) +#define COMSIG_CLICK "atom_click" +///from base of atom/ShiftClick(): (/mob) +#define COMSIG_CLICK_SHIFT "shift_click" + //#define COMPONENT_ALLOW_EXAMINATE (1<<0) //Allows the user to examinate regardless of client.eye. +///from base of atom/CtrlClickOn(): (/mob) +#define COMSIG_CLICK_CTRL "ctrl_click" +///from base of atom/AltClick(): (/mob) +#define COMSIG_CLICK_ALT "alt_click" +///from base of atom/CtrlShiftClick(/mob) +#define COMSIG_CLICK_CTRL_SHIFT "ctrl_shift_click" +///from base of atom/MouseDrop(): (/atom/over, /mob/user) +#define COMSIG_MOUSEDROP_ONTO "mousedrop_onto" + #define COMPONENT_NO_MOUSEDROP (1<<0) +///from base of atom/MouseDrop_T: (/atom/from, /mob/user) +#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto" +///from base of mob/MouseWheelOn(): (/atom, delta_x, delta_y, params) +#define COMSIG_MOUSE_SCROLL_ON "mousescroll_on" /* // /turf signals @@ -251,24 +260,6 @@ #define COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH "obj_default_unfasten_wrench" //from base of code/game/machinery obj/item signals -*/ -#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user) -#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob) - #define COMPONENT_NO_INTERACT 1 -#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob) - #define COMPONENT_NO_ATTACK_OBJ 1 -#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack" //from base of obj/item/pre_attack(): (atom/target, mob/user, params) - #define COMPONENT_NO_ATTACK 1 -#define COMSIG_ITEM_AFTERATTACK "item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, params) -#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot) -#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (mob/user) -#define COMSIG_ITEM_PICKUP "item_pickup" //from base of obj/item/pickup(): (/mob/taker) -#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" //from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone) -#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user) -#define COMSIG_ITEM_MARK_RETRIEVAL "item_mark_retrieval" //called before marking an object for retrieval, checked in /obj/effect/proc_holder/spell/targeted/summonitem/cast() : (mob/user) - #define COMPONENT_BLOCK_MARK_RETRIEVAL 1 -#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args) -/* // /obj/item/clothing signals #define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): () @@ -397,3 +388,6 @@ obj/item signals #define COMSIG_CONFLICT_ELEMENT_CHECK "conflict_element_check" /// A conflict was found #define ELEMENT_CONFLICT_FOUND (1<<0) + +/// from datum ui_act (usr, action) +#define COMSIG_UI_ACT "COMSIG_UI_ACT" diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm new file mode 100644 index 00000000000..81c0b28c3c7 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -0,0 +1,386 @@ +// Object signals. Format: +// When the signal is called: (signal arguments) +// All signals send the source datum of the signal as the first argument + +// /obj signals +///from base of obj/deconstruct(): (disassembled) +#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" +///from base of code/game/machinery +#define COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH "obj_default_unfasten_wrench" +///from base of /turf/proc/levelupdate(). (intact) true to hide and false to unhide +#define COMSIG_OBJ_HIDE "obj_hide" +/// from /obj/item/toy/crayon/spraycan/afterattack: (color_is_dark) +#define COMSIG_OBJ_PAINTED "obj_painted" + +// /obj/machinery signals + +///from /obj/machinery/atom_break(damage_flag): (damage_flag) +#define COMSIG_MACHINERY_BROKEN "machinery_broken" +///from base power_change() when power is lost +#define COMSIG_MACHINERY_POWER_LOST "machinery_power_lost" +///from base power_change() when power is restored +#define COMSIG_MACHINERY_POWER_RESTORED "machinery_power_restored" +///from /obj/machinery/set_occupant(atom/movable/O): (new_occupant) +#define COMSIG_MACHINERY_SET_OCCUPANT "machinery_set_occupant" +///from /obj/machinery/destructive_scanner/proc/open(aggressive): Runs when the destructive scanner scans a group of objects. (list/scanned_atoms) +#define COMSIG_MACHINERY_DESTRUCTIVE_SCAN "machinery_destructive_scan" +///from /obj/machinery/computer/arcade/prizevend(mob/user, prizes = 1) +#define COMSIG_ARCADE_PRIZEVEND "arcade_prizevend" +///from /datum/controller/subsystem/air/proc/start_processing_machine: () +#define COMSIG_MACHINERY_START_PROCESSING_AIR "start_processing_air" +///from /datum/controller/subsystem/air/proc/stop_processing_machine: () +#define COMSIG_MACHINERY_STOP_PROCESSING_AIR "stop_processing_air" + +///from /obj/machinery/can_interact(mob/user): Called on user when attempting to interact with a machine (obj/machinery/machine) +#define COMSIG_TRY_USE_MACHINE "try_use_machine" + /// Can't interact with the machine + #define COMPONENT_CANT_USE_MACHINE_INTERACT (1<<0) + /// Can't use tools on the machine + #define COMPONENT_CANT_USE_MACHINE_TOOLS (1<<1) + +///from obj/machinery/iv_drip/IV_attach(target, usr) : (attachee) +#define COMSIG_IV_ATTACH "iv_attach" +///from obj/machinery/iv_drip/IV_detach() : (detachee) +#define COMSIG_IV_DETACH "iv_detach" + + +// /obj/machinery/computer/teleporter +/// from /obj/machinery/computer/teleporter/proc/set_target(target, old_target) +#define COMSIG_TELEPORTER_NEW_TARGET "teleporter_new_target" + +// /obj/machinery/power/supermatter_crystal signals +/// from /obj/machinery/power/supermatter_crystal/process_atmos(); when the SM delam reaches the point of sounding alarms +#define COMSIG_SUPERMATTER_DELAM_START_ALARM "sm_delam_start_alarm" +/// from /obj/machinery/power/supermatter_crystal/process_atmos(); when the SM sounds an audible alarm +#define COMSIG_SUPERMATTER_DELAM_ALARM "sm_delam_alarm" + +// /obj/machinery/atmospherics/components/unary/cryo_cell signals + +/// from /obj/machinery/atmospherics/components/unary/cryo_cell/set_on(bool): (on) +#define COMSIG_CRYO_SET_ON "cryo_set_on" + +// /obj/machinery/atmospherics/components/binary/valve signals + +/// from /obj/machinery/atmospherics/components/binary/valve/toggle(): (on) +#define COMSIG_VALVE_SET_OPEN "valve_toggled" + +/// from /obj/machinery/atmospherics/set_on(active): (on) +#define COMSIG_ATMOS_MACHINE_SET_ON "atmos_machine_set_on" + +/// from /obj/machinery/light_switch/set_lights(), sent to every switch in the area: (status) +#define COMSIG_LIGHT_SWITCH_SET "light_switch_set" + +/// from /obj/machinery/fire_alarm/reset(), /obj/machinery/fire_alarm/alarm(): (status) +#define COMSIG_FIREALARM_ON_TRIGGER "firealarm_trigger" +#define COMSIG_FIREALARM_ON_RESET "firealarm_reset" + +// /obj access signals + +#define COMSIG_OBJ_ALLOWED "door_try_to_activate" + #define COMPONENT_OBJ_ALLOW (1<<0) + +#define COMSIG_AIRLOCK_SHELL_ALLOWED "airlock_shell_try_allowed" + #define COMPONENT_AIRLOCK_SHELL_ALLOW (1<<0) + +// /obj/machinery/door/airlock signals + +//from /obj/machinery/door/airlock/open(): (forced) +#define COMSIG_AIRLOCK_OPEN "airlock_open" +//from /obj/machinery/door/airlock/close(): (forced) +#define COMSIG_AIRLOCK_CLOSE "airlock_close" +///from /obj/machinery/door/airlock/set_bolt(): +#define COMSIG_AIRLOCK_SET_BOLT "airlock_set_bolt" +// /obj/item signals + +///from base of obj/item/equipped(): (/mob/equipper, slot) +#define COMSIG_ITEM_EQUIPPED "item_equip" +/// A mob has just equipped an item. Called on [/mob] from base of [/obj/item/equipped()]: (/obj/item/equipped_item, slot) +#define COMSIG_MOB_EQUIPPED_ITEM "mob_equipped_item" +/// A mob has just unequipped an item. +#define COMSIG_MOB_UNEQUIPPED_ITEM "mob_unequipped_item" +///called on [/obj/item] before unequip from base of [mob/proc/doUnEquip]: (force, atom/newloc, no_move, invdrop, silent) +#define COMSIG_ITEM_PRE_UNEQUIP "item_pre_unequip" + ///only the pre unequip can be cancelled + #define COMPONENT_ITEM_BLOCK_UNEQUIP (1<<0) +///called on [/obj/item] AFTER unequip from base of [mob/proc/doUnEquip]: (force, atom/newloc, no_move, invdrop, silent) +#define COMSIG_ITEM_POST_UNEQUIP "item_post_unequip" +///from base of obj/item/on_grind(): ()) +#define COMSIG_ITEM_ON_GRIND "on_grind" +///from base of obj/item/on_juice(): () +#define COMSIG_ITEM_ON_JUICE "on_juice" +///from /obj/machinery/hydroponics/attackby(obj/item/O, mob/user, params) when an object is used as compost: (mob/user) +#define COMSIG_ITEM_ON_COMPOSTED "on_composted" +///Called when an item is dried by a drying rack: +#define COMSIG_ITEM_DRIED "item_dried" +///from base of obj/item/dropped(): (mob/user) +#define COMSIG_ITEM_DROPPED "item_drop" +///from base of obj/item/pickup(): (/mob/taker) +#define COMSIG_ITEM_PICKUP "item_pickup" +///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone) +#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" +///return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user) +#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" + #define COMPONENT_BLOCK_IMBUE (1 << 0) +///called before marking an object for retrieval, checked in /obj/effect/proc_holder/spell/targeted/summonitem/cast() : (mob/user) +#define COMSIG_ITEM_MARK_RETRIEVAL "item_mark_retrieval" + #define COMPONENT_BLOCK_MARK_RETRIEVAL (1<<0) +///from base of obj/item/hit_reaction(): (list/args) +#define COMSIG_ITEM_HIT_REACT "item_hit_react" + #define COMPONENT_HIT_REACTION_BLOCK (1<<0) +///called on item when microwaved (): (obj/machinery/microwave/M) +#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act" + #define COMPONENT_SUCCESFUL_MICROWAVE (1<<0) +///called on item when created through microwaving (): (obj/machinery/microwave/M, cooking_efficiency) +#define COMSIG_ITEM_MICROWAVE_COOKED "microwave_cooked" +///from base of item/sharpener/attackby(): (amount, max) +#define COMSIG_ITEM_SHARPEN_ACT "sharpen_act" + #define COMPONENT_BLOCK_SHARPEN_APPLIED (1<<0) + #define COMPONENT_BLOCK_SHARPEN_BLOCKED (1<<1) + #define COMPONENT_BLOCK_SHARPEN_ALREADY (1<<2) + #define COMPONENT_BLOCK_SHARPEN_MAXED (1<<3) +///Called when an object is grilled ontop of a griddle +#define COMSIG_ITEM_GRILLED "item_griddled" + #define COMPONENT_HANDLED_GRILLING (1<<0) +///Called when an object is turned into another item through grilling ontop of a griddle +#define COMSIG_GRILL_COMPLETED "item_grill_completed" +///Called when an object is meant to be grilled through a grill: (atom/fry_object, grill_time) +#define COMSIG_GRILL_FOOD "item_grill_food" +//Called when an object is in an oven +#define COMSIG_ITEM_BAKED "item_baked" + #define COMPONENT_HANDLED_BAKING (1<<0) + #define COMPONENT_BAKING_GOOD_RESULT (1<<1) + #define COMPONENT_BAKING_BAD_RESULT (1<<2) +///Called when an object is turned into another item through baking in an oven +#define COMSIG_BAKE_COMPLETED "item_bake_completed" +///Called when an armor plate is successfully applied to an object +#define COMSIG_ARMOR_PLATED "armor_plated" +///Called when an item gets recharged by the ammo powerup +#define COMSIG_ITEM_RECHARGED "item_recharged" +///Called when an item is being offered, from [/obj/item/proc/on_offered(mob/living/carbon/offerer)] +#define COMSIG_ITEM_OFFERING "item_offering" + ///Interrupts the offer proc + #define COMPONENT_OFFER_INTERRUPT (1<<0) +///Called when an someone tries accepting an offered item, from [/obj/item/proc/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker)] +#define COMSIG_ITEM_OFFER_TAKEN "item_offer_taken" + ///Interrupts the offer acceptance + #define COMPONENT_OFFER_TAKE_INTERRUPT (1<<0) +/// sent from obj/effect/attackby(): (/obj/effect/hit_effect, /mob/living/attacker, params) +#define COMSIG_ITEM_ATTACK_EFFECT "item_effect_attacked" + +///from base of [/obj/item/proc/tool_check_callback]: (mob/living/user) +#define COMSIG_TOOL_IN_USE "tool_in_use" +///from base of [/obj/item/proc/tool_start_check]: (mob/living/user) +#define COMSIG_TOOL_START_USE "tool_start_use" +///from [/obj/item/proc/disableEmbedding]: +#define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed" +///from [/obj/effect/mine/proc/triggermine]: +#define COMSIG_MINE_TRIGGERED "minegoboom" +///from [/obj/structure/closet/supplypod/proc/preOpen]: +#define COMSIG_SUPPLYPOD_LANDED "supplypodgoboom" + +///from /obj/item/storage/book/bible/afterattack(): (mob/user, proximity) +#define COMSIG_BIBLE_SMACKED "bible_smacked" + ///stops the bible chain from continuing. When all of the effects of the bible smacking have been moved to a signal we can kill this + #define COMSIG_END_BIBLE_CHAIN (1<<0) +///Closets +///From base of [/obj/structure/closet/proc/insert]: (atom/movable/inserted) +#define COMSIG_CLOSET_INSERT "closet_insert" + ///used to interrupt insertion + #define COMPONENT_CLOSET_INSERT_INTERRUPT (1<<0) + +///From open: (forced) +#define COMSIG_CLOSET_PRE_OPEN "closet_pre_open" + #define BLOCK_OPEN (1<<0) +///From open: (forced) +#define COMSIG_CLOSET_POST_OPEN "closet_post_open" + +///a deliver_first element closet was successfully delivered +#define COMSIG_CLOSET_DELIVERED "crate_delivered" + +///Eigenstasium +///From base of [/datum/controller/subsystem/eigenstates/proc/use_eigenlinked_atom]: (var/target) +#define COMSIG_EIGENSTATE_ACTIVATE "eigenstate_activate" + +// /obj signals for economy +///called when the payment component tries to charge an account. +#define COMSIG_OBJ_ATTEMPT_CHARGE "obj_attempt_simple_charge" + #define COMPONENT_OBJ_CANCEL_CHARGE (1<<0) +///Called when a payment component changes value +#define COMSIG_OBJ_ATTEMPT_CHARGE_CHANGE "obj_attempt_simple_charge_change" + +// /obj/item signals for economy +///called before an item is sold by the exports system. +#define COMSIG_ITEM_PRE_EXPORT "item_pre_sold" + /// Stops the export from calling sell_object() on the item, so you can handle it manually. + #define COMPONENT_STOP_EXPORT (1<<0) +///called when an item is sold by the exports subsystem +#define COMSIG_ITEM_EXPORTED "item_sold" + /// Stops the export from adding the export information to the report, so you can handle it manually. + #define COMPONENT_STOP_EXPORT_REPORT (1<<0) +///called when a wrapped up item is opened by hand +#define COMSIG_ITEM_UNWRAPPED "item_unwrapped" +///called when getting the item's exact ratio for cargo's profit. +#define COMSIG_ITEM_SPLIT_PROFIT "item_split_profits" +///called when getting the item's exact ratio for cargo's profit, without selling the item. +#define COMSIG_ITEM_SPLIT_PROFIT_DRY "item_split_profits_dry" + +// /obj/item/clothing signals + +///from [/mob/living/carbon/human/Move]: () +#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" +///from base of /obj/item/clothing/suit/space/proc/toggle_spacesuit(): (obj/item/clothing/suit/space/suit) +#define COMSIG_SUIT_SPACE_TOGGLE "suit_space_toggle" + +// /obj/item/implant signals +///from base of /obj/item/implant/proc/activate(): () +#define COMSIG_IMPLANT_ACTIVATED "implant_activated" +///from base of /obj/item/implant/proc/implant(): (list/args) +#define COMSIG_IMPLANT_IMPLANTING "implant_implanting" + #define COMPONENT_STOP_IMPLANTING (1<<0) +///called on already installed implants when a new one is being added in /obj/item/implant/proc/implant(): (list/args, obj/item/implant/new_implant) +#define COMSIG_IMPLANT_OTHER "implant_other" + //#define COMPONENT_STOP_IMPLANTING (1<<0) //The name makes sense for both + #define COMPONENT_DELETE_NEW_IMPLANT (1<<1) + #define COMPONENT_DELETE_OLD_IMPLANT (1<<2) + +/// called on implants, after a successful implantation: (mob/living/target, mob/user, silent, force) +#define COMSIG_IMPLANT_IMPLANTED "implant_implanted" + +/// called on implants, after an implant has been removed: (mob/living/source, silent, special) +#define COMSIG_IMPLANT_REMOVED "implant_removed" + +/// called as a mindshield is implanted: (mob/user) +#define COMSIG_PRE_MINDSHIELD_IMPLANT "pre_mindshield_implant" + /// Did they successfully get mindshielded? + #define COMPONENT_MINDSHIELD_PASSED (NONE) + /// Did they resist the mindshield? + #define COMPONENT_MINDSHIELD_RESISTED (1<<0) + +/// called once a mindshield is implanted: (mob/user) +#define COMSIG_MINDSHIELD_IMPLANTED "mindshield_implanted" + /// Are we the reason for deconversion? + #define COMPONENT_MINDSHIELD_DECONVERTED (1<<0) + +///called on implants being implanted into someone with an uplink implant: (datum/component/uplink) +#define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists" + //This uses all return values of COMSIG_IMPLANT_OTHER + +// /obj/item/pda signals + +///called on pda when the user changes the ringtone: (mob/living/user, new_ringtone) +#define COMSIG_PDA_CHANGE_RINGTONE "pda_change_ringtone" + #define COMPONENT_STOP_RINGTONE_CHANGE (1<<0) +#define COMSIG_PDA_CHECK_DETONATE "pda_check_detonate" + #define COMPONENT_PDA_NO_DETONATE (1<<0) + +// /obj/item/radio signals + +///called from base of /obj/item/radio/proc/set_frequency(): (list/args) +#define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency" + +// /obj/item/pen signals + +///called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user) +#define COMSIG_PEN_ROTATED "pen_rotated" + +// /obj/item/gun signals + +///called in /obj/item/gun/process_fire (src, target, params, zone_override) +#define COMSIG_MOB_FIRED_GUN "mob_fired_gun" +///called in /obj/item/gun/process_fire (user, target, params, zone_override) +#define COMSIG_GUN_FIRED "gun_fired" +///called in /obj/item/gun/process_chamber (src) +#define COMSIG_GUN_CHAMBER_PROCESSED "gun_chamber_processed" +///called in /obj/item/gun/ballistic/process_chamber (casing) +#define COMSIG_CASING_EJECTED "casing_ejected" + +// /obj/effect/proc_holder/spell signals + +///called from /obj/effect/proc_holder/spell/cast_check (src) +#define COMSIG_MOB_PRE_CAST_SPELL "mob_cast_spell" + /// Return to cancel the cast from beginning. + #define COMPONENT_CANCEL_SPELL (1<<0) +///called from /obj/effect/proc_holder/spell/perform (src) +#define COMSIG_MOB_CAST_SPELL "mob_cast_spell" + +// /obj/item/camera signals + +///from /obj/item/camera/captureimage(): (atom/target, mob/user) +#define COMSIG_CAMERA_IMAGE_CAPTURED "camera_image_captured" + +// /obj/item/grenade signals + +///called in /obj/item/gun/process_fire (user, target, params, zone_override) +#define COMSIG_GRENADE_DETONATE "grenade_prime" +//called from many places in grenade code (armed_by, nade, det_time, delayoverride) +#define COMSIG_MOB_GRENADE_ARMED "grenade_mob_armed" +///called in /obj/item/gun/process_fire (user, target, params, zone_override) +#define COMSIG_GRENADE_ARMED "grenade_armed" + +// /obj/projectile signals (sent to the firer) + +///from base of /obj/projectile/proc/on_hit(), like COMSIG_PROJECTILE_ON_HIT but on the projectile itself and with the hit limb (if any): (atom/movable/firer, atom/target, Angle, hit_limb) +#define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" +///from base of /obj/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle) +#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" +///from base of /obj/projectile/proc/fire(): (obj/projectile, atom/original_target) +#define COMSIG_PROJECTILE_BEFORE_FIRE "projectile_before_fire" +///from the base of /obj/projectile/proc/fire(): () +#define COMSIG_PROJECTILE_FIRE "projectile_fire" +///sent to targets during the process_hit proc of projectiles +#define COMSIG_PROJECTILE_PREHIT "com_proj_prehit" +///sent to targets during the process_hit proc of projectiles +#define COMSIG_PROJECTILE_RANGE_OUT "projectile_range_out" +///from [/obj/item/proc/tryEmbed] sent when trying to force an embed (mainly for projectiles and eating glass) +#define COMSIG_EMBED_TRY_FORCE "item_try_embed" + #define COMPONENT_EMBED_SUCCESS (1<<1) + +///sent to targets during the process_hit proc of projectiles +#define COMSIG_PELLET_CLOUD_INIT "pellet_cloud_init" + +// /obj/vehicle/sealed/mecha signals + +///sent from mecha action buttons to the mecha they're linked to +#define COMSIG_MECHA_ACTION_TRIGGER "mecha_action_activate" + +///sent from clicking while you have no equipment selected. Sent before cooldown and adjacency checks, so you can use this for infinite range things if you want. +#define COMSIG_MECHA_MELEE_CLICK "mecha_action_melee_click" + /// Prevents click from happening. + #define COMPONENT_CANCEL_MELEE_CLICK (1<<0) +///sent from clicking while you have equipment selected. +#define COMSIG_MECHA_EQUIPMENT_CLICK "mecha_action_equipment_click" + /// Prevents click from happening. + #define COMPONENT_CANCEL_EQUIPMENT_CLICK (1<<0) + +#define COMSIG_ITEM_ATTACK "item_attack" +///from base of obj/item/attack_self(): (/mob) +#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" +//from base of obj/item/attack_self_secondary(): (/mob) +#define COMSIG_ITEM_ATTACK_SELF_SECONDARY "item_attack_self_secondary" +///from base of obj/item/attack_atom(): (/obj, /mob) +#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" +///from base of obj/item/pre_attack(): (atom/target, mob/user, params) +#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack" +/// From base of [/obj/item/proc/pre_attack_secondary()]: (atom/target, mob/user, params) +#define COMSIG_ITEM_PRE_ATTACK_SECONDARY "item_pre_attack_secondary" + #define COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN (1<<0) + #define COMPONENT_SECONDARY_CONTINUE_ATTACK_CHAIN (1<<1) + #define COMPONENT_SECONDARY_CALL_NORMAL_ATTACK_CHAIN (1<<2) +/// From base of [/obj/item/proc/attack_secondary()]: (atom/target, mob/user, params) +#define COMSIG_ITEM_ATTACK_SECONDARY "item_pre_attack_secondary" +///from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters) +#define COMSIG_ITEM_AFTERATTACK "item_afterattack" +///from base of obj/item/afterattack_secondary(): (atom/target, mob/user, proximity_flag, click_parameters) +#define COMSIG_ITEM_AFTERATTACK_SECONDARY "item_afterattack_secondary" +///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, params) +#define COMSIG_ITEM_ATTACK_QDELETED "item_attack_qdeleted" + +///from /obj/item/assembly/proc/pulsed() +#define COMSIG_ASSEMBLY_PULSED "assembly_pulsed" + +///from base of /obj/item/mmi/set_brainmob(): (mob/living/brain/new_brainmob) +#define COMSIG_MMI_SET_BRAINMOB "mmi_set_brainmob" + +/// from base of /obj/item/slimepotion/speed/afterattack(): (obj/target, /obj/src, mob/user) +#define COMSIG_SPEED_POTION_APPLIED "speed_potion" + #define SPEED_POTION_STOP (1<<0) diff --git a/code/__DEFINES/machinery.dm b/code/__DEFINES/machinery.dm index 0cb02ed6ae9..8dd450b9c47 100644 --- a/code/__DEFINES/machinery.dm +++ b/code/__DEFINES/machinery.dm @@ -30,6 +30,11 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called manu #define MAINT 0x8 // Under maintenance. #define EMPED 0x10 // Temporary broken by EMP pulse. +// Remote control states +#define RCON_NO 1 +#define RCON_AUTO 2 +#define RCON_YES 3 + // Used by firelocks #define FIREDOOR_OPEN 1 #define FIREDOOR_CLOSED 2 diff --git a/code/modules/hydroponics/_hydro_setup.dm b/code/__DEFINES/plants.dm similarity index 89% rename from code/modules/hydroponics/_hydro_setup.dm rename to code/__DEFINES/plants.dm index a16c542fef0..470e59c2d4a 100644 --- a/code/modules/hydroponics/_hydro_setup.dm +++ b/code/__DEFINES/plants.dm @@ -16,7 +16,20 @@ #define GENE_FRUIT "fruit" #define GENE_SPECIAL "special" -#define ALL_GENES list(GENE_BIOCHEMISTRY,GENE_HARDINESS,GENE_ENVIRONMENT,GENE_METABOLISM,GENE_STRUCTURE,GENE_DIET,GENE_PIGMENT,GENE_OUTPUT,GENE_ATMOSPHERE,GENE_VIGOUR,GENE_FRUIT,GENE_SPECIAL) +#define ALL_GENES list(\ + GENE_BIOCHEMISTRY,\ + GENE_HARDINESS,\ + GENE_ENVIRONMENT,\ + GENE_METABOLISM,\ + GENE_STRUCTURE,\ + GENE_DIET,\ + GENE_PIGMENT,\ + GENE_OUTPUT,\ + GENE_ATMOSPHERE,\ + GENE_VIGOUR\ + ,GENE_FRUIT,\ + GENE_SPECIAL\ + ) //Definitions for traits (individual descriptors) #define TRAIT_CHEMS 1 diff --git a/code/__DEFINES/spans.dm b/code/__DEFINES/spans.dm index 793e4d5f16d..7bd028353e8 100644 --- a/code/__DEFINES/spans.dm +++ b/code/__DEFINES/spans.dm @@ -1,7 +1,123 @@ -// all span defines go here -#define SPAN_CAUTION(X) "[X]" -#define SPAN_DANGER(X) "[X]" -#define SPAN_INFO(X) "[X]" -#define SPAN_NOTICE(X) "[X]" -#define SPAN_OCCULT(X) "[X]" -#define SPAN_WARNING(X) "[X]" +// Sorted alphabetically +#define SPAN_ABDUCTOR(str) ("" + str + "") +#define SPAN_ADMIN(str) ("" + str + "") +#define SPAN_ADMINHELP(str) ("" + str + "") +#define SPAN_ADMINNOTICE(str) ("" + str + "") +#define SPAN_ADMINOBSERVEROOC(str) ("" + str + "") +#define SPAN_ADMINOOC(str) ("" + str + "") +#define SPAN_ADMINSAY(str) ("" + str + "") +#define SPAN_AIPRIVRADIO(str) ("" + str + "") +#define SPAN_ALERT(str) ("" + str + "") +#define SPAN_ALERTALIEN(str) ("" + str + "") +#define SPAN_ALERTSYNDIE(str) ("" + str + "") +#define SPAN_ALERTWARNING(str) ("" + str + "") +#define SPAN_ALIEN(str) ("" + str + "") +#define SPAN_ANNOUNCE(str) ("" + str + "") +#define SPAN_BIG(str) ("" + str + "") +#define SPAN_BIGICON(str) ("" + str + "") +#define SPAN_BINARYSAY(str) ("" + str + "") +#define SPAN_BLUE(str) ("" + str + "") +#define SPAN_BLUETEAMRADIO(str) ("" + str + "") +#define SPAN_BOLD(str) ("" + str + "") +#define SPAN_BOLDANNOUNCE(str) ("" + str + "") +#define SPAN_BOLDDANGER(str) ("" + str + "") +#define SPAN_BOLDNICEGREEN(str) ("" + str + "") +#define SPAN_BOLDNOTICE(str) ("" + str + "") +#define SPAN_BOLDWARNING(str) ("" + str + "") +#define SPAN_CAUTION(str) ("" + str + "") +#define SPAN_CENTCOMRADIO(str) ("" + str + "") +#define SPAN_CHANGELING(str) ("" + str + "") +#define SPAN_CLOWN(str) ("" + str + "") +#define SPAN_COLOSSUS(str) ("" + str + "") +#define SPAN_COMMAND_HEADSET(str) ("" + str + "") +#define SPAN_COMRADIO(str) ("" + str + "") +#define SPAN_CULT(str) ("" + str + "") +#define SPAN_CULTBOLD(str) ("" + str + "") +#define SPAN_CULTBOLDTALIC(str) ("" + str + "") +#define SPAN_CULTITALIC(str) ("" + str + "") +#define SPAN_CULTLARGE(str) ("" + str + "") +#define SPAN_DANGER(str) ("" + str + "") +#define SPAN_DEADSAY(str) ("" + str + "") +#define SPAN_DECONVERSION_MESSAGE(str) ("" + str + "") +#define SPAN_DRONE(str) ("" + str + "") +#define SPAN_ENGRADIO(str) ("" + str + "") +#define SPAN_EXTREMELYBIG(str) ("" + str + "") +#define SPAN_GHOSTALERT(str) ("" + str + "") +#define SPAN_GREEN(str) ("" + str + "") +#define SPAN_GREENANNOUNCE(str) ("" + str + "") +#define SPAN_GREENTEAMRADIO(str) ("" + str + "") +#define SPAN_GREENTEXT(str) ("" + str + "") +#define SPAN_GREY(str) ("" + str + "") +#define SPAN_GANGRADIO(str) ("" + str + "") +#define SPAN_HEAR(str) ("" + str + "") +#define SPAN_HIDDEN(str) ("") +#define SPAN_HIEROPHANT(str) ("" + str + "") +#define SPAN_HIEROPHANT_WARNING(str) ("" + str + "") +#define SPAN_HIGHLIGHT(str) ("" + str + "") +#define SPAN_HIS_GRACE(str) ("" + str + "") +#define SPAN_HOLOPARASITE(str) ("" + str + "") +#define SPAN_HYPNOPHRASE(str) ("" + str + "") +#define SPAN_ICON(str) ("" + str + "") +#define SPAN_INFO(str) ("" + str + "") +#define SPAN_INFOPLAIN(str) ("" + str + "") +#define SPAN_INTERFACE(str) ("" + str + "") +#define SPAN_LOOC(str) ("" + str + "") +#define SPAN_MEDAL(str) ("" + str + "") +#define SPAN_MEDRADIO(str) ("" + str + "") +#define SPAN_MEMO(str) ("" + str + "") +#define SPAN_MEMOEDIT(str) ("" + str + "") +#define SPAN_MIND_CONTROL(str) ("" + str + "") +#define SPAN_MINORANNOUNCE(str) ("" + str + "") +#define SPAN_MONKEY(str) ("" + str + "") +#define SPAN_MONKEYHIVE(str) ("" + str + "") +#define SPAN_MONKEYLEAD(str) ("" + str + "") +#define SPAN_NAME(str) ("" + str + "") +#define SPAN_NARSIE(str) ("" + str + "") +#define SPAN_NARSIESMALL(str) ("" + str + "") +#define SPAN_NICEGREEN(str) ("" + str + "") +#define SPAN_NOTICE(str) ("" + str + "") +#define SPAN_NOTICEALIEN(str) ("" + str + "") +#define SPAN_OOC(str) ("" + str + "") +#define SPAN_PAPYRUS(str) ("" + str + "") +#define SPAN_PHOBIA(str) ("" + str + "") +#define SPAN_PREFIX(str) ("" + str + "") +#define SPAN_PURPLE(str) ("" + str + "") +#define SPAN_RADIO(str) ("" + str + "") +#define SPAN_REALLYBIG(str) ("" + str + "") +#define SPAN_RED(str) ("" + str + "") +#define SPAN_REDTEAMRADIO(str) ("" + str + "") +#define SPAN_REDTEXT(str) ("" + str + "") +#define SPAN_RESONATE(str) ("" + str + "") +#define SPAN_REVENBIGNOTICE(str) ("" + str + "") +#define SPAN_REVENBOLDNOTICE(str) ("" + str + "") +#define SPAN_REVENDANGER(str) ("" + str + "") +#define SPAN_REVENMINOR(str) ("" + str + "") +#define SPAN_REVENNOTICE(str) ("" + str + "") +#define SPAN_REVENWARNING(str) ("" + str + "") +#define SPAN_ROBOT(str) ("" + str + "") +#define SPAN_ROSE(str) ("" + str + "") +#define SPAN_SANS(str) ("" + str + "") +#define SPAN_SCIRADIO(str) ("" + str + "") +#define SPAN_SECRADIO(str) ("" + str + "") +#define SPAN_SERVRADIO(str) ("" + str + "") +#define SPAN_SINGING(str) ("" + str + "") +#define SPAN_SLIME(str) ("" + str + "") +#define SPAN_SMALL(str) ("" + str + "") +#define SPAN_SMALLNOTICE(str) ("" + str + "") +#define SPAN_SMALLNOTICEITAL(str) ("" + str + "") +#define SPAN_SPIDER(str) ("" + str + "") +#define SPAN_SUICIDE(str) ("" + str + "") +#define SPAN_SUPPRADIO(str) ("" + str + "") +#define SPAN_SYNDRADIO(str) ("" + str + "") +#define SPAN_TAPE_RECORDER(str) ("" + str + "") +#define SPAN_TINYNOTICE(str) ("" + str + "") +#define SPAN_TINYNOTICEITAL(str) ("" + str + "") +#define SPAN_UNCONSCIOUS(str) ("" + str + "") +#define SPAN_USERDANGER(str) ("" + str + "") +#define SPAN_WARNING(str) ("" + str + "") +#define SPAN_YELL(str) ("" + str + "") +#define SPAN_YELLOWTEAMRADIO(str) ("" + str + "") + +// Spans that use embedded tgui components: +// Sorted alphabetically +#define SPAN_TOOLTIP(tip, main_text) ("" + main_text + "") diff --git a/code/__HELPERS/_lists_tg.dm b/code/__HELPERS/_lists_tg.dm index 36732ce2594..65f8b3c6c24 100644 --- a/code/__HELPERS/_lists_tg.dm +++ b/code/__HELPERS/_lists_tg.dm @@ -426,3 +426,11 @@ proc/dd_sortedObjectList(list/incoming) result += pick(shifts) return result + +///sort any value in a list +/proc/sort_list(list/list_to_sort, cmp=/proc/cmp_text_asc) + return sortTim(list_to_sort.Copy(), cmp) + +///uses sort_list() but uses the var's name specifically. This should probably be using mergeAtom() instead +/proc/sort_names(list/list_to_sort, order=1) + return sortTim(list_to_sort.Copy(), order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index b4d4e615e2e..ff664fac024 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -292,21 +292,19 @@ var/list/hearturfs = list() for(var/thing in hear) - if(istype(thing,/obj)) + if(istype(thing, /obj)) //Can't use isobj() because /atom/movable returns true in that, and so lighting overlays would be included objs += thing hearturfs |= get_turf(thing) - else if(istype(thing,/mob)) + if(ismob(thing)) mobs += thing hearturfs |= get_turf(thing) //A list of every mob with a client for(var/mob in player_list) - //VOREStation Edit - Trying to fix some vorestation bug. - if(!istype(mob, /mob)) + if(!ismob(mob)) player_list -= mob crash_with("There is a null or non-mob reference inside player_list ([mob]).") continue - //VOREStation Edit End - Trying to fix some vorestation bug. if(get_turf(mob) in hearturfs) mobs |= mob continue diff --git a/code/__HELPERS/piping_colors_lists.dm b/code/__HELPERS/piping_colors_lists.dm new file mode 100644 index 00000000000..a875875c57d --- /dev/null +++ b/code/__HELPERS/piping_colors_lists.dm @@ -0,0 +1,54 @@ +// Pipe colors +#define PIPE_COLOR_GREY "#ffffff" //yes white is grey +#define PIPE_COLOR_RED "#ff0000" +#define PIPE_COLOR_BLUE "#0000ff" +#define PIPE_COLOR_CYAN "#00ffff" +#define PIPE_COLOR_GREEN "#00ff00" +#define PIPE_COLOR_ORANGE "#ff9900" +#define PIPE_COLOR_YELLOW "#ffcc00" +#define PIPE_COLOR_BROWN "#4e462f" +#define PIPE_COLOR_BLACK "#333333" +#define PIPE_COLOR_PURPLE "#5c1ec0" + + +///All colors available to pipes and atmos components +GLOBAL_LIST_INIT(pipe_paint_colors, list( + "green" = PIPE_COLOR_GREEN, + "blue" = PIPE_COLOR_BLUE, + "red" = PIPE_COLOR_RED, + "orange" = PIPE_COLOR_ORANGE, + "cyan" = PIPE_COLOR_CYAN, + "dark" = PIPE_COLOR_BLACK, + "yellow" = PIPE_COLOR_YELLOW, + "brown" = PIPE_COLOR_BROWN, + "purple" = PIPE_COLOR_PURPLE, + "omni" = PIPE_COLOR_GREY +)) + +///List that sorts the colors and is used for setting up the pipes layer so that they overlap correctly +GLOBAL_LIST_INIT(pipe_colors_ordered, sort_list(list( + PIPE_COLOR_BLUE = -5, + PIPE_COLOR_BROWN = -4, + PIPE_COLOR_CYAN = -3, + PIPE_COLOR_BLACK = -2, + PIPE_COLOR_GREEN = -1, + PIPE_COLOR_GREY = 0, + PIPE_COLOR_ORANGE = 1, + PIPE_COLOR_PURPLE = 2, + PIPE_COLOR_RED = 3, + PIPE_COLOR_YELLOW = 4 +))) + +///Names shown in the examine for every colored atmos component +GLOBAL_LIST_INIT(pipe_color_name, sort_list(list( + PIPE_COLOR_GREY = "omni", + PIPE_COLOR_BLUE = "blue", + PIPE_COLOR_RED = "red", + PIPE_COLOR_GREEN = "green", + PIPE_COLOR_ORANGE = "orange", + PIPE_COLOR_CYAN = "cyan", + PIPE_COLOR_BLACK = "dark", + PIPE_COLOR_YELLOW = "yellow", + PIPE_COLOR_BROWN = "brown", + PIPE_COLOR_PURPLE = "purple" +))) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 59975770e77..da53566d934 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -277,7 +277,10 @@ Turf and target are seperate in case you want to teleport some distance from a t /proc/format_frequency(var/f) return "[round(f / 10)].[f % 10]" - +//Opposite of format, returns as a number +/proc/unformat_frequency(frequency) + frequency = text2num(frequency) + return frequency * 10 ///This will update a mob's name, real_name, mind.name, data_core records, pda and id diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 2708a1e10d1..4fcd23d8d97 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -18,18 +18,23 @@ /atom/Click(var/location, var/control, var/params) // This is their reaction to being clicked on (standard proc) if(!(flags & INITIALIZED)) - to_chat(usr, "[type] initialization failure. Click dropped. Contact a coder or admin.") + to_chat(usr, SPAN_WARNING("[type] initialization failure. Click dropped. Contact a coder or admin.")) return if(src) + SEND_SIGNAL(src, COMSIG_CLICK, location, control, params, usr) usr.ClickOn(src, params) /atom/DblClick(var/location, var/control, var/params) if(!(flags & INITIALIZED)) - to_chat(usr, "[type] initialization failure. Click dropped. Contact a coder or admin.") + to_chat(usr, SPAN_WARNING("[type] initialization failure. Click dropped. Contact a coder or admin.")) return if(src) usr.DblClickOn(src, params) +/atom/MouseWheel(delta_x,delta_y,location,control,params) + usr.MouseWheelOn(src, delta_x, delta_y, params) + + /* Standard mob ClickOn() Handles exceptions: Buildmode, middle click, modified clicks, mech actions @@ -390,3 +395,7 @@ if(T) T.Click(location, control, params) . = 1 + +/// MouseWheelOn +/mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params) + SEND_SIGNAL(src, COMSIG_MOUSE_SCROLL_ON, A, delta_x, delta_y, params) diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index 57776654c07..30b0285d9d7 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -30,7 +30,7 @@ #define ui_swaphand2 "CENTER:16,SOUTH+1:5" #define ui_storage1 "CENTER+1:16,SOUTH:5" #define ui_storage2 "CENTER+2:16,SOUTH:5" -#define ui_crafting "EAST-4:18,SOUTH:5" +#define ui_smallquad "EAST-4:18,SOUTH:4" #define ui_alien_head "CENTER-3:12,SOUTH:5" //aliens #define ui_alien_oclothing "CENTER-2:14,SOUTH:5"//aliens diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 410fd5f5628..e0eec06814d 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -182,7 +182,10 @@ GLOBAL_DATUM_INIT(global_hud, /datum/global_hud, new) var/list/static_inventory = list() //the screen objects which are static var/list/adding + ///Misc hud elements that are hidden when the hud is minimized var/list/other + ///Misc hud elements that are always shown even when the hud is minimized + var/list/other_important var/list/miniobjs var/list/atom/movable/screen/hotkeybuttons @@ -219,6 +222,7 @@ GLOBAL_DATUM_INIT(global_hud, /datum/global_hud, new) move_intent = null adding = null other = null + other_important = null hotkeybuttons = null // item_action_list = null // ? mymob = null @@ -438,6 +442,8 @@ GLOBAL_DATUM_INIT(global_hud, /datum/global_hud, new) src.client.screen -= src.hud_used.other if(src.hud_used.hotkeybuttons) src.client.screen -= src.hud_used.hotkeybuttons + if(src.hud_used.other_important) + src.client.screen -= src.hud_used.other_important src.client.screen -= src.internals src.client.screen += src.hud_used.action_intent //we want the intent swticher visible else @@ -446,6 +452,8 @@ GLOBAL_DATUM_INIT(global_hud, /datum/global_hud, new) src.client.screen += src.hud_used.adding if(src.hud_used.other && src.hud_used.inventory_shown) src.client.screen += src.hud_used.other + if(src.hud_used.other_important) + src.client.screen += src.hud_used.other_important if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden) src.client.screen += src.hud_used.hotkeybuttons if(src.internals) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index e516875f485..845096cace0 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -178,14 +178,16 @@ name = "crafting menu" icon = 'icons/mob/screen/midnight.dmi' icon_state = "craft" - screen_loc = ui_crafting + screen_loc = ui_smallquad /atom/movable/screen/craft/Click(location, control, params) var/datum/component/personal_crafting/C = usr.GetComponent(/datum/component/personal_crafting) C?.ui_interact(usr) /atom/movable/screen/Click(location, control, params) - if(!usr) return 1 + ..() //Why the FUCK was this not called before + if(!usr) + return TRUE switch(name) if("toggle") if(usr.hud_used.inventory_shown) diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm index 434d7be132e..86583366de5 100644 --- a/code/controllers/communications.dm +++ b/code/controllers/communications.dm @@ -169,7 +169,7 @@ var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, ENT_FREQ, MED_FREQ, SEC return "comradio" // AI private channel if(frequency == AI_FREQ) - return "airadio" + return "aiprivradio" // department radio formatting (poorly optimized, ugh) if(frequency == SEC_FREQ) return "secradio" @@ -182,7 +182,7 @@ var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, ENT_FREQ, MED_FREQ, SEC if(frequency == SUP_FREQ) // cargo return "suppradio" if(frequency == SRV_FREQ) // service - return "srvradio" + return "servradio" if(frequency == EXP_FREQ) // explorer return "expradio" if(frequency == ENT_FREQ) // entertainment diff --git a/code/controllers/subsystems/alarm.dm b/code/controllers/subsystems/alarm.dm index 394e68267e8..bd49631cb6f 100644 --- a/code/controllers/subsystems/alarm.dm +++ b/code/controllers/subsystems/alarm.dm @@ -1,38 +1,44 @@ +// We manually initialize the alarm handlers instead of looping over all existing types +// to make it possible to write: camera_alarm.triggerAlarm() rather than SSalarms.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof. +/var/global/datum/alarm_handler/atmosphere/atmosphere_alarm = new() +/var/global/datum/alarm_handler/camera/camera_alarm = new() +/var/global/datum/alarm_handler/fire/fire_alarm = new() +/var/global/datum/alarm_handler/motion/motion_alarm = new() +/var/global/datum/alarm_handler/power/power_alarm = new() + SUBSYSTEM_DEF(alarms) name = "Alarms" - wait = 20 + wait = 2 SECONDS + priority = FIRE_PRIORITY_ALARMS init_order = INIT_ORDER_ALARMS - flags = SS_NO_TICK_CHECK var/static/list/datum/alarm/all_handlers - // We manually initialize the alarm handlers instead of looping over all existing types - // to make it possible to write: camera.triggerAlarm() rather than alarm_manager.managers[datum/alarm_handler/camera].triggerAlarm() or a variant thereof. - var/static/datum/alarm_handler/atmosphere/atmosphere_alarm - var/static/datum/alarm_handler/camera/camera_alarm - var/static/datum/alarm_handler/fire/fire_alarm - var/static/datum/alarm_handler/motion/motion_alarm - var/static/datum/alarm_handler/power/power_alarm + var/tmp/list/currentrun = null + var/static/list/active_alarm_cache = list() /datum/controller/subsystem/alarms/Initialize() - atmosphere_alarm = new - camera_alarm = new - fire_alarm = new - motion_alarm = new - power_alarm = new - all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm) - return ..() + SSalarms.all_handlers = list(atmosphere_alarm, camera_alarm, fire_alarm, motion_alarm, power_alarm) + . = ..() -/datum/controller/subsystem/alarms/fire() - var/dt = (flags & SS_TICKER)? (wait * world.tick_lag * 0.1) : (wait * 0.1) - for(var/datum/alarm_handler/A in all_handlers) - A.process(dt) +/datum/controller/subsystem/alarms/fire(resumed = FALSE) + if(!resumed) + src.currentrun = SSalarms.all_handlers.Copy() + active_alarm_cache.Cut() + + var/list/currentrun = src.currentrun // Cache for sanic speed + while (currentrun.len) + var/datum/alarm_handler/AH = currentrun[currentrun.len] + currentrun.len-- + AH.process() + active_alarm_cache += AH.alarms + + if (MC_TICK_CHECK) + return /datum/controller/subsystem/alarms/proc/active_alarms() - . = list() - for(var/datum/alarm_handler/AH in all_handlers) - . += AH.alarms + return active_alarm_cache.Copy() /datum/controller/subsystem/alarms/proc/number_of_active_alarms() - return length(active_alarms()) + return active_alarm_cache.len /datum/controller/subsystem/alarms/stat_entry() - ..("[number_of_active_alarms()] alarms") + ..("[number_of_active_alarms()] alarm\s") diff --git a/code/controllers/subsystems/plants.dm b/code/controllers/subsystems/plants.dm new file mode 100644 index 00000000000..df0b8f6fa7c --- /dev/null +++ b/code/controllers/subsystems/plants.dm @@ -0,0 +1,164 @@ +///Number of ticks between the plant processor cycling. +#define PLANT_TICK_TIME 75 + +SUBSYSTEM_DEF(plants) + name = "Plants" + init_order = INIT_ORDER_PLANTS + priority = FIRE_PRIORITY_PLANTS + wait = PLANT_TICK_TIME + + ///Stores generated fruit descs. + var/list/product_descs = list() + ///All seed data stored here. + var/list/seeds = list() + ///Gene obfuscation for delicious trial and error goodness. + var/list/gene_tag_masks = list() + ///Stores images of growth, fruits and seeds. + var/list/plant_icon_cache = list() + ///List of all harvested product sprites. + var/list/plant_sprites = list() + ///List of all growth sprites plus number of growth stages. + var/list/plant_product_sprites = list() + ///Stored gene masked list, rather than recreating it when needed. + var/list/gene_masked_list = list() + ///Stored datum versions of the gene masked list. + var/list/plant_gene_datums = list() + + // To be clear, the only thing this processes are spreading plants + // Hydro trays and growing food normally just chill in SSobj + var/list/processing = list() + var/list/currentrun = list() + +/datum/controller/subsystem/plants/stat_entry() + ..("P:[processing.len]|S:[seeds.len]") + +/datum/controller/subsystem/plants/Initialize(timeofday) + setup() + return ..() + +/** + * Predefined/roundstart varieties use a string key to make it + * easier to grab the new variety when mutating. Post-roundstart + * and mutant varieties use their uid converted to a string instead. + * Looks like shit but it's sort of necessary. + */ +/datum/controller/subsystem/plants/proc/setup() + //Build the icon lists. + for(var/icostate in icon_states('icons/obj/hydroponics_growing.dmi')) + var/split = findtext(icostate,"-") + if(!split) + //Invalid icon_state + continue + + var/ikey = copytext(icostate,(split+1)) + if(ikey == "dead") + //Don't count dead icons + continue + ikey = text2num(ikey) + var/base = copytext(icostate,1,split) + + if(!(plant_sprites[base]) || (plant_sprites[base]Crew Transfer Factor: [factor]") + to_chat(world, "\nCrew Transfer Factor: [factor]") greatest_votes = max(choices["Initiate Crew Transfer"], choices["Extend the Shift"]) //VOREStation Edit . = list() // Get all options with that many votes and return them in a list @@ -247,7 +247,7 @@ SUBSYSTEM_DEF(vote) log_vote(text) - to_chat(world, "[text]\nType vote or click here to place your votes.\nYou have [config_legacy.vote_period / 10] seconds to vote.") + to_chat(world, "[text]\nType vote or click here to place your votes.\nYou have [config_legacy.vote_period / 10] seconds to vote.") if(vote_type == VOTE_CREW_TRANSFER || vote_type == VOTE_GAMEMODE || vote_type == VOTE_CUSTOM) SEND_SOUND(world, sound('sound/ambience/alarm4.ogg', repeat = 0, wait = 0, volume = 50, channel = 3)) diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index f51c6296a75..1289381bf6d 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -95,7 +95,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick) options["LEGACY: radio_controller"] = radio_controller options["LEGACY: paiController"] = paiController options["LEGACY: cameranet"] = cameranet - options["LEGACY: plant_controller"] = plant_controller var/pick = input(mob, "Choose a controller to debug/view variables of.", "VV controller:") as null|anything in options if(!pick) diff --git a/code/datums/autolathe/arms.dm b/code/datums/autolathe/arms.dm index 709dd53e813..75de3f827e4 100644 --- a/code/datums/autolathe/arms.dm +++ b/code/datums/autolathe/arms.dm @@ -46,7 +46,7 @@ /datum/category_item/autolathe/arms/pistol_5mm name = "pistol magazine (5mm)" path =/obj/item/ammo_magazine/c5mm - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 */ ////// 10x24mm @@ -232,93 +232,93 @@ /datum/category_item/autolathe/arms/pistol_5mm name = "pistol magazine (5mm)" path =/obj/item/ammo_magazine/c5mm/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/smg_5mm name = "top-mounted SMG magazine (5mm)" path =/obj/item/ammo_magazine/c5mmt/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/pistol_45 name = "pistol magazine (.45)" path =/obj/item/ammo_magazine/m45/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/pistol_45uzi name = "stick magazine (.45)" path =/obj/item/ammo_magazine/m45uzi/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/tommymag name = "Tommy Gun magazine (.45)" path =/obj/item/ammo_magazine/m45tommy/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/tommydrum name = "Tommy Gun drum magazine (.45)" path =/obj/item/ammo_magazine/m45tommydrum/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/pistol_9mm name = "pistol magazine (9mm)" path =/obj/item/ammo_magazine/m9mm/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/smg_9mm name = "top-mounted SMG magazine (9mm)" path =/obj/item/ammo_magazine/m9mmt/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/smg_10mm name = "SMG magazine (10mm)" path =/obj/item/ammo_magazine/m10mm/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/pistol_44 name = "pistol magazine (.44)" path =/obj/item/ammo_magazine/m44/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/rifle_545 name = "10rnd rifle magazine (5.45mm)" path =/obj/item/ammo_magazine/m545saw/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/rifle_545m name = "20rnd rifle magazine (5.45mm)" path =/obj/item/ammo_magazine/m545sawm/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/rifle_SVD name = "10rnd rifle magazine (7.62mm)" path =/obj/item/ammo_magazine/m762svd/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/rifle_762 name = "20rnd rifle magazine (7.62mm)" path =/obj/item/ammo_magazine/m762/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/machinegun_762 name = "machinegun box magazine (7.62)" path =/obj/item/ammo_magazine/a762/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/shotgun_magazine name = "24rnd shotgun magazine (12g)" path =/obj/item/ammo_magazine/m12gdrum/empty - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1*/ /////////////////////////////// @@ -352,73 +352,73 @@ /*/datum/category_item/autolathe/arms/pistol_clip_45 name = "ammo clip (.45)" path =/obj/item/ammo_magazine/clip/c45 - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/pistol_clip_45r name = "ammo clip (.45 rubber)" path =/obj/item/ammo_magazine/clip/c45/rubber - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/pistol_clip_45f name = "ammo clip (.45 flash)" path =/obj/item/ammo_magazine/clip/c45/flash - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/pistol_clip_45p name = "ammo clip (.45 practice)" path =/obj/item/ammo_magazine/clip/c45/practice - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/pistol_clip_9mm name = "ammo clip (9mm)" path =/obj/item/ammo_magazine/clip/c9mm - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/pistol_clip_9mmr name = "ammo clip (9mm rubber)" path =/obj/item/ammo_magazine/clip/c9mm/rubber - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/pistol_clip_9mmp name = "ammo clip (9mm practice)" path =/obj/item/ammo_magazine/clip/c9mm/practice - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/pistol_clip_9mmf name = "ammo clip (9mm flash)" path =/obj/item/ammo_magazine/clip/c9mm/flash - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/pistol_clip_5mm name = "ammo clip (5mm)" path =/obj/item/ammo_magazine/clip/c5mm - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/pistol_clip_10mm name = "ammo clip (10mm)" path =/obj/item/ammo_magazine/clip/c10mm - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/pistol_clip_50 name = "ammo clip (.44)" path =/obj/item/ammo_magazine/clip/c50 - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 */ /datum/category_item/autolathe/arms/rifle_clip_545 name = "ammo clip (5.45mm)" path =/obj/item/ammo_magazine/clip/c545 - category = "Arms and Ammunition" + category = list("Arms and Ammunition") hidden = 1 /datum/category_item/autolathe/arms/rifle_clip_545_practice name = "ammo clip (5.45mm practice)" path =/obj/item/ammo_magazine/clip/c545/practice - category = "Arms and Ammunition" + category = list("Arms and Ammunition") /datum/category_item/autolathe/arms/rifle_clip_762 name = "ammo clip (7.62mm)" diff --git a/code/datums/autolathe/autolathe.dm b/code/datums/autolathe/autolathe.dm index 6dbc2b67b35..eac7c2c2ddf 100644 --- a/code/datums/autolathe/autolathe.dm +++ b/code/datums/autolathe/autolathe.dm @@ -1,13 +1,11 @@ -var/datum/category_collection/autolathe/autolathe_recipes - /datum/category_item/autolathe/New() ..() var/obj/item/I = new path() if(I.matter && !resources) resources = list() for(var/material in I.matter) - var/coeff = (no_scale ? 1 : 1.25) //most objects are more expensive to produce than to recycle - resources[material] = I.matter[material]*coeff // but if it's a sheet or RCD cartridge, it's 1:1 + var/coeff = (no_scale ? 1 : 1.25) //Most objects are more expensive to produce than to recycle + resources[material] = I.matter[material]*coeff //But if it's a sheet or RCD cartridge, it's 1:1 if(is_stack) if(istype(I, /obj/item/stack)) var/obj/item/stack/IS = I @@ -71,6 +69,7 @@ var/datum/category_collection/autolathe/autolathe_recipes var/is_stack // Creates multiple of an item if applied to non-stack items var/max_stack var/no_scale + var/man_rating = 0 /datum/category_item/autolathe/dd_SortValue() return name diff --git a/code/datums/repositories/cameras.dm b/code/datums/repositories/cameras.dm index 98dc0d0012e..6d3011ac682 100644 --- a/code/datums/repositories/cameras.dm +++ b/code/datums/repositories/cameras.dm @@ -26,7 +26,7 @@ var/global/datum/repository/cameras/camera_repository = new() cameranet.process_sort() for(var/obj/machinery/camera/C in cameranet.cameras) - var/cam = C.nano_structure() + var/cam = C.ui_structure() for(var/network in C.network) if(!networks[network]) networks[network] = list() diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm index 0de661bbf82..114d0671f5a 100644 --- a/code/datums/wires/autolathe.dm +++ b/code/datums/wires/autolathe.dm @@ -25,6 +25,7 @@ switch(wire) if(WIRE_AUTOLATHE_HACK) A.hacked = !mend + A.update_static_data(usr) if(WIRE_ELECTRIFY) A.shocked = !mend if(WIRE_AUTOLATHE_DISABLE) @@ -38,17 +39,19 @@ switch(wire) if(WIRE_AUTOLATHE_HACK) A.hacked = !A.hacked + A.update_static_data(usr) spawn(50) if(A && !is_cut(wire)) - A.hacked = 0 + A.hacked = FALSE + A.update_static_data(usr) if(WIRE_ELECTRIFY) A.shocked = !A.shocked spawn(50) if(A && !is_cut(wire)) - A.shocked = 0 + A.shocked = FALSE if(WIRE_AUTOLATHE_DISABLE) A.disabled = !A.disabled spawn(50) if(A && !is_cut(wire)) - A.disabled = 0 + A.disabled = FALSE ..() diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 58efd58ba3a..b2442bef5bc 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -203,13 +203,13 @@ /area/proc/atmosalert(danger_level, var/alarm_source) if (danger_level == 0) - SSalarms.atmosphere_alarm.clearAlarm(src, alarm_source) + atmosphere_alarm.clearAlarm(src, alarm_source) else var/obj/machinery/alarm/atmosalarm = alarm_source //maybe other things can trigger these, who knows if(istype(atmosalarm)) - SSalarms.atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level, hidden = atmosalarm.alarms_hidden) + atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level, hidden = atmosalarm.alarms_hidden) else - SSalarms.atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level) + atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level) //Check all the alarms before lowering atmosalm. Raising is perfectly fine. for (var/obj/machinery/alarm/AA in src) diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 50912466c7d..8c5d3679873 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -107,18 +107,23 @@ Class Procs: //2 = run auto, use active var/idle_power_usage = 0 var/active_power_usage = 0 - var/power_channel = EQUIP //EQUIP, ENVIRON or LIGHT + ///EQUIP, ENVIRON or LIGHT + var/power_channel = EQUIP var/power_init_complete = FALSE - var/list/component_parts = null //list of all the parts used to build it, if made from certain kinds of frames. + ///List of all the parts used to build it, if made from certain kinds of frames. + var/list/component_parts = null var/uid - var/panel_open = 0 + var/panel_open = FALSE var/global/gl_uid = 1 - var/clicksound // sound played on succesful interface. Just put it in the list of vars at the start. - var/clickvol = 40 // volume - var/interact_offline = 0 // Can the machine be interacted with while de-powered. + ///Sound played on succesful interface. Just put it in the list of vars at the start. + var/clicksound + ///Volume of interface sounds. + var/clickvol = 40 + ///Can the machine be interacted with while de-powered. + var/interact_offline = FALSE var/obj/item/circuitboard/circuit = null - - var/speed_process = FALSE //If false, SSmachines. If true, SSfastprocess. + ///If false, SSmachines. If true, SSfastprocess. + var/speed_process = FALSE /obj/machinery/Initialize(mapload, newdir) if(newdir) @@ -329,7 +334,7 @@ Class Procs: B.loc = null to_chat(user, "[A.name] replaced with [B.name].") break - update_icon() + update_appearance() RefreshParts() return 1 @@ -351,7 +356,7 @@ Class Procs: "You [anchored ? "un" : ""]secure \the [src].") anchored = !anchored power_change() //Turn on or off the machine depending on the status of power in the new area. - update_icon() + update_appearance() return TRUE /obj/machinery/proc/default_deconstruction_crowbar(var/mob/user, var/obj/item/C) @@ -367,7 +372,7 @@ Class Procs: playsound(src, S.usesound, 50, 1) panel_open = !panel_open to_chat(user, "You [panel_open ? "open" : "close"] the maintenance hatch of [src].") - update_icon() + update_appearance() return 1 /obj/machinery/proc/computer_deconstruction_screwdriver(var/mob/user, var/obj/item/S) @@ -391,7 +396,7 @@ Class Procs: playsound(src, S.usesound, 50, 1) panel_open = !panel_open to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"]") - update_icon() + update_appearance() return 1 /obj/machinery/proc/alarm_deconstruction_wirecutters(var/mob/user, var/obj/item/W) @@ -446,7 +451,7 @@ Class Procs: A.pixel_x = pixel_x A.pixel_y = pixel_y A.update_desc() - A.update_icon() + A.update_appearance() M.loc = null M.deconstruct(src) qdel(src) diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm new file mode 100644 index 00000000000..c82cc3f305e --- /dev/null +++ b/code/game/machinery/air_alarm.dm @@ -0,0 +1,839 @@ +#define DECLARE_TLV_VALUES var/red_min; var/yel_min; var/yel_max; var/red_max; var/tlv_comparitor; +#define LOAD_TLV_VALUES(x, y) red_min = x[1]; yel_min = x[2]; yel_max = x[3]; red_max = x[4]; tlv_comparitor = y; +#define TEST_TLV_VALUES (((tlv_comparitor >= red_max && red_max > 0) || tlv_comparitor <= red_min) ? 2 : ((tlv_comparitor >= yel_max && yel_max > 0) || tlv_comparitor <= yel_min) ? 1 : 0) + +#define AALARM_MODE_SCRUBBING 1 +#define AALARM_MODE_REPLACEMENT 2 //like scrubbing, but faster. +#define AALARM_MODE_PANIC 3 //constantly sucks all air +#define AALARM_MODE_CYCLE 4 //sucks off all air, then refill and switches to scrubbing +#define AALARM_MODE_FILL 5 //emergency fill +#define AALARM_MODE_OFF 6 //Shuts it all down. + +#define AALARM_SCREEN_MAIN 1 +#define AALARM_SCREEN_VENT 2 +#define AALARM_SCREEN_SCRUB 3 +#define AALARM_SCREEN_MODE 4 +#define AALARM_SCREEN_SENSORS 5 + +#define AALARM_REPORT_TIMEOUT 100 + +#define MAX_TEMPERATURE 90 +#define MIN_TEMPERATURE -40 + +//all air alarms in area are connected via magic +/area + var/obj/machinery/alarm/master_air_alarm + var/list/air_vent_names = list() + var/list/air_scrub_names = list() + var/list/air_vent_info = list() + var/list/air_scrub_info = list() + +/obj/machinery/alarm + name = "alarm" + desc = "Used to control various station atmospheric systems. The light indicates the current air status of the area." + icon = 'icons/obj/monitors.dmi' + icon_state = "alarm0" + plane = TURF_PLANE + layer = ABOVE_TURF_LAYER + anchored = TRUE + use_power = USE_POWER_IDLE + idle_power_usage = 80 + active_power_usage = 1000 //For heating/cooling rooms. 1000 joules equates to about 1 degree every 2 seconds for a single tile of air. + power_channel = ENVIRON + req_one_access = list(access_atmospherics, access_engine_equip) + clicksound = "button" + clickvol = 30 + //blocks_emissive = NONE + light_power = 0.25 + var/alarm_id = null + ///Whether to use automatic breach detection or not + var/breach_detection = TRUE + var/frequency = 1439 + //var/skipprocess = 0 //Experimenting + var/alarm_frequency = 1437 + var/remote_control = TRUE + var/rcon_setting = RCON_AUTO + var/rcon_time = 0 + var/locked = TRUE + ///If it's been screwdrivered open. + panel_open = FALSE + var/aidisabled = FALSE + var/shorted = FALSE + circuit = /obj/item/circuitboard/airalarm + //armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, FIRE = 90, ACID = 30) + + var/datum/wires/alarm/wires + + var/mode = AALARM_MODE_SCRUBBING + var/screen = AALARM_SCREEN_MAIN + var/area_uid + var/area/alarm_area + + var/target_temperature = T0C+20 + var/regulating_temperature = 0 + + var/datum/radio_frequency/radio_connection + + /// Keys are things like temperature and certain gasses. Values are lists, which contain, in order: + /// red warning minimum value, yellow warning minimum value, yellow warning maximum value, red warning maximum value + var/list/TLV = list() + var/list/trace_gas = list("nitrous_oxide", "volatile_fuel") //list of other gases that this air alarm is able to detect + + var/danger_level = 0 + var/pressure_dangerlevel = 0 + + var/report_danger_level = 1 + ///If the alarms from this machine are visible on consoles + var/alarms_hidden = FALSE + +/obj/machinery/alarm/nobreach + breach_detection = 0 + +/obj/machinery/alarm/monitor + report_danger_level = 0 + breach_detection = 0 + +/obj/machinery/alarm/alarms_hidden + alarms_hidden = TRUE + +/obj/machinery/alarm/angled +// icon = 'icons/obj/wall_machines_angled.dmi' + +/obj/machinery/alarm/angled/hidden + alarms_hidden = TRUE + +/obj/machinery/alarm/angled/offset_airalarm() + pixel_x = (dir & 3) ? 0 : (dir == 4 ? -21 : 21) + pixel_y = (dir & 3) ? (dir == 1 ? -18 : 20) : 0 + +/obj/machinery/alarm/server/Initialize(mapload) + . = ..() + req_access = list(access_rd, access_atmospherics, access_engine_equip) + TLV[/datum/gas/oxygen] = list(16, 19, 135, 140) // Partial pressure, kpa + TLV[/datum/gas/carbon_dioxide] = list(-1.0, -1.0, 5, 10) // Partial pressure, kpa + TLV[/datum/gas/phoron] = list(-1.0, -1.0, 0, 0.5) // Partial pressure, kpa + TLV["other"] = list(-1.0, -1.0, 0.5, 1.0) // Partial pressure, kpa + TLV["pressure"] = list(ONE_ATMOSPHERE * 0.80, ONE_ATMOSPHERE * 0.90, ONE_ATMOSPHERE * 1.10, ONE_ATMOSPHERE * 1.20) /* kpa */ + TLV["temperature"] = list(T0C - 26, T0C, T0C + 40, T0C + 66) // K + +/obj/machinery/alarm/Initialize(mapload) + . = ..() + if(!pixel_x && !pixel_y) + offset_airalarm() + first_run() + +/obj/machinery/alarm/Destroy() + unregister_radio(src, frequency) + qdel(wires) + wires = null + if(alarm_area && alarm_area.master_air_alarm == src) + alarm_area.master_air_alarm = null + elect_master(exclude_self = TRUE) + return ..() + +/obj/machinery/alarm/proc/offset_airalarm() + pixel_x = (dir & 3) ? 0 : (dir == 4 ? -26 : 26) + pixel_y = (dir & 3) ? (dir == 1 ? -26 : 26) : 0 + +/obj/machinery/alarm/proc/first_run() + alarm_area = get_area(src) + area_uid = "\ref[alarm_area]" + if(name == "alarm") + name = "[alarm_area.name] Air Alarm" + + if(!wires) + wires = new(src) + + // breathable air according to human/Life() + TLV["oxygen"] = list(16, 19, 135, 140) // Partial pressure, kpa + TLV["nitrogen"] = list(0, 0, 135, 140) // Partial pressure, kpa + TLV["carbon dioxide"] = list(-1.0, -1.0, 5, 10) // Partial pressure, kpa + TLV["phoron"] = list(-1.0, -1.0, 0, 0.5) // Partial pressure, kpa + TLV["other"] = list(-1.0, -1.0, 0.5, 1.0) // Partial pressure, kpa + TLV["pressure"] = list(ONE_ATMOSPHERE * 0.80, ONE_ATMOSPHERE * 0.90, ONE_ATMOSPHERE * 1.10, ONE_ATMOSPHERE * 1.20) /* kpa */ + TLV["temperature"] = list(T0C - 26, T0C, T0C + 40, T0C + 66) // K + + update_icon() + +/obj/machinery/alarm/Initialize(mapload) + . = ..() + set_frequency(frequency) + if(!master_is_operating()) + elect_master() + +/obj/machinery/alarm/process(delta_time) + if((stat & (NOPOWER|BROKEN)) || shorted) + return + + var/turf/simulated/location = src.loc + if(!istype(location)) return//returns if loc is not simulated + + var/datum/gas_mixture/environment = location.return_air() + + //Handle temperature adjustment here. + handle_heating_cooling(environment) + + var/old_level = danger_level + var/old_pressurelevel = pressure_dangerlevel + danger_level = overall_danger_level(environment) + + if(old_level != danger_level) + apply_danger_level(danger_level) + + if(old_pressurelevel != pressure_dangerlevel) + if(breach_detected()) + mode = AALARM_MODE_OFF + apply_mode() + + if(mode == AALARM_MODE_CYCLE && environment.return_pressure() < ONE_ATMOSPHERE * 0.05) + mode = AALARM_MODE_FILL + apply_mode() + + //atmos computer remote control stuff + switch(rcon_setting) + if(RCON_NO) + remote_control = 0 + if(RCON_AUTO) + if(danger_level == 2) + remote_control = 1 + else + remote_control = 0 + if(RCON_YES) + remote_control = 1 + + return + +/obj/machinery/alarm/proc/handle_heating_cooling(var/datum/gas_mixture/environment) + DECLARE_TLV_VALUES + LOAD_TLV_VALUES(TLV["temperature"], target_temperature) + if(!regulating_temperature) + //check for when we should start adjusting temperature + if(!TEST_TLV_VALUES && abs(environment.temperature - target_temperature) > 2.0 && environment.return_pressure() >= 1) + update_use_power(USE_POWER_ACTIVE) + regulating_temperature = 1 + audible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\ + "You hear a click and a faint electronic hum.") + playsound(src, 'sound/machines/click.ogg', 50, 1) + else + //check for when we should stop adjusting temperature + if(TEST_TLV_VALUES || abs(environment.temperature - target_temperature) <= 0.5 || environment.return_pressure() < 1) + update_use_power(USE_POWER_IDLE) + regulating_temperature = 0 + audible_message("\The [src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\ + "You hear a click as a faint electronic humming stops.") + playsound(src, 'sound/machines/click.ogg', 50, 1) + + if(regulating_temperature) + if(target_temperature > T0C + MAX_TEMPERATURE) + target_temperature = T0C + MAX_TEMPERATURE + + if(target_temperature < T0C + MIN_TEMPERATURE) + target_temperature = T0C + MIN_TEMPERATURE + + var/datum/gas_mixture/gas + gas = environment.remove(0.25 * environment.total_moles) + if(gas) + + if(gas.temperature <= target_temperature) //gas heating + var/energy_used = min(gas.get_thermal_energy_change(target_temperature) , active_power_usage) + + gas.add_thermal_energy(energy_used) + //use_power(energy_used, ENVIRON) //handle by update_use_power instead + else //gas cooling + var/heat_transfer = min(abs(gas.get_thermal_energy_change(target_temperature)), active_power_usage) + + //Assume the heat is being pumped into the hull which is fixed at 20 C + //none of this is really proper thermodynamics but whatever + + var/cop = gas.temperature / T20C //coefficient of performance -> power used = heat_transfer/cop + + heat_transfer = min(heat_transfer, cop * active_power_usage) //this ensures that we don't use more than active_power_usage amount of power + + heat_transfer = -gas.add_thermal_energy(-heat_transfer) //get the actual heat transfer + + //use_power(heat_transfer / cop, ENVIRON) //handle by update_use_power instead + + environment.merge(gas) + +/obj/machinery/alarm/proc/overall_danger_level(var/datum/gas_mixture/environment) + var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature/environment.volume + var/environment_pressure = environment.return_pressure() + + var/other_moles = 0 + for(var/g in trace_gas) + other_moles += environment.gas[g] //this is only going to be used in a partial pressure calc, so we don't need to worry about group_multiplier here. + + DECLARE_TLV_VALUES + LOAD_TLV_VALUES(TLV["pressure"], environment_pressure) + pressure_dangerlevel = TEST_TLV_VALUES // not local because it's used in process() + LOAD_TLV_VALUES(TLV["oxygen"], environment.gas[/datum/gas/oxygen]*partial_pressure) + var/oxygen_dangerlevel = TEST_TLV_VALUES + LOAD_TLV_VALUES(TLV["carbon dioxide"], environment.gas[/datum/gas/carbon_dioxide]*partial_pressure) + var/co2_dangerlevel = TEST_TLV_VALUES + LOAD_TLV_VALUES(TLV["phoron"], environment.gas[/datum/gas/phoron]*partial_pressure) + var/phoron_dangerlevel = TEST_TLV_VALUES + LOAD_TLV_VALUES(TLV["temperature"], environment.temperature) + var/temperature_dangerlevel = TEST_TLV_VALUES + LOAD_TLV_VALUES(TLV["other"], other_moles*partial_pressure) + var/other_dangerlevel = TEST_TLV_VALUES + + return max( + pressure_dangerlevel, + oxygen_dangerlevel, + co2_dangerlevel, + phoron_dangerlevel, + other_dangerlevel, + temperature_dangerlevel + ) + +// Returns whether this air alarm thinks there is a breach, given the sensors that are available to it. +/obj/machinery/alarm/proc/breach_detected() + var/turf/simulated/location = src.loc + + if(!istype(location)) + return 0 + + if(breach_detection == 0) + return 0 + + var/datum/gas_mixture/environment = location.return_air() + var/environment_pressure = environment.return_pressure() + var/pressure_levels = TLV["pressure"] + + if(environment_pressure <= pressure_levels[1]) //low pressures + if(!(mode == AALARM_MODE_PANIC || mode == AALARM_MODE_CYCLE)) + return 1 + + return 0 + +/obj/machinery/alarm/proc/master_is_operating() + return alarm_area && alarm_area.master_air_alarm && !(alarm_area.master_air_alarm.stat & (NOPOWER | BROKEN)) + +/obj/machinery/alarm/proc/elect_master(exclude_self = FALSE) + for(var/obj/machinery/alarm/AA in alarm_area) + if(exclude_self && AA == src) + continue + if(!(AA.stat & (NOPOWER|BROKEN))) + alarm_area.master_air_alarm = AA + return 1 + return 0 + +/obj/machinery/alarm/update_icon() + cut_overlays() + + if(panel_open) + icon_state = "alarmx" + set_light(0) + //set_light_on(FALSE) + return + if((stat & (NOPOWER|BROKEN)) || shorted) + icon_state = "alarmp" + set_light(0) + //set_light_on(FALSE) + return + + var/icon_level = danger_level + if(alarm_area?.atmosalm) + icon_level = max(icon_level, 1) //if there's an atmos alarm but everything is okay locally, no need to go past yellow + + var/new_color = null + switch(icon_level) + if(0) + icon_state = "alarm0" + //add_overlay(mutable_appearance(icon, "alarm_ov0")) + //add_overlay(emissive_appearance(icon, "alarm_ov0")) + new_color = "#03A728" + if(1) + icon_state = "alarm2" //yes, alarm2 is yellow alarm + //add_overlay(mutable_appearance(icon, "alarm_ov2")) + //add_overlay(emissive_appearance(icon, "alarm_ov2")) + new_color = "#EC8B2F" + if(2) + icon_state = "alarm1" + //add_overlay(mutable_appearance(icon, "alarm_ov1")) + //add_overlay(emissive_appearance(icon, "alarm_ov1")) + new_color = "#DA0205" + + set_light(l_range = 2, l_power = 0.25, l_color = new_color) + //set_light_on(TRUE) + +/obj/machinery/alarm/receive_signal(datum/signal/signal) + if(stat & (NOPOWER|BROKEN)) + return + if(alarm_area.master_air_alarm != src) + if(master_is_operating()) + return + elect_master() + if(alarm_area.master_air_alarm != src) + return + if(!signal || signal.encryption) + return + var/id_tag = signal.data["tag"] + if(!id_tag) + return + if(signal.data["area"] != area_uid) + return + if(signal.data["sigtype"] != "status") + return + + var/dev_type = signal.data["device"] + if(!(id_tag in alarm_area.air_scrub_names) && !(id_tag in alarm_area.air_vent_names)) + register_env_machine(id_tag, dev_type) + if(dev_type == "AScr") + alarm_area.air_scrub_info[id_tag] = signal.data + else if(dev_type == "AVP") + alarm_area.air_vent_info[id_tag] = signal.data + +/obj/machinery/alarm/proc/register_env_machine(var/m_id, var/device_type) + var/new_name + if(device_type == "AVP") + new_name = "[alarm_area.name] Vent Pump #[alarm_area.air_vent_names.len+1]" + alarm_area.air_vent_names[m_id] = new_name + else if(device_type == "AScr") + new_name = "[alarm_area.name] Air Scrubber #[alarm_area.air_scrub_names.len+1]" + alarm_area.air_scrub_names[m_id] = new_name + else + return + spawn(10) + send_signal(m_id, list("init" = new_name)) + +/obj/machinery/alarm/proc/refresh_all() + for(var/id_tag in alarm_area.air_vent_names) + var/list/I = alarm_area.air_vent_info[id_tag] + if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time) + continue + send_signal(id_tag, list("status")) + for(var/id_tag in alarm_area.air_scrub_names) + var/list/I = alarm_area.air_scrub_info[id_tag] + if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time) + continue + send_signal(id_tag, list("status")) + +/obj/machinery/alarm/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_TO_AIRALARM) + +/obj/machinery/alarm/proc/send_signal(var/target, var/list/command)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise + if(!radio_connection) + return 0 + + var/datum/signal/signal = new + signal.transmission_method = TRANSMISSION_RADIO //radio signal + signal.source = src + + signal.data = command + signal.data["tag"] = target + signal.data["sigtype"] = "command" + + radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM) +// to_world("Signal [command] Broadcasted to [target]") + + return 1 + +/obj/machinery/alarm/proc/apply_mode() + //propagate mode to other air alarms in the area + //TODO: make it so that players can choose between applying the new mode to the room they are in (related area) vs the entire alarm area + for(var/obj/machinery/alarm/AA in alarm_area) + AA.mode = mode + + switch(mode) + if(AALARM_MODE_SCRUBBING) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 1, "co2_scrub"= 1, "scrubbing"= 1, "panic_siphon"= 0)) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 1, "checks"= "default", "set_external_pressure"= "default")) + + if(AALARM_MODE_PANIC, AALARM_MODE_CYCLE) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 1, "panic_siphon"= 1)) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 0)) + + if(AALARM_MODE_REPLACEMENT) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 1, "panic_siphon"= 1)) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 1, "checks"= "default", "set_external_pressure"= "default")) + + if(AALARM_MODE_FILL) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 0)) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 1, "checks"= "default", "set_external_pressure"= "default")) + + if(AALARM_MODE_OFF) + for(var/device_id in alarm_area.air_scrub_names) + send_signal(device_id, list("power"= 0)) + for(var/device_id in alarm_area.air_vent_names) + send_signal(device_id, list("power"= 0)) + +/obj/machinery/alarm/proc/apply_danger_level(var/new_danger_level) + if(report_danger_level && alarm_area.atmosalert(new_danger_level, src)) + post_alert(new_danger_level) + + update_icon() + +/obj/machinery/alarm/proc/post_alert(alert_level) + var/datum/radio_frequency/frequency = radio_controller.return_frequency(alarm_frequency) + if(!frequency) + return + + var/datum/signal/alert_signal = new + alert_signal.source = src + alert_signal.transmission_method = TRANSMISSION_RADIO + alert_signal.data["zone"] = alarm_area.name + alert_signal.data["type"] = "Atmospheric" + + if(alert_level==2) + alert_signal.data["alert"] = "severe" + else if(alert_level==1) + alert_signal.data["alert"] = "minor" + else if(alert_level==0) + alert_signal.data["alert"] = "clear" + + frequency.post_signal(src, alert_signal) + +/obj/machinery/alarm/attack_ai(mob/user) + ui_interact(user) + +/obj/machinery/alarm/attack_hand(mob/user) + . = ..() + if(.) + return + return interact(user) + +/obj/machinery/alarm/interact(mob/user) + ui_interact(user) + wires.Interact(user) + +/obj/machinery/alarm/ui_status(mob/user) + if(isAI(user) && aidisabled) + to_chat(user, "AI control has been disabled.") + else if(!shorted) + return ..() + return UI_CLOSE + +/obj/machinery/alarm/ui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AirAlarm", name, parent_ui) + if(state) + ui.set_state(state) + ui.open() + +/obj/machinery/alarm/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = list( + "locked" = locked, + "siliconUser" = issilicon(user), + "remoteUser" = !!ui.parent_ui, + "danger_level" = danger_level, + "target_temperature" = "[target_temperature - T0C]C", + "rcon" = rcon_setting, + ) + + var/area/A = get_area(src) + data["atmos_alarm"] = A?.atmosalm + data["fire_alarm"] = A?.fire + + var/turf/T = get_turf(src) + var/datum/gas_mixture/environment = T.return_air() + + var/list/list/environment_data = list() + data["environment_data"] = environment_data + + DECLARE_TLV_VALUES + + var/pressure = environment.return_pressure() + LOAD_TLV_VALUES(TLV["pressure"], pressure) + environment_data.Add(list(list( + "name" = "Pressure", + "value" = pressure, + "unit" = "kPa", + "danger_level" = TEST_TLV_VALUES + ))) + + var/temperature = environment.temperature + LOAD_TLV_VALUES(TLV["temperature"], temperature) + environment_data.Add(list(list( + "name" = "Temperature", + "value" = temperature, + "unit" = "K ([round(temperature - T0C, 0.1)]C)", + "danger_level" = TEST_TLV_VALUES + ))) + + var/total_moles = environment.total_moles + var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume + for(var/gas_id in environment.gas) + if(!(gas_id in TLV)) + continue + LOAD_TLV_VALUES(TLV[gas_id], environment.gas[gas_id] * partial_pressure) + environment_data.Add(list(list( + "name" = gas_id, + "value" = environment.gas[gas_id] / total_moles * 100, + "unit" = "%", + "danger_level" = TEST_TLV_VALUES + ))) + + if(!locked || issilicon(user) || data["remoteUser"]) + var/list/list/vents = list() + data["vents"] = vents + for(var/id_tag in A.air_vent_names) + var/long_name = A.air_vent_names[id_tag] + var/list/info = A.air_vent_info[id_tag] + if(!info) + continue + vents.Add(list(list( + "id_tag" = id_tag, + "long_name" = sanitize(long_name), + "power" = info["power"], + "checks" = info["checks"], + "excheck" = info["checks"]&1, + "incheck" = info["checks"]&2, + "direction" = info["direction"], + "external" = info["external"], + "internal" = info["internal"], + "extdefault"= (info["external"] == ONE_ATMOSPHERE), + "intdefault"= (info["internal"] == 0), + ))) + + + var/list/list/scrubbers = list() + data["scrubbers"] = scrubbers + for(var/id_tag in alarm_area.air_scrub_names) + var/long_name = alarm_area.air_scrub_names[id_tag] + var/list/info = alarm_area.air_scrub_info[id_tag] + if(!info) + continue + scrubbers += list(list( + "id_tag" = id_tag, + "long_name" = sanitize(long_name), + "power" = info["power"], + "scrubbing" = info["scrubbing"], + "panic" = info["panic"], + "filters" = list( + list("name" = "Oxygen", "command" = "o2_scrub", "val" = info["filter_o2"]), + list("name" = "Nitrogen", "command" = "n2_scrub", "val" = info["filter_n2"]), + list("name" = "Carbon Dioxide", "command" = "co2_scrub","val" = info["filter_co2"]), + list("name" = "Toxin" , "command" = "tox_scrub","val" = info["filter_phoron"]), + list("name" = "Nitrous Oxide", "command" = "n2o_scrub","val" = info["filter_n2o"]), + list("name" = "Fuel", "command" = "fuel_scrub","val" = info["filter_fuel"]) + ) + )) + data["scrubbers"] = scrubbers + + data["mode"] = mode + + var/list/list/modes = list() + data["modes"] = modes + modes[++modes.len] = list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0) + modes[++modes.len] = list("name" = "Replace Air - Siphons out air while replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 0) + modes[++modes.len] = list("name" = "Panic - Siphons air out of the room", "mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1) + modes[++modes.len] = list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_CYCLE, "selected" = mode == AALARM_MODE_CYCLE, "danger" = 1) + modes[++modes.len] = list("name" = "Fill - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FILL, "selected" = mode == AALARM_MODE_FILL, "danger" = 0) + modes[++modes.len] = list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0) + + var/list/selected + var/list/thresholds = list() + + var/list/gas_names = list("oxygen", "carbon dioxide", "phoron", "other") + for(var/g in gas_names) + thresholds[++thresholds.len] = list("name" = g, "settings" = list()) + selected = TLV[g] + for(var/i = 1, i <= 4, i++) + thresholds[thresholds.len]["settings"] += list(list("env" = g, "val" = i, "selected" = selected[i])) + + selected = TLV["pressure"] + thresholds[++thresholds.len] = list("name" = "Pressure", "settings" = list()) + for(var/i = 1, i <= 4, i++) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = i, "selected" = selected[i])) + + selected = TLV["temperature"] + thresholds[++thresholds.len] = list("name" = "Temperature", "settings" = list()) + for(var/i = 1, i <= 4, i++) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = i, "selected" = selected[i])) + + data["thresholds"] = thresholds + return data + +/obj/machinery/alarm/ui_act(action, params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE + + if(action == "rcon") + var/attempted_rcon_setting = text2num(params["rcon"]) + + switch(attempted_rcon_setting) + if(RCON_NO) + rcon_setting = RCON_NO + if(RCON_AUTO) + rcon_setting = RCON_AUTO + if(RCON_YES) + rcon_setting = RCON_YES + return TRUE + + if(action == "temperature") + var/list/selected = TLV["temperature"] + var/max_temperature = min(selected[3] - T0C, MAX_TEMPERATURE) + var/min_temperature = max(selected[2] - T0C, MIN_TEMPERATURE) + var/input_temperature = input(usr, "What temperature would you like the system to mantain? (Capped between [min_temperature] and [max_temperature]C)", "Thermostat Controls", target_temperature - T0C) as num|null + if(isnum(input_temperature)) + if(input_temperature > max_temperature || input_temperature < min_temperature) + to_chat(usr, "Temperature must be between [min_temperature]C and [max_temperature]C") + else + target_temperature = input_temperature + T0C + return TRUE + + // Account for remote users here. + // Yes, this is kinda snowflaky; however, I would argue it would be far more snowflakey + // to include "custom hrefs" and all the other bullshit that nano states have just for the + // like, two UIs, that want remote access to other UIs. + if((locked && !issilicon(usr) && !istype(state, /datum/ui_state/air_alarm_remote)) || (issilicon(usr) && aidisabled)) + return + + var/device_id = params["id_tag"] + switch(action) + if("lock") + if(issilicon(usr) && !wires.is_cut(WIRE_IDSCAN)) + locked = !locked + . = TRUE + if( "power", + "o2_scrub", + "n2_scrub", + "co2_scrub", + "tox_scrub", + "n2o_scrub", + "fuel_scrub", + "panic_siphon", + "scrubbing", + "direction") + send_signal(device_id, list("[action]" = text2num(params["val"])), usr) + . = TRUE + if("excheck") + send_signal(device_id, list("checks" = text2num(params["val"])^1), usr) + . = TRUE + if("incheck") + send_signal(device_id, list("checks" = text2num(params["val"])^2), usr) + . = TRUE + if("set_external_pressure", "set_internal_pressure") + var/target = params["value"] + if(!isnull(target)) + send_signal(device_id, list("[action]" = target), usr) + . = TRUE + if("reset_external_pressure") + send_signal(device_id, list("reset_external_pressure"), usr) + . = TRUE + if("reset_internal_pressure") + send_signal(device_id, list("reset_internal_pressure"), usr) + . = TRUE + if("threshold") + var/env = params["env"] + + var/name = params["var"] + var/value = input(usr, "New [name] for [env]:", name, TLV[env][name]) as num|null + if(!isnull(value) && !..()) + if(value < 0) + TLV[env][name] = -1 + else + TLV[env][name] = round(value, 0.01) + clamp_tlv_values(env, name) + // investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(usr)]",INVESTIGATE_ATMOS) + . = TRUE + if("mode") + mode = text2num(params["mode"]) + // investigate_log("was turned to [get_mode_name(mode)] mode by [key_name(usr)]",INVESTIGATE_ATMOS) + apply_mode(usr) + . = TRUE + if("alarm") + if(alarm_area.atmosalert(2, src)) + apply_danger_level(2) + . = TRUE + if("reset") + atmos_reset() + . = TRUE + update_icon() + +// This big ol' mess just ensures that TLV always makes sense. If you set the max value below the min value, +// it'll automatically update all the other values to keep it sane. +/obj/machinery/alarm/proc/clamp_tlv_values(env, changed_threshold) + var/list/selected = TLV[env] + switch(changed_threshold) + if(1) + if(selected[1] > selected[2]) + selected[2] = selected[1] + if(selected[1] > selected[3]) + selected[3] = selected[1] + if(selected[1] > selected[4]) + selected[4] = selected[1] + if(2) + if(selected[1] > selected[2]) + selected[1] = selected[2] + if(selected[2] > selected[3]) + selected[3] = selected[2] + if(selected[2] > selected[4]) + selected[4] = selected[2] + if(3) + if(selected[1] > selected[3]) + selected[1] = selected[3] + if(selected[2] > selected[3]) + selected[2] = selected[3] + if(selected[3] > selected[4]) + selected[4] = selected[3] + if(4) + if(selected[1] > selected[4]) + selected[1] = selected[4] + if(selected[2] > selected[4]) + selected[2] = selected[4] + if(selected[3] > selected[4]) + selected[3] = selected[4] + + + + +/obj/machinery/alarm/proc/atmos_reset() + if(alarm_area.atmosalert(0, src)) + apply_danger_level(0) + update_icon() + +/obj/machinery/alarm/attackby(obj/item/W as obj, mob/user as mob) + add_fingerprint(user) + if(alarm_deconstruction_screwdriver(user, W)) + return + if(alarm_deconstruction_wirecutters(user, W)) + return + + if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda))// trying to unlock the interface with an ID card + togglelock() + return ..() + +/obj/machinery/alarm/verb/togglelock(mob/user as mob) + if(stat & (NOPOWER|BROKEN)) + to_chat(user, "It does nothing.") + return + else + if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN)) + locked = !locked + to_chat(user, SPAN_NOTICE("You [locked ? "lock" : "unlock"] the Air Alarm interface.")) + else + to_chat(user, SPAN_BOLDWARNING("Access denied.")) + return + +/obj/machinery/alarm/AltClick() + ..() + togglelock() + +/obj/machinery/alarm/power_change() + ..() + spawn(rand(0,15)) + update_icon() +/obj/machinery/alarm/freezer + target_temperature = T0C - 13.15 // Chilly freezer room + +/obj/machinery/alarm/freezer/first_run() + . = ..() + + TLV["temperature"] = list(T0C - 40, T0C - 20, T0C + 40, T0C + 66) // K, Lower Temperature for Freezer Air Alarms (This is because TLV is hardcoded to be generated on first_run, and therefore the only way to modify this without changing TLV generation) + +#undef LOAD_TLV_VALUES +#undef TEST_TLV_VALUES +#undef DECLARE_TLV_VALUES diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm deleted file mode 100644 index 889c7f8f585..00000000000 --- a/code/game/machinery/alarm.dm +++ /dev/null @@ -1,1129 +0,0 @@ -//////////////////////////////////////// -//CONTAINS: Air Alarms and Fire Alarms// -//////////////////////////////////////// - -#define AALARM_MODE_SCRUBBING 1 -#define AALARM_MODE_REPLACEMENT 2 //like scrubbing, but faster. -#define AALARM_MODE_PANIC 3 //constantly sucks all air -#define AALARM_MODE_CYCLE 4 //sucks off all air, then refill and switches to scrubbing -#define AALARM_MODE_FILL 5 //emergency fill -#define AALARM_MODE_OFF 6 //Shuts it all down. - -#define AALARM_SCREEN_MAIN 1 -#define AALARM_SCREEN_VENT 2 -#define AALARM_SCREEN_SCRUB 3 -#define AALARM_SCREEN_MODE 4 -#define AALARM_SCREEN_SENSORS 5 - -#define AALARM_REPORT_TIMEOUT 100 - -#define RCON_NO 1 -#define RCON_AUTO 2 -#define RCON_YES 3 - -#define MAX_TEMPERATURE 90 -#define MIN_TEMPERATURE -40 - -//all air alarms in area are connected via magic -/area - var/obj/machinery/alarm/master_air_alarm - var/list/air_vent_names = list() - var/list/air_scrub_names = list() - var/list/air_vent_info = list() - var/list/air_scrub_info = list() - -/obj/machinery/alarm - name = "alarm" - icon = 'icons/obj/monitors.dmi' - icon_state = "alarm0" - plane = TURF_PLANE - layer = ABOVE_TURF_LAYER - anchored = 1 - use_power = USE_POWER_IDLE - idle_power_usage = 80 - active_power_usage = 1000 //For heating/cooling rooms. 1000 joules equates to about 1 degree every 2 seconds for a single tile of air. - power_channel = ENVIRON - req_one_access = list(access_atmospherics, access_engine_equip) - var/alarm_id = null - var/breach_detection = 1 // Whether to use automatic breach detection or not - var/frequency = 1439 - //var/skipprocess = 0 //Experimenting - var/alarm_frequency = 1437 - var/remote_control = 0 - var/rcon_setting = 2 - var/rcon_time = 0 - var/locked = 1 - panel_open = 0 // If it's been screwdrivered open. - var/aidisabled = 0 - var/shorted = 0 - circuit = /obj/item/circuitboard/airalarm - - var/datum/wires/alarm/wires - - var/mode = AALARM_MODE_SCRUBBING - var/screen = AALARM_SCREEN_MAIN - var/area_uid - var/area/alarm_area - - var/target_temperature = T0C+20 - var/regulating_temperature = 0 - - var/datum/radio_frequency/radio_connection - - var/list/TLV = list() - var/list/trace_gas = list(/datum/gas/nitrous_oxide, /datum/gas/volatile_fuel) //list of other gases that this air alarm is able to detect - - var/danger_level = 0 - var/pressure_dangerlevel = 0 - var/oxygen_dangerlevel = 0 - var/co2_dangerlevel = 0 - var/phoron_dangerlevel = 0 - var/temperature_dangerlevel = 0 - var/other_dangerlevel = 0 - - var/report_danger_level = 1 - - var/alarms_hidden = FALSE //If the alarms from this machine are visible on consoles - -/obj/machinery/alarm/nobreach - breach_detection = 0 - -/obj/machinery/alarm/monitor - report_danger_level = 0 - breach_detection = 0 - -/obj/machinery/alarm/alarms_hidden - alarms_hidden = TRUE - -/obj/machinery/alarm/server/Initialize(mapload) - . = ..() - req_access = list(access_rd, access_atmospherics, access_engine_equip) - TLV["oxygen"] = list(-1.0, -1.0,-1.0,-1.0) // Partial pressure, kpa - TLV["carbon dioxide"] = list(-1.0, -1.0, 5, 10) // Partial pressure, kpa - TLV["phoron"] = list(-1.0, -1.0, 0, 0.5) // Partial pressure, kpa - TLV["other"] = list(-1.0, -1.0, 0.5, 1.0) // Partial pressure, kpa - TLV["pressure"] = list(0,ONE_ATMOSPHERE*0.10,ONE_ATMOSPHERE*1.40,ONE_ATMOSPHERE*1.60) /* kpa */ - TLV["temperature"] = list(20, 40, 140, 160) // K - target_temperature = 90 - -/obj/machinery/alarm/Destroy() - unregister_radio(src, frequency) - qdel(wires) - wires = null - if(alarm_area && alarm_area.master_air_alarm == src) - alarm_area.master_air_alarm = null - elect_master(exclude_self = TRUE) - return ..() - -/obj/machinery/alarm/Initialize(mapload) - . = ..() - first_run() - -/obj/machinery/alarm/proc/first_run() - alarm_area = get_area(src) - area_uid = alarm_area.uid - if(name == "alarm") - name = "[alarm_area.name] Air Alarm" - - if(!wires) - wires = new(src) - - // breathable air according to human/Life() - TLV["oxygen"] = list(16, 19, 135, 140) // Partial pressure, kpa - TLV["carbon dioxide"] = list(-1.0, -1.0, 5, 10) // Partial pressure, kpa - TLV["phoron"] = list(-1.0, -1.0, 0, 0.5) // Partial pressure, kpa - TLV["other"] = list(-1.0, -1.0, 0.5, 1.0) // Partial pressure, kpa - TLV["pressure"] = list(ONE_ATMOSPHERE * 0.80, ONE_ATMOSPHERE * 0.90, ONE_ATMOSPHERE * 1.10, ONE_ATMOSPHERE * 1.20) /* kpa */ - TLV["temperature"] = list(T0C - 26, T0C, T0C + 40, T0C + 66) // K - - -/obj/machinery/alarm/Initialize(mapload) - . = ..() - set_frequency(frequency) - if(!master_is_operating()) - elect_master() - -/obj/machinery/alarm/process(delta_time) - if((stat & (NOPOWER|BROKEN)) || shorted) - return - - var/turf/simulated/location = src.loc - if(!istype(location)) return//returns if loc is not simulated - - var/datum/gas_mixture/environment = location.return_air() - - //Handle temperature adjustment here. - handle_heating_cooling(environment) - - var/old_level = danger_level - var/old_pressurelevel = pressure_dangerlevel - danger_level = overall_danger_level(environment) - - if(old_level != danger_level) - apply_danger_level(danger_level) - - if(old_pressurelevel != pressure_dangerlevel) - if(breach_detected()) - mode = AALARM_MODE_OFF - apply_mode() - - if(mode == AALARM_MODE_CYCLE && environment.return_pressure() < ONE_ATMOSPHERE * 0.05) - mode = AALARM_MODE_FILL - apply_mode() - - //atmos computer remote controll stuff - switch(rcon_setting) - if(RCON_NO) - remote_control = 0 - if(RCON_AUTO) - if(danger_level == 2) - remote_control = 1 - else - remote_control = 0 - if(RCON_YES) - remote_control = 1 - - return - -/obj/machinery/alarm/proc/handle_heating_cooling(var/datum/gas_mixture/environment) - if(!regulating_temperature) - //check for when we should start adjusting temperature - if(!get_danger_level(target_temperature, TLV["temperature"]) && abs(environment.temperature - target_temperature) > 2.0) - update_use_power(USE_POWER_ACTIVE) - regulating_temperature = 1 - audible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\ - "You hear a click and a faint electronic hum.") - playsound(src.loc, 'sound/machines/click.ogg', 50, 1) - else - //check for when we should stop adjusting temperature - if(get_danger_level(target_temperature, TLV["temperature"]) || abs(environment.temperature - target_temperature) <= 0.5) - update_use_power(USE_POWER_IDLE) - regulating_temperature = 0 - audible_message("\The [src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\ - "You hear a click as a faint electronic humming stops.") - playsound(src.loc, 'sound/machines/click.ogg', 50, 1) - - if(regulating_temperature) - if(target_temperature > T0C + MAX_TEMPERATURE) - target_temperature = T0C + MAX_TEMPERATURE - - if(target_temperature < T0C + MIN_TEMPERATURE) - target_temperature = T0C + MIN_TEMPERATURE - - var/datum/gas_mixture/gas - gas = environment.remove(0.25 * environment.total_moles) - if(gas) - - if(gas.temperature <= target_temperature) //gas heating - var/energy_used = min(gas.get_thermal_energy_change(target_temperature) , active_power_usage) - - gas.add_thermal_energy(energy_used) - //use_power(energy_used, ENVIRON) //handle by update_use_power instead - else //gas cooling - var/heat_transfer = min(abs(gas.get_thermal_energy_change(target_temperature)), active_power_usage) - - //Assume the heat is being pumped into the hull which is fixed at 20 C - //none of this is really proper thermodynamics but whatever - - var/cop = gas.temperature / T20C //coefficient of performance -> power used = heat_transfer/cop - - heat_transfer = min(heat_transfer, cop * active_power_usage) //this ensures that we don't use more than active_power_usage amount of power - - heat_transfer = -gas.add_thermal_energy(-heat_transfer) //get the actual heat transfer - - //use_power(heat_transfer / cop, ENVIRON) //handle by update_use_power instead - - environment.merge(gas) - -/obj/machinery/alarm/proc/overall_danger_level(var/datum/gas_mixture/environment) - var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature/environment.volume - var/environment_pressure = environment.return_pressure() - - var/other_moles = 0 - for(var/g in trace_gas) - other_moles += environment.gas[g] //this is only going to be used in a partial pressure calc, so we don't need to worry about group_multiplier here. - - pressure_dangerlevel = get_danger_level(environment_pressure, TLV["pressure"]) - oxygen_dangerlevel = get_danger_level(environment.gas[/datum/gas/oxygen]*partial_pressure, TLV["oxygen"]) - co2_dangerlevel = get_danger_level(environment.gas[/datum/gas/carbon_dioxide]*partial_pressure, TLV["carbon dioxide"]) - phoron_dangerlevel = get_danger_level(environment.gas[/datum/gas/phoron]*partial_pressure, TLV["phoron"]) - temperature_dangerlevel = get_danger_level(environment.temperature, TLV["temperature"]) - other_dangerlevel = get_danger_level(other_moles*partial_pressure, TLV["other"]) - - return max( - pressure_dangerlevel, - oxygen_dangerlevel, - co2_dangerlevel, - phoron_dangerlevel, - other_dangerlevel, - temperature_dangerlevel - ) - -// Returns whether this air alarm thinks there is a breach, given the sensors that are available to it. -/obj/machinery/alarm/proc/breach_detected() - var/turf/simulated/location = src.loc - - if(!istype(location)) - return 0 - - if(breach_detection == 0) - return 0 - - var/datum/gas_mixture/environment = location.return_air() - var/environment_pressure = environment.return_pressure() - var/pressure_levels = TLV["pressure"] - - if(environment_pressure <= pressure_levels[1]) //low pressures - if(!(mode == AALARM_MODE_PANIC || mode == AALARM_MODE_CYCLE)) - playsound(src.loc, 'sound/machines/airalarm.ogg', 25, 0, 4) - return 1 - - return 0 - -/obj/machinery/alarm/proc/master_is_operating() - return alarm_area && alarm_area.master_air_alarm && !(alarm_area.master_air_alarm.stat & (NOPOWER | BROKEN)) - -/obj/machinery/alarm/proc/elect_master(exclude_self = FALSE) - for(var/obj/machinery/alarm/AA in alarm_area) - if(exclude_self && AA == src) - continue - if(!(AA.stat & (NOPOWER|BROKEN))) - alarm_area.master_air_alarm = AA - return 1 - return 0 - -/obj/machinery/alarm/proc/get_danger_level(var/current_value, var/list/danger_levels) - if((current_value >= danger_levels[4] && danger_levels[4] > 0) || current_value <= danger_levels[1]) - return 2 - if((current_value >= danger_levels[3] && danger_levels[3] > 0) || current_value <= danger_levels[2]) - return 1 - return 0 - -/obj/machinery/alarm/update_icon() - if(panel_open) - icon_state = "alarmx" - set_light(0) - return - if((stat & (NOPOWER|BROKEN)) || shorted) - icon_state = "alarmp" - set_light(0) - return - - var/icon_level = danger_level - if(alarm_area.atmosalm) - icon_level = max(icon_level, 1) //if there's an atmos alarm but everything is okay locally, no need to go past yellow - - var/new_color = null - switch(icon_level) - if(0) - icon_state = "alarm0" - new_color = "#03A728" - if(1) - icon_state = "alarm2" //yes, alarm2 is yellow alarm - new_color = "#EC8B2F" - if(2) - icon_state = "alarm1" - new_color = "#DA0205" - - set_light(l_range = 2, l_power = 0.25, l_color = new_color) - -/obj/machinery/alarm/receive_signal(datum/signal/signal) - if(stat & (NOPOWER|BROKEN)) - return - if(alarm_area.master_air_alarm != src) - if(master_is_operating()) - return - elect_master() - if(alarm_area.master_air_alarm != src) - return - if(!signal || signal.encryption) - return - var/id_tag = signal.data["tag"] - if(!id_tag) - return - if(signal.data["area"] != area_uid) - return - if(signal.data["sigtype"] != "status") - return - - var/dev_type = signal.data["device"] - if(!(id_tag in alarm_area.air_scrub_names) && !(id_tag in alarm_area.air_vent_names)) - register_env_machine(id_tag, dev_type) - if(dev_type == "AScr") - alarm_area.air_scrub_info[id_tag] = signal.data - else if(dev_type == "AVP") - alarm_area.air_vent_info[id_tag] = signal.data - -/obj/machinery/alarm/proc/register_env_machine(var/m_id, var/device_type) - var/new_name - if(device_type == "AVP") - new_name = "[alarm_area.name] Vent Pump #[alarm_area.air_vent_names.len+1]" - alarm_area.air_vent_names[m_id] = new_name - else if(device_type == "AScr") - new_name = "[alarm_area.name] Air Scrubber #[alarm_area.air_scrub_names.len+1]" - alarm_area.air_scrub_names[m_id] = new_name - else - return - spawn(10) - send_signal(m_id, list("init" = new_name)) - -/obj/machinery/alarm/proc/refresh_all() - for(var/id_tag in alarm_area.air_vent_names) - var/list/I = alarm_area.air_vent_info[id_tag] - if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time) - continue - send_signal(id_tag, list("status")) - for(var/id_tag in alarm_area.air_scrub_names) - var/list/I = alarm_area.air_scrub_info[id_tag] - if(I && I["timestamp"] + AALARM_REPORT_TIMEOUT / 2 > world.time) - continue - send_signal(id_tag, list("status")) - -/obj/machinery/alarm/proc/set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, RADIO_TO_AIRALARM) - -/obj/machinery/alarm/proc/send_signal(var/target, var/list/command)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise - if(!radio_connection) - return 0 - - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - - signal.data = command - signal.data["tag"] = target - signal.data["sigtype"] = "command" - - radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM) -// world << text("Signal [] Broadcasted to []", command, target) - - return 1 - -/obj/machinery/alarm/proc/apply_mode() - //propagate mode to other air alarms in the area - //TODO: make it so that players can choose between applying the new mode to the room they are in (related area) vs the entire alarm area - for(var/obj/machinery/alarm/AA in alarm_area) - AA.mode = mode - - switch(mode) - if(AALARM_MODE_SCRUBBING) - for(var/device_id in alarm_area.air_scrub_names) - send_signal(device_id, list("power"= 1, "co2_scrub"= 1, "scrubbing"= 1, "panic_siphon"= 0)) - for(var/device_id in alarm_area.air_vent_names) - send_signal(device_id, list("power"= 1, "checks"= "default", "set_external_pressure"= "default")) - - if(AALARM_MODE_PANIC, AALARM_MODE_CYCLE) - for(var/device_id in alarm_area.air_scrub_names) - send_signal(device_id, list("power"= 1, "panic_siphon"= 1)) - for(var/device_id in alarm_area.air_vent_names) - send_signal(device_id, list("power"= 0)) - - if(AALARM_MODE_REPLACEMENT) - for(var/device_id in alarm_area.air_scrub_names) - send_signal(device_id, list("power"= 1, "panic_siphon"= 1)) - for(var/device_id in alarm_area.air_vent_names) - send_signal(device_id, list("power"= 1, "checks"= "default", "set_external_pressure"= "default")) - - if(AALARM_MODE_FILL) - for(var/device_id in alarm_area.air_scrub_names) - send_signal(device_id, list("power"= 0)) - for(var/device_id in alarm_area.air_vent_names) - send_signal(device_id, list("power"= 1, "checks"= "default", "set_external_pressure"= "default")) - - if(AALARM_MODE_OFF) - for(var/device_id in alarm_area.air_scrub_names) - send_signal(device_id, list("power"= 0)) - for(var/device_id in alarm_area.air_vent_names) - send_signal(device_id, list("power"= 0)) - -/obj/machinery/alarm/proc/apply_danger_level(var/new_danger_level) - if(report_danger_level && alarm_area.atmosalert(new_danger_level, src)) - post_alert(new_danger_level) - - update_icon() - -/obj/machinery/alarm/proc/post_alert(alert_level) - var/datum/radio_frequency/frequency = radio_controller.return_frequency(alarm_frequency) - if(!frequency) - return - - var/datum/signal/alert_signal = new - alert_signal.source = src - alert_signal.transmission_method = 1 - alert_signal.data["zone"] = alarm_area.name - alert_signal.data["type"] = "Atmospheric" - - if(alert_level==2) - alert_signal.data["alert"] = "severe" - else if(alert_level==1) - alert_signal.data["alert"] = "minor" - else if(alert_level==0) - alert_signal.data["alert"] = "clear" - - frequency.post_signal(src, alert_signal) - -/obj/machinery/alarm/attack_ai(mob/user) - nano_ui_interact(user) - -/obj/machinery/alarm/attack_hand(mob/user) - . = ..() - if(.) - return - return interact(user) - -/obj/machinery/alarm/interact(mob/user) - nano_ui_interact(user) - wires.Interact(user) - -/obj/machinery/alarm/nano_ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = default_state) - var/data[0] - var/remote_connection = 0 - var/remote_access = 0 - if(state) - var/list/href = state.href_list(user) - remote_connection = href["remote_connection"] // Remote connection means we're non-adjacent/connecting from another computer - remote_access = href["remote_access"] // Remote access means we also have the privilege to alter the air alarm. - - data["locked"] = locked && !issilicon(user) - data["remote_connection"] = remote_connection - data["remote_access"] = remote_access - data["rcon"] = rcon_setting - data["screen"] = screen - - populate_status(data) - - if(!(locked && !remote_connection) || remote_access || issilicon(user)) - populate_controls(data) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "air_alarm.tmpl", name, 325, 625, master_ui = master_ui, state = state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/alarm/proc/populate_status(var/data) - var/turf/location = get_turf(src) - var/datum/gas_mixture/environment = location.return_air() - var/total = environment.total_moles - - var/list/environment_data = new - data["has_environment"] = total - if(total) - var/pressure = environment.return_pressure() - environment_data[++environment_data.len] = list("name" = "Pressure", "value" = pressure, "unit" = "kPa", "danger_level" = pressure_dangerlevel) - environment_data[++environment_data.len] = list("name" = "Oxygen", "value" = environment.gas[/datum/gas/oxygen] / total * 100, "unit" = "%", "danger_level" = oxygen_dangerlevel) - environment_data[++environment_data.len] = list("name" = "Carbon dioxide", "value" = environment.gas[/datum/gas/carbon_dioxide] / total * 100, "unit" = "%", "danger_level" = co2_dangerlevel) - environment_data[++environment_data.len] = list("name" = "Toxins", "value" = environment.gas[/datum/gas/phoron] / total * 100, "unit" = "%", "danger_level" = phoron_dangerlevel) - environment_data[++environment_data.len] = list("name" = "Temperature", "value" = environment.temperature, "unit" = "K ([round(environment.temperature - T0C, 0.1)]C)", "danger_level" = temperature_dangerlevel) - data["total_danger"] = danger_level - data["environment"] = environment_data - data["atmos_alarm"] = alarm_area.atmosalm - data["fire_alarm"] = alarm_area.fire != null - data["target_temperature"] = "[target_temperature - T0C]C" - -/obj/machinery/alarm/proc/populate_controls(var/list/data) - switch(screen) - if(AALARM_SCREEN_MAIN) - data["mode"] = mode - if(AALARM_SCREEN_VENT) - var/vents[0] - for(var/id_tag in alarm_area.air_vent_names) - var/long_name = alarm_area.air_vent_names[id_tag] - var/list/info = alarm_area.air_vent_info[id_tag] - if(!info) - continue - vents[++vents.len] = list( - "id_tag" = id_tag, - "long_name" = sanitize(long_name), - "power" = info["power"], - "checks" = info["checks"], - "direction" = info["direction"], - "external" = info["external"] - ) - data["vents"] = vents - if(AALARM_SCREEN_SCRUB) - var/scrubbers[0] - for(var/id_tag in alarm_area.air_scrub_names) - var/long_name = alarm_area.air_scrub_names[id_tag] - var/list/info = alarm_area.air_scrub_info[id_tag] - if(!info) - continue - scrubbers[++scrubbers.len] = list( - "id_tag" = id_tag, - "long_name" = sanitize(long_name), - "power" = info["power"], - "scrubbing" = info["scrubbing"], - "panic" = info["panic"], - "filters" = list() - ) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Oxygen", "command" = "o2_scrub", "val" = info["filter_o2"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Nitrogen", "command" = "n2_scrub", "val" = info["filter_n2"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Carbon Dioxide", "command" = "co2_scrub","val" = info["filter_co2"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Toxin" , "command" = "tox_scrub","val" = info["filter_phoron"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Nitrous Oxide", "command" = "n2o_scrub","val" = info["filter_n2o"])) - scrubbers[scrubbers.len]["filters"] += list(list("name" = "Fuel", "command" = "fuel_scrub","val" = info["filter_fuel"])) - data["scrubbers"] = scrubbers - if(AALARM_SCREEN_MODE) - var/modes[0] - modes[++modes.len] = list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0) - modes[++modes.len] = list("name" = "Replace Air - Siphons out air while replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 0) - modes[++modes.len] = list("name" = "Panic - Siphons air out of the room", "mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1) - modes[++modes.len] = list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_CYCLE, "selected" = mode == AALARM_MODE_CYCLE, "danger" = 1) - modes[++modes.len] = list("name" = "Fill - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FILL, "selected" = mode == AALARM_MODE_FILL, "danger" = 0) - modes[++modes.len] = list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0) - data["modes"] = modes - data["mode"] = mode - if(AALARM_SCREEN_SENSORS) - var/list/selected - var/thresholds[0] - - var/list/gas_names = list( - "oxygen" = "O2", - "carbon dioxide" = "CO2", - "phoron" = "Toxin", - "other" = "Other") - for(var/g in gas_names) - thresholds[++thresholds.len] = list("name" = gas_names[g], "settings" = list()) - selected = TLV[g] - for(var/i = 1, i <= 4, i++) - thresholds[thresholds.len]["settings"] += list(list("env" = g, "val" = i, "selected" = selected[i])) - - selected = TLV["pressure"] - thresholds[++thresholds.len] = list("name" = "Pressure", "settings" = list()) - for(var/i = 1, i <= 4, i++) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = i, "selected" = selected[i])) - - selected = TLV["temperature"] - thresholds[++thresholds.len] = list("name" = "Temperature", "settings" = list()) - for(var/i = 1, i <= 4, i++) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = i, "selected" = selected[i])) - - data["thresholds"] = thresholds - -/obj/machinery/alarm/CanUseTopic(var/mob/user, var/datum/topic_state/state, var/href_list = list()) - if(aidisabled && isAI(user)) - to_chat(user, SPAN_WARNING("AI control for \the [src] interface has been disabled.")) - return UI_CLOSE - - . = shorted ? UI_DISABLED : UI_INTERACTIVE - - if(. == UI_INTERACTIVE) - var/extra_href = state.href_list(usr) - // Prevent remote users from altering RCON settings unless they already have access - if(href_list["rcon"] && extra_href["remote_connection"] && !extra_href["remote_access"]) - . = UI_UPDATE - - return min(..(), .) - -/obj/machinery/alarm/Topic(href, href_list, var/datum/topic_state/state) - if(..(href, href_list, state)) - return 1 - - // 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 - if(RCON_AUTO) - rcon_setting = RCON_AUTO - if(RCON_YES) - rcon_setting = RCON_YES - return 1 - - if(href_list["temperature"]) - var/list/selected = TLV["temperature"] - var/max_temperature = min(selected[3] - T0C, MAX_TEMPERATURE) - var/min_temperature = max(selected[2] - T0C, MIN_TEMPERATURE) - var/input_temperature = input("What temperature would you like the system to mantain? (Capped between [min_temperature] and [max_temperature]C)", "Thermostat Controls", target_temperature - T0C) as num|null - if(isnum(input_temperature)) - if(input_temperature > max_temperature || input_temperature < min_temperature) - to_chat(usr, "Temperature must be between [min_temperature]C and [max_temperature]C") - else - target_temperature = input_temperature + T0C - return 1 - - // hrefs that need the AA unlocked -walter0o - var/extra_href = state.href_list(usr) - if(!(locked && !extra_href["remote_connection"]) || extra_href["remote_access"] || issilicon(usr)) - if(href_list["command"]) - var/device_id = href_list["id_tag"] - switch(href_list["command"]) - if("set_external_pressure") - var/input_pressure = input("What pressure you like the system to mantain?", "Pressure Controls") as num|null - if(isnum(input_pressure)) - send_signal(device_id, list(href_list["command"] = input_pressure)) - return 1 - - if("reset_external_pressure") - send_signal(device_id, list(href_list["command"] = ONE_ATMOSPHERE)) - return 1 - - if( "power", - "adjust_external_pressure", - "checks", - "o2_scrub", - "n2_scrub", - "co2_scrub", - "tox_scrub", - "n2o_scrub", - "fuel_scrub", - "panic_siphon", - "scrubbing", - "direction") - - send_signal(device_id, list(href_list["command"] = text2num(href_list["val"]))) - return 1 - - if("set_threshold") - var/env = href_list["env"] - var/threshold = text2num(href_list["var"]) - var/list/selected = TLV[env] - var/list/thresholds = list("lower bound", "low warning", "high warning", "upper bound") - var/newval = input("Enter [thresholds[threshold]] for [env]", "Alarm triggers", selected[threshold]) as null | num - if(isnull(newval)) - return 1 - if(newval<0) - selected[threshold] = -1.0 - else if(env=="temperature" && newval>5000) - selected[threshold] = 5000 - else if(env=="pressure" && newval>50*ONE_ATMOSPHERE) - selected[threshold] = 50*ONE_ATMOSPHERE - else if(env!="temperature" && env!="pressure" && newval>200) - selected[threshold] = 200 - else - newval = round(newval,0.01) - selected[threshold] = newval - if(threshold == 1) - if(selected[1] > selected[2]) - selected[2] = selected[1] - if(selected[1] > selected[3]) - selected[3] = selected[1] - if(selected[1] > selected[4]) - selected[4] = selected[1] - if(threshold == 2) - if(selected[1] > selected[2]) - selected[1] = selected[2] - if(selected[2] > selected[3]) - selected[3] = selected[2] - if(selected[2] > selected[4]) - selected[4] = selected[2] - if(threshold == 3) - if(selected[1] > selected[3]) - selected[1] = selected[3] - if(selected[2] > selected[3]) - selected[2] = selected[3] - if(selected[3] > selected[4]) - selected[4] = selected[3] - if(threshold == 4) - if(selected[1] > selected[4]) - selected[1] = selected[4] - if(selected[2] > selected[4]) - selected[2] = selected[4] - if(selected[3] > selected[4]) - selected[3] = selected[4] - - apply_mode() - return 1 - - if(href_list["screen"]) - screen = text2num(href_list["screen"]) - return 1 - - if(href_list["atmos_unlock"]) - switch(href_list["atmos_unlock"]) - if("0") - alarm_area.firedoors_close() - if("1") - alarm_area.firedoors_open() - return 1 - - if(href_list["atmos_alarm"]) - if(alarm_area.atmosalert(2, src)) - apply_danger_level(2) - update_icon() - return 1 - - if(href_list["atmos_reset"]) - if(alarm_area.atmosalert(0, src)) - apply_danger_level(0) - update_icon() - return 1 - - if(href_list["mode"]) - mode = text2num(href_list["mode"]) - apply_mode() - return 1 - -/obj/machinery/alarm/attackby(obj/item/W as obj, mob/user as mob) - if(alarm_deconstruction_screwdriver(user, W)) - return - if(alarm_deconstruction_wirecutters(user, W)) - return - - if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda))// trying to unlock the interface with an ID card - if(stat & (NOPOWER|BROKEN)) - to_chat(user, "It does nothing") - return - else - if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN)) - locked = !locked - to_chat(user, SPAN_NOTICE("You [ locked ? "lock" : "unlock"] the Air Alarm interface.")) - else - to_chat(user, SPAN_WARNING("Access denied.")) - return - return ..() - -//Altclick airalarms to toggle the controlls -/obj/machinery/alarm/AltClick(mob/user) - if(user.Adjacent(src)) - if(allowed(usr) && !wires.is_cut(WIRE_IDSCAN)) - locked = !locked - to_chat(user, SPAN_NOTICE("You [ locked ? "lock" : "unlock"] the Air Alarm interface.")) - else - to_chat(user, SPAN_WARNING("Access denied.")) - -/obj/machinery/alarm/power_change() - ..() - spawn(rand(0,15)) - update_icon() - -/* -AIR ALARM CIRCUIT -Just a object used in constructing air alarms - -/obj/item/airalarm_electronics - name = "air alarm electronics" - icon = 'icons/obj/doors/door_assembly.dmi' - icon_state = "door_electronics" - desc = "Looks like a circuit. Probably is." - w_class = ITEMSIZE_SMALL - matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) -*/ -/* -FIRE ALARM -*/ -/obj/machinery/firealarm - name = "fire alarm" - desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever." - icon = 'icons/obj/monitors.dmi' - icon_state = "fire0" - plane = TURF_PLANE - layer = ABOVE_TURF_LAYER - var/detecting = 1.0 - var/working = 1.0 - var/time = 10.0 - var/timing = 0.0 - var/lockdownbyai = 0 - anchored = 1.0 - use_power = USE_POWER_IDLE - idle_power_usage = 2 - active_power_usage = 6 - power_channel = ENVIRON - var/last_process = 0 - panel_open = 0 - var/seclevel - circuit = /obj/item/circuitboard/firealarm - var/alarms_hidden = FALSE //If the alarms from this machine are visible on consoles - -/obj/machinery/firealarm/alarms_hidden - alarms_hidden = TRUE - -/obj/machinery/firealarm/update_icon() - cut_overlays() - - if(panel_open) - set_light(0) - return - - if(stat & BROKEN) - icon_state = "firex" - set_light(0) - else if(stat & NOPOWER) - icon_state = "firep" - set_light(0) - else - if(!detecting) - icon_state = "fire1" - set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000") - else - icon_state = "fire0" - switch(seclevel) - if("green") set_light(l_range = 2, l_power = 0.25, l_color = "#00ff00") - if("yellow") set_light(l_range = 2, l_power = 0.25, l_color = "#ffff00") - if("violet") set_light(l_range = 2, l_power = 0.25, l_color = "#9933ff") - if("orange") set_light(l_range = 2, l_power = 0.25, l_color = "#ff9900") - if("blue") set_light(l_range = 2, l_power = 0.25, l_color = "#1024A9") - if("red") set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000") - if("delta") set_light(l_range = 4, l_power = 0.9, l_color = "#FF6633") - add_overlay("overlay_[seclevel]") - -/obj/machinery/firealarm/fire_act(datum/gas_mixture/air, temperature, volume) - if(detecting) - if(temperature > T0C + 200) - alarm() // added check of detector status here - return - -/obj/machinery/firealarm/attack_ai(mob/user as mob) - return attack_hand(user) - -/obj/machinery/firealarm/bullet_act() - return alarm() - -/obj/machinery/firealarm/emp_act(severity) - if(prob(50 / severity)) - alarm(rand(30 / severity, 60 / severity)) - ..() - -/obj/machinery/firealarm/attackby(obj/item/W as obj, mob/user as mob) - - if(alarm_deconstruction_screwdriver(user, W)) - return - if(alarm_deconstruction_wirecutters(user, W)) - return - - if(panel_open) - if(istype(W, /obj/item/multitool)) - detecting = !(detecting) - if(detecting) - user.visible_message(SPAN_NOTICE("\The [user] has reconnected [src]'s detecting unit!"), SPAN_NOTICE("You have reconnected [src]'s detecting unit.")) - else - user.visible_message(SPAN_NOTICE("\The [user] has disconnected [src]'s detecting unit!"), SPAN_NOTICE("You have disconnected [src]'s detecting unit.")) - return - - alarm() - return - -/obj/machinery/firealarm/process(delta_time)//Note: this processing was mostly phased out due to other code, and only runs when needed - if(stat & (NOPOWER|BROKEN)) - return - - if(timing) - if(time > 0) - time = time - ((world.timeofday - last_process) / 10) - else - alarm() - time = 0 - timing = 0 - STOP_PROCESSING(SSobj, src) - updateDialog() - last_process = world.timeofday - - if(locate(/obj/fire) in src.loc) - alarm() - - return - -/obj/machinery/firealarm/power_change() - ..() - spawn(rand(0,15)) - update_icon() - -/obj/machinery/firealarm/attack_hand(mob/user as mob) - if(user.stat || stat & (NOPOWER | BROKEN)) - return - - user.set_machine(src) - var/area/A = src.loc - var/d1 - var/d2 - if(istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon)) - A = A.loc - - if(A.fire) - d1 = text("Reset - Lockdown", src) - else - d1 = text("Alarm - Lockdown", src) - if(timing) - d2 = text("Stop Time Lock", src) - else - d2 = text("Initiate Time Lock", src) - var/second = round(time) % 60 - var/minute = (round(time) - second) / 60 - var/dat = "Fire alarm [d1]\n
The current alert level is: [get_security_level()]

\nTimer System: [d2]
\nTime Left: [(minute ? "[minute]:" : null)][second] - - + +\n
" - user << browse(dat, "window=firealarm") - onclose(user, "firealarm") - else - A = A.loc - if(A.fire) - d1 = text("[]", src, stars("Reset - Lockdown")) - else - d1 = text("[]", src, stars("Alarm - Lockdown")) - if(timing) - d2 = text("[]", src, stars("Stop Time Lock")) - else - d2 = text("[]", src, stars("Initiate Time Lock")) - var/second = round(time) % 60 - var/minute = (round(time) - second) / 60 - var/dat = "[stars("Fire alarm")] [d1]\n
The current alert level is: [stars(get_security_level())]

\nTimer System: [d2]
\nTime Left: [(minute ? text("[]:", minute) : null)][second] - - + +\n
" - user << browse(dat, "window=firealarm") - onclose(user, "firealarm") - return - -/obj/machinery/firealarm/Topic(href, href_list) - ..() - if(usr.stat || stat & (BROKEN | NOPOWER)) - return - - if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - if(href_list["reset"]) - reset() - else if(href_list["alarm"]) - alarm() - else if(href_list["time"]) - timing = text2num(href_list["time"]) - last_process = world.timeofday - START_PROCESSING(SSobj, src) - else if(href_list["tp"]) - var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 0), 120) - - updateUsrDialog() - - add_fingerprint(usr) - else - usr << browse(null, "window=firealarm") - return - return - -/obj/machinery/firealarm/proc/reset() - if(!(working)) - return - var/area/area = get_area(src) - for(var/obj/machinery/firealarm/FA in area) - SSalarms.fire_alarm.clearAlarm(src.loc, FA) - update_icon() - return - -/obj/machinery/firealarm/proc/alarm(var/duration = 0) - if(!(working)) - return - var/area/area = get_area(src) - for(var/obj/machinery/firealarm/FA in area) - SSalarms.fire_alarm.triggerAlarm(loc, FA, duration, hidden = alarms_hidden) - update_icon() - playsound(src.loc, 'sound/machines/airalarm.ogg', 25, 0, 4) - return - -/obj/machinery/firealarm/proc/set_security_level(var/newlevel) - if(seclevel != newlevel) - seclevel = newlevel - update_icon() - -/obj/machinery/firealarm/Initialize(mapload) - . = ..() - if(z in GLOB.using_map.contact_levels) - set_security_level(security_level? get_security_level() : "green") - -/* -FIRE ALARM CIRCUIT -Just a object used in constructing fire alarms - -/obj/item/firealarm_electronics - name = "fire alarm electronics" - icon = 'icons/obj/doors/door_assembly.dmi' - 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 = ITEMSIZE_SMALL - matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) -*/ -/obj/machinery/partyalarm - name = "\improper PARTY BUTTON" - desc = "Cuban Pete is in the house!" - icon = 'icons/obj/monitors.dmi' - icon_state = "fire0" - var/detecting = 1.0 - var/working = 1.0 - var/time = 10.0 - var/timing = 0.0 - var/lockdownbyai = 0 - anchored = 1.0 - use_power = USE_POWER_IDLE - idle_power_usage = 2 - active_power_usage = 6 - -/obj/machinery/partyalarm/attack_hand(mob/user as mob) - if(user.stat || stat & (NOPOWER|BROKEN)) - return - - user.machine = src - var/area/A = get_area(src) - ASSERT(isarea(A)) - var/d1 - var/d2 - if(istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon/ai)) - - if(A.party) - d1 = text("No Party :(", src) - else - d1 = text("PARTY!!!", src) - if(timing) - d2 = text("Stop Time Lock", src) - else - d2 = text("Initiate Time Lock", src) - var/second = time % 60 - var/minute = (time - second) / 60 - var/dat = text("Party Button []\n
\nTimer System: []
\nTime Left: [][] - - + +\n
", d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) - user << browse(dat, "window=partyalarm") - onclose(user, "partyalarm") - else - if(A.fire) - d1 = text("[]", src, stars("No Party :(")) - else - d1 = text("[]", src, stars("PARTY!!!")) - if(timing) - d2 = text("[]", src, stars("Stop Time Lock")) - else - d2 = text("[]", src, stars("Initiate Time Lock")) - var/second = time % 60 - var/minute = (time - second) / 60 - var/dat = text("[] []\n
\nTimer System: []
\nTime Left: [][] - - + +\n
", stars("Party Button"), d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) - user << browse(dat, "window=partyalarm") - onclose(user, "partyalarm") - return - -/obj/machinery/partyalarm/proc/reset() - if(!(working)) - return - var/area/A = get_area(src) - ASSERT(isarea(A)) - A.partyreset() - return - -/obj/machinery/partyalarm/proc/alarm() - if(!(working)) - return - var/area/A = get_area(src) - ASSERT(isarea(A)) - A.partyalert() - return - -/obj/machinery/partyalarm/Topic(href, href_list) - ..() - if(usr.stat || stat & (BROKEN|NOPOWER)) - return - if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) - usr.machine = src - if(href_list["reset"]) - reset() - else if(href_list["alarm"]) - alarm() - else if(href_list["time"]) - timing = text2num(href_list["time"]) - else if(href_list["tp"]) - var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 0), 120) - updateUsrDialog() - - add_fingerprint(usr) - else - usr << browse(null, "window=partyalarm") - return - return diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm index 79a3ef33535..14558fe5048 100644 --- a/code/game/machinery/atmo_control.dm +++ b/code/game/machinery/atmo_control.dm @@ -92,7 +92,7 @@ obj/machinery/computer/general_air_control/Destroy() if(..(user)) return - nano_ui_interact(user) + ui_interact(user) /obj/machinery/computer/general_air_control/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -102,9 +102,13 @@ obj/machinery/computer/general_air_control/Destroy() sensor_information[id_tag] = signal.data -/obj/machinery/computer/general_air_control/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/general_air_control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GeneralAtmoControl", name) + ui.open() +/obj/machinery/computer/general_air_control/ui_data(mob/user) var/list/data = list() var/sensors_ui[0] if(sensors.len) @@ -117,12 +121,7 @@ obj/machinery/computer/general_air_control/Destroy() data["sensors"] = sensors_ui - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmo_control.tmpl", name, 525, 600) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data /obj/machinery/computer/general_air_control/proc/set_frequency(new_frequency) radio_controller.remove_object(src, frequency) @@ -145,20 +144,9 @@ obj/machinery/computer/general_air_control/Destroy() var/pressure_setting = ONE_ATMOSPHERE * 45 circuit = /obj/item/circuitboard/air_management/tank_control -/obj/machinery/computer/general_air_control/large_tank_control/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/computer/general_air_control/large_tank_control/ui_data(mob/user) + var/list/data = ..() - var/list/data = list() - var/sensors_ui[0] - if(sensors.len) - for(var/id_tag in sensors) - var/long_name = sensors[id_tag] - var/list/sensor_data = sensor_information[id_tag] - sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) - else - sensors_ui = null - - data["sensors"] = sensors_ui data["tanks"] = 1 if(input_info) @@ -173,13 +161,10 @@ obj/machinery/computer/general_air_control/Destroy() data["input_flow_setting"] = round(input_flow_setting, 0.1) data["pressure_setting"] = pressure_setting + data["max_pressure"] = 50*ONE_ATMOSPHERE + data["max_flowrate"] = ATMOS_DEFAULT_VOLUME_PUMP + 500 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmo_control.tmpl", name, 660, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data /obj/machinery/computer/general_air_control/large_tank_control/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -193,54 +178,56 @@ obj/machinery/computer/general_air_control/Destroy() else ..(signal) -/obj/machinery/computer/general_air_control/large_tank_control/Topic(href, href_list) +/obj/machinery/computer/general_air_control/large_tank_control/ui_act(action, params) if(..()) - return 1 + return TRUE - if(href_list["adj_pressure"]) - var/change = text2num(href_list["adj_pressure"]) - pressure_setting = between(0, pressure_setting + change, 50*ONE_ATMOSPHERE) - return 1 + switch(action) + if("adj_pressure") + var/new_pressure = text2num(params["adj_pressure"]) + pressure_setting = between(0, new_pressure, 50*ONE_ATMOSPHERE) + return TRUE - if(href_list["adj_input_flow_rate"]) - var/change = text2num(href_list["adj_input_flow_rate"]) - input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors - return 1 + if("adj_input_flow_rate") + var/new_flow = text2num(params["adj_input_flow_rate"]) + input_flow_setting = between(0, new_flow, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors + return TRUE if(!radio_connection) - return 0 + return FALSE var/datum/signal/signal = new signal.transmission_method = 1 //radio signal signal.source = src - if(href_list["in_refresh_status"]) - input_info = null - signal.data = list ("tag" = input_tag, "status" = 1) - . = 1 + switch(action) + if("in_refresh_status") + input_info = null + signal.data = list ("tag" = input_tag, "status" = 1) + . = TRUE - if(href_list["in_toggle_injector"]) - input_info = null - signal.data = list ("tag" = input_tag, "power_toggle" = 1) - . = 1 + if("in_toggle_injector") + input_info = null + signal.data = list ("tag" = input_tag, "power_toggle" = 1) + . = TRUE - if(href_list["in_set_flowrate"]) - input_info = null - signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") - . = 1 + if("in_set_flowrate") + input_info = null + signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") + . = TRUE - if(href_list["out_refresh_status"]) - output_info = null - signal.data = list ("tag" = output_tag, "status" = 1) - . = 1 + if("out_refresh_status") + output_info = null + signal.data = list ("tag" = output_tag, "status" = 1) + . = TRUE - if(href_list["out_toggle_power"]) - output_info = null - signal.data = list ("tag" = output_tag, "power_toggle" = 1) - . = 1 + if("out_toggle_power") + output_info = null + signal.data = list ("tag" = output_tag, "power_toggle" = 1) + . = TRUE - if(href_list["out_set_pressure"]) - output_info = null - signal.data = list ("tag" = output_tag, "set_internal_pressure" = "[pressure_setting]") - . = 1 + if("out_set_pressure") + output_info = null + signal.data = list ("tag" = output_tag, "set_internal_pressure" = "[pressure_setting]") + . = TRUE signal.data["sigtype"]="command" radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) @@ -256,40 +243,29 @@ obj/machinery/computer/general_air_control/Destroy() var/pressure_setting = 100 circuit = /obj/item/circuitboard/air_management/supermatter_core -/obj/machinery/computer/general_air_control/supermatter_core/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - var/list/data = list() - var/sensors_ui[0] - if(sensors.len) - for(var/id_tag in sensors) - var/long_name = sensors[id_tag] - var/list/sensor_data = sensor_information[id_tag] - sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) - else - sensors_ui = null - - data["sensors"] = sensors_ui +/obj/machinery/computer/general_air_control/supermatter_core/ui_data(mob/user) + var/list/data = ..() data["core"] = 1 if(input_info) data["input_info"] = list("power" = input_info["power"], "volume_rate" = round(input_info["volume_rate"], 0.1)) else data["input_info"] = null + if(output_info) - data["output_info"] = list("power" = output_info["power"], "pressure_limit" = output_info["external"]) + // Yes, TECHNICALLY this is not output pressure, it's a pressure LIMIT. HOWEVER. The fact that the UI uses "output_pressure" + // in EXACTLY THE SAME WAY as "pressure_limit" means this should just pass it as the other fucking data argument because holy shit what the + // fuck + data["output_info"] = list("power" = output_info["power"], "output_pressure" = output_info["external"]) else data["output_info"] = null data["input_flow_setting"] = round(input_flow_setting, 0.1) data["pressure_setting"] = pressure_setting + data["max_pressure"] = 10*ONE_ATMOSPHERE + data["max_flowrate"] = ATMOS_DEFAULT_VOLUME_PUMP + 500 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmo_control.tmpl", name, 650, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data /obj/machinery/computer/general_air_control/supermatter_core/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -303,54 +279,56 @@ obj/machinery/computer/general_air_control/Destroy() else ..(signal) -/obj/machinery/computer/general_air_control/supermatter_core/Topic(href, href_list) +/obj/machinery/computer/general_air_control/supermatter_core/ui_act(action, params) if(..()) - return 1 + return TRUE - if(href_list["adj_pressure"]) - var/change = text2num(href_list["adj_pressure"]) - pressure_setting = between(0, pressure_setting + change, 10*ONE_ATMOSPHERE) - return 1 + switch(action) + if("adj_pressure") + var/new_pressure = text2num(params["adj_pressure"]) + pressure_setting = between(0, new_pressure, 10*ONE_ATMOSPHERE) + return TRUE - if(href_list["adj_input_flow_rate"]) - var/change = text2num(href_list["adj_input_flow_rate"]) - input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors - return 1 + if("adj_input_flow_rate") + var/new_flow = text2num(params["adj_input_flow_rate"]) + input_flow_setting = between(0, new_flow, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors + return TRUE if(!radio_connection) - return 0 + return FALSE var/datum/signal/signal = new signal.transmission_method = 1 //radio signal signal.source = src - if(href_list["in_refresh_status"]) - input_info = null - signal.data = list ("tag" = input_tag, "status" = 1) - . = 1 + switch(action) + if("in_refresh_status") + input_info = null + signal.data = list ("tag" = input_tag, "status" = 1) + . = TRUE - if(href_list["in_toggle_injector"]) - input_info = null - signal.data = list ("tag" = input_tag, "power_toggle" = 1) - . = 1 + if("in_toggle_injector") + input_info = null + signal.data = list ("tag" = input_tag, "power_toggle" = 1) + . = TRUE - if(href_list["in_set_flowrate"]) - input_info = null - signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") - . = 1 + if("in_set_flowrate") + input_info = null + signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") + . = TRUE - if(href_list["out_refresh_status"]) - output_info = null - signal.data = list ("tag" = output_tag, "status" = 1) - . = 1 + if("out_refresh_status") + output_info = null + signal.data = list ("tag" = output_tag, "status" = 1) + . = TRUE - if(href_list["out_toggle_power"]) - output_info = null - signal.data = list ("tag" = output_tag, "power_toggle" = 1) - . = 1 + if("out_toggle_power") + output_info = null + signal.data = list ("tag" = output_tag, "power_toggle" = 1) + . = TRUE - if(href_list["out_set_pressure"]) - output_info = null - signal.data = list ("tag" = output_tag, "set_external_pressure" = "[pressure_setting]", "checks" = 1) - . = 1 + if("out_set_pressure") + output_info = null + signal.data = list ("tag" = output_tag, "set_external_pressure" = "[pressure_setting]", "checks" = 1) + . = TRUE signal.data["sigtype"]="command" radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) @@ -368,7 +346,7 @@ obj/machinery/computer/general_air_control/Destroy() /obj/machinery/computer/general_air_control/fuel_injection/process(delta_time) if(automation) if(!radio_connection) - return 0 + return FALSE var/injecting = 0 for(var/id_tag in sensor_information) @@ -394,20 +372,8 @@ obj/machinery/computer/general_air_control/Destroy() ..() -/obj/machinery/computer/general_air_control/fuel_injection/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - var/list/data = list() - var/sensors_ui[0] - if(sensors.len) - for(var/id_tag in sensors) - var/long_name = sensors[id_tag] - var/list/sensor_data = sensor_information[id_tag] - sensors_ui[++sensors_ui.len] = list("long_name" = long_name, "sensor_data" = sensor_data) - else - sensors_ui = null - - data["sensors"] = sensors_ui +/obj/machinery/computer/general_air_control/fuel_injection/ui_data(mob/user) + var/list/data = ..() data["fuel"] = 1 data["automation"] = automation @@ -416,12 +382,7 @@ obj/machinery/computer/general_air_control/Destroy() else data["device_info"] = null - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmo_control.tmpl", name, 650, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data /obj/machinery/computer/general_air_control/fuel_injection/receive_signal(datum/signal/signal) if(!signal || signal.encryption) return @@ -433,55 +394,60 @@ obj/machinery/computer/general_air_control/Destroy() else ..(signal) -/obj/machinery/computer/general_air_control/fuel_injection/Topic(href, href_list) +/obj/machinery/computer/general_air_control/fuel_injection/ui_act(action, params) if(..()) - return + return TRUE - if(href_list["refresh_status"]) - device_info = null - if(!radio_connection) - return 0 + switch(action) + if("refresh_status") + device_info = null + if(!radio_connection) + return FALSE - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - signal.data = list( - "tag" = device_tag, - "status" = 1, - "sigtype"="command" - ) - radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + var/datum/signal/signal = new + signal.transmission_method = TRANSMISSION_RADIO //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "status" = 1, + "sigtype"="command" + ) + radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + . = TRUE - if(href_list["toggle_automation"]) - automation = !automation + if("toggle_automation") + automation = !automation + . = TRUE - if(href_list["toggle_injector"]) - device_info = null - if(!radio_connection) - return 0 + if("toggle_injector") + device_info = null + if(!radio_connection) + return FALSE - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - signal.data = list( - "tag" = device_tag, - "power_toggle" = 1, - "sigtype"="command" - ) + var/datum/signal/signal = new + signal.transmission_method = TRANSMISSION_RADIO //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "power_toggle" = 1, + "sigtype"="command" + ) - radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + . = TRUE - if(href_list["injection"]) - if(!radio_connection) - return 0 + if("injection") + if(!radio_connection) + return FALSE - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - signal.data = list( - "tag" = device_tag, - "inject" = 1, - "sigtype"="command" - ) + var/datum/signal/signal = new + signal.transmission_method = TRANSMISSION_RADIO //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "inject" = 1, + "sigtype"="command" + ) - radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + radio_connection.post_signal(src, signal, radio_filter = RADIO_ATMOSIA) + . = TRUE diff --git a/code/game/machinery/atmoalter/area_atmos_computer.dm b/code/game/machinery/atmoalter/area_atmos_computer.dm index e86d76190c8..45c6bfe72fb 100644 --- a/code/game/machinery/atmoalter/area_atmos_computer.dm +++ b/code/game/machinery/atmoalter/area_atmos_computer.dm @@ -24,92 +24,68 @@ /obj/machinery/computer/area_atmos/attack_hand(var/mob/user as mob) if(..(user)) return - var/dat = {" - - - - - -

Area Air Control

- [status]
- Scan - "} - for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in connectedscrubbers) - dat += {" - - - - "} + ui_interact(user) - dat += {" -
- [scrubber.name]
- Pressure: [round(scrubber.air_contents.return_pressure(), 0.01)] kPa
- Flow Rate: [round(scrubber.last_flow_rate,0.1)] L/s
-
- Turn On - Turn Off
- Load: [round(scrubber.last_power_draw)] W -

- [zone] - - "} - user << browse("[dat]", "window=miningshuttle;size=400x400") - status = "" - -/obj/machinery/computer/area_atmos/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - - - if(href_list["scan"]) - scanscrubbers() - else if(href_list["toggle"]) - var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber = locate(href_list["scrub"]) +/obj/machinery/computer/area_atmos/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AreaScrubberControl", name) + ui.open() +/obj/machinery/computer/area_atmos/ui_data(mob/user) + var/list/working = list() + for(var/id in connectedscrubbers) + var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber = connectedscrubbers[id] if(!validscrubber(scrubber)) - spawn(20) - status = "ERROR: Couldn't connect to scrubber! (timeout)" - connectedscrubbers -= scrubber - src.updateUsrDialog() - return + connectedscrubbers -= scrubber + continue + working.Add(list(list( + "id" = id, + "name" = scrubber.name, + "on" = scrubber.on, + "pressure" = scrubber.air_contents.return_pressure(), + "flow_rate" = scrubber.last_flow_rate, + "load" = scrubber.last_power_draw, + "area" = get_area(scrubber), + ))) - scrubber.on = text2num(href_list["toggle"]) - scrubber.update_icon() + return list("scrubbers" = working) + +/obj/machinery/computer/area_atmos/ui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("toggle") + var/scrub_id = params["id"] + var/obj/machinery/portable_atmospherics/powered/scrubber/huge/S = connectedscrubbers["[scrub_id]"] + if(!validscrubber(S)) + connectedscrubbers -= S + return TRUE + S.on = !S.on + S.update_icon() + . = TRUE + if("allon") + INVOKE_ASYNC(src, .proc/toggle_all, TRUE) + . = TRUE + if("alloff") + INVOKE_ASYNC(src, .proc/toggle_all, FALSE) + . = TRUE + if("scan") + scanscrubbers() + . = TRUE + + add_fingerprint(usr) + +/obj/machinery/computer/area_atmos/proc/toggle_all(on) + for(var/id in connectedscrubbers) + var/obj/machinery/portable_atmospherics/powered/scrubber/huge/S = connectedscrubbers["[id]"] + if(!validscrubber(S)) + connectedscrubbers -= S + continue + S.on = on + S.update_icon() + CHECK_TICK /obj/machinery/computer/area_atmos/proc/validscrubber(obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber as obj) if(!isobj(scrubber) || get_dist(scrubber.loc, src.loc) > src.range || scrubber.loc.z != src.loc.z) @@ -117,12 +93,12 @@ return TRUE /obj/machinery/computer/area_atmos/proc/scanscrubbers() - connectedscrubbers.Cut() + connectedscrubbers = list() - var/found = 0 + var/found = FALSE for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in range(range, src.loc)) - found = 1 - connectedscrubbers += scrubber + found = TRUE + connectedscrubbers["[scrubber.id]"] = scrubber if(!found) status = "ERROR: No scrubber found!" @@ -134,13 +110,13 @@ zone = "This computer is working in a wired network limited to this area." /obj/machinery/computer/area_atmos/area/scanscrubbers() - connectedscrubbers.Cut() + connectedscrubbers = list() - var/found = 0 + var/found = FALSE var/area/A = get_area(src) for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in A) - connectedscrubbers += scrubber - found = 1 + connectedscrubbers["[scrubber.id]"] = scrubber + found = TRUE if(!found) status = "ERROR: No scrubber found!" @@ -148,10 +124,11 @@ src.updateUsrDialog() /obj/machinery/computer/area_atmos/area/validscrubber(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) + if(!istype(scrubber)) + return FALSE if(get_area(scrubber) == get_area(src)) - return 1 - - return 0 + return TRUE + return FALSE // The one that only works in the same map area /obj/machinery/portable_atmospherics/powered/scrubber/huge/var/scrub_id = "generic" @@ -164,7 +141,7 @@ /obj/machinery/computer/area_atmos/tag/scanscrubbers() if(last_scan && world.time - last_scan < 20 SECONDS) - return 0 + return FALSE else last_scan = world.time @@ -172,12 +149,13 @@ for(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in world) if(scrubber.scrub_id == src.scrub_id) - connectedscrubbers += scrubber + connectedscrubbers["[scrubber.id]"] = scrubber - src.updateUsrDialog() + SStgui.update_uis(src) /obj/machinery/computer/area_atmos/tag/validscrubber(var/obj/machinery/portable_atmospherics/powered/scrubber/huge/scrubber) + if(!istype(scrubber)) + return FALSE if(scrubber.scrub_id == src.scrub_id) - return 1 - - return 0 + return TRUE + return FALSE diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 5f03ae1fcdd..a78107411bd 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -1,3 +1,5 @@ +#define CAN_DEFAULT_RELEASE_PRESSURE (ONE_ATMOSPHERE) + /obj/machinery/portable_atmospherics/canister name = "canister" icon = 'icons/obj/atmos.dmi' @@ -8,19 +10,34 @@ layer = TABLE_LAYER // Above catwalks, hopefully below other things - var/valve_open = 0 + ///Is the valve open? + var/valve_open = FALSE + ///Used to log opening and closing of the valve, available on VV + var/release_log = "" + ///How much the canister should be filled (recommended from 0 to 1) + //var/filled = 0.5 + ///Stores the path of the gas for mapped canisters + //var/gas_type + ///Player controlled var that set the release pressure of the canister var/release_pressure = ONE_ATMOSPHERE - var/release_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP //in L/s + ///Maximum pressure allowed for release_pressure var + var/can_max_release_pressure = (ONE_ATMOSPHERE * 10) + ///Minimum pressure allower for release_pressure var + var/can_min_release_pressure = (ONE_ATMOSPHERE * 0.1) + ///Max amount of heat allowed inside of the canister before it starts to melt (different tiers have different limits) + var/heat_limit = 5000 + ///Max amount of pressure allowed inside of the canister before it starts to break (different tiers have different limits) + var/pressure_limit = 46000 + var/release_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP //in L/s var/canister_color = "yellow" - var/can_label = 1 + var/can_label = TRUE start_pressure = 45 * ONE_ATMOSPHERE pressure_resistance = 7 * ONE_ATMOSPHERE var/temperature_resistance = 1000 + T0C volume = 1000 use_power = USE_POWER_OFF interact_offline = 1 // Allows this to be used when not in powered area. - var/release_log = "" var/update_flag = 0 /obj/machinery/portable_atmospherics/canister/drain_power() @@ -312,105 +329,124 @@ update_flag return src.attack_hand(user) /obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user as mob) - return src.nano_ui_interact(user) + return src.ui_interact(user) -/obj/machinery/portable_atmospherics/canister/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if (src.destroyed) - return +/obj/machinery/portable_atmospherics/canister/ui_state(mob/user) + return GLOB.physical_state - // this is the data which will be sent to the ui - var/data[0] - data["name"] = name - data["canLabel"] = can_label ? 1 : 0 - data["portConnected"] = connected_port ? 1 : 0 - data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) - data["tankMoles"] = round(air_contents.total_moles, 0.01) - data["releasePressure"] = round(release_pressure ? release_pressure : 0) - data["minReleasePressure"] = round(ONE_ATMOSPHERE/10) - data["maxReleasePressure"] = round(10*ONE_ATMOSPHERE) - data["valveOpen"] = valve_open ? 1 : 0 - - data["hasHoldingTank"] = holding ? 1 : 0 - if (holding) - data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure())) - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "canister.tmpl", "Canister", 480, 400) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window +/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Canister", name) ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) -/obj/machinery/portable_atmospherics/canister/Topic(href, href_list) +/obj/machinery/portable_atmospherics/canister/ui_static_data(mob/user) + return list( + "defaultReleasePressure" = round(CAN_DEFAULT_RELEASE_PRESSURE), + "minReleasePressure" = round(can_min_release_pressure), + "maxReleasePressure" = round(can_max_release_pressure), + "pressureLimit" = round(pressure_limit), + "holdingTankLeakPressure" = round(TANK_LEAK_PRESSURE), + "holdingTankFragPressure" = round(TANK_FRAGMENT_PRESSURE) + ) - //Do not use "if(..()) return" here, canisters will stop working in unpowered areas like space or on the derelict. // yeah but without SOME sort of Topic check any dick can mess with them via exploits as he pleases -walter0o - //First comment might be outdated. - if (!istype(src.loc, /turf)) - return 0 +/obj/machinery/portable_atmospherics/canister/ui_data() + . = list( + "portConnected" = !!connected_port, + "tankPressure" = round(air_contents.return_pressure()), + "releasePressure" = round(release_pressure), + "valveOpen" = !!valve_open, + //"isPrototype" = !!prototype, + "hasHoldingTank" = !!holding + ) +/* + if(prototype) + . += list( + "restricted" = restricted, + "timing" = timing, + "time_left" = get_time_left(), + "timer_set" = timer_set, + "timer_is_not_default" = timer_set != default_timer_set, + "timer_is_not_min" = timer_set != minimum_timer_set, + "timer_is_not_max" = timer_set != maximum_timer_set + ) +*/ + if(holding) + . += list( + "holdingTank" = list( + "name" = holding.name, + "tankPressure" = round(holding.air_contents.return_pressure()) + ) + ) - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) // exploit protection -walter0o - usr << browse(null, "window=canister") - onclose(usr, "canister") +/obj/machinery/portable_atmospherics/canister/ui_act(action, params) + . = ..() + if(.) return - if(href_list["toggle"]) - if (valve_open) - if (holding) - release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
" + switch(action) + if("relabel") + if(can_label) + var/list/colors = list(\ + "\[N2O\]" = "redws", \ + "\[N2\]" = "red", \ + "\[O2\]" = "blue", \ + "\[Phoron\]" = "orangeps", \ + "\[CO2\]" = "black", \ + "\[Air\]" = "grey", \ + "\[CAUTION\]" = "yellow", \ + ) + var/label = input("Choose canister label", "Gas canister") as null|anything in colors + if(label) + canister_color = colors[label] + icon_state = colors[label] + name = "Canister: [label]" + if("pressure") + var/pressure = params["pressure"] + if(pressure == "reset") + pressure = initial(release_pressure) + . = TRUE + else if(pressure == "min") + pressure = can_min_release_pressure + . = TRUE + else if(pressure == "max") + pressure = can_max_release_pressure + . = TRUE + else if(pressure == "input") + pressure = input("New release pressure ([can_min_release_pressure]-[can_max_release_pressure] kPa):", name, release_pressure) as num|null + if(!isnull(pressure) && !..()) + . = TRUE + else if(text2num(pressure) != null) + pressure = text2num(pressure) + . = TRUE + if(.) + release_pressure = clamp(round(pressure), can_min_release_pressure, can_max_release_pressure) + investigate_log("was set to [release_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS) + if("valve") + if(valve_open) + if(holding) + release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
" + else + release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the air
" else - release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the air
" - else - if (holding) - release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the [holding]
" - else - release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the air
" - log_open() - valve_open = !valve_open - - 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]
" - if(istype(holding, /obj/item/tank)) - holding.manipulated_by = usr.real_name - holding.loc = loc - holding = null - - if (href_list["pressure_adj"]) - var/diff = text2num(href_list["pressure_adj"]) - if(diff > 0) - release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff) - else - release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff) - - if (href_list["relabel"]) - if (can_label) - var/list/colors = list(\ - "\[N2O\]" = "redws", \ - "\[N2\]" = "red", \ - "\[O2\]" = "blue", \ - "\[Phoron\]" = "orangeps", \ - "\[CO2\]" = "black", \ - "\[Air\]" = "grey", \ - "\[CAUTION\]" = "yellow", \ - ) - var/label = input("Choose canister label", "Gas canister") as null|anything in colors - if (label) - src.canister_color = colors[label] - src.icon_state = colors[label] - src.name = "Canister: [label]" - - src.add_fingerprint(usr) - update_icon() - - return 1 + if(holding) + release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the [holding]
" + else + release_log += "Valve was opened by [usr] ([usr.ckey]), starting the transfer into the air
" + log_open() + valve_open = !valve_open + . = TRUE + if("eject") + if(holding) + if(valve_open) + valve_open = 0 + release_log += "Valve was closed by [usr] ([usr.ckey]), stopping the transfer into the [holding]
" + if(istype(holding, /obj/item/tank)) + holding.manipulated_by = usr.real_name + holding.loc = loc + holding = null + . = TRUE + update_appearance() /obj/machinery/portable_atmospherics/canister/phoron/Initialize(mapload) . = ..() diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm index b336cf2b418..7454c44b391 100644 --- a/code/game/machinery/atmoalter/portable_atmospherics.dm +++ b/code/game/machinery/atmoalter/portable_atmospherics.dm @@ -11,6 +11,7 @@ var/destroyed = 0 var/start_pressure = ONE_ATMOSPHERE + ///Maximum pressure allowed on initialize inside the canister, multiplied by the filled var var/maximum_pressure = 90 * ONE_ATMOSPHERE /obj/machinery/portable_atmospherics/Initialize(mapload) diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm index 6636182226d..18022eeee80 100644 --- a/code/game/machinery/atmoalter/pump.dm +++ b/code/game/machinery/atmoalter/pump.dm @@ -117,54 +117,78 @@ return src.attack_hand(user) /obj/machinery/portable_atmospherics/powered/pump/attack_hand(var/mob/user) - nano_ui_interact(user) + ui_interact(user) + +/obj/machinery/portable_atmospherics/powered/pump/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortablePump", name) + ui.open() + + +/obj/machinery/portable_atmospherics/powered/pump/ui_state(mob/user) + return GLOB.physical_state + +/obj/machinery/portable_atmospherics/powered/pump/ui_data(mob/user) + var/list/data = list() + + data["on"] = on ? TRUE : FALSE + data["direction"] = !direction_out ? TRUE : FALSE + data["connected"] = connected_port ? TRUE : FALSE + data["pressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) + data["target_pressure"] = round(target_pressure ? target_pressure : 0) + data["default_pressure"] = round(initial(target_pressure)) + data["min_pressure"] = round(pressuremin) + data["max_pressure"] = round(pressuremax) + -/obj/machinery/portable_atmospherics/powered/pump/nano_ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1) - var/list/data[0] - data["portConnected"] = connected_port ? 1 : 0 - data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) - data["targetpressure"] = round(target_pressure) - data["pump_dir"] = direction_out - data["minpressure"] = round(pressuremin) - data["maxpressure"] = round(pressuremax) data["powerDraw"] = round(last_power_draw) data["cellCharge"] = cell ? cell.charge : 0 data["cellMaxCharge"] = cell ? cell.maxcharge : 1 - data["on"] = on ? 1 : 0 - data["hasHoldingTank"] = holding ? 1 : 0 - if (holding) - data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0)) + if(holding) + data["holding"] = list() + data["holding"]["name"] = holding.name + data["holding"]["pressure"] = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0) + else + data["holding"] = null - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "portpump.tmpl", "Portable Pump", 480, 410, state = physical_state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data -/obj/machinery/portable_atmospherics/powered/pump/Topic(href, href_list) +/obj/machinery/portable_atmospherics/powered/pump/ui_act(action, params) if(..()) - return 1 + return TRUE - if(href_list["power"]) - on = !on - . = 1 - if(href_list["direction"]) - direction_out = !direction_out - . = 1 - if (href_list["remove_tank"]) - if(holding) - holding.loc = loc - holding = null - . = 1 - if (href_list["pressure_adj"]) - var/diff = text2num(href_list["pressure_adj"]) - target_pressure = min(10*ONE_ATMOSPHERE, max(0, target_pressure+diff)) - . = 1 + switch(action) + if("power") + on = !on + . = 1 + if("direction") + direction_out = !direction_out + . = 1 + if("eject") + if(holding) + holding.loc = loc + holding = null + . = 1 + if("pressure") + var/pressure = params["pressure"] + if(pressure == "reset") + pressure = initial(target_pressure) + . = TRUE + else if(pressure == "min") + pressure = pressuremin + . = TRUE + else if(pressure == "max") + pressure = pressuremax + . = TRUE + else if(text2num(pressure) != null) + pressure = text2num(pressure) + . = TRUE + if(.) + target_pressure = clamp(round(pressure), pressuremin, pressuremax) - if(.) - update_icon() + update_icon() /obj/machinery/portable_atmospherics/powered/pump/huge name = "Huge Air Pump" diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm index 6c0900946a1..f59907430e0 100644 --- a/code/game/machinery/atmoalter/scrubber.dm +++ b/code/game/machinery/atmoalter/scrubber.dm @@ -105,58 +105,61 @@ return src.attack_hand(user) /obj/machinery/portable_atmospherics/powered/scrubber/attack_hand(var/mob/user) - nano_ui_interact(user) - return + ui_interact(user) -/obj/machinery/portable_atmospherics/powered/scrubber/nano_ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1) - var/list/data[0] - data["portConnected"] = connected_port ? 1 : 0 - data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) +/obj/machinery/portable_atmospherics/powered/scrubber/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PortableScrubber", name) + ui.open() + +/obj/machinery/portable_atmospherics/powered/scrubber/ui_data(mob/user) + var/list/data = list() + + data["on"] = on ? 1 : 0 + data["connected"] = connected_port ? 1 : 0 + data["pressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) data["rate"] = round(volume_rate) data["minrate"] = round(minrate) data["maxrate"] = round(maxrate) data["powerDraw"] = round(last_power_draw) data["cellCharge"] = cell ? cell.charge : 0 data["cellMaxCharge"] = cell ? cell.maxcharge : 1 - data["on"] = on ? 1 : 0 - data["hasHoldingTank"] = holding ? 1 : 0 - if (holding) - data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0)) + if(holding) + data["holding"] = list() + data["holding"]["name"] = holding.name + data["holding"]["pressure"] = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0) + else + data["holding"] = null - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "portscrubber.tmpl", "Portable Scrubber", 480, 400, state = physical_state) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data - -/obj/machinery/portable_atmospherics/powered/scrubber/Topic(href, href_list) +/obj/machinery/portable_atmospherics/powered/scrubber/ui_act(action, params) if(..()) - return 1 + return TRUE + + switch(action) + if("power") + on = !on + . = TRUE + if("eject") + if(holding) + holding.loc = loc + holding = null + . = TRUE + if("volume_adj") + volume_rate = clamp(text2num(params["vol"]), minrate, maxrate) + . = TRUE - if(href_list["power"]) - on = !on - . = 1 - if (href_list["remove_tank"]) - if(holding) - holding.loc = loc - holding = null - . = 1 - if (href_list["volume_adj"]) - var/diff = text2num(href_list["volume_adj"]) - volume_rate = clamp(volume_rate+diff, minrate, maxrate) - . = 1 update_icon() - //Huge scrubber /obj/machinery/portable_atmospherics/powered/scrubber/huge name = "Huge Air Scrubber" - icon = 'icons/obj/atmos_vr.dmi' //VOREStation Edit - New Sprite + icon = 'icons/obj/atmos_vr.dmi' icon_state = "scrubber:0" - anchored = 1 + anchored = TRUE volume = 500000 volume_rate = 7000 diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 8638e674716..825726cfe3e 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -12,15 +12,15 @@ clickvol = 30 circuit = /obj/item/circuitboard/autolathe - var/datum/category_collection/autolathe/machine_recipes + + var/static/datum/category_collection/autolathe/autolathe_recipes var/list/stored_material = list(DEFAULT_WALL_MATERIAL = 0, MAT_GLASS = 0) var/list/storage_capacity = list(DEFAULT_WALL_MATERIAL = 0, MAT_GLASS = 0) - var/datum/category_group/autolathe/current_category - var/hacked = 0 - var/disabled = 0 - var/shocked = 0 - var/busy = 0 + var/hacked = FALSE + var/disabled = FALSE + var/shocked = FALSE + var/busy = FALSE var/mat_efficiency = 1 var/build_time = 50 @@ -34,6 +34,8 @@ /obj/machinery/autolathe/Initialize(mapload) . = ..() + if(!autolathe_recipes) + autolathe_recipes = new() wires = new(src) default_apply_parts() RefreshParts() @@ -43,82 +45,77 @@ wires = null return ..() -/obj/machinery/autolathe/proc/update_recipe_list() - if(!machine_recipes) - if(!autolathe_recipes) - autolathe_recipes = new() - machine_recipes = autolathe_recipes - current_category = machine_recipes.categories[1] +/obj/machinery/autolathe/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Autolathe", name) + ui.open() -/obj/machinery/autolathe/interact(mob/user as mob) - update_recipe_list() +/obj/machinery/autolathe/ui_status(mob/user) + if(disabled) + return UI_CLOSE + return ..() - if(..() || (disabled && !panel_open)) +/obj/machinery/autolathe/ui_static_data(mob/user) + var/list/data = ..() + + var/list/categories = list() + var/list/recipes = list() + for(var/datum/category_group/autolathe/A in autolathe_recipes.categories) + categories += A.name + for(var/datum/category_item/autolathe/M in A.items) + if(M.hidden && !hacked) + continue + if(M.man_rating > man_rating) + continue + recipes.Add(list(list( + "category" = A.name, + "name" = M.name, + "ref" = REF(M), + "requirements" = M.resources, + "hidden" = M.hidden, + "coeff_applies" = !M.no_scale, + ))) + data["recipes"] = recipes + data["categories"] = categories + + return data + +/obj/machinery/autolathe/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/sheetmaterials) + ) + +/obj/machinery/autolathe/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + + var/list/material_data = list() + for(var/mat_id in stored_material) + var/amount = stored_material[mat_id] + var/list/material_info = list( + "name" = mat_id, + "amount" = amount, + "sheets" = round(amount / SHEET_MATERIAL_AMOUNT), + "removable" = amount >= SHEET_MATERIAL_AMOUNT + ) + material_data += list(material_info) + data["busy"] = busy + data["materials"] = material_data + data["mat_efficiency"] = mat_efficiency + return data + +/obj/machinery/autolathe/interact(mob/user) + if(panel_open) + return wires.Interact(user) + + if(disabled) to_chat(user, SPAN_DANGER("\The [src] is disabled!")) return if(shocked) shock(user, 50) - var/list/dat = list() - dat += "

Autolathe Control Panel


" - if(!disabled) - dat += "" - var/list/material_top = list("") - var/list/material_bottom = list("") - - for(var/material in stored_material) - material_top += "" - material_bottom += "" - - dat += "[material_top.Join()][material_bottom.Join()]
[material][stored_material[material]]/[storage_capacity[material]]

" - dat += "Filter: [filtertext ? filtertext : "None Set"]
" - dat += "

Printable Designs

Showing: [current_category].

" - - for(var/datum/category_item/autolathe/R in current_category.items) - if(R.hidden && !hacked) // Illegal or nonstandard. - continue - if(filtertext && findtext(R.name, filtertext) == 0) - continue - var/can_make = 1 - var/list/material_string = list() - var/list/multiplier_string = list() - var/max_sheets - var/comma - if(!R.resources || !R.resources.len) - material_string += "No resources required." - else - //Make sure it's buildable and list requires resources. - for(var/material in R.resources) - var/coeff = (R.no_scale ? 1 : mat_efficiency) //stacks are unaffected by production coefficient - var/sheets = round(stored_material[material]/round(R.resources[material]*coeff)) - if(isnull(max_sheets) || max_sheets > sheets) - max_sheets = sheets - if(!isnull(stored_material[material]) && stored_material[material] < round(R.resources[material]*coeff)) - can_make = 0 - if(!comma) - comma = 1 - else - material_string += ", " - material_string += "[round(R.resources[material] * coeff)] [material]" - material_string += ".
" - //Build list of multipliers for sheets. - if(R.is_stack) - if(max_sheets && max_sheets > 0) - max_sheets = min(max_sheets, R.max_stack) // Limit to the max allowed by stack type. - multiplier_string += "
" - for(var/i = 5;i*" : ""][can_make ? "" : ""][R.name][can_make ? "" : ""][R.hidden ? "*" : ""][multiplier_string.Join()]" - - dat += "
[material_string.Join()]

" - - dat = jointext(dat, null) - var/datum/browser/popup = new(user, "autolathe", "Autolathe Production Menu", 550, 700) - popup.set_content(dat) - popup.open() + ui_interact(user) /obj/machinery/autolathe/attackby(var/obj/item/O as obj, var/mob/user as mob) if(busy) @@ -126,7 +123,7 @@ return if(default_deconstruction_screwdriver(user, O)) - updateUsrDialog() + interact(user) return if(default_deconstruction_crowbar(user, O)) return @@ -143,36 +140,27 @@ return if(O.loc != user && !(istype(O,/obj/item/stack))) - return 0 + return FALSE if(is_robot_module(O)) - return 0 + return FALSE if(istype(O,/obj/item/ammo_magazine/clip) || istype(O,/obj/item/ammo_magazine/s357) || istype(O,/obj/item/ammo_magazine/s38) || istype (O,/obj/item/ammo_magazine/s44)/* VOREstation Edit*/) // Prevents ammo recycling exploit with speedloaders. to_chat(user, "\The [O] is too hazardous to recycle with the autolathe!") return - /* ToDo: Make this actually check for ammo and change the value of the magazine if it's empty. -Spades - var/obj/item/ammo_magazine/speedloader = O - if(speedloader.stored_ammo) - to_chat(user, "\The [speedloader] is too hazardous to put back into the autolathe while there's ammunition inside of it!") - return - else - speedloader.matter = list(DEFAULT_WALL_MATERIAL = 75) // It's just a hunk of scrap metal now. - if(istype(O,/obj/item/ammo_magazine)) // This was just for immersion consistency with above. - var/obj/item/ammo_magazine/mag = O - if(mag.stored_ammo) - to_chat(user, "\The [mag] is too hazardous to put back into the autolathe while there's ammunition inside of it!") - return*/ - //Resources are being loaded. + ///Resources are being loaded. var/obj/item/eating = O if(!eating.matter) to_chat(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. + ///Used to determine message. + var/filltype = 0 + ///Amount of material used. + var/total_used = 0 + ///Amount of material constituting one sheet. + var/mass_per_sheet = 0 for(var/material in eating.matter) @@ -207,11 +195,11 @@ else to_chat(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 + 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. + stack.use(max(1, round(total_used/mass_per_sheet))) //Always use at least 1 to prevent infinite materials. else user.remove_from_mob(O) qdel(O) @@ -223,9 +211,9 @@ user.set_machine(src) interact(user) -/obj/machinery/autolathe/Topic(href, href_list) +/obj/machinery/autolathe/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return + return TRUE usr.set_machine(src) @@ -233,73 +221,69 @@ to_chat(usr, SPAN_NOTICE("The autolathe is busy. Please wait for completion of previous operation.")) return - else if(href_list["setfilter"]) - var/filterstring = input(usr, "Input a filter string, or blank to not filter:", "Design Filter", filtertext) as null|text - if(!Adjacent(usr)) - return - if(isnull(filterstring)) //Clicked Cancel - return - if(filterstring == "") //Cleared value - filtertext = null - filtertext = sanitize(filterstring, 25) + switch(action) + if("make") + var/datum/category_item/autolathe/making = locate(params["make"]) + if(!istype(making)) + return + if(making.hidden && !hacked) + return - if(href_list["change_category"]) + var/multiplier = 1 - var/choice = input("Which category do you wish to display?") as null|anything in machine_recipes.categories - if(!choice) return - current_category = choice + if(making.is_stack) + var/max_sheets + for(var/material in making.resources) + var/coeff = (making.no_scale ? 1 : mat_efficiency) //Stacks are unaffected by production coefficient + var/sheets = round(stored_material[material]/round(making.resources[material]*coeff)) + if(isnull(max_sheets) || max_sheets > sheets) + max_sheets = sheets + if(!isnull(stored_material[material]) && stored_material[material] < round(making.resources[material]*coeff)) + max_sheets = 0 + //Build list of multipliers for sheets. + multiplier = input(usr, "How many do you want to print? (0-[max_sheets])") as num|null + if(!multiplier || multiplier <= 0 || multiplier > max_sheets || ui_status(usr, state) != UI_INTERACTIVE) + return FALSE - if(href_list["make"] && machine_recipes) - var/multiplier = text2num(href_list["multiplier"]) - var/datum/category_item/autolathe/making = locate(href_list["make"]) in current_category.items + busy = making.name + update_use_power(USE_POWER_ACTIVE) - //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 + //Check if we still have the materials. + var/coeff = (making.no_scale ? 1 : mat_efficiency) //Stacks are unaffected by production coefficient + for(var/material in making.resources) + if(!isnull(stored_material[material])) + if(stored_material[material] < round(making.resources[material] * coeff) * multiplier) + return - var/logstring = "[key_name(usr)] has made [multiplier] of [making.name]" + //Consume materials. + for(var/material in making.resources) + if(!isnull(stored_material[material])) + stored_material[material] = max(0, stored_material[material] - round(making.resources[material] * coeff) * multiplier) - busy = 1 - update_use_power(USE_POWER_ACTIVE) + update_icon() //So lid closes - //Check if we still have the materials. - var/coeff = (making.no_scale ? 1 : mat_efficiency) //stacks are unaffected by production coefficient - for(var/material in making.resources) - if(!isnull(stored_material[material])) - if(stored_material[material] < round(making.resources[material] * coeff) * multiplier) - return + sleep(build_time) - //Consume materials. - for(var/material in making.resources) - if(!isnull(stored_material[material])) - stored_material[material] = max(0, stored_material[material] - round(making.resources[material] * coeff) * multiplier) + busy = 0 + update_use_power(USE_POWER_IDLE) + update_icon() //So lid opens - update_icon() // So lid closes + //Sanity check. + if(!making || !src) + return - sleep(build_time) - - busy = 0 - update_use_power(USE_POWER_IDLE) - update_icon() // So lid opens - - //Sanity check. - if(!making || !src) return - - //Create the desired item. - log_game(logstring) - var/obj/item/I = new making.path(src.loc) - if(multiplier > 1) - if(istype(I, /obj/item/stack)) - var/obj/item/stack/S = I - S.amount = multiplier - else - for(multiplier; multiplier > 1; --multiplier) // Create multiple items if it's not a stack. - new making.path(src.loc) - - updateUsrDialog() + //Create the desired item. + var/obj/item/I = new making.path(src.loc) + flick("[initial(icon_state)]_finish", src) + if(multiplier > 1) + if(istype(I, /obj/item/stack)) + var/obj/item/stack/S = I + S.amount = multiplier + else + for(multiplier; multiplier > 1; --multiplier) //Create multiple items if it's not a stack. + new making.path(src.loc) + return TRUE + return FALSE /obj/machinery/autolathe/update_icon() overlays.Cut() @@ -312,7 +296,7 @@ icon_state = "autolathe_n" else if(icon_state == "autolathe_n") - flick("autolathe_u", src) // If lid WAS closed, show opening animation + flick("autolathe_u", src) //If lid WAS closed, show opening animation icon_state = "autolathe" //Updates overall lathe storage size. @@ -328,7 +312,8 @@ storage_capacity[DEFAULT_WALL_MATERIAL] = mb_rating * 25000 storage_capacity[MAT_GLASS] = mb_rating * 12500 build_time = 50 / man_rating - mat_efficiency = 1.1 - man_rating * 0.1// Normally, price is 1.25 the amount of material, so this shouldn't go higher than 0.6. Maximum rating of parts is 5 + mat_efficiency = 1.1 - man_rating * 0.1 //Normally, price is 1.25 the amount of material, so this shouldn't go higher than 0.6. Maximum rating of parts is 5 + update_static_data(usr) /obj/machinery/autolathe/dismantle() for(var/mat in stored_material) @@ -360,3 +345,25 @@ name = "SMG magazine (9mm flash)" path = /obj/item/ammo_magazine/m9mml/flash */ + +// 0 amount = 0 means ejecting a full stack; -1 means eject everything +/obj/machinery/partslathe/proc/eject_materials(var/material, var/amount) + var/recursive = amount == -1 ? TRUE : FALSE + material = lowertext(material) + var/mattype + switch(material) + if(MAT_STEEL) + mattype = /obj/item/stack/material/steel + if(MAT_GLASS) + mattype = /obj/item/stack/material/glass + else + return + var/obj/item/stack/material/S = new mattype(loc) + if(amount <= 0) + amount = S.max_amount + var/ejected = min(round(materials[material] / S.perunit), amount) + if(!S.set_amount(min(ejected, amount))) + return + materials[material] -= ejected * S.perunit + if(recursive && materials[material] >= S.perunit) + eject_materials(material, -1) diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm index 62b63f01ef1..e48457a38db 100644 --- a/code/game/machinery/bioprinter.dm +++ b/code/game/machinery/bioprinter.dm @@ -4,26 +4,31 @@ /obj/machinery/organ_printer name = "organ printer" desc = "It's a machine that prints organs." - icon = 'icons/obj/surgery.dmi' + icon = 'icons/obj/machines/fabricators/bioprinter.dmi' icon_state = "bioprinter" + base_icon_state = "bioprinter" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE use_power = USE_POWER_IDLE idle_power_usage = 40 active_power_usage = 300 - - var/obj/item/reagent_containers/container = null // This is the beaker that holds all of the biomass + ///This is the beaker that holds all of the biomass + var/obj/item/reagent_containers/container = null var/print_delay = 100 - var/base_print_delay = 100 // For Adminbus reasons - var/printing = FALSE // is the bioprinter printing - var/loaded_dna //Blood sample for DNA hashing. - var/malfunctioning = FALSE // May cause rejection, or the printing of some alien limb instead! - - var/complex_organs = FALSE // Can it print more 'complex' organs? - - var/anomalous_organs = FALSE // Can it print anomalous organs? + ///For Adminbus reasons + var/base_print_delay = 100 + ///Is the bioprinter printing + var/printing = FALSE + ///Blood sample for DNA hashing. + var/loaded_dna + ///May cause rejection, or the printing of some alien limb instead! + var/malfunctioning = FALSE + ///Can it print more 'complex' organs? + var/complex_organs = FALSE + /// Can it print anomalous organs? + var/anomalous_organs = FALSE // These should be subtypes of /obj/item/organ // Costs roughly 20u Phoron (1 sheet) per internal organ, limbs are 60u for limb and extremity @@ -56,6 +61,26 @@ "Adrenal Valve Cluster" = list(/obj/item/organ/internal/heart/replicant/rage, 80) ) +/obj/machinery/organ_printer/Initialize(mapload, newdir) + . = ..() + default_apply_parts() + RefreshParts() + +/obj/machinery/organ_printer/update_icon_state() + . = ..() + if(stat & NOPOWER) + icon_state = "[base_icon_state]-off" + else + icon_state = base_icon_state + +/obj/machinery/organ_printer/update_overlays() + . = ..() + cut_overlays() + if(panel_open) + add_overlay("[base_icon_state]-panel") + if(printing) + add_overlay("[base_icon_state]-active") + /obj/machinery/organ_printer/attackby(var/obj/item/O, var/mob/user) if(default_deconstruction_screwdriver(user, O)) updateUsrDialog() @@ -68,24 +93,13 @@ return return ..() -/obj/machinery/organ_printer/update_icon() - cut_overlays() - if(panel_open) - add_overlay("bioprinter_panel_open") - if(printing) - add_overlay("bioprinter_working") - -/obj/machinery/organ_printer/Initialize(mapload, newdir) - . = ..() - default_apply_parts() - /obj/machinery/organ_printer/examine(var/mob/user) . = ..() var/biomass = get_biomass_volume() if(biomass) - . +="It is loaded with [biomass] units of biomass." + . += SPAN_INFO("It is loaded with [biomass] units of biomass.") else - . += "It is not loaded with any biomass." + . += SPAN_INFO("It is not loaded with any biomass.") /obj/machinery/organ_printer/RefreshParts() // Print Delay updating @@ -134,7 +148,7 @@ if(response == "Print Limbs") printing_menu(user) else - to_chat(user, "\The [src] can't operate without a reagent reservoir!") + to_chat(user, SPAN_WARNING("\The [src] can't operate without a reagent reservoir!")) /obj/machinery/organ_printer/proc/printing_menu(mob/user) var/list/possible_list = list() @@ -159,15 +173,15 @@ update_use_power(USE_POWER_ACTIVE) printing = TRUE - update_icon() + update_appearance() - visible_message("\The [src] begins churning.") + visible_message(SPAN_NOTICE("\The [src] begins churning.")) sleep(print_delay) update_use_power(USE_POWER_IDLE) printing = FALSE - update_icon() + update_appearance() if(!choice || !src || (stat & (BROKEN|NOPOWER))) return @@ -209,11 +223,11 @@ /obj/machinery/organ_printer/proc/can_print(var/choice, var/biomass_needed = 0) var/biomass = get_biomass_volume() if(biomass < biomass_needed) - visible_message("\The [src] displays a warning: 'Not enough biomass. [biomass] stored and [biomass_needed] needed.'") + visible_message(SPAN_INFO("\The [src] displays a warning: 'Not enough biomass. [biomass] stored and [biomass_needed] needed.'")) return 0 if(!loaded_dna || !loaded_dna["donor"]) - visible_message("\The [src] displays a warning: 'No DNA saved. Insert a blood sample.'") + visible_message(SPAN_INFO("\The [src] displays a warning: 'No DNA saved. Insert a blood sample.'")) return 0 return 1 @@ -265,7 +279,6 @@ /obj/machinery/organ_printer/flesh name = "bioprinter" desc = "It's a machine that prints replacement organs." - icon_state = "bioprinter" circuit = /obj/item/circuitboard/bioprinter /obj/machinery/organ_printer/flesh/full/Initialize(mapload, newdir) @@ -283,8 +296,8 @@ /obj/machinery/organ_printer/flesh/print_organ(var/choice) var/obj/item/organ/O = ..() - playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) - visible_message("\The [src] dings, then spits out \a [O].") + playsound(src.loc, 'sound/machines/ding.ogg', 50, TRUE) + visible_message(SPAN_INFO("\The [src] dings, then spits out \a [O].")) return O /obj/machinery/organ_printer/flesh/attackby(obj/item/W, mob/user) @@ -295,12 +308,12 @@ if(injected && injected.data) loaded_dna = injected.data S.reagents.remove_reagent("blood", injected.volume) - to_chat(user, "You scan the blood sample into the bioprinter.") + to_chat(user, SPAN_INFO("You scan the blood sample into the bioprinter.")) return else if(istype(W,/obj/item/reagent_containers/glass)) var/obj/item/reagent_containers/glass/G = W if(container) - to_chat(user, "\The [src] already has a container loaded!") + to_chat(user, SPAN_WARNING("\The [src] already has a container loaded!")) return else if(do_after(user, 1 SECOND)) user.visible_message("[user] has loaded \the [G] into \the [src].", "You load \the [G] into \the [src].") diff --git a/code/game/machinery/bomb_tester_vr.dm b/code/game/machinery/bomb_tester.dm similarity index 68% rename from code/game/machinery/bomb_tester_vr.dm rename to code/game/machinery/bomb_tester.dm index 8f6b43a44f0..b711c05b43c 100644 --- a/code/game/machinery/bomb_tester_vr.dm +++ b/code/game/machinery/bomb_tester.dm @@ -7,8 +7,8 @@ desc = "A device that can calculate the potential explosive yield of provided gases." icon = 'icons/obj/machines/bomb_tester_vr.dmi' icon_state = "generic" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE idle_power_usage = 50 active_power_usage = 1.5 KILOWATTS @@ -23,8 +23,11 @@ var/sim_mode = MODE_SINGLE var/sim_canister_output = 10*ONE_ATMOSPHERE - var/simulating = 0 - var/simulation_started = 0 + ///Are we simulating? + var/simulating = FALSE + ///Have we started simulating? + var/simulation_started = FALSE + ///The delay before we start simulating. var/simulation_delay = 20 SECONDS var/simulation_results @@ -101,112 +104,104 @@ else tank2 = I update_icon() - updateUsrDialog() - to_chat(user, "You connect \the [I] to \the [src]'s [I==tank1 ? "primary" : "secondary"] slot.") + SStgui.update_uis(src) + to_chat(user, SPAN_NOTICE("You connect \the [I] to \the [src]'s [I==tank1 ? "primary" : "secondary"] slot.")) return ..() /obj/machinery/bomb_tester/attack_hand(var/mob/user) add_fingerprint(user) - interact(user) + ui_interact(user) -/obj/machinery/bomb_tester/interact(var/mob/user) - if(stat & NOPOWER) - return +/obj/machinery/bomb_tester/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "BombTester", name) + ui.open() - var/dat = "Bomb Tester" +/obj/machinery/bomb_tester/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + data["simulating"] = simulating + if(!simulating) + data["mode"] = sim_mode + data["tank1"] = tank1 + data["tank1ref"] = REF(tank1) + data["tank2"] = tank2 + data["tank2ref"] = REF(tank2) + data["canister"] = test_canister + data["sim_canister_output"] = sim_canister_output - dat += "Virtual Explosive Simulator v1.03" - dat += "
" + return data - if(simulating) - dat += "
Simulation in progress! Please wait for results.
" - - else - dat += "
Mode: [sim_mode==MODE_SINGLE?"Single Tank":"Single Tank"] -- [sim_mode==MODE_DOUBLE?"Transfer Valve":"Transfer Valve"] -- [sim_mode==MODE_CANISTER?"Canister":"Canister"]
" - dat += "
" - dat += "
Gas Sources
" - dat += "
[tank1?"\[[tank1.name]\]":"\[Primary Slot\]"] -- [tank2?"\[[tank2.name]\]":"\[Secondary Slot\]"]
" - dat += "
Connected Canister: [test_canister?"[test_canister.name] -- ":"None -- "][test_canister?"\[Rescan\]":"\[Scan for canister\]"]
" - if(test_canister) - dat += "
Canister Release Pressure: [sim_canister_output] Kilopascals
" - - dat += "
" - dat += "-1000|" - dat += "-100|" - dat += "-10|" - dat += "-1 ||| " - - dat += "+1|" - dat += "+10|" - dat += "+100|" - dat += "+1000" - dat += "
" - - dat += "

" - dat += "
BEGIN SIMULATION
" - - user.set_machine(src) - user << browse(dat, "window=bomb_tester") - onclose(user, "bomb_tester") - -/obj/machinery/bomb_tester/Topic(href, href_list) +/obj/machinery/bomb_tester/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return - if(stat & NOPOWER) - return - if(!usr.Adjacent(src)) - usr << browse(null, "window=bomb_tester") - usr.unset_machine() - return + return TRUE + if(simulating) return - if(href_list["set_mode"]) - sim_mode = text2num(href_list["set_mode"]) - var/text_mode - switch(sim_mode) - if(MODE_SINGLE) - text_mode = "single gas tank detonation" - if(MODE_DOUBLE) - text_mode = "tank transfer valve detonation" - if(MODE_CANISTER) - text_mode = "canister-assisted single gas tank detonation" - to_chat(usr, "[src] set to simulate a [text_mode].") + switch(action) + if("set_mode") + sim_mode = clamp(text2num(params["mode"]), MODE_SINGLE, MODE_CANISTER) + var/text_mode + switch(sim_mode) + if(MODE_SINGLE) + text_mode = "single gas tank detonation" + if(MODE_DOUBLE) + text_mode = "tank transfer valve detonation" + if(MODE_CANISTER) + text_mode = "canister-assisted single gas tank detonation" + to_chat(usr, SPAN_NOTICE("[src] set to simulate a [text_mode].")) + return TRUE - if(href_list["tank"]) - var/tankvar = "tank[href_list["tank"]]" - var/obj/item/tank/T - if(vars[tankvar]) - T = vars[tankvar] - T.forceMove(get_turf(src)) - vars[tankvar] = null - else if(istype(usr.get_active_hand(),/obj/item/tank)) - T = usr.get_active_hand() - usr.drop_item(T) - T.forceMove(src) - vars[tankvar] = T - update_icon() + if("add_tank") + if(istype(usr.get_active_hand(), /obj/item/tank)) + var/obj/item/tank/T = usr.get_active_hand() + var/slot = params["slot"] + if(slot == 1 && !tank1) + tank1 = T + else if(slot == 2 && !tank2) + tank2 = T + else + to_chat(usr, SPAN_WARNING("Slot [slot] is full.")) + return - if(href_list["canister_scan"]) - for(var/obj/machinery/portable_atmospherics/canister/C in orange(1,src)) - if(C && C == test_canister) - continue - else if(C) - test_canister = C - break + usr.drop_item(T) + T.forceMove(src) + return TRUE else - test_canister = null + to_chat(usr, SPAN_WARNING("You must be wielding a tank to insert it!")) - if(href_list["set_can_pressure"]) - var/change = text2num(href_list["set_can_pressure"]) - sim_canister_output = clamp(sim_canister_output+change, ONE_ATMOSPHERE/10, ONE_ATMOSPHERE*10) + if("remove_tank") + var/obj/item/tank/T = locate(params["ref"]) in list(tank1, tank2) + if(istype(T)) + if(T == tank1) + tank1 = null + if(T == tank2) + tank2 = null + T.forceMove(get_turf(src)) + update_icon() + return TRUE - if(href_list["start_sim"]) - start_simulating() + if("canister_scan") + for(var/obj/machinery/portable_atmospherics/canister/C in orange(1,src)) + if(C && C == test_canister) + continue + else if(C) + test_canister = C + break + else + test_canister = null + return TRUE - updateUsrDialog() + if("set_can_pressure") + sim_canister_output = clamp(text2num(params["pressure"]), ONE_ATMOSPHERE/10, ONE_ATMOSPHERE*10) + return TRUE + + if("start_sim") + start_simulating() + return TRUE /obj/machinery/bomb_tester/proc/start_simulating() simulating = 1 @@ -235,7 +230,8 @@ spawn() canister_sim() -/obj/machinery/bomb_tester/proc/simulate_tank() //This is a heavily cut down version of check_status() from tanks.dm +///This is a heavily cut down version of check_status() from tanks.dm +/obj/machinery/bomb_tester/proc/simulate_tank() faketank.react() var/pressure = faketank.return_pressure() if(pressure > TANK_FRAGMENT_PRESSURE) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 207b62e0ad0..173e3c79232 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -302,14 +302,14 @@ /obj/machinery/camera/proc/triggerCameraAlarm(var/duration = 0) alarm_on = 1 - SSalarms.camera_alarm.triggerAlarm(loc, src, duration) + camera_alarm.triggerAlarm(loc, src, duration) /obj/machinery/camera/proc/cancelCameraAlarm() if(wires.is_cut(WIRE_CAM_ALARM)) return alarm_on = 0 - SSalarms.camera_alarm.clearAlarm(loc, src) + camera_alarm.clearAlarm(loc, src) //if false, then the camera is listed as DEACTIVATED and cannot be used /obj/machinery/camera/proc/can_use() @@ -437,7 +437,7 @@ network.Cut() update_coverage(1) -/obj/machinery/camera/proc/nano_structure() +/obj/machinery/camera/proc/ui_structure() var/cam[0] cam["name"] = sanitize(c_tag) cam["deact"] = !can_use() diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm index 48110f0a7ac..e68e963c141 100644 --- a/code/game/machinery/camera/motion.dm +++ b/code/game/machinery/camera/motion.dm @@ -27,12 +27,13 @@ lostTarget(target) /obj/machinery/camera/proc/newTarget(var/mob/target) - if (istype(target, /mob/living/silicon/ai)) return 0 + if (istype(target, /mob/living/silicon/ai)) + return FALSE if (detectTime == 0) detectTime = world.time // start the clock if (!(target in motionTargets)) motionTargets += target - return 1 + return TRUE /obj/machinery/camera/proc/lostTarget(var/mob/target) if (target in motionTargets) @@ -42,23 +43,23 @@ /obj/machinery/camera/proc/cancelAlarm() if (!status || (stat & NOPOWER)) - return 0 + return FALSE if (detectTime == -1) - SSalarms.motion_alarm.clearAlarm(loc, src) + motion_alarm.clearAlarm(loc, src) detectTime = 0 - return 1 + return TRUE /obj/machinery/camera/proc/triggerAlarm() if (!status || (stat & NOPOWER)) - return 0 - if (!detectTime) return 0 - SSalarms.motion_alarm.triggerAlarm(loc, src) + return FALSE + if (!detectTime) + return FALSE + motion_alarm.triggerAlarm(loc, src) detectTime = -1 - return 1 + return TRUE /obj/machinery/camera/HasProximity(atom/movable/AM as mob|obj) // Motion cameras outside of an "ai monitored" area will use this to detect stuff. if (!area_motion) if(isliving(AM)) newTarget(AM) - diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm index fb15362af4e..2e5ae6acabd 100644 --- a/code/game/machinery/computer/aifixer.dm +++ b/code/game/machinery/computer/aifixer.dm @@ -18,16 +18,16 @@ if(I.is_screwdriver()) if(occupier) if(stat & (NOPOWER|BROKEN)) - to_chat(user, "The screws on [name]'s screen won't budge.") + to_chat(user, SPAN_WARNING("The screws on [name]'s screen won't budge.")) else - to_chat(user, "The screws on [name]'s screen won't budge and it emits a warning beep.") + to_chat(user, SPAN_WARNING("The screws on [name]'s screen won't budge and it emits a warning beep.")) return if(istype(I, /obj/item/aicard)) if(stat & (NOPOWER|BROKEN)) - to_chat(user, "This terminal isn't functioning right now.") + to_chat(user, SPAN_WARNING("This terminal isn't functioning right now.")) return if(restoring) - to_chat(user, "Terminal is busy restoring [occupier] right now.") + to_chat(user, SPAN_DANGER("Terminal is busy restoring [occupier] right now.")) return var/obj/item/aicard/card = I @@ -36,7 +36,7 @@ occupier = null else if(card.carded_ai) var/mob/living/silicon/ai/new_occupant = card.carded_ai - to_chat(new_occupant, "You have been transferred into a stationary terminal. Sadly there is no remote access from here.") + to_chat(new_occupant, SPAN_NOTICE("You have been transferred into a stationary terminal. Sadly there is no remote access from here.")) to_chat(user, "Transfer Successful: [new_occupant] placed within stationary terminal.") new_occupant.forceMove(src) new_occupant.cancel_camera() @@ -45,7 +45,7 @@ card.clear() update_icon() else - to_chat(user, "There is no AI loaded onto this computer, and no AI loaded onto [I]. What exactly are you trying to do here?") + to_chat(user, SPAN_NOTICE("There is no AI loaded onto this computer, and no AI loaded onto [I]. What exactly are you trying to do here?")) return ..() /obj/machinery/computer/aifixer/attack_hand(mob/user) @@ -82,7 +82,7 @@ /obj/machinery/computer/aifixer/ui_act(action, params) if(..()) - return + return TRUE if(!occupier) restoring = FALSE diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm index 9760987fab8..f54d8ee7b2e 100644 --- a/code/game/machinery/computer/atmos_alert.dm +++ b/code/game/machinery/computer/atmos_alert.dm @@ -14,69 +14,65 @@ var/global/list/minor_air_alarms = list() /obj/machinery/computer/atmos_alert/Initialize(mapload) . = ..() - SSalarms.atmosphere_alarm.register_alarm(src, /atom/proc/update_icon) + atmosphere_alarm.register_alarm(src, /atom/proc/update_icon) /obj/machinery/computer/atmos_alert/Destroy() - SSalarms.atmosphere_alarm.unregister_alarm(src) - return ..() + atmosphere_alarm.unregister_alarm(src) + return ..() /obj/machinery/computer/atmos_alert/attack_hand(mob/user) - nano_ui_interact(user) + ui_interact(user) -/obj/machinery/computer/atmos_alert/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - var/major_alarms[0] - var/minor_alarms[0] +/obj/machinery/computer/atmos_alert/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AtmosAlertConsole", name) + ui.open() - for(var/datum/alarm/alarm in SSalarms.atmosphere_alarm.major_alarms()) +/obj/machinery/computer/atmos_alert/ui_data(mob/user) + var/list/data = list() + var/list/major_alarms = list() + var/list/minor_alarms = list() + + for(var/datum/alarm/alarm in atmosphere_alarm.major_alarms()) major_alarms[++major_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]") - for(var/datum/alarm/alarm in SSalarms.atmosphere_alarm.minor_alarms()) + for(var/datum/alarm/alarm in atmosphere_alarm.minor_alarms()) minor_alarms[++minor_alarms.len] = list("name" = sanitize(alarm.alarm_name()), "ref" = "\ref[alarm]") data["priority_alarms"] = major_alarms data["minor_alarms"] = minor_alarms - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "atmos_alert.tmpl", src.name, 500, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) + return data /obj/machinery/computer/atmos_alert/update_icon() if(!(stat & (NOPOWER|BROKEN))) - var/list/alarms = SSalarms.atmosphere_alarm.major_alarms() + var/list/alarms = atmosphere_alarm.major_alarms() if(alarms.len) icon_screen = "alert:2" else - alarms = SSalarms.atmosphere_alarm.minor_alarms() + alarms = atmosphere_alarm.minor_alarms() if(alarms.len) icon_screen = "alert:1" else icon_screen = initial(icon_screen) ..() -/obj/machinery/computer/atmos_alert/Topic(href, href_list) +/obj/machinery/computer/atmos_alert/ui_act(action, params) if(..()) - return 1 + return TRUE - if(href_list["clear_alarm"]) - var/datum/alarm/alarm = locate(href_list["clear_alarm"]) in SSalarms.atmosphere_alarm.alarms - if(alarm) - for(var/datum/alarm_source/alarm_source in alarm.sources) - var/obj/machinery/alarm/air_alarm = alarm_source.source - if(istype(air_alarm)) - var/list/new_ref = list("atmos_reset" = 1) - air_alarm.Topic(href, new_ref, state = air_alarm_topic) - return 1 - - -var/datum/topic_state/air_alarm_topic/air_alarm_topic = new() - -/datum/topic_state/air_alarm_topic/href_list(var/mob/user) - var/list/extra_href = list() - extra_href["remote_connection"] = 1 - extra_href["remote_access"] = 1 - - return extra_href + switch(action) + if("clear") + var/datum/alarm/alarm = locate(params["ref"]) in atmosphere_alarm.alarms + if(alarm) + for(var/datum/alarm_source/alarm_source in alarm.sources) + var/obj/machinery/alarm/air_alarm = alarm_source.source + if(istype(air_alarm)) + // I have to leave a note here: + // Once upon a time, this called air_alarm.Topic() with a custom topic state + // in order to perform three lines of code. In other words, pure insanity. + // Whyyyyyyyyyyyyyyyyyyyyyyy. + air_alarm.atmos_reset() + . = TRUE + update_icon() diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm index d54cf47476f..f3102ec982c 100644 --- a/code/game/machinery/computer/atmos_control.dm +++ b/code/game/machinery/computer/atmos_control.dm @@ -7,12 +7,12 @@ icon_keyboard = "generic_key" icon_screen = "comm_logs" light_color = "#00b000" - density = 1 - anchored = 1.0 + density = TRUE + anchored = TRUE circuit = /obj/item/circuitboard/atmoscontrol req_access = list(access_ce) var/list/monitored_alarm_ids = null - var/datum/nano_module/atmos_control/atmos_control + var/datum/tgui_module/atmos_control/atmos_control /obj/machinery/computer/atmoscontrol/laptop name = "Atmospherics Laptop" @@ -20,25 +20,25 @@ icon_screen = "atmoslaptop" icon_state = "laptop" icon_keyboard = "laptop_key" - density = 0 + density = FALSE /obj/machinery/computer/atmoscontrol/attack_ai(var/mob/user as mob) - nano_ui_interact(user) + ui_interact(user) /obj/machinery/computer/atmoscontrol/attack_hand(mob/user) if(..()) - return 1 - nano_ui_interact(user) + return TRUE + ui_interact(user) /obj/machinery/computer/atmoscontrol/emag_act(var/remaining_carges, var/mob/user) if(!emagged) - user.visible_message("\The [user] does something \the [src], causing the screen to flash!",\ - "You cause the screen to flash as you gain full control.",\ + user.visible_message(SPAN_WARNING("\The [user] does something \the [src], causing the screen to flash!"),\ + SPAN_WARNING("You cause the screen to flash as you gain full control."),\ "You hear an electronic warble.") - atmos_control.emagged = 1 - return 1 + atmos_control.emagged = TRUE + return TRUE -/obj/machinery/computer/atmoscontrol/nano_ui_interact(var/mob/user) +/obj/machinery/computer/atmoscontrol/ui_interact(var/mob/user) if(!atmos_control) atmos_control = new(src, req_access, req_one_access, monitored_alarm_ids) - atmos_control.nano_ui_interact(user) + atmos_control.ui_interact(user) diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 6224bcd535d..16497d3c1dc 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -6,162 +6,225 @@ light_color = "#a97faa" req_access = list(access_robotics) circuit = /obj/item/circuitboard/robotics + var/safety = TRUE /obj/machinery/computer/robotics/attack_ai(var/mob/user as mob) - nano_ui_interact(user) + ui_interact(user) /obj/machinery/computer/robotics/attack_hand(var/mob/user as mob) - nano_ui_interact(user) - -/obj/machinery/computer/robotics/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - data["robots"] = get_cyborgs(user) - data["is_ai"] = issilicon(user) - - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "robot_control.tmpl", "Robotic Control Console", 400, 500) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/computer/robotics/Topic(href, href_list) if(..()) return - var/mob/user = usr - if(!src.allowed(user)) - to_chat(user, "Access Denied") + if(stat & (NOPOWER|BROKEN)) return + ui_interact(user) - // Locks or unlocks the cyborg - if (href_list["lockdown"]) - var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["lockdown"]) - var/failmsg = "" - if(!target || !istype(target)) - return +/obj/machinery/computer/robotics/proc/is_authenticated(mob/user) + if(!istype(user)) + return FALSE + if(isobserver(user)) + var/mob/observer/dead/D = user + if(D.can_admin_interact()) + return TRUE + if(allowed(user)) + return TRUE + return FALSE - if(isAI(user) && (target.connected_ai != user)) - to_chat(user, "Access Denied. This robot is not linked to you.") - return +/** + * Does this borg show up in the console + * + * Returns TRUE if a robot will show up in the console + * Returns FALSE if a robot will not show up in the console + * Arguments: + * * R - The [mob/living/silicon/robot] to be checked + */ +/obj/machinery/computer/robotics/proc/console_shows(mob/living/silicon/robot/R) + if(!istype(R)) + return FALSE + if(istype(R, /mob/living/silicon/robot/drone)) + return FALSE + if(R.scrambledcodes) + return FALSE + if(!AreConnectedZLevels(get_z(src), get_z(R))) + return FALSE + return TRUE - if(isrobot(user)) - to_chat(user, "Access Denied.") - return +/** + * Check if a user can send a lockdown/detonate command to a specific borg + * + * Returns TRUE if a user can send the command (does not guarantee it will work) + * Returns FALSE if a user cannot + * Arguments: + * * user - The [mob/user] to be checked + * * R - The [mob/living/silicon/robot] to be checked + * * telluserwhy - Bool of whether the user should be sent a to_chat message if they don't have access + */ +/obj/machinery/computer/robotics/proc/can_control(mob/user, mob/living/silicon/robot/R, telluserwhy = FALSE) + if(!istype(user)) + return FALSE + if(!console_shows(R)) + return FALSE + if(isAI(user)) + if(R.connected_ai != user) + if(telluserwhy) + to_chat(user, SPAN_WARNING("AIs can only control cyborgs which are linked to them.")) + return FALSE + if(isrobot(user)) + if(R != user) + if(telluserwhy) + to_chat(user, SPAN_WARNING("Cyborgs cannot control other cyborgs.")) + return FALSE + return TRUE - var/choice = input("Really [target.lockcharge ? "unlock" : "lockdown"] [target.name] ?") in list ("Yes", "No") - if(choice != "Yes") - return +/** + * Check if the user is the right kind of entity to be able to hack borgs + * + * Returns TRUE if a user is a traitor AI, or aghost + * Returns FALSE otherwise + * Arguments: + * * user - The [mob/user] to be checked + */ +/obj/machinery/computer/robotics/proc/can_hack_any(mob/user) + if(!istype(user)) + return FALSE + if(isobserver(user)) + var/mob/observer/dead/D = user + if(D.can_admin_interact()) + return TRUE + if(!isAI(user)) + return FALSE + return (user.mind.special_role && user.mind.original == user) - if(!target || !istype(target)) - return - - var/istraitor = target.mind.special_role - if (istraitor) - failmsg = "failed (target is traitor) " - target.lockcharge = !target.lockcharge - if (target.lockcharge) - to_chat(target, "Someone tried to lock you down!") - else - to_chat(target, "Someone tried to lift your lockdown!") - else if (target.emagged) - failmsg = "failed (target is hacked) " - target.lockcharge = !target.lockcharge - if (target.lockcharge) - to_chat(target, "Someone tried to lock you down!") - else - to_chat(target, "Someone tried to lift your lockdown!") - else - target.canmove = !target.canmove - target.lockcharge = !target.canmove //when canmove is 1, lockcharge should be 0 - target.lockdown = !target.canmove - if (target.lockcharge) - to_chat(target, "You have been locked down!") - else - to_chat(target, "Your lockdown has been lifted!") - message_admins("[key_name_admin(usr)] [failmsg][target.lockcharge ? "lockdown" : "release"] on [target.name]!") - log_game("[key_name(usr)] attempted to [target.lockcharge ? "lockdown" : "release"] [target.name] on the robotics console!") +/** + * Check if the user is allowed to hack a specific borg + * + * Returns TRUE if a user can hack the specific cyborg + * Returns FALSE if a user cannot + * Arguments: + * * user - The [mob/user] to be checked + * * R - The [mob/living/silicon/robot] to be checked + */ +/obj/machinery/computer/robotics/proc/can_hack(mob/user, mob/living/silicon/robot/R) + if(!can_hack_any(user)) + return FALSE + if(!istype(R)) + return FALSE + if(R.emagged) + return FALSE + if(R.connected_ai != user) + return FALSE + return TRUE - // Remotely hacks the cyborg. Only antag AIs can do this and only to linked cyborgs. - else if (href_list["hack"]) - var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["hack"]) - if(!target || !istype(target)) - return - - // Antag synthetic checks - if(!istype(user, /mob/living/silicon) || !(user.mind.special_role && user.mind.original == user)) - to_chat(user, "Access Denied") - return - - if(target.emagged) - to_chat(user, "Robot is already hacked.") - return - - var/choice = input("Really hack [target.name]? This cannot be undone.") in list("Yes", "No") - if(choice != "Yes") - return - - if(!target || !istype(target)) - return - - message_admins("[key_name_admin(usr)] emagged [target.name] using the robotic console!") - log_game("[key_name(usr)] emagged [target.name] using robotic console!") - target.emagged = 1 - to_chat(target, "Failsafe protocols overriden. New tools available.") - - -// Proc: get_cyborgs() -// Parameters: 1 (operator - mob which is operating the console.) -// Description: Returns NanoUI-friendly list of accessible cyborgs. -/obj/machinery/computer/robotics/proc/get_cyborgs(var/mob/operator) - var/list/robots = list() +/obj/machinery/computer/robotics/ui_interact(mob/user, datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "RoboticsControlConsole", name) + ui.open() +/obj/machinery/computer/robotics/ui_data(mob/user) + var/list/data = list() + data["auth"] = is_authenticated(user) + data["can_hack"] = can_hack_any(user) + data["cyborgs"] = list() + data["safety"] = safety for(var/mob/living/silicon/robot/R in GLOB.mob_list) - // Ignore drones - if(istype(R, /mob/living/silicon/robot/drone)) - continue - // Ignore antagonistic cyborgs - if(R.scrambledcodes) + if(!console_shows(R)) continue + var/area/A = get_area(R) + var/turf/T = get_turf(R) + var/list/cyborg_data = list( + name = R.name, + ref = REF(R), + locked_down = R.lockcharge, + locstring = "[A.name] ([T.x], [T.y])", + status = R.stat, + health = round(R.health * 100 / R.maxHealth, 0.1), + charge = R.cell ? round(R.cell.percent()) : null, + cell_capacity = R.cell ? R.cell.maxcharge : null, + module = R.module ? R.module.name : "No Module Detected", + synchronization = R.connected_ai, + is_hacked = R.connected_ai && R.emagged, + hackable = can_hack(user, R), + ) + data["cyborgs"] += list(cyborg_data) + data["show_detonate_all"] = (data["auth"] && length(data["cyborgs"]) > 0 && ishuman(user)) + return data - var/list/robot = list() - robot["name"] = R.name - if(R.stat) - robot["status"] = "Not Responding" - else if (R.lockcharge) - robot["status"] = "Lockdown" - else - robot["status"] = "Operational" - - if(R.cell) - robot["cell"] = 1 - robot["cell_capacity"] = R.cell.maxcharge - robot["cell_current"] = R.cell.charge - robot["cell_percentage"] = round(R.cell.percent()) - else - robot["cell"] = 0 - - robot["module"] = R.module ? R.module.name : "None" - robot["master_ai"] = R.connected_ai ? R.connected_ai.name : "None" - robot["hackable"] = 0 - //Antag synths should be able to hack themselves and see their hacked status. - if(operator && isrobot(operator) && (operator.mind.special_role && operator.mind.original == operator) && (operator == R)) - robot["hacked"] = R.emagged ? 1 : 0 - robot["hackable"] = R.emagged? 0 : 1 - // Antag AIs know whether linked cyborgs are hacked or not. - if(operator && isAI(operator) && (R.connected_ai == operator) && (operator.mind.special_role && operator.mind.original == operator)) - robot["hacked"] = R.emagged ? 1 : 0 - robot["hackable"] = R.emagged? 0 : 1 - robots.Add(list(robot)) - return robots - -// Proc: get_cyborg_by_name() -// Parameters: 1 (name - Cyborg we are trying to find) -// Description: Helper proc for finding cyborg by name -/obj/machinery/computer/robotics/proc/get_cyborg_by_name(var/name) - if (!name) +/obj/machinery/computer/robotics/ui_act(action, params) + if(..()) + return TRUE + . = FALSE + if(!is_authenticated(usr)) + to_chat(usr, SPAN_WARNING("Access denied.")) return - for(var/mob/living/silicon/robot/R in GLOB.mob_list) - if(R.name == name) - return R + switch(action) + if("arm") //Arms the emergency self-destruct system + if(issilicon(usr)) + to_chat(usr, SPAN_DANGER("Access Denied (silicon detected)")) + return + safety = !safety + to_chat(usr, SPAN_NOTICE("You [safety ? "disarm" : "arm"] the emergency self destruct.")) + . = TRUE + if("nuke") // Destroys all accessible cyborgs if safety is disabled + if(issilicon(usr)) + to_chat(usr, SPAN_DANGER("Access Denied (silicon detected)")) + return + if(safety) + to_chat(usr, SPAN_DANGER("Self-destruct aborted - safety active")) + return + message_admins(SPAN_NOTICE("[key_name_admin(usr)] detonated all cyborgs!")) + log_game(SPAN_NOTICE("[key_name(usr)] detonated all cyborgs!")) + for(var/mob/living/silicon/robot/R in GLOB.mob_list) + if(istype(R, /mob/living/silicon/robot/drone)) + continue + // Ignore antagonistic cyborgs + if(R.scrambledcodes) + continue + to_chat(R, SPAN_DANGER("Self-destruct command received.")) + if(R.connected_ai) + to_chat(R.connected_ai, SPAN_ALERT("

ALERT - Cyborg detonation detected: [R.name]
")) + R.self_destruct() + . = TRUE + if("killbot") // destroys one specific cyborg + var/mob/living/silicon/robot/R = locate(params["ref"]) + if(!can_control(usr, R, TRUE)) + return + if(R.mind && R.mind.special_role && R.emagged) + to_chat(R, SPAN_USERDANGER("Extreme danger! Termination codes detected. Scrambling security codes and automatic AI unlink triggered.")) + R.ResetSecurityCodes() + . = TRUE + return + var/turf/T = get_turf(R) + message_admins(SPAN_NOTICE("[key_name_admin(usr)] detonated [key_name_admin(R)] ([ADMIN_COORDJMP(T)])!")) + log_game(SPAN_NOTICE("[key_name(usr)] detonated [key_name(R)]!")) + to_chat(R, SPAN_DANGER("Self-destruct command received.")) + if(R.connected_ai) + to_chat(R.connected_ai, SPAN_ALERT("

ALERT - Cyborg detonation detected: [R.name]
")) + R.self_destruct() + . = TRUE + if("stopbot") // lock or unlock the borg + if(isrobot(usr)) + to_chat(usr, SPAN_DANGER("Access Denied.")) + return + var/mob/living/silicon/robot/R = locate(params["ref"]) + if(!can_control(usr, R, TRUE)) + return + message_admins(SPAN_NOTICE("[ADMIN_LOOKUPFLW(usr)] [!R.lockcharge ? "locked down" : "released"] [ADMIN_LOOKUPFLW(R)]!")) + log_game("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)]!") + R.SetLockdown(!R.lockcharge) + to_chat(R, (!R.lockcharge ? SPAN_NOTICE("Your lockdown has been lifted!") : SPAN_ALERT("You have been locked down!"))) + if(R.connected_ai) + to_chat(R.connected_ai, "[!R.lockcharge ? SPAN_NOTICE("NOTICE - Cyborg lockdown lifted") : SPAN_ALERT("ALERT - Cyborg lockdown detected")]: [R.name]

") + . = TRUE + if("hackbot") // AIs hacking/emagging a borg + var/mob/living/silicon/robot/R = locate(params["ref"]) + if(!can_hack(usr, R)) + return + var/choice = input("Really hack [R.name]? This cannot be undone.") in list("Yes", "No") + if(choice != "Yes") + return + log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!") + message_admins(SPAN_NOTICE("[key_name_admin(usr)] emagged [key_name_admin(R)] using robotic console!")) + R.emagged = TRUE + to_chat(R, SPAN_NOTICE("Failsafe protocols overriden. New tools available.")) + . = TRUE diff --git a/code/game/machinery/computer/shutoff_monitor.dm b/code/game/machinery/computer/shutoff_monitor.dm index dc21f911793..a979a6f32e0 100644 --- a/code/game/machinery/computer/shutoff_monitor.dm +++ b/code/game/machinery/computer/shutoff_monitor.dm @@ -2,41 +2,26 @@ name = "automated shutoff valve monitor" desc = "Console used to remotely monitor shutoff valves on the station." icon_keyboard = "power_key" - icon_screen = "power:0" + icon_screen = "power_monitor" light_color = "#a97faa" circuit = /obj/item/circuitboard/shutoff_monitor + var/datum/tgui_module/shutoff_monitor/monitor -/obj/machinery/computer/shutoff_monitor/attack_hand(var/mob/user) +/obj/machinery/computer/shutoff_monitor/New() ..() - nano_ui_interact(user) + ui_interact(user) -/obj/machinery/computer/shutoff_monitor/attack_robot(var/mob/user) // Borgs and AI will want to see this too +/obj/machinery/computer/shutoff_monitor/Destroy() + QDEL_NULL(monitor) ..() - nano_ui_interact(user) -/obj/machinery/computer/shutoff_monitor/attack_ai(var/mob/user) - nano_ui_interact(user) - -/obj/machinery/computer/shutoff_monitor/nano_ui_interact(mob/user, ui_key = "shutoff_monitor", var/datum/nanoui/ui = null, var/force_open = 1, var/key_state = null) - var/data[0] - data["valves"] = list() - for(var/obj/machinery/atmospherics/valve/shutoff/S in GLOB.shutoff_valves) - data["valves"][++data["valves"].len] = list("name" = S.name, "enable" = S.close_on_leaks, "open" = S.open, "x" = S.x, "y" = S.y, "z" = S.z) - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "shutoff_monitor.tmpl", "Automated Shutoff Valve Monitor", 625, 700, state = key_state) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every 20 Master Controller tick - ui.set_auto_update(20) // Longer term to reduce the rate of data collection and processing +/obj/machinery/computer/shutoff_monitor/attack_hand(var/mob/user as mob) + ..() + monitor.ui_interact(user) /obj/machinery/computer/shutoff_monitor/update_icon() ..() if(!(stat & (NOPOWER|BROKEN))) - overlays += image('icons/obj/computer.dmi', "ai-fixer-empty", overlay_layer) + add_overlay("ai-fixer-empty") + else + cut_overlay("ai-fixer-empty") diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm index 6ee31449395..cb44140d077 100644 --- a/code/game/machinery/computer/station_alert.dm +++ b/code/game/machinery/computer/station_alert.dm @@ -6,15 +6,15 @@ icon_screen = "alert:0" light_color = "#e6ffff" circuit = /obj/item/circuitboard/stationalert_engineering - var/datum/nano_module/alarm_monitor/alarm_monitor - var/monitor_type = /datum/nano_module/alarm_monitor/engineering + var/datum/tgui_module/alarm_monitor/alarm_monitor + var/monitor_type = /datum/tgui_module/alarm_monitor/engineering /obj/machinery/computer/station_alert/security - monitor_type = /datum/nano_module/alarm_monitor/security + monitor_type = /datum/tgui_module/alarm_monitor/security circuit = /obj/item/circuitboard/stationalert_security /obj/machinery/computer/station_alert/all - monitor_type = /datum/nano_module/alarm_monitor/all + monitor_type = /datum/tgui_module/alarm_monitor/all circuit = /obj/item/circuitboard/stationalert_all /obj/machinery/computer/station_alert/Initialize(mapload) @@ -31,18 +31,18 @@ add_fingerprint(user) if(stat & (BROKEN|NOPOWER)) return - interact(user) + ui_interact(user) return /obj/machinery/computer/station_alert/attack_hand(mob/user) add_fingerprint(user) if(stat & (BROKEN|NOPOWER)) return - interact(user) + ui_interact(user) return -/obj/machinery/computer/station_alert/interact(mob/user) - alarm_monitor.nano_ui_interact(user) +/obj/machinery/computer/station_alert/ui_interact(mob/user) + alarm_monitor.ui_interact(user) /obj/machinery/computer/station_alert/update_icon() if(!(stat & (BROKEN|NOPOWER))) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 1406e5fb797..85cd25706bb 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -79,7 +79,7 @@ var/mob/living/carbon/human/X = user if(istype(X.species, /datum/species/xenos)) if(src.locked || src.welded) - visible_message("\The [user] begins digging into \the [src] internals!") + visible_message("\The [user] begins digging into \the [src] internals!") src.do_animate("deny") if(do_after(user,5 SECONDS,src)) visible_message("\The [user] forces \the [src] open, sparks flying from its electronics!") @@ -91,7 +91,7 @@ open(1) src.emag_act() else if(src.density) - visible_message("\The [user] begins forcing \the [src] open!") + visible_message("\The [user] begins forcing \the [src] open!") if(do_after(user, 5 SECONDS,src)) playsound(src.loc, 'sound/machines/airlock_creaking.ogg', 100, 1) visible_message("\The [user] forces \the [src] open!") @@ -838,32 +838,52 @@ About the new airlock wires panel: return /obj/machinery/door/airlock/attack_ai(mob/user as mob) - nano_ui_interact(user) + ui_interact(user) -/obj/machinery/door/airlock/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) - var/data[0] +/obj/machinery/door/airlock/attack_ghost(mob/user) + ui_interact(user) - data["main_power_loss"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) - data["backup_power_loss"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1) - data["electrified"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1) - data["open"] = !density - - var/commands[0] - commands[++commands.len] = list("name" = "IdScan", "command"= "idscan", "active" = !aiDisabledIdScanner, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) - commands[++commands.len] = list("name" = "Bolts", "command"= "bolts", "active" = !locked, "enabled" = "Raised ", "disabled" = "Dropped", "danger" = 0, "act" = 0) - commands[++commands.len] = list("name" = "Bolt Lights", "command"= "lights", "active" = lights, "enabled" = "Enabled", "disabled" = "Disable", "danger" = 0, "act" = 1) - commands[++commands.len] = list("name" = "Safeties", "command"= "safeties", "active" = safe, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) - commands[++commands.len] = list("name" = "Timing", "command"= "timing", "active" = normalspeed, "enabled" = "Nominal", "disabled" = "Overridden", "danger" = 1, "act" = 0) - commands[++commands.len] = list("name" = "Door State", "command"= "open", "active" = density, "enabled" = "Closed", "disabled" = "Opened", "danger" = 0, "act" = 0) - - data["commands"] = commands - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "door_control.tmpl", "Door Controls", 450, 350, state = state) - ui.set_initial_data(data) +/obj/machinery/door/airlock/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AiAirlock", name) ui.open() - ui.set_auto_update(1) + return TRUE + +/obj/machinery/door/airlock/ui_data(mob/user) + var/list/data = list() + + var/list/power = list() + power["main"] = main_power_lost_until > 0 ? 0 : 2 + power["main_timeleft"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1) + power["backup"] = backup_power_lost_until > 0 ? 0 : 2 + power["backup_timeleft"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1) + data["power"] = power + + data["shock"] = (electrified_until == 0) ? 2 : 0 + data["shock_timeleft"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1) + data["id_scanner"] = !aiDisabledIdScanner + data["locked"] = locked // bolted + data["lights"] = lights // bolt lights + data["safe"] = safe // safeties + data["speed"] = normalspeed // safe speed + data["welded"] = welded // welded + data["opened"] = !density // opened + + var/list/wire = list() + wire["main_1"] = !wires.is_cut(WIRE_MAIN_POWER1) + wire["main_2"] = !wires.is_cut(WIRE_MAIN_POWER2) + wire["backup_1"] = !wires.is_cut(WIRE_BACKUP_POWER1) + wire["backup_2"] = !wires.is_cut(WIRE_BACKUP_POWER2) + wire["shock"] = !wires.is_cut(WIRE_ELECTRIFY) + wire["id_scanner"] = !wires.is_cut(WIRE_IDSCAN) + wire["bolts"] = !wires.is_cut(WIRE_DOOR_BOLTS) + wire["lights"] = !wires.is_cut(WIRE_BOLT_LIGHT) + wire["safe"] = !wires.is_cut(WIRE_SAFETY) + wire["timing"] = !wires.is_cut(WIRE_SPEED) + + data["wires"] = wire + return data /obj/machinery/door/airlock/proc/hack(mob/user as mob) if(src.aiHacking==0) @@ -944,79 +964,105 @@ About the new airlock wires panel: ..(user) return -/obj/machinery/door/airlock/CanUseTopic(var/mob/user) - if(operating < 0) //emagged - to_chat(user, "Unable to interface: Internal error.") - return UI_CLOSE - if(issilicon(user) && !src.canAIControl()) - if(src.canAIHack(user)) - src.hack(user) - else - if (src.isAllPowerLoss()) //don't really like how this gets checked a second time, but not sure how else to do it. - to_chat(user, "Unable to interface: Connection timed out.") - else - to_chat(user, "Unable to interface: Connection refused.") - return UI_CLOSE - - return ..() - -/obj/machinery/door/airlock/Topic(href, href_list) +/obj/machinery/door/airlock/ui_act(action, params) if(..()) - return 1 + return TRUE + if(!user_allowed(usr)) + return TRUE - var/activate = text2num(href_list["activate"]) - switch (href_list["command"]) - if("idscan") - set_idscan(activate, 1) - if("main_power") + switch(action) + if("disrupt-main") if(!main_power_lost_until) - src.loseMainPower() - if("backup_power") + loseMainPower() + update_icon() + else + to_chat(usr, SPAN_WARNING("Main power is already offline.")) + . = TRUE + if("disrupt-backup") if(!backup_power_lost_until) - src.loseBackupPower() - if("bolts") - if(wires.is_cut(WIRE_DOOR_BOLTS)) - to_chat(usr, "The door bolt control wire is cut - Door bolts permanently dropped.") - else if(activate && src.lock()) - to_chat(usr, "The door bolts have been dropped.") - else if(!activate && src.unlock()) - to_chat(usr, "The door bolts have been raised.") - if("electrify_temporary") - electrify(30 * activate, 1) - if("electrify_permanently") - electrify(-1 * activate, 1) - if("open") - if(src.welded) - to_chat(usr, "The airlock has been welded shut!") - else if(src.locked) - to_chat(usr, "The door bolts are down!") - else if(activate && density) - open() - else if(!activate && !density) - close() - if("safeties") - set_safeties(!activate, 1) - if("timing") - // Door speed control - if(wires.is_cut(WIRE_SPEED)) - to_chat(usr, "The timing wire is cut - Cannot alter timing.") - else if (activate && src.normalspeed) - normalspeed = 0 - else if (!activate && !src.normalspeed) - normalspeed = 1 - if("lights") - // Bolt lights + loseBackupPower() + update_icon() + else + to_chat(usr, SPAN_WARNING("Backup power is already offline.")) + . = TRUE + if("shock-restore") + electrify(0, 1) + . = TRUE + if("shock-temp") + electrify(30, 1) + . = TRUE + if("shock-perm") + electrify(-1, 1) + . = TRUE + if("idscan-toggle") + set_idscan(aiDisabledIdScanner, 1) + . = TRUE + // if("emergency-toggle") + // toggle_emergency(usr) + // . = TRUE + if("bolt-toggle") + toggle_bolt(usr) + . = TRUE + if("light-toggle") if(wires.is_cut(WIRE_BOLT_LIGHT)) to_chat(usr, "The bolt lights wire is cut - The door bolt lights are permanently disabled.") - else if (!activate && src.lights) - lights = 0 - to_chat(usr, "The door bolt lights have been disabled.") - else if (activate && !src.lights) - lights = 1 - to_chat(usr, "The door bolt lights have been enabled.") + return + lights = !lights + update_icon() + . = TRUE + if("safe-toggle") + set_safeties(!safe, 1) + . = TRUE + if("speed-toggle") + if(wires.is_cut(WIRE_SPEED)) + to_chat(usr, "The timing wire is cut - Cannot alter timing.") + return + normalspeed = !normalspeed + . = TRUE + if("open-close") + user_toggle_open(usr) + . = TRUE update_icon() - return 1 + return TRUE + +/obj/machinery/door/airlock/proc/user_allowed(mob/user) + var/allowed = (issilicon(user) && canAIControl(user)) + if(!allowed && isobserver(user)) + var/mob/observer/dead/D = user + if(D.can_admin_interact()) + allowed = TRUE + return allowed + +/obj/machinery/door/airlock/proc/toggle_bolt(mob/user) + if(!user_allowed(user)) + return + if(wires.is_cut(WIRE_DOOR_BOLTS)) + to_chat(user, SPAN_WARNING("The door bolt drop wire is cut - you can't toggle the door bolts.")) + return + if(locked) + if(!arePowerSystemsOn()) + to_chat(user, SPAN_WARNING("The door has no power - you can't raise the door bolts.")) + else + unlock() + to_chat(user, SPAN_NOTICE("The door bolts have been raised.")) + // log_combat(user, src, "unbolted") + else + lock() + to_chat(user, SPAN_WARNING("The door bolts have been dropped.")) + // log_combat(user, src, "bolted") + +/obj/machinery/door/airlock/proc/user_toggle_open(mob/user) + if(!user_allowed(user)) + return + if(welded) + to_chat(user, SPAN_WARNING("The airlock has been welded shut!")) + else if(locked) + to_chat(user, SPAN_WARNING("The door bolts are down!")) + else if(!density) + close() + else + open() /obj/machinery/door/airlock/proc/can_remove_electronics() return src.p_open && (operating < 0 || (!operating && welded && !src.arePowerSystemsOn() && density && (!src.locked || (stat & BROKEN)))) @@ -1298,12 +1344,6 @@ About the new airlock wires panel: update_icon() return 1 -/obj/machinery/door/airlock/proc/toggle_bolt(var/forced=0)//Toggles bolts either up or down - if(locked) - unlock(forced)//checks for ligitamacy run here - else - lock(forced)//checks for ligitamacy run here - /obj/machinery/door/airlock/allowed(mob/M) if(locked) return 0 diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm index 2c9481934a8..b68b78a957d 100644 --- a/code/game/machinery/doors/blast_door.dm +++ b/code/game/machinery/doors/blast_door.dm @@ -192,13 +192,13 @@ var/mob/living/carbon/human/X = user if(istype(X.species, /datum/species/xenos)) if(src.density) - visible_message("\The [user] begins forcing \the [src] open!") + visible_message("\The [user] begins forcing \the [src] open!") if(do_after(user, 15 SECONDS,src)) playsound(src.loc, 'sound/machines/airlock_creaking.ogg', 100, 1) visible_message("\The [user] forces \the [src] open!") force_open(1) else - visible_message("\The [user] begins forcing \the [src] closed!") + visible_message("\The [user] begins forcing \the [src] closed!") if(do_after(user, 5 SECONDS,src)) playsound(src.loc, 'sound/machines/airlock_creaking.ogg', 100, 1) visible_message("\The [user] forces \the [src] closed!") diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 0674eaef8ce..62104460d1f 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -194,14 +194,14 @@ var/mob/living/carbon/human/X = user if(istype(X.species, /datum/species/xenos)) if(src.blocked) - visible_message("\The [user] begins digging into \the [src] internals!") + visible_message("\The [user] begins digging into \the [src] internals!") if(do_after(user,5 SECONDS,src)) playsound(src.loc, 'sound/machines/airlock_creaking.ogg', 100, 1) src.blocked = 0 update_icon() open(1) else if(src.density) - visible_message("\The [user] begins forcing \the [src] open!") + visible_message("\The [user] begins forcing \the [src] open!") if(do_after(user, 2 SECONDS,src)) playsound(src.loc, 'sound/machines/airlock_creaking.ogg', 100, 1) visible_message("\The [user] forces \the [src] open!") diff --git a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm index 0992a9bdbd2..2dd89d8e136 100644 --- a/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm +++ b/code/game/machinery/embedded_controller/airlock_docking_controller_multi.dm @@ -30,7 +30,7 @@ ) /obj/machinery/embedded_controller/radio/docking_port_multi/ui_act(action, params) - return // Apparently we swallow all input (this is corrected legacy code) + return //Apparently we swallow all input (this is corrected legacy code) //a docking port based on an airlock // This is the actual controller that will be commanded by the master defined above diff --git a/code/game/machinery/exonet_node.dm b/code/game/machinery/exonet_node.dm index 7f250db5882..0da8d9e07e3 100644 --- a/code/game/machinery/exonet_node.dm +++ b/code/game/machinery/exonet_node.dm @@ -4,17 +4,17 @@ icon = 'icons/obj/stationobjs.dmi' icon_state = "exonet_node" idle_power_usage = 2500 - density = 1 - var/on = 1 - var/toggle = 1 + density = TRUE + var/on = TRUE + var/toggle = TRUE - var/allow_external_PDAs = 1 - var/allow_external_communicators = 1 - var/allow_external_newscasters = 1 + var/allow_external_PDAs = TRUE + var/allow_external_communicators = TRUE + var/allow_external_newscasters = TRUE - var/opened = 0 - - var/list/logs = list() // Gets written to by exonet's send_message() function. + var/opened = FALSE + ///Gets written to by exonet's send_message() function. + var/list/logs = list() circuit = /obj/item/circuitboard/telecomms/exonet_node // Proc: New() @@ -103,17 +103,25 @@ // Proc: attack_hand() // Parameters: 1 (user - the person clicking on the machine) -// Description: Opens the NanoUI interface with nano_ui_interact() +// Description: Opens the TGUI interface with ui_interact() /obj/machinery/exonet_node/attack_hand(mob/user) - nano_ui_interact(user) + ui_interact(user) -// Proc: nano_ui_interact() -// Parameters: 4 (standard NanoUI arguments) +// Proc: ui_interact() +// Parameters: 2 (user - person interacting with the UI, ui - the UI itself, in a refresh) +// Description: Handles opening the TGUI interface +/obj/machinery/exonet_node/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ExonetNode", src) + ui.open() + +// Proc: ui_data() +// Parameters: 1 (user - the person using the interface) // Description: Allows the user to turn the machine on or off, or open or close certain 'ports' for things like external PDA messages, newscasters, etc. -/obj/machinery/exonet_node/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/exonet_node/ui_data(mob/user) // this is the data which will be sent to the ui - var/data[0] - + var/list/data = list() data["on"] = toggle ? 1 : 0 data["allowPDAs"] = allow_external_PDAs @@ -121,53 +129,46 @@ data["allowNewscasters"] = allow_external_newscasters data["logs"] = logs + return data - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "exonet_node.tmpl", "Exonet Node #157", 400, 400) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) - -// Proc: Topic() -// Parameters: 2 (standard Topic arguments) -// Description: Responds to button presses on the NanoUI interface. -/obj/machinery/exonet_node/Topic(href, href_list) +// Proc: ui_act() +// Parameters: 2 (standard ui_act arguments) +// Description: Responds to button presses on the TGUI interface. +/obj/machinery/exonet_node/ui_act(action, params) if(..()) - return 1 - if(href_list["toggle_power"]) - toggle = !toggle - update_power() - if(!toggle) - var/msg = "[usr.client.key] ([usr]) has turned [src] off, at [x],[y],[z]." - message_admins(msg) - log_game(msg) + return TRUE - if(href_list["toggle_PDA_port"]) - allow_external_PDAs = !allow_external_PDAs + switch(action) + if("toggle_power") + . = TRUE + toggle = !toggle + update_power() + if(!toggle) + var/msg = "[usr.client.key] ([usr]) has turned [src] off, at [x],[y],[z]." + message_admins(msg) + log_game(msg) - if(href_list["toggle_communicator_port"]) - allow_external_communicators = !allow_external_communicators - if(!allow_external_communicators) - var/msg = "[usr.client.key] ([usr]) has turned [src]'s communicator port off, at [x],[y],[z]." - message_admins(msg) - log_game(msg) + if("toggle_PDA_port") + . = TRUE + allow_external_PDAs = !allow_external_PDAs - if(href_list["toggle_newscaster_port"]) - allow_external_newscasters = !allow_external_newscasters - if(!allow_external_newscasters) - var/msg = "[usr.client.key] ([usr]) has turned [src]'s newscaster port off, at [x],[y],[z]." - message_admins(msg) - log_game(msg) + if("toggle_communicator_port") + . = TRUE + allow_external_communicators = !allow_external_communicators + if(!allow_external_communicators) + var/msg = "[usr.client.key] ([usr]) has turned [src]'s communicator port off, at [x],[y],[z]." + message_admins(msg) + log_game(msg) + + if("toggle_newscaster_port") + . = TRUE + allow_external_newscasters = !allow_external_newscasters + if(!allow_external_newscasters) + var/msg = "[usr.client.key] ([usr]) has turned [src]'s newscaster port off, at [x],[y],[z]." + message_admins(msg) + log_game(msg) update_icon() - SSnanoui.update_uis(src) add_fingerprint(usr) // Proc: get_exonet_node() diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm new file mode 100644 index 00000000000..e9fe69de3ea --- /dev/null +++ b/code/game/machinery/fire_alarm.dm @@ -0,0 +1,323 @@ +/* +FIRE ALARM +*/ +/obj/machinery/firealarm + name = "fire alarm" + desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever." + icon = 'icons/obj/monitors.dmi' + icon_state = "fire0" + plane = TURF_PLANE + layer = ABOVE_TURF_LAYER + var/detecting = 1.0 + var/working = 1.0 + var/time = 10.0 + var/timing = 0.0 + var/lockdownbyai = 0 + anchored = 1.0 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 6 + power_channel = ENVIRON + var/last_process = 0 + panel_open = 0 + var/seclevel + circuit = /obj/item/circuitboard/firealarm + var/alarms_hidden = FALSE //If the alarms from this machine are visible on consoles + +/obj/machinery/firealarm/alarms_hidden + alarms_hidden = TRUE + +/obj/machinery/firealarm/Initialize() + . = ..() + if(z in GLOB.using_map.contact_levels) + set_security_level(security_level ? get_security_level() : "green") + +/obj/machinery/firealarm/update_icon() + cut_overlays() + + if(panel_open) + set_light(0) + return + + if(stat & BROKEN) + icon_state = "firex" + set_light(0) + else if(stat & NOPOWER) + icon_state = "firep" + set_light(0) + else + if(!detecting) + icon_state = "fire1" + set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000") + else + icon_state = "fire0" + switch(seclevel) + if("green") set_light(l_range = 2, l_power = 0.25, l_color = "#00ff00") + if("yellow") set_light(l_range = 2, l_power = 0.25, l_color = "#ffff00") + if("violet") set_light(l_range = 2, l_power = 0.25, l_color = "#9933ff") + if("orange") set_light(l_range = 2, l_power = 0.25, l_color = "#ff9900") + if("blue") set_light(l_range = 2, l_power = 0.25, l_color = "#1024A9") + if("red") set_light(l_range = 4, l_power = 0.9, l_color = "#ff0000") + if("delta") set_light(l_range = 4, l_power = 0.9, l_color = "#FF6633") + add_overlay("overlay_[seclevel]") + +/obj/machinery/firealarm/fire_act(datum/gas_mixture/air, temperature, volume) + if(detecting) + if(temperature > T0C + 200) + alarm() // added check of detector status here + return + +/obj/machinery/firealarm/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/firealarm/bullet_act() + return alarm() + +/obj/machinery/firealarm/emp_act(severity) + if(prob(50 / severity)) + alarm(rand(30 / severity, 60 / severity)) + ..() + +/obj/machinery/firealarm/attackby(obj/item/W as obj, mob/user as mob) + add_fingerprint(user) + + if(alarm_deconstruction_screwdriver(user, W)) + return + if(alarm_deconstruction_wirecutters(user, W)) + return + + if(panel_open) + if(istype(W, /obj/item/multitool)) + detecting = !(detecting) + if(detecting) + user.visible_message("\The [user] has reconnected [src]'s detecting unit!", "You have reconnected [src]'s detecting unit.") + else + user.visible_message("\The [user] has disconnected [src]'s detecting unit!", "You have disconnected [src]'s detecting unit.") + return + + alarm() + return + +/obj/machinery/firealarm/process()//Note: this processing was mostly phased out due to other code, and only runs when needed + if(stat & (NOPOWER|BROKEN)) + return + + if(timing) + if(time > 0) + time = time - ((world.timeofday - last_process) / 10) + else + alarm() + time = 0 + timing = 0 + STOP_PROCESSING(SSobj, src) + updateDialog() + last_process = world.timeofday + + if(locate(/obj/fire) in src.loc) + alarm() + + return + +/obj/machinery/firealarm/power_change() + ..() + spawn(rand(0,15)) + update_icon() + +/obj/machinery/firealarm/attack_hand(mob/user as mob) + if(user.stat || stat & (NOPOWER | BROKEN)) + return + + user.set_machine(src) + var/area/A = src.loc + var/d1 + var/d2 + if(istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon)) + A = A.loc + + if(A.fire) + d1 = text("Reset - Lockdown", src) + else + d1 = text("Alarm - Lockdown", src) + if(timing) + d2 = text("Stop Time Lock", src) + else + d2 = text("Initiate Time Lock", src) + var/second = round(time) % 60 + var/minute = (round(time) - second) / 60 + var/dat = "Fire alarm [d1]\n
The current alert level is: [get_security_level()]

\nTimer System: [d2]
\nTime Left: [(minute ? "[minute]:" : null)][second] - - + +\n
" + user << browse(dat, "window=firealarm") + onclose(user, "firealarm") + else + A = A.loc + if(A.fire) + d1 = text("[]", src, stars("Reset - Lockdown")) + else + d1 = text("[]", src, stars("Alarm - Lockdown")) + if(timing) + d2 = text("[]", src, stars("Stop Time Lock")) + else + d2 = text("[]", src, stars("Initiate Time Lock")) + var/second = round(time) % 60 + var/minute = (round(time) - second) / 60 + var/dat = "[stars("Fire alarm")] [d1]\n
The current alert level is: [stars(get_security_level())]

\nTimer System: [d2]
\nTime Left: [(minute ? text("[]:", minute) : null)][second] - - + +\n
" + user << browse(dat, "window=firealarm") + onclose(user, "firealarm") + return + +/obj/machinery/firealarm/Topic(href, href_list) + ..() + if(usr.stat || stat & (BROKEN | NOPOWER)) + return + + if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.set_machine(src) + if(href_list["reset"]) + reset() + else if(href_list["alarm"]) + alarm() + else if(href_list["time"]) + timing = text2num(href_list["time"]) + last_process = world.timeofday + START_PROCESSING(SSobj, src) + else if(href_list["tp"]) + var/tp = text2num(href_list["tp"]) + time += tp + time = min(max(round(time), 0), 120) + + updateUsrDialog() + + add_fingerprint(usr) + else + usr << browse(null, "window=firealarm") + return + return + +/obj/machinery/firealarm/proc/reset() + if(!(working)) + return + var/area/area = get_area(src) + for(var/obj/machinery/firealarm/FA in area) + fire_alarm.clearAlarm(src.loc, FA) + update_icon() + return + +/obj/machinery/firealarm/proc/alarm(var/duration = 0) + if(!(working)) + return + var/area/area = get_area(src) + for(var/obj/machinery/firealarm/FA in area) + fire_alarm.triggerAlarm(loc, FA, duration, hidden = alarms_hidden) + update_icon() + playsound(src.loc, 'sound/machines/airalarm.ogg', 25, 0, 4) + return + +/obj/machinery/firealarm/proc/set_security_level(var/newlevel) + if(seclevel != newlevel) + seclevel = newlevel + update_icon() + +/* +FIRE ALARM CIRCUIT +Just a object used in constructing fire alarms +/obj/item/firealarm_electronics + name = "fire alarm electronics" + icon = 'icons/obj/doors/door_assembly.dmi' + 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 = ITEMSIZE_SMALL + matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50) +*/ +/obj/machinery/partyalarm + name = "\improper PARTY BUTTON" + desc = "Cuban Pete is in the house!" + icon = 'icons/obj/monitors.dmi' + icon_state = "fire0" + var/detecting = 1.0 + var/working = 1.0 + var/time = 10.0 + var/timing = 0.0 + var/lockdownbyai = 0 + anchored = 1.0 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 6 + +/obj/machinery/partyalarm/attack_hand(mob/user as mob) + if(user.stat || stat & (NOPOWER|BROKEN)) + return + + user.machine = src + var/area/A = get_area(src) + ASSERT(isarea(A)) + var/d1 + var/d2 + if(istype(user, /mob/living/carbon/human) || istype(user, /mob/living/silicon/ai)) + + if(A.party) + d1 = text("No Party :(", src) + else + d1 = text("PARTY!!!", src) + if(timing) + d2 = text("Stop Time Lock", src) + else + d2 = text("Initiate Time Lock", src) + var/second = time % 60 + var/minute = (time - second) / 60 + var/dat = text("Party Button []\n
\nTimer System: []
\nTime Left: [][] - - + +\n
", d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=partyalarm") + onclose(user, "partyalarm") + else + if(A.fire) + d1 = text("[]", src, stars("No Party :(")) + else + d1 = text("[]", src, stars("PARTY!!!")) + if(timing) + d2 = text("[]", src, stars("Stop Time Lock")) + else + d2 = text("[]", src, stars("Initiate Time Lock")) + var/second = time % 60 + var/minute = (time - second) / 60 + var/dat = text("[] []\n
\nTimer System: []
\nTime Left: [][] - - + +\n
", stars("Party Button"), d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=partyalarm") + onclose(user, "partyalarm") + return + +/obj/machinery/partyalarm/proc/reset() + if(!(working)) + return + var/area/A = get_area(src) + ASSERT(isarea(A)) + A.partyreset() + return + +/obj/machinery/partyalarm/proc/alarm() + if(!(working)) + return + var/area/A = get_area(src) + ASSERT(isarea(A)) + A.partyalert() + return + +/obj/machinery/partyalarm/Topic(href, href_list) + ..() + if(usr.stat || stat & (BROKEN|NOPOWER)) + return + if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) + usr.machine = src + if(href_list["reset"]) + reset() + else if(href_list["alarm"]) + alarm() + else if(href_list["time"]) + timing = text2num(href_list["time"]) + else if(href_list["tp"]) + var/tp = text2num(href_list["tp"]) + time += tp + time = min(max(round(time), 0), 120) + updateUsrDialog() + + add_fingerprint(usr) + else + usr << browse(null, "window=partyalarm") + return + return diff --git a/code/game/machinery/oxygen_pump.dm b/code/game/machinery/oxygen_pump.dm index 75793a40a3a..265384ceb07 100644 --- a/code/game/machinery/oxygen_pump.dm +++ b/code/game/machinery/oxygen_pump.dm @@ -1,7 +1,3 @@ -#define TANK_MAX_RELEASE_PRESSURE (3*ONE_ATMOSPHERE) -#define TANK_DEFAULT_RELEASE_PRESSURE ONE_ATMOSPHERE -#define TANK_IDEAL_PRESSURE 1015 //Arbitrary. - /obj/machinery/oxygen_pump name = "emergency oxygen pump" icon = 'icons/obj/walllocker.dmi' diff --git a/code/game/machinery/partslathe_vr.dm b/code/game/machinery/partslathe_vr.dm index 826c4237419..fd29b6abf1f 100644 --- a/code/game/machinery/partslathe_vr.dm +++ b/code/game/machinery/partslathe_vr.dm @@ -21,26 +21,30 @@ icon = 'icons/obj/partslathe_vr.dmi' icon_state = "partslathe-idle" circuit = /obj/item/circuitboard/partslathe - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE use_power = USE_POWER_IDLE idle_power_usage = 30 active_power_usage = 5000 - // Amount of materials we can store total + ///Amount of materials we can store total var/list/materials = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0) var/list/storage_capacity = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0) + ///The inserted board + var/obj/item/circuitboard/copy_board + ///The queue of things to build + var/list/datum/category_item/partslathe/queue = list() + ///Are we currently busy building stuff? + var/busy = 0 + ///How many machine ticks have we spent building current thing? + var/progress = 0 + ///Material usage efficiency (less efficient than protolathe) + var/mat_efficiency = 3 + /// Ticks per tick build speed multiplier + var/speed = 1 - var/obj/item/circuitboard/copy_board // Inserted board - - var/list/datum/category_item/partslathe/queue = list() // Queue of things to build - var/busy = 0 // Currently building stuff y/n - var/progress = 0 // How many machine ticks have we spent building current thing? - var/mat_efficiency = 3 // Material usage efficiency (less efficient than protolathe) - var/speed = 1 // Ticks per tick build speed multiplier - - // Static list of recipies we will lazily generate - // type -> /datum/category_item/partslathe/ + /// Static list of recipies we will lazily generate + /// type -> /datum/category_item/partslathe/ var/static/list/partslathe_recipies /obj/machinery/partslathe/Initialize(mapload) @@ -51,7 +55,7 @@ /obj/machinery/partslathe/proc/getHighestOriginTechLevel(var/obj/item/I) if(!istype(I) || !I.origin_tech) - return 0 + return FALSE var/highest = 0 for(var/tech in I.origin_tech) highest = max(highest, I.origin_tech[tech]) @@ -88,8 +92,8 @@ /obj/machinery/partslathe/attackby(var/obj/item/O as obj, var/mob/user as mob) if(busy) - to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") - return 1 + to_chat(user, SPAN_NOTICE("\The [src] is busy. Please wait for completion of previous operation.")) + return TRUE if(default_deconstruction_screwdriver(user, O)) return if(default_deconstruction_crowbar(user, O)) @@ -99,34 +103,34 @@ if(inoperable()) return if(panel_open) - to_chat(user, "You can't load \the [src] while it's opened.") + to_chat(user, SPAN_NOTICE("You can't load \the [src] while it's opened.")) return if(istype(O, /obj/item/circuitboard)) if(copy_board) - to_chat(user, "There is already a board inserted in \the [src].") + to_chat(user, SPAN_WARNING("There is already a board inserted in \the [src].")) return if(!user.unEquip(O)) return copy_board = O O.forceMove(src) - user.visible_message("[user] inserts [O] into \the [src]'s circuit reader.", "You insert [O] into \the [src]'s circuit reader.") + user.visible_message("[user] inserts [O] into \the [src]'s circuit reader.", SPAN_NOTICE("You insert [O] into \the [src]'s circuit reader.")) updateUsrDialog() return if(try_load_materials(user, O)) return else - to_chat(user, "You cannot insert this item into \the [src]!") + to_chat(user, SPAN_NOTICE("You cannot insert this item into \the [src]!")) return // Attept to load materials. Returns 0 if item wasn't a stack of materials, otherwise 1 (even if failed to load) /obj/machinery/partslathe/proc/try_load_materials(var/mob/user, var/obj/item/stack/material/S) if(!istype(S)) - return 0 + return FALSE if(!(S.material.name in materials)) - to_chat(user, "The [src] doesn't accept [S.material]!") - return 1 + to_chat(user, SPAN_WARNING("The [src] doesn't accept [S.material]!")) + return TRUE if(S.amount < 1) - return 1 // Does this even happen? Sanity check I guess. + return TRUE // Does this even happen? Sanity check I guess. var/max_res_amount = storage_capacity[S.material.name] if(materials[S.material.name] + S.perunit <= max_res_amount) var/count = 0 @@ -134,12 +138,12 @@ materials[S.material.name] += S.perunit S.use(1) count++ - user.visible_message("[user] inserts [S.name] into \the [src].", "You insert [count] [S.name] into \the [src].") + user.visible_message("[user] inserts [S.name] into \the [src].", SPAN_NOTICE("You insert [count] [S.name] into \the [src].")) flick("partslathe-load-[S.material.name]", src) updateUsrDialog() else - to_chat(user, "\The [src] cannot hold more [S.name].") - return 1 + to_chat(user, SPAN_WARNING("\The [src] cannot hold more [S.name].")) + return TRUE /obj/machinery/partslathe/process(delta_time) ..() @@ -149,12 +153,12 @@ if(queue.len == 0) if (busy) ping() // Job's done! - busy = 0 + busy = FALSE update_icon() return var/datum/category_item/partslathe/D = queue[1] if(canBuild(D)) - busy = 1 + busy = TRUE update_use_power(USE_POWER_ACTIVE) progress += speed if(progress >= D.time) @@ -163,8 +167,8 @@ removeFromQueue(1) update_icon() else if(busy) - visible_message("\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].") - busy = 0 + visible_message(SPAN_NOTICE("\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].")) + busy = FALSE update_use_power(USE_POWER_IDLE) update_icon() playsound(src.loc, 'sound/machines/chime.ogg', 50, 0) @@ -180,8 +184,8 @@ /obj/machinery/partslathe/proc/canBuild(var/datum/category_item/partslathe/D) for(var/M in D.resources) if(materials[M] < CEILING((D.resources[M] * mat_efficiency), 1)) - return 0 - return 1 + return FALSE + return TRUE /obj/machinery/partslathe/proc/getLackingMaterials(var/datum/category_item/partslathe/D) var/ret = "" @@ -198,154 +202,136 @@ var/obj/new_item = D.build(loc); if(new_item) new_item.loc = loc - if(mat_efficiency < 1) // No matter out of nowhere + if(mat_efficiency < 1) //No matter out of nowhere if(new_item.matter && new_item.matter.len > 0) for(var/i in new_item.matter) new_item.matter[i] = CEILING((new_item.matter[i] * mat_efficiency), 1) -// 0 amount = 0 means ejecting a full stack; -1 means eject everything -/obj/machinery/partslathe/proc/eject_materials(var/material, var/amount) - var/recursive = amount == -1 ? 1 : 0 - material = lowertext(material) - var/mattype - switch(material) - if(DEFAULT_WALL_MATERIAL) - mattype = /obj/item/stack/material/steel - if("glass") - mattype = /obj/item/stack/material/glass - else - return - var/obj/item/stack/material/S = new mattype(loc) - if(amount <= 0) - amount = S.max_amount - var/ejected = min(round(materials[material] / S.perunit), amount) - S.amount = min(ejected, amount) - if(S.amount <= 0) - qdel(S) - return - materials[material] -= ejected * S.perunit - if(recursive && materials[material] >= S.perunit) - eject_materials(material, -1) - /obj/machinery/partslathe/attack_ai(mob/user) src.attack_hand(user) /obj/machinery/partslathe/attack_hand(mob/user) if(..()) return - nano_ui_interact(user) + ui_interact(user) -/obj/machinery/partslathe/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) +/obj/machinery/partslathe/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/sheetmaterials) + ) - var/data[0] +/obj/machinery/partslathe/ui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PartsLathe", name) + ui.open() + +/obj/machinery/partslathe/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() data["panelOpen"] = panel_open - var/materials_ui[0] + var/list/materials_ui = list() for(var/M in materials) - materials_ui[++materials_ui.len] = list( - "name" = M, - "display" = material_display_name(M), - "qty" = materials[M], - "max" = storage_capacity[M], - "percent" = (materials[M] / storage_capacity[M] * 100)) + materials_ui.Add(list(list( + "name" = M, + "amount" = materials[M], + "sheets" = round(materials[M] / SHEET_MATERIAL_AMOUNT), + "removable" = materials[M] >= SHEET_MATERIAL_AMOUNT, + ))) data["materials"] = materials_ui + data["copyBoard"] = null + data["copyBoardReqComponents"] = null if(istype(copy_board)) data["copyBoard"] = copy_board.name - var/req_components_ui[0] + var/list/req_components_ui = list() for(var/CP in (copy_board.req_components || list())) var/obj/comp_path = CP var/comp_amt = copy_board.req_components[comp_path] if(comp_amt && (comp_path in partslathe_recipies)) - req_components_ui[++req_components_ui.len] = list("name" = initial(comp_path.name), "qty" = comp_amt) + req_components_ui.Add(list(list("name" = initial(comp_path.name), "qty" = comp_amt))) data["copyBoardReqComponents"] = req_components_ui data["queue"] = list() for(var/datum/category_item/partslathe/Q in queue) data["queue"] += Q.name + data["building"] = null + data["buildPercent"] = null if(busy && queue.len > 0) var/datum/category_item/partslathe/current = queue[1] data["building"] = current.name - data["buildProgress"] = progress - data["buildTime"] = current.time data["buildPercent"] = (progress / current.time * 100) + + data["error"] = null if(queue.len > 0 && !canBuild(queue[1])) data["error"] = getLackingMaterials(queue[1]) - var/recipies_ui[0] + var/list/recipies_ui = list() for(var/T in partslathe_recipies) var/datum/category_item/partslathe/R = partslathe_recipies[T] - recipies_ui[++recipies_ui.len] = list("name" = R.name, "type" = "[T]") + recipies_ui.Add(list(list("name" = R.name, "type" = "[T]"))) data["recipies"] = recipies_ui - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "partslathe.tmpl", "Parts Lathe UI", 500, 450) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(5) + return data -/obj/machinery/partslathe/Topic(href, href_list) +/obj/machinery/partslathe/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return 1 - usr.set_machine(src) + return TRUE + add_fingerprint(usr) - - // Queue management can be done even while busy - if(href_list["queue"]) - var/type_to_build = text2path(href_list["queue"]) - var/datum/category_item/partslathe/to_build = partslathe_recipies[type_to_build] - if(to_build) - addToQueue(to_build) - updateUsrDialog() - return - - if(href_list["queueBoard"]) - if(!istype(copy_board) || !copy_board.req_components) - return - for(var/comp_path in copy_board.req_components) - var/comp_amt = copy_board.req_components[comp_path] - if(!comp_amt) - continue - var/datum/category_item/partslathe/to_build = partslathe_recipies[comp_path] - if(!to_build) - continue // We don't support building whatever this is - for(var/i in 1 to comp_amt) + switch(action) + //Queue management can be done even while busy + if("queue") + var/type_to_build = text2path(params["queue"]) + var/datum/category_item/partslathe/to_build = partslathe_recipies[type_to_build] + if(to_build) addToQueue(to_build) - return + return TRUE - if(href_list["cancel"]) - var/index = text2num(href_list["cancel"]) - if(index < 1 || index > queue.len) - return - if(busy && index == 1) - return - removeFromQueue(index) - return + if("queueBoard") + if(!istype(copy_board) || !copy_board.req_components) + return + for(var/comp_path in copy_board.req_components) + var/comp_amt = copy_board.req_components[comp_path] + if(!comp_amt) + continue + var/datum/category_item/partslathe/to_build = partslathe_recipies[comp_path] + if(!to_build) + continue //We don't support building whatever this is + for(var/i in 1 to comp_amt) + addToQueue(to_build) + return TRUE + + if("cancel") + var/index = text2num(params["cancel"]) + if(index < 1 || index > queue.len) + return + if(busy && index == 1) + return + removeFromQueue(index) + return TRUE if(busy) - to_chat(usr, "\The [src]is busy. Please wait for completion of previous operation.") + to_chat(usr, SPAN_NOTICE("[src] is busy. Please wait for completion of previous operation.")) return - if(href_list["ejectBoard"]) - if(copy_board) - visible_message("\The [copy_board] is ejected from \the [src]'s circuit reader.") - copy_board.forceMove(src.loc) - copy_board = null - updateUsrDialog() - return + switch(action) + if("ejectBoard") + if(copy_board) + visible_message(SPAN_NOTICE("[copy_board] is ejected from [src]'s circuit reader.")) + copy_board.forceMove(src.loc) + copy_board = null + return TRUE - if(href_list["ejectMaterial"]) - var/matName = href_list["ejectMaterial"] - if(!(matName in materials)) + if("remove_mat") + // Remove a material from the fab + var/mat_id = params["id"] + var/amount = text2num(params["amount"]) + eject_materials(mat_id, amount) return - eject_materials(matName, 0) - updateUsrDialog() - return -/** Build list of recipies to include all tech level 1 stock parts. */ +///Builds a list of recipies to include all tech level 1 stock parts. /obj/machinery/partslathe/proc/update_recipe_list() if(!partslathe_recipies) partslathe_recipies = list() diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm index 9d72ca5d325..cd4ed2942d0 100644 --- a/code/game/machinery/pipe/pipe_dispenser.dm +++ b/code/game/machinery/pipe/pipe_dispenser.dm @@ -2,10 +2,10 @@ name = "Pipe Dispenser" icon = 'icons/obj/stationobjs.dmi' icon_state = "pipe_d" - density = 1 - anchored = 1 - var/unwrenched = 0 - var/wait = 0 + density = TRUE + anchored = TRUE + var/unwrenched = FALSE + var/wait = FALSE var/p_layer = PIPING_LAYER_REGULAR var/static/list/pipe_layers = list( "Regular" = PIPING_LAYER_REGULAR, @@ -14,68 +14,93 @@ "Fuel" = PIPING_LAYER_FUEL, "Aux" = PIPING_LAYER_AUX ) + var/disposals = FALSE -// TODO - Its about time to make this NanoUI don't we think? /obj/machinery/pipedispenser/attack_hand(var/mob/user as mob) if((. = ..())) return - src.interact(user) + ui_interact(user) -/obj/machinery/pipedispenser/interact(mob/user) - user.set_machine(src) +/obj/machinery/pipedispenser/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/pipes), + ) - var/list/lines = list() - for(var/category in atmos_pipe_recipes) - lines += "[category]:
" - for(var/pipename in pipe_layers) - var/pipelayer = pipe_layers[pipename] - lines += "[pipename] " - lines += "
" - for(var/datum/pipe_recipe/PI in atmos_pipe_recipes[category]) - lines += PI.Render(src) - var/dat = lines.Join() - var/datum/browser/popup = new(user, "pipedispenser", name, 300, 800, src) - popup.set_content("[dat]") - popup.open() - return +/obj/machinery/pipedispenser/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PipeDispenser", name) + ui.open() -/obj/machinery/pipedispenser/Topic(href, href_list) +/obj/machinery/pipedispenser/ui_data(mob/user) + var/list/data = list( + "disposals" = disposals, + "p_layer" = p_layer, + "pipe_layers" = pipe_layers, + ) + + var/list/recipes + if(disposals) + recipes = GLOB.disposal_pipe_recipes + else + recipes = GLOB.atmos_pipe_recipes + + for(var/c in recipes) + var/list/cat = recipes[c] + var/list/r = list() + for(var/i in 1 to cat.len) + var/datum/pipe_info/info = cat[i] + r += list(list("pipe_name" = info.name, "pipe_index" = i)) + data["categories"] += list(list("cat_name" = c, "recipes" = r)) + + return data + +/obj/machinery/pipedispenser/ui_act(action, params) if(..()) - return + return TRUE if(unwrenched || !usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=pipedispenser") - usr.unset_machine(src) - return - usr.set_machine(src) - if(href_list["setlayer"]) - var/new_pipe_layer = text2num(href_list["setlayer"]) - if(isnum(new_pipe_layer)) - p_layer = new_pipe_layer - updateDialog() - else if(href_list["makepipe"]) - if(!wait) - var/obj/machinery/atmospherics/p_type = text2path(href_list["makepipe"]) - if(!ispath(p_type, /obj/machinery/atmospherics)) - return - var/p_dir = text2num(href_list["dir"]) - var/pi_type = initial(p_type.construction_type) - var/obj/item/pipe/P = new pi_type(src.loc, p_type, p_dir) - P.setPipingLayer(p_layer) - wait = 1 - spawn(10) - wait = 0 - else if(href_list["makemeter"]) - if(!wait) - new /obj/item/pipe_meter(/*usr.loc*/ src.loc) - wait = 1 - spawn(15) - wait = 0 - return + return TRUE + + . = TRUE + switch(action) + if("p_layer") + p_layer = text2num(params["p_layer"]) + if("dispense_pipe") + if(!wait) + var/list/recipes + if(disposals) + recipes = GLOB.disposal_pipe_recipes + else + recipes = GLOB.atmos_pipe_recipes + + var/datum/pipe_info/recipe = recipes[params["category"]][text2num(params["pipe_type"])] + + var/obj/created_object = null + if(istype(recipe, /datum/pipe_info/pipe)) + var/datum/pipe_info/pipe/R = recipe + created_object = new R.construction_type(loc, recipe.pipe_type, NORTH) + var/obj/item/pipe/P = created_object + P.setPipingLayer(p_layer) + else if(istype(recipe, /datum/pipe_info/disposal)) + var/datum/pipe_info/disposal/D = recipe + var/obj/structure/disposalconstruct/C = new(loc, D.pipe_type, NORTH, 0, D.subtype ? D.subtype : 0) + C.update() + created_object = C + else if(istype(recipe, /datum/pipe_info/meter)) + created_object = new recipe.pipe_type(loc) + else + log_runtime(EXCEPTION("Warning: [usr] attempted to spawn pipe recipe type by params [json_encode(params)] ([recipe] [recipe?.type]), but it was not allowed by this machine ([src] [type])")) + return + + created_object.add_fingerprint(usr) + wait = TRUE + VARSET_IN(src, wait, FALSE, 15) + /obj/machinery/pipedispenser/attackby(var/obj/item/W as obj, var/mob/user as mob) if (istype(W, /obj/item/pipe) || istype(W, /obj/item/pipe_meter)) - to_chat(usr, "You put [W] back to [src].") + to_chat(usr, SPAN_NOTICE("You put [W] back in [src].")) user.drop_item() add_fingerprint(usr) qdel(W) @@ -84,11 +109,11 @@ add_fingerprint(usr) if (unwrenched==0) playsound(src, W.usesound, 50, 1) - to_chat(user, "You begin to unfasten \the [src] from the floor...") + to_chat(user, SPAN_NOTICE("You begin to unfasten \the [src] from the floor...")) if (do_after(user, 40 * W.toolspeed)) user.visible_message( \ - "[user] unfastens \the [src].", \ - "You have unfastened \the [src]. Now it can be pulled somewhere else.", \ + SPAN_NOTICE("[user] unfastens \the [src]."), \ + SPAN_NOTICE("You have unfastened \the [src]. Now it can be pulled somewhere else."), \ "You hear ratchet.") src.anchored = 0 src.stat |= MAINT @@ -97,11 +122,11 @@ usr << browse(null, "window=pipedispenser") else /*if (unwrenched==1)*/ playsound(src, W.usesound, 50, 1) - to_chat(user, "You begin to fasten \the [src] to the floor...") + to_chat(user, SPAN_NOTICE("You begin to fasten \the [src] to the floor...")) if (do_after(user, 20 * W.toolspeed)) user.visible_message( \ - "[user] fastens \the [src].", \ - "You have fastened \the [src]. Now it can dispense pipes.", \ + SPAN_NOTICE("[user] fastens \the [src]."), \ + SPAN_NOTICE("You have fastened \the [src]. Now it can dispense pipes."), \ "You hear ratchet.") src.anchored = 1 src.stat &= ~MAINT @@ -114,17 +139,9 @@ name = "Disposal Pipe Dispenser" icon = 'icons/obj/stationobjs.dmi' icon_state = "pipe_d" - density = 1 - anchored = 1.0 - -/* -//Allow you to push disposal pipes into it (for those with density 1) -/obj/machinery/pipedispenser/disposal/Crossed(var/obj/structure/disposalconstruct/pipe as obj) - if(istype(pipe) && !pipe.anchored) - qdel(pipe) - -Nah -*/ + density = TRUE + anchored = TRUE + disposals = TRUE //Allow you to drag-drop disposal pipes into it /obj/machinery/pipedispenser/disposal/MouseDrop_T(var/obj/structure/disposalconstruct/pipe as obj, mob/usr as mob) @@ -137,45 +154,14 @@ Nah if (pipe.anchored) return + to_chat(usr, SPAN_NOTICE("You shove [pipe] back in [src].")) qdel(pipe) -/obj/machinery/pipedispenser/disposal/interact(mob/user) - user.set_machine(src) - - var/list/lines = list() - for(var/category in disposal_pipe_recipes) - lines += "[category]:
" - for(var/datum/pipe_recipe/PI in disposal_pipe_recipes[category]) - lines += PI.Render(src) - var/dat = lines.Join() - var/datum/browser/popup = new(user, "pipedispenser", name, 300, 500, src) - popup.set_content("[dat]") - popup.open() - return - -/obj/machinery/pipedispenser/disposal/Topic(href, href_list) - if(href_list["makepipe"] || href_list["setlayer"] || href_list["makemeter"]) // Asking the disposal machine to do atmos stuff? - return // That's a no no. - if(..()) - return - if(href_list["dmake"]) - if(!wait) - var/ptype = text2num(href_list["dmake"]) - var/pdir = (href_list["dir"] ? text2num(href_list["dir"]) : NORTH) - var/psub = (href_list["sort"] ? text2num(href_list["sort"]) : 0) - var/obj/structure/disposalconstruct/C = new (src.loc, ptype, pdir, 0, psub) - - C.update() - wait = 1 - spawn(15) - wait = 0 - return - -// adding a pipe dispensers that spawn unhooked from the ground +//Adding a pipe dispensers that spawn unhooked from the ground /obj/machinery/pipedispenser/orderable - anchored = 0 - unwrenched = 1 + anchored = FALSE + unwrenched = TRUE /obj/machinery/pipedispenser/disposal/orderable - anchored = 0 - unwrenched = 1 + anchored = FALSE + unwrenched = TRUE diff --git a/code/game/machinery/pipe/pipe_recipes.dm b/code/game/machinery/pipe/pipe_recipes.dm index 62419b4fe94..3a87a22d9b9 100644 --- a/code/game/machinery/pipe/pipe_recipes.dm +++ b/code/game/machinery/pipe/pipe_recipes.dm @@ -1,84 +1,78 @@ // -// Recipies for Pipe Dispenser and (someday) the RPD +// Recipies for Pipe Dispenser and the RPD // -var/global/list/atmos_pipe_recipes = null -var/global/list/disposal_pipe_recipes = null -var/global/list/all_pipe_recipes = null +GLOBAL_LIST_INIT(atmos_pipe_recipes, list( + "Pipes" = list( + new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple, TRUE), + new /datum/pipe_info/pipe("Manifold", /obj/machinery/atmospherics/pipe/manifold, TRUE), + new /datum/pipe_info/pipe("Manual Valve", /obj/machinery/atmospherics/valve, TRUE), + new /datum/pipe_info/pipe("Digital Valve", /obj/machinery/atmospherics/valve/digital, TRUE), + new /datum/pipe_info/pipe("Pipe cap", /obj/machinery/atmospherics/pipe/cap, TRUE), + new /datum/pipe_info/pipe("4-Way Manifold", /obj/machinery/atmospherics/pipe/manifold4w, TRUE), + new /datum/pipe_info/pipe("Manual T-Valve", /obj/machinery/atmospherics/tvalve, TRUE), + new /datum/pipe_info/pipe("Digital T-Valve", /obj/machinery/atmospherics/tvalve/digital, TRUE), + new /datum/pipe_info/pipe("Upward Pipe", /obj/machinery/atmospherics/pipe/zpipe/up, TRUE), + new /datum/pipe_info/pipe("Downward Pipe", /obj/machinery/atmospherics/pipe/zpipe/down, TRUE), + new /datum/pipe_info/pipe("Universal Pipe Adaptor",/obj/machinery/atmospherics/pipe/simple/visible/universal, FALSE), + ), + "Devices" = list( + new /datum/pipe_info/pipe("Connector", /obj/machinery/atmospherics/portables_connector, TRUE), + new /datum/pipe_info/pipe("Unary Vent", /obj/machinery/atmospherics/unary/vent_pump, TRUE), + new /datum/pipe_info/pipe("Aux Vent", /obj/machinery/atmospherics/unary/vent_pump/aux, TRUE), + new /datum/pipe_info/pipe("Passive Vent", /obj/machinery/atmospherics/pipe/vent, TRUE), + new /datum/pipe_info/pipe("Injector", /obj/machinery/atmospherics/unary/outlet_injector, TRUE), + new /datum/pipe_info/pipe("Gas Pump", /obj/machinery/atmospherics/binary/pump, TRUE), + new /datum/pipe_info/pipe("Fuel Pump", /obj/machinery/atmospherics/binary/pump/fuel, TRUE), + new /datum/pipe_info/pipe("Aux Pump", /obj/machinery/atmospherics/binary/pump/aux, TRUE), + new /datum/pipe_info/pipe("Pressure Regulator", /obj/machinery/atmospherics/binary/passive_gate, TRUE), + new /datum/pipe_info/pipe("High Power Gas Pump", /obj/machinery/atmospherics/binary/pump/high_power, TRUE), + new /datum/pipe_info/pipe("Heat Pump", /obj/machinery/atmospherics/binary/heat_pump, TRUE), + //new /datum/pipe_info/pipe("Automatic Shutoff Valve",/obj/machinery/atmospherics/valve/shutoff, TRUE), + new /datum/pipe_info/pipe("Scrubber", /obj/machinery/atmospherics/unary/vent_scrubber, TRUE), + new /datum/pipe_info/pipe("Gas Filter", /obj/machinery/atmospherics/trinary/atmos_filter, TRUE), + new /datum/pipe_info/pipe("Gas Mixer", /obj/machinery/atmospherics/trinary/mixer, TRUE), + new /datum/pipe_info/pipe("Gas Mixer 'T'", /obj/machinery/atmospherics/trinary/mixer/t_mixer, TRUE), + new /datum/pipe_info/pipe("Omni Gas Mixer", /obj/machinery/atmospherics/omni/mixer, TRUE), + new /datum/pipe_info/pipe("Omni Gas Filter", /obj/machinery/atmospherics/omni/atmos_filter, TRUE), + new /datum/pipe_info/meter("Meter"), + ), + "Heat Exchange" = list( + new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple/heat_exchanging, FALSE), + new /datum/pipe_info/pipe("Junction", /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction, FALSE), + new /datum/pipe_info/pipe("Heat Exchanger", /obj/machinery/atmospherics/unary/heat_exchanger, FALSE), + ), + "Insulated pipes" = list( + new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple/insulated, TRUE), + ) +)) -/hook/startup/proc/init_pipe_recipes() - RETURN_TYPE(/list) - global.atmos_pipe_recipes = list( - "Pipes" = list( - new /datum/pipe_recipe/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple), - new /datum/pipe_recipe/pipe("Manifold", /obj/machinery/atmospherics/pipe/manifold), - new /datum/pipe_recipe/pipe("Manual Valve", /obj/machinery/atmospherics/valve), - new /datum/pipe_recipe/pipe("Digital Valve", /obj/machinery/atmospherics/valve/digital), - new /datum/pipe_recipe/pipe("Pipe cap", /obj/machinery/atmospherics/pipe/cap), - new /datum/pipe_recipe/pipe("4-Way Manifold", /obj/machinery/atmospherics/pipe/manifold4w), - new /datum/pipe_recipe/pipe("Manual T-Valve", /obj/machinery/atmospherics/tvalve), - new /datum/pipe_recipe/pipe("Digital T-Valve", /obj/machinery/atmospherics/tvalve/digital), - new /datum/pipe_recipe/pipe("Upward Pipe", /obj/machinery/atmospherics/pipe/zpipe/up), - new /datum/pipe_recipe/pipe("Downward Pipe", /obj/machinery/atmospherics/pipe/zpipe/down), - new /datum/pipe_recipe/pipe("Universal Pipe Adaptor",/obj/machinery/atmospherics/pipe/simple/visible/universal), - ), - "Devices" = list( - new /datum/pipe_recipe/pipe("Connector", /obj/machinery/atmospherics/portables_connector), - new /datum/pipe_recipe/pipe("Unary Vent", /obj/machinery/atmospherics/unary/vent_pump), - new /datum/pipe_recipe/pipe("Aux Vent", /obj/machinery/atmospherics/unary/vent_pump/aux), - new /datum/pipe_recipe/pipe("Passive Vent", /obj/machinery/atmospherics/pipe/vent), - new /datum/pipe_recipe/pipe("Injector", /obj/machinery/atmospherics/unary/outlet_injector), - new /datum/pipe_recipe/pipe("Gas Pump", /obj/machinery/atmospherics/binary/pump), - new /datum/pipe_recipe/pipe("Fuel Pump", /obj/machinery/atmospherics/binary/pump/fuel), - new /datum/pipe_recipe/pipe("Aux Pump", /obj/machinery/atmospherics/binary/pump/aux), - new /datum/pipe_recipe/pipe("Pressure Regulator", /obj/machinery/atmospherics/binary/passive_gate), - new /datum/pipe_recipe/pipe("High Power Gas Pump", /obj/machinery/atmospherics/binary/pump/high_power), - new /datum/pipe_recipe/pipe("Scrubber", /obj/machinery/atmospherics/unary/vent_scrubber), - new /datum/pipe_recipe/meter("Meter"), - new /datum/pipe_recipe/pipe("Gas Filter", /obj/machinery/atmospherics/trinary/atmos_filter), - new /datum/pipe_recipe/pipe("Gas Mixer", /obj/machinery/atmospherics/trinary/mixer), - new /datum/pipe_recipe/pipe("Gas Mixer 'T'", /obj/machinery/atmospherics/trinary/mixer/t_mixer), - new /datum/pipe_recipe/pipe("Omni Gas Mixer", /obj/machinery/atmospherics/omni/mixer), - new /datum/pipe_recipe/pipe("Omni Gas Filter", /obj/machinery/atmospherics/omni/atmos_filter), - ), - "Heat Exchange" = list( - new /datum/pipe_recipe/pipe("Heat pump", /obj/machinery/atmospherics/binary/heat_pump), - new /datum/pipe_recipe/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple/heat_exchanging), - new /datum/pipe_recipe/pipe("Junction", /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction), - new /datum/pipe_recipe/pipe("Heat Exchanger", /obj/machinery/atmospherics/unary/heat_exchanger), - ), - "Insulated pipes" = list( - new /datum/pipe_recipe/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple/insulated), - ) +GLOBAL_LIST_INIT(disposal_pipe_recipes, list( + "Disposal Pipes" = list( + new /datum/pipe_info/disposal("Pipe", DISPOSAL_PIPE_STRAIGHT, "conpipe-s", PIPE_STRAIGHT), + new /datum/pipe_info/disposal("Bent Pipe", DISPOSAL_PIPE_CORNER, "conpipe-c"), + new /datum/pipe_info/disposal("Junction", DISPOSAL_PIPE_JUNCTION, "conpipe-j1", PIPE_TRIN_M), + new /datum/pipe_info/disposal("Y-Junction", DISPOSAL_PIPE_JUNCTION_Y, "conpipe-y"), + new /datum/pipe_info/disposal("Sort Junction", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, DISPOSAL_SORT_NORMAL), + new /datum/pipe_info/disposal("Sort Junction (Wildcard)", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, DISPOSAL_SORT_WILDCARD), + new /datum/pipe_info/disposal("Sort Junction (Untagged)", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, DISPOSAL_SORT_UNTAGGED), + new /datum/pipe_info/disposal("Tagger", DISPOSAL_PIPE_TAGGER, "pipe-tagger", PIPE_STRAIGHT), + new /datum/pipe_info/disposal("Tagger (Partial)", DISPOSAL_PIPE_TAGGER_PARTIAL, "pipe-tagger-partial", PIPE_STRAIGHT), + new /datum/pipe_info/disposal("Trunk", DISPOSAL_PIPE_TRUNK, "conpipe-t"), + new /datum/pipe_info/disposal("Upwards", DISPOSAL_PIPE_UPWARD, "pipe-u"), + new /datum/pipe_info/disposal("Downwards", DISPOSAL_PIPE_DOWNWARD, "pipe-d"), + new /datum/pipe_info/disposal("Bin", DISPOSAL_PIPE_BIN, "disposal", PIPE_ONEDIR), + new /datum/pipe_info/disposal("Outlet", DISPOSAL_PIPE_OUTLET, "outlet"), + new /datum/pipe_info/disposal("Chute", DISPOSAL_PIPE_CHUTE, "intake"), ) - global.disposal_pipe_recipes = list( - "Disposal Pipes" = list( - new /datum/pipe_recipe/disposal("Pipe", DISPOSAL_PIPE_STRAIGHT, "conpipe-s", PIPE_STRAIGHT), - new /datum/pipe_recipe/disposal("Bent Pipe", DISPOSAL_PIPE_CORNER, "conpipe-c"), - new /datum/pipe_recipe/disposal("Junction", DISPOSAL_PIPE_JUNCTION, "conpipe-j1", PIPE_TRIN_M, "conpipe-j2"), - new /datum/pipe_recipe/disposal("Y-Junction", DISPOSAL_PIPE_JUNCTION_Y, "conpipe-y"), - new /datum/pipe_recipe/disposal("Sort Junction", DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, "conpipe-j2s", DISPOSAL_SORT_NORMAL), - new /datum/pipe_recipe/disposal("Sort Junction (Wildcard)",DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, "conpipe-j2s", DISPOSAL_SORT_WILDCARD), - new /datum/pipe_recipe/disposal("Sort Junction (Untagged)",DISPOSAL_PIPE_SORTER, "conpipe-j1s", PIPE_TRIN_M, "conpipe-j2s", DISPOSAL_SORT_UNTAGGED), - new /datum/pipe_recipe/disposal("Tagger", DISPOSAL_PIPE_TAGGER, "pipe-tagger", PIPE_STRAIGHT), - new /datum/pipe_recipe/disposal("Tagger (Partial)", DISPOSAL_PIPE_TAGGER_PARTIAL, "pipe-tagger-partial", PIPE_STRAIGHT), - new /datum/pipe_recipe/disposal("Trunk", DISPOSAL_PIPE_TRUNK, "conpipe-t"), - new /datum/pipe_recipe/disposal("Upwards", DISPOSAL_PIPE_UPWARD, "pipe-u"), - new /datum/pipe_recipe/disposal("Downwards", DISPOSAL_PIPE_DOWNWARD, "pipe-d"), - new /datum/pipe_recipe/disposal("Bin", DISPOSAL_PIPE_BIN, "disposal", PIPE_ONEDIR), - new /datum/pipe_recipe/disposal("Outlet", DISPOSAL_PIPE_OUTLET, "outlet"), - new /datum/pipe_recipe/disposal("Chute", DISPOSAL_PIPE_CHUTE, "intake"), - ) - ) - global.all_pipe_recipes = disposal_pipe_recipes + atmos_pipe_recipes - return TRUE +)) // // New method of handling pipe construction. Instead of numeric constants and a giant switch statement of doom // every pipe type has a datum instance which describes its name, placement rules and construction method, dispensing etc. // The advantages are obvious, mostly in simplifying the code of the dispenser, and the ability to add new pipes without hassle. // -/datum/pipe_recipe +/datum/pipe_info var/name = "Abstract Pipe (fixme)" // Recipe name var/pipe_type // The type PATH of what actual pipe the fitting becomes, used by RCD to print the pipe. var/icon = 'icons/obj/pipe-item.dmi' // This tells the RPD which icon file to look for preview images in. @@ -87,33 +81,95 @@ var/global/list/all_pipe_recipes = null var/dirtype // If using an RPD, this tells more about what previews to show. var/subtype = 0 // Used for certain disposals pipes types. var/paintable = FALSE // If TRUE, allow the RPD to paint this pipe. + var/all_layers // Render an HTML link to select this pipe type. Returns text. -/datum/pipe_recipe/proc/Render(dispenser) +/datum/pipe_info/proc/Render(dispenser) return "[name]
" +// Get preview for UIs +/datum/pipe_info/proc/get_preview(selected_dir) + var/list/dirs + + switch(dirtype) + + if(PIPE_STRAIGHT, PIPE_BENDABLE) + dirs = list("[NORTH]" = "Vertical", "[EAST]" = "Horizontal") + if(dirtype == PIPE_BENDABLE) + dirs += list( + "[NORTHWEST]" = "West to North", "[NORTHEAST]" = "North to East", + "[SOUTHWEST]" = "South to West", "[SOUTHEAST]" = "East to South" + ) + + if(PIPE_TRINARY) + dirs = list( + "[NORTH]" = "West South East", "[SOUTH]" = "East North West", + "[EAST]" = "North West South", "[WEST]" = "South East North" + ) + + if(PIPE_TRIN_M) + dirs = list( + "[NORTH]" = "North East South", "[SOUTHWEST]" = "North West South", + "[NORTHEAST]" = "South East North", "[SOUTH]" = "South West North", + "[WEST]" = "West North East", "[SOUTHEAST]" = "West South East", + "[NORTHWEST]" = "East North West", "[EAST]" = "East South West", + ) + + if(PIPE_DIRECTIONAL) + dirs = list( + "[NORTH]" = "North", "[SOUTH]" = "South", + "[WEST]" = "West", "[EAST]" = "East" + ) + + if(PIPE_ONEDIR) + dirs = list("[SOUTH]" = name) + + if(PIPE_UNARY_FLIPPABLE) + dirs = list( + "[NORTH]" = "North", "[EAST]" = "East", + "[SOUTH]" = "South", "[WEST]" = "West", + "[NORTHEAST]" = "North Flipped", "[SOUTHEAST]" = "East Flipped", + "[SOUTHWEST]" = "South Flipped", "[NORTHWEST]" = "West Flipped" + ) + + + var/list/rows = list() + var/list/row = list("previews" = list()) + var/i = 0 + for(var/dir in dirs) + var/numdir = text2num(dir) + var/flipped = ((dirtype == PIPE_TRIN_M) || (dirtype == PIPE_UNARY_FLIPPABLE)) && (numdir in GLOB.cornerdirs) + row["previews"] += list(list("selected" = (numdir == selected_dir), "dir" = dir2text(numdir), "dir_name" = dirs[dir], "icon_state" = icon_state, "flipped" = flipped)) + if(i++ || dirtype == PIPE_ONEDIR) + rows += list(row) + row = list("previews" = list()) + i = 0 + + return rows + // Parameters for the Topic link returned by Render(). Returns text. -/datum/pipe_recipe/proc/Params() +/datum/pipe_info/proc/Params() return "" // // Subtype for actual pipes // -/datum/pipe_recipe/pipe - var/obj/item/pipe/construction_type // The type PATH to the type of pipe fitting object the recipe makes. +/datum/pipe_info/pipe + var/obj/item/pipe/construction_type //The type PATH to the type of pipe fitting object the recipe makes. -/datum/pipe_recipe/pipe/New(var/label, var/obj/machinery/atmospherics/path, var/colorable=FALSE) +/datum/pipe_info/pipe/New(label, obj/machinery/atmospherics/path, var/use_five_layers, var/colorable=FALSE) name = label pipe_type = path + all_layers = use_five_layers construction_type = initial(path.construction_type) icon_state = initial(path.pipe_state) dirtype = initial(construction_type.dispenser_class) - if (dirtype == PIPE_TRIN_M) + if(dirtype == PIPE_TRIN_M) icon_state_m = "[icon_state]m" paintable = colorable -// Render an HTML link to select this pipe type -/datum/pipe_recipe/pipe/Render(dispenser) +//Render an HTML link to select this pipe type +/datum/pipe_info/pipe/Render(dispenser) var/dat = ..(dispenser) // Stationary pipe dispensers don't allow you to pre-select pipe directions. // This makes it impossble to spawn bent versions of bendable pipes. @@ -122,29 +178,30 @@ var/global/list/all_pipe_recipes = null dat += "Bent [name]
" return dat -/datum/pipe_recipe/pipe/Params() +/datum/pipe_info/pipe/Params() return "makepipe=[pipe_type]" // // Subtype for meters // -/datum/pipe_recipe/meter +/datum/pipe_info/meter dirtype = PIPE_ONEDIR icon_state = "meter" + pipe_type = /obj/item/pipe_meter -/datum/pipe_recipe/meter/New(label) +/datum/pipe_info/meter/New(label) name = label -/datum/pipe_recipe/meter/Params() +/datum/pipe_info/meter/Params() return "makemeter=1" // // Subtype for disposal pipes // -/datum/pipe_recipe/disposal +/datum/pipe_info/disposal icon = 'icons/obj/pipes/disposal.dmi' -/datum/pipe_recipe/disposal/New(var/label, var/path, var/state, dt=PIPE_DIRECTIONAL, var/state_mirror=0, var/sort=0) +/datum/pipe_info/disposal/New(var/label, var/path, var/state, dt=PIPE_DIRECTIONAL, var/state_mirror=0, var/sort=0) name = label icon_state = state pipe_type = path @@ -154,7 +211,7 @@ var/global/list/all_pipe_recipes = null icon_state_m = state_mirror // Render an HTML link to select this pipe type -/datum/pipe_recipe/disposal/Render(dispenser) +/datum/pipe_info/disposal/Render(dispenser) var/dat = ..(dispenser) // Blah blah, add corner pipes because dispensers have no directional information. Look up for more info. @@ -162,7 +219,7 @@ var/global/list/all_pipe_recipes = null dat += "Bent [name]
" return dat -/datum/pipe_recipe/disposal/Params() +/datum/pipe_info/disposal/Params() var/param = "dmake=[pipe_type]" if (subtype) param += "&sort=[subtype]" diff --git a/code/game/machinery/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm index 14643dc4407..13d902cebcd 100644 --- a/code/game/machinery/robot_fabricator.dm +++ b/code/game/machinery/robot_fabricator.dm @@ -1,9 +1,9 @@ -/obj/machinery/robotic_fabricator +/obj/machinery/robotic_fabricator //Does this stille even need to exist? name = "robotic fabricator" - icon = 'icons/obj/robotics.dmi' - icon_state = "fab-idle" - density = 1 - anchored = 1 + icon = 'icons/obj/machines/fabricators/robotics.dmi' + icon_state = "mechfab" + density = TRUE + anchored = TRUE var/metal_amount = 0 var/operating = 0 var/obj/item/robot_parts/being_built = null @@ -16,7 +16,7 @@ var/obj/item/stack/M = O if(metal_amount < 150000.0) var/count = 0 - overlays += "fab-load-metal" + add_overlay("[base_icon_state]-load-metal") spawn(15) if(M) if(!M.get_amount()) @@ -27,7 +27,7 @@ count++ to_chat(user, "You insert [count] metal sheet\s into the fabricator.") - overlays -= "fab-load-metal" + cut_overlay("[base_icon_state]-load-metal") updateDialog() else to_chat(user, "The robot part maker is full. Please remove metal from the robot part maker in order to insert more.") @@ -120,7 +120,7 @@ Please wait until completion...
being_built = new building(src) - overlays += "fab-active" + add_overlay("[base_icon_state]-active") updateUsrDialog() spawn (build_time) @@ -129,7 +129,7 @@ Please wait until completion...
being_built = null update_use_power(USE_POWER_IDLE) operating = 0 - overlays -= "fab-active" + cut_overlay("[base_icon_state]-active") return for (var/mob/M in viewers(1, src)) diff --git a/code/game/machinery/seed_extractor.dm b/code/game/machinery/seed_extractor.dm index 77d3c4c3abd..69ffe8874ce 100644 --- a/code/game/machinery/seed_extractor.dm +++ b/code/game/machinery/seed_extractor.dm @@ -3,8 +3,8 @@ desc = "Extracts and bags seeds from produce." icon = 'icons/obj/hydroponics_machines.dmi' icon_state = "sextractor" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE obj/machinery/seed_extractor/attackby(var/obj/item/O as obj, var/mob/user as mob) @@ -16,13 +16,13 @@ obj/machinery/seed_extractor/attackby(var/obj/item/O as obj, var/mob/user as mob var/datum/seed/new_seed_type if(istype(O, /obj/item/grown)) var/obj/item/grown/F = O - new_seed_type = plant_controller.seeds[F.plantname] + new_seed_type = SSplants.seeds[F.plantname] else var/obj/item/reagent_containers/food/snacks/grown/F = O - new_seed_type = plant_controller.seeds[F.plantname] + new_seed_type = SSplants.seeds[F.plantname] if(new_seed_type) - to_chat(user, "You extract some seeds from [O].") + to_chat(user, SPAN_NOTICE("You extract some seeds from [O].")) var/produce = rand(1,4) for(var/i = 0;i<=produce;i++) var/obj/item/seeds/seeds = new(get_turf(src)) @@ -37,10 +37,9 @@ obj/machinery/seed_extractor/attackby(var/obj/item/O as obj, var/mob/user as mob else if(istype(O, /obj/item/stack/tile/grass)) var/obj/item/stack/tile/grass/S = O if(S.use(1)) - to_chat(user, "You extract some seeds from the grass tile.") + to_chat(user, SPAN_NOTICE("You extract some seeds from the grass tile.")) new /obj/item/seeds/grassseed(loc) else if(default_unfasten_wrench(user, O, 20)) return - return diff --git a/code/game/machinery/virtual_reality/ar_console.dm b/code/game/machinery/virtual_reality/ar_console.dm index 9e85680004d..1ed09e03018 100644 --- a/code/game/machinery/virtual_reality/ar_console.dm +++ b/code/game/machinery/virtual_reality/ar_console.dm @@ -108,7 +108,7 @@ avatar.real_name = newname avatar.forceMove(T) - visible_message("\The [src] [pick("gurgles", "churns", "sloshes")] before spitting out \the [avatar]!") + visible_message("\The [src] [pick("gurgles", "churns", "sloshes")] before spitting out \the [avatar]!") else diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm index 689784b251e..a64ccc29886 100644 --- a/code/game/mecha/equipment/mecha_equipment.dm +++ b/code/game/mecha/equipment/mecha_equipment.dm @@ -4,10 +4,9 @@ #define EQUIP_WEAPON "weapon" #define EQUIP_UTILITY "utility" #define EQUIP_SPECIAL "core" -//VOREStation Addition begin: MICROMECHS + #define EQUIP_MICRO_UTILITY "micro_utility" #define EQUIP_MICRO_WEAPON "micro_weapon" -//VOREStation Addition end: MICROMECHS /obj/item/mecha_parts/mecha_equipment name = "mecha equipment" @@ -17,20 +16,24 @@ origin_tech = list(TECH_MATERIAL = 2) description_info = "Some equipment may gain new abilities or advantages if equipped to certain types of Exosuits." var/equip_cooldown = 0 - var/equip_ready = 1 + var/equip_ready = TRUE var/energy_drain = 0 var/obj/mecha/chassis = null var/range = MELEE //bitflags /// Bitflag. Used by exosuit fabricator to assign sub-categories based on which exosuits can equip this. var/mech_flags = NONE - var/salvageable = 1 - var/required_type = /obj/mecha //may be either a type or a list of allowed types - var/equip_type = null //mechaequip2 + var/salvageable = TRUE + ///May be either a type or a list of allowed types + var/required_type = /obj/mecha + ///mechaequip2 + var/equip_type = null var/allow_duplicate = FALSE - var/ready_sound = 'sound/mecha/mech_reload_default.ogg' //Sound to play once the fire delay passed. - var/enable_special = FALSE // Will the tool do its special? - - var/step_delay = 0 // Does the component slow/speed up the suit? + ///Sound to play once the fire delay passed. + var/ready_sound = 'sound/mecha/mech_reload_default.ogg' + /// Will the tool do its special? + var/enable_special = FALSE + ///Does the component slow/speed up the suit? + var/step_delay = 0 /obj/item/mecha_parts/mecha_equipment/proc/do_after_cooldown(target=1) sleep(equip_cooldown) @@ -38,12 +41,12 @@ if(ready_sound) //Kind of like the kinetic accelerator. playsound(src, ready_sound, 50, 1, -1) if(target && chassis) - return 1 - return 0 + return TRUE + return FALSE /obj/item/mecha_parts/mecha_equipment/examine(mob/user) . = ..() - . += "[src] will fill [equip_type?"a [equip_type]":"any"] slot." + . += SPAN_NOTICE("[src] will fill [equip_type?"a [equip_type]":"any"] slot.") /obj/item/mecha_parts/mecha_equipment/proc/add_equip_overlay(obj/mecha/M as obj) return @@ -52,16 +55,17 @@ if(chassis) send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list()) send_byjax(chassis.occupant,"exosuit.browser","equipment_menu",chassis.get_equipment_menu(),"dropdowns") - return 1 + return TRUE return /obj/item/mecha_parts/mecha_equipment/proc/update_equip_info() if(chassis) send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",get_equip_info()) - return 1 + return TRUE return -/obj/item/mecha_parts/mecha_equipment/proc/destroy()//missiles detonating, teleporter creating singularity? +///Missiles detonating, teleporter creating singularity? +/obj/item/mecha_parts/mecha_equipment/proc/destroy() if(chassis) if(equip_type) if(equip_type == EQUIP_HULL) @@ -90,7 +94,7 @@ if(chassis.selected == src) chassis.selected = null src.update_chassis_page() - chassis.occupant_message("The [src] is destroyed!") + chassis.occupant_message(SPAN_DANGER("The [src] is destroyed!")) chassis.log_append_to_last("[src] is destroyed.",1) if(istype(src, /obj/item/mecha_parts/mecha_equipment/weapon))//Gun switch(chassis.mech_faction) @@ -133,81 +137,76 @@ for (var/path in required_type) if (istype(target, path)) - return 1 - - return 0 + return TRUE + return FALSE /obj/item/mecha_parts/mecha_equipment/proc/action_checks(atom/target) if(!target) - return 0 + return FALSE if(!chassis) - return 0 + return FALSE if(!equip_ready) - return 0 + return FALSE if(energy_drain && !chassis.has_charge(energy_drain)) - return 0 - return 1 + return FALSE + return TRUE /obj/item/mecha_parts/mecha_equipment/proc/action(atom/target) return /obj/item/mecha_parts/mecha_equipment/proc/can_attach(obj/mecha/M as obj) //if(M.equipment.len >= M.max_equip) - // return 0 + // return FALSE if(!allow_duplicate) for(var/obj/item/mecha_parts/mecha_equipment/ME in M.equipment) //Exact duplicate components aren't allowed. if(ME.type == src.type) - return 0 + return FALSE if(equip_type == EQUIP_HULL && M.hull_equipment.len < M.max_hull_equip) - return 1 + return TRUE if(equip_type == EQUIP_WEAPON && M.weapon_equipment.len < M.max_weapon_equip) - return 1 + return TRUE if(equip_type == EQUIP_UTILITY && M.utility_equipment.len < M.max_utility_equip) - return 1 + return TRUE if(equip_type == EQUIP_SPECIAL && M.special_equipment.len < M.max_special_equip) - return 1 - //VOREStation Addition begin: MICROMECHS + return TRUE if(equip_type == EQUIP_MICRO_UTILITY && M.micro_utility_equipment.len < M.max_micro_utility_equip) - return 1 + return TRUE if(equip_type == EQUIP_MICRO_WEAPON && M.micro_weapon_equipment.len < M.max_micro_weapon_equip) - return 1 - //VOREStation Addition end: MICROMECHS + return TRUE if(equip_type != EQUIP_SPECIAL && M.universal_equipment.len < M.max_universal_equip) //The exosuit needs to be military grade to actually have a universal slot capable of accepting a true weapon. if(equip_type == EQUIP_WEAPON && !istype(M, /obj/mecha/combat)) - return 0 - return 1 + return FALSE + return TRUE /*if (ispath(required_type)) return istype(M, required_type) for (var/path in required_type) if (istype(M, path)) - return 1 + return TRUE */ - return 0 + return FALSE /obj/item/mecha_parts/mecha_equipment/proc/attach(obj/mecha/M as obj) //M.equipment += src - var/has_equipped = 0 + var/has_equipped = FALSE if(equip_type == EQUIP_HULL && M.hull_equipment.len < M.max_hull_equip && !has_equipped) M.hull_equipment += src - has_equipped = 1 + has_equipped = TRUE if(equip_type == EQUIP_WEAPON && M.weapon_equipment.len < M.max_weapon_equip && !has_equipped) M.weapon_equipment += src - has_equipped = 1 + has_equipped = TRUE if(equip_type == EQUIP_UTILITY && M.utility_equipment.len < M.max_utility_equip && !has_equipped) M.utility_equipment += src - has_equipped = 1 + has_equipped = TRUE if(equip_type == EQUIP_SPECIAL && M.special_equipment.len < M.max_special_equip && !has_equipped) M.special_equipment += src - has_equipped = 1 - //VOREStation Addition begin: MICROMECHS + has_equipped = TRUE if(equip_type == EQUIP_MICRO_UTILITY && M.micro_utility_equipment.len < M.max_micro_utility_equip && !has_equipped) M.micro_utility_equipment += src - has_equipped = 1 + has_equipped = TRUE if(equip_type == EQUIP_MICRO_WEAPON && M.micro_weapon_equipment.len < M.max_micro_weapon_equip && !has_equipped) M.micro_weapon_equipment += src - has_equipped = 1 - //VOREStation Addition end: MICROMECHS + has_equipped = TRUE if(equip_type != EQUIP_SPECIAL && M.universal_equipment.len < M.max_universal_equip && !has_equipped) M.universal_equipment += src M.equipment += src @@ -238,12 +237,10 @@ chassis.utility_equipment -= src if(EQUIP_SPECIAL) chassis.special_equipment -= src - //VOREStation Addition begin: MICROMECHS if(EQUIP_MICRO_UTILITY) chassis.micro_utility_equipment -= src if(EQUIP_MICRO_WEAPON) chassis.micro_weapon_equipment -= src - //VOREStation Addition end: MICROMECHS if(chassis.selected == src) chassis.selected = null update_chassis_page() @@ -274,8 +271,10 @@ chassis.log_message("[src]: [message]") return -/obj/item/mecha_parts/mecha_equipment/proc/MoveAction() //Allows mech equipment to do an action upon the mech moving +///Allows mech equipment to do an action upon the mech moving +/obj/item/mecha_parts/mecha_equipment/proc/MoveAction() return -/obj/item/mecha_parts/mecha_equipment/proc/get_step_delay() // Equipment returns its slowdown or speedboost. +///Equipment returns its slowdown or speedboost. +/obj/item/mecha_parts/mecha_equipment/proc/get_step_delay() return step_delay diff --git a/code/game/mecha/equipment/tools/extinguisher.dm b/code/game/mecha/equipment/tools/extinguisher.dm index 17ea727c14b..05778968eb3 100644 --- a/code/game/mecha/equipment/tools/extinguisher.dm +++ b/code/game/mecha/equipment/tools/extinguisher.dm @@ -8,29 +8,30 @@ range = MELEE|RANGED required_type = list(/obj/mecha/working) var/spray_particles = 5 - var/spray_amount = 5 //units of liquid per particle. 5 is enough to wet the floor - it's a big fire extinguisher, so should be fine + ///Units of liquid per particle. 5 is enough to wet the floor - it's a big fire extinguisher, so should be fine + var/spray_amount = 5 var/max_water = 1000 /obj/item/mecha_parts/mecha_equipment/tool/extinguisher/Initialize() . = ..() reagents = new/datum/reagents(max_water) reagents.my_atom = src - reagents.add_reagent("firefoam", max_water) //VOREStation Edit + reagents.add_reagent("firefoam", max_water) /obj/item/mecha_parts/mecha_equipment/tool/extinguisher/action(atom/target) //copypasted from extinguisher. TODO: Rewrite from scratch. if(!action_checks(target) || get_dist(chassis, target)>3) return if(get_dist(chassis, target)>2) return set_ready_state(0) if(do_after_cooldown(target)) - if( istype(target, /obj/structure/reagent_dispensers) && get_dist(chassis,target) <= 1) //VOREStation Edit + if( istype(target, /obj/structure/reagent_dispensers) && get_dist(chassis,target) <= 1) var/obj/o = target var/amount = o.reagents.trans_to_obj(src, 200) - occupant_message("[amount] units transferred into internal tank.") + occupant_message(SPAN_NOTICE("[amount] units transferred into internal tank.")) playsound(src, 'sound/effects/refill.ogg', 50, 1, -6) return if (src.reagents.total_volume < 1) - occupant_message("\The [src] is empty.") + occupant_message(SPAN_WARNING("\The [src] is empty.")) return playsound(src, 'sound/effects/extinguish.ogg', 75, 1, -3) @@ -61,7 +62,7 @@ reagents.trans_to_obj(W, spray_amount) W.set_color() W.set_up(my_target) - return 1 + return TRUE /obj/item/mecha_parts/mecha_equipment/tool/extinguisher/get_equip_info() return "[..()] \[[src.reagents.total_volume]\]" diff --git a/code/game/mecha/equipment/tools/sleeper.dm b/code/game/mecha/equipment/tools/sleeper.dm index e0cd8a7ea8e..45f4e6835fb 100644 --- a/code/game/mecha/equipment/tools/sleeper.dm +++ b/code/game/mecha/equipment/tools/sleeper.dm @@ -12,7 +12,7 @@ var/datum/global_iterator/pr_mech_sleeper var/inject_amount = 5 required_type = list(/obj/mecha/medical) - salvageable = 0 + salvageable = FALSE allow_duplicate = TRUE /obj/item/mecha_parts/mecha_equipment/tool/sleeper/Initialize(mapload) @@ -28,7 +28,7 @@ return ..() /obj/item/mecha_parts/mecha_equipment/tool/sleeper/Exit(atom/movable/O) - return 0 + return FALSE /obj/item/mecha_parts/mecha_equipment/tool/sleeper/action(var/mob/living/carbon/human/target) if(!action_checks(target)) @@ -42,7 +42,7 @@ occupant_message("The sleeper is already occupied") return if(target.has_buckled_mobs()) - occupant_message(span("warning", "\The [target] has other entities attached to it. Remove them first.")) + occupant_message(SPAN_WARNING("\The [target] has other entities attached to it. Remove them first.")) return occupant_message("You start putting [target] into [src].") chassis.visible_message("[chassis] starts putting [target] into the [src].") @@ -52,7 +52,7 @@ if(chassis.loc!=C || target.loc!=T) return if(occupant) - occupant_message("The sleeper is already occupied!") + occupant_message(SPAN_DANGER("The sleeper is already occupied!")) return target.forceMove(src) occupant = target diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index b8057bce0fb..8e021066d28 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -1,54 +1,55 @@ /obj/machinery/mecha_part_fabricator - icon = 'icons/obj/robotics_vr.dmi' //VOREStation Edit - New icon - icon_state = "mechfab-idle" + icon = 'icons/obj/machines/fabricators/robotics.dmi' + icon_state = "mechfab" + base_icon_state = "mechfab" name = "Exosuit Fabricator" desc = "A machine used for construction of mechas." - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE use_power = USE_POWER_IDLE idle_power_usage = 20 active_power_usage = 5000 req_access = list(access_robotics) circuit = /obj/item/circuitboard/mechfab - /// Current items in the build queue. + ///Current items in the build queue. var/list/queue = list() - /// Whether or not the machine is building the entire queue automagically. + ///Whether or not the machine is building the entire queue automatically. var/process_queue = FALSE - /// The current design datum that the machine is building. + ///The current design datum that the machine is building. var/datum/design/being_built - /// World time when the build will finish. + ///Is the fabricator currently printing something? + var/printing = FALSE + ///World time when the build will finish. var/build_finish = 0 - /// World time when the build started. + ///World time when the build started. var/build_start = 0 - /// Reference to all materials used in the creation of the item being_built. + ///Reference to all materials used in the creation of the item being_built. var/list/build_materials - /// Part currently stored in the Exofab. + ///Part currently stored in the Exofab. var/obj/item/stored_part - /// Coefficient for the speed of item building. Based on the installed parts. + ///Coefficient for the speed of item building. Based on the installed parts. var/time_coeff = 1 - /// Coefficient for the efficiency of material usage in item building. Based on the installed parts. + ///Coefficient for the efficiency of material usage in item building. Based on the installed parts. var/component_coeff = 1 - var/loading_icon_state = "mechfab-idle" - var/list/materials = list( DEFAULT_WALL_MATERIAL = 0, - "glass" = 0, - "plastic" = 0, + MAT_GLASS = 0, + MAT_PLASTIC = 0, MAT_GRAPHITE = 0, MAT_PLASTEEL = 0, - "gold" = 0, - "silver" = 0, + MAT_GOLD = 0, + MAT_SILVER = 0, MAT_COPPER = 0, MAT_LEAD = 0, - "osmium" = 0, - "diamond" = 0, + MAT_OSMIUM = 0, + MAT_DIAMOND = 0, MAT_DURASTEEL = 0, - "phoron" = 0, - "uranium" = 0, + MAT_PHORON = 0, + MAT_URANIUM= 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0, MAT_METALHYDROGEN = 0, @@ -59,39 +60,39 @@ var/datum/research/files var/valid_buildtype = MECHFAB - /// A list of categories that valid MECHFAB design datums will broadly categorise themselves under. + ///A list of categories that valid MECHFAB design datums will broadly categorise themselves under. var/list/part_sets = list( - "Cyborg", - "Ripley", - "Odysseus", - "Gygax", - "Durand", - "H.O.N.K.", - "Reticent", - "Janus", - "Vehicle", - "Rigsuit", - "Phazon", - "Gopher", // VOREStation Add - "Polecat", // VOREStation Add - "Weasel", // VOREStation Add - "Exosuit Equipment", - "Exosuit Internals", - "Exosuit Ammunition", - "Cyborg Upgrade Modules", - "Cybernetics", - "Implants", - "Control Interfaces", - "Components", - "Other", - "Misc", - "Augments" - ) + "Cyborg", + "Ripley", + "Odysseus", + "Gygax", + "Durand", + "H.O.N.K.", + "Reticent", + "Janus", + "Vehicle", + "Rigsuit", + "Phazon", + "Gopher", + "Polecat", + "Weasel", + "Exosuit Equipment", + "Exosuit Internals", + "Exosuit Ammunition", + "Cyborg Upgrade Modules", + "Cybernetics", + "Implants", + "Control Interfaces", + "Components", + "Other", + "Misc", + "Augments" + ) -/obj/machinery/mecha_part_fabricator/Initialize() +/obj/machinery/mecha_part_fabricator/Initialize(mapload) . = ..() -// Go through all materials, and add them to the possible storage, but hide them unless we contain them. + //Go through all materials, and add them to the possible storage, but hide them unless we contain them. for(var/Name in name_to_material) if(Name in materials) continue @@ -99,8 +100,25 @@ materials[Name] = 0 default_apply_parts() + RefreshParts() files = new /datum/research(src) //Setup the research data holder. + +/obj/machinery/mecha_part_fabricator/update_icon_state() + . = ..() + if(stat & NOPOWER) + icon_state = "[base_icon_state]-off" + else + icon_state = base_icon_state + +/obj/machinery/mecha_part_fabricator/update_overlays() + . = ..() + cut_overlays() + if(panel_open) + add_overlay("[base_icon_state]-panel") + if(printing) + add_overlay("[base_icon_state]-active") + /obj/machinery/mecha_part_fabricator/dismantle() for(var/f in materials) eject_materials(f, -1) @@ -109,12 +127,12 @@ /obj/machinery/mecha_part_fabricator/RefreshParts() res_max_amount = 0 for(var/obj/item/stock_parts/matter_bin/M in component_parts) - res_max_amount += M.rating * 100000 // 200k -> 600k + res_max_amount += M.rating * 100000 //200k -> 600k var/T = 0 for(var/obj/item/stock_parts/manipulator/M in component_parts) T += M.rating component_coeff = max(1 - (T - 1) / 4, 0.2) // 1 -> 0.2 - for(var/obj/item/stock_parts/micro_laser/M in component_parts) // Not resetting T is intended; time_coeff is affected by both + for(var/obj/item/stock_parts/micro_laser/M in component_parts) //Not resetting T is intended; time_coeff is affected by both T += M.rating time_coeff = T / 2 // 1 -> 3 update_static_data(usr) @@ -138,8 +156,8 @@ var/list/sub_category = null if(categories) - // Handle some special cases to build up sub-categories for the fab interface. - // Start with checking if this design builds a cyborg module. + //Handle some special cases to build up sub-categories for the fab interface. + //Start with checking if this design builds a cyborg module. if(built_item in typesof(/obj/item/borg/upgrade)) var/obj/item/borg/upgrade/U = built_item var/module_types = initial(U.module_flags) @@ -157,7 +175,7 @@ sub_category += "Engineering" else sub_category += "All Cyborgs" - // Else check if this design builds a piece of exosuit equipment. + //Else check if this design builds a piece of exosuit equipment. else if(built_item in typesof(/obj/item/mecha_parts/mecha_equipment)) var/obj/item/mecha_parts/mecha_equipment/E = built_item var/mech_types = initial(E.mech_flags) @@ -217,8 +235,9 @@ * Adds the overlay to show the fab working and sets active power usage settings. */ /obj/machinery/mecha_part_fabricator/proc/on_start_printing() - add_overlay("fab-active") use_power = USE_POWER_ACTIVE + printing = TRUE + update_appearance() /** * Intended to be called when the exofab has stopped working and is no longer printing items. @@ -226,10 +245,11 @@ * Removes the overlay to show the fab working and sets idle power usage settings. Additionally resets the description and turns off queue processing. */ /obj/machinery/mecha_part_fabricator/proc/on_finish_printing() - cut_overlay("fab-active") use_power = USE_POWER_IDLE desc = initial(desc) + printing = FALSE process_queue = FALSE + update_appearance() /** * Calculates resource/material costs for printing an item based on the machine's resource coefficient. @@ -305,9 +325,9 @@ return TRUE -/obj/machinery/mecha_part_fabricator/process() +/obj/machinery/mecha_part_fabricator/process(delta_time) ..() - // If there's a stored part to dispense due to an obstruction, try to dispense it. + //If there's a stored part to dispense due to an obstruction, try to dispense it. if(stored_part) var/turf/exit = get_step(src,(dir)) if(exit.density) @@ -317,17 +337,17 @@ stored_part.forceMove(exit) stored_part = null - // If there's nothing being built, try to build something + //If there's nothing being built, try to build something if(!being_built) - // If we're not processing the queue anymore or there's nothing to build, end processing. + //If we're not processing the queue anymore or there's nothing to build, end processing. if(!process_queue || !build_next_in_queue()) on_finish_printing() return PROCESS_KILL on_start_printing() - // If there's an item being built, check if it is complete. + //If there's an item being built, check if it is complete. if(being_built && (build_finish < world.time)) - // Then attempt to dispense it and if appropriate build the next item. + //Then attempt to dispense it and if appropriate build the next item. dispense_built_part(being_built) if(process_queue) build_next_in_queue(FALSE) @@ -618,8 +638,8 @@ /obj/machinery/mecha_part_fabricator/attackby(var/obj/item/I, var/mob/user) if(being_built) - to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") - return 1 + to_chat(user, SPAN_NOTICE("\The [src] is busy. Please wait for completion of previous operation.")) + return TRUE if(default_deconstruction_screwdriver(user, I)) return if(default_deconstruction_crowbar(user, I)) @@ -630,20 +650,19 @@ if(istype(I,/obj/item/stack/material)) var/obj/item/stack/material/S = I if(!(S.material.name in materials)) - to_chat(user, "The [src] doesn't accept [S.material]!") + to_chat(user, SPAN_WARNING("The [src] doesn't accept [S.material]!")) return var/sname = "[S.name]" + var/matname = "[S.material.name]" var/amnt = S.perunit if(materials[S.material.name] + amnt <= res_max_amount) if(S && S.get_amount() >= 1) var/count = 0 - flick("[loading_icon_state]", src) - // yess hacky but whatever - if(loading_icon_state == "mechfab-idle") - overlays += "mechfab-load-metal" - spawn(10) - overlays -= "mechfab-load-metal" + //This is dumb that it happens here but whatever. I guess it's a TODO then. + add_overlay("[initial(icon_state)]-load-[matname]") + spawn(10) + cut_overlay("[initial(icon_state)]-load-[matname]") while(materials[S.material.name] + amnt <= res_max_amount && S.get_amount() >= 1) materials[S.material.name] += amnt S.use(1) diff --git a/code/game/mecha/mech_prosthetics.dm b/code/game/mecha/mech_prosthetics.dm index 8eec91baf18..5c8e7f81576 100644 --- a/code/game/mecha/mech_prosthetics.dm +++ b/code/game/mecha/mech_prosthetics.dm @@ -1,8 +1,8 @@ /obj/machinery/mecha_part_fabricator/pros - icon = 'icons/obj/robotics.dmi' - icon_state = "prosfab" name = "Prosthetics Fabricator" desc = "A machine used for construction of prosthetics." + icon_state = "profab" + base_icon_state = "profab" density = TRUE anchored = TRUE use_power = USE_POWER_IDLE @@ -11,13 +11,11 @@ req_access = list(access_robotics) circuit = /obj/item/circuitboard/prosthetics - // Prosfab specific stuff + //Prosfab specific stuff var/manufacturer = null var/species_types = list("Human") var/species = "Human" - loading_icon_state = "prosfab_loading" - materials = list( DEFAULT_WALL_MATERIAL = 0, MAT_GLASS = 0, @@ -38,7 +36,7 @@ res_max_amount = 200000 valid_buildtype = PROSFAB - /// A list of categories that valid PROSFAB design datums will broadly categorise themselves under. + ///A list of categories that valid PROSFAB design datums will broadly categorise themselves under. part_sets = list( "Cyborg", "Ripley", @@ -68,9 +66,11 @@ "Misc", ) -/obj/machinery/mecha_part_fabricator/pros/Initialize() +/obj/machinery/mecha_part_fabricator/pros/Initialize(mapload) . = ..() manufacturer = basic_robolimb.company + default_apply_parts() + RefreshParts() /obj/machinery/mecha_part_fabricator/pros/dispense_built_part(datum/design/D) var/obj/item/I = ..() @@ -105,7 +105,6 @@ . = TRUE - add_fingerprint(usr) usr.set_machine(src) switch(action) @@ -134,6 +133,8 @@ if(..()) return TRUE + add_fingerprint(usr) + if(istype(I,/obj/item/disk/limb)) var/obj/item/disk/limb/D = I if(!D.company || !(D.company in all_robolimbs)) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index ee2f352ae2a..e23c96f9b65 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -282,7 +282,7 @@ if(E.salvageable && prob(30)) WR.crowbar_salvage += E E.forceMove(WR) - E.equip_ready = 1 + E.equip_ready = TRUE else E.forceMove(loc) E.destroy() diff --git a/code/game/objects/effects/alien/aliens.dm b/code/game/objects/effects/alien/aliens.dm index 965c3f3bb92..a90cdb4104b 100644 --- a/code/game/objects/effects/alien/aliens.dm +++ b/code/game/objects/effects/alien/aliens.dm @@ -412,7 +412,7 @@ Alien plants should do something if theres a lot of poison if(ticks >= target_strength) for(var/mob/O in hearers(src, null)) - O.show_message("[src.target] collapses under its own weight into a puddle of goop and undigested debris!", 1) + O.show_message("[src.target] collapses under its own weight into a puddle of goop and undigested debris!", 1) if(istype(target, /turf/simulated/wall)) // I hate turf code. var/turf/simulated/wall/W = target @@ -424,13 +424,13 @@ Alien plants should do something if theres a lot of poison switch(target_strength - ticks) if(6) - visible_message("[src.target] is holding up against the acid!") + visible_message("[src.target] is holding up against the acid!") if(4) - visible_message("[src.target]\s structure is being melted by the acid!") + visible_message("[src.target]\s structure is being melted by the acid!") if(2) - visible_message("[src.target] is struggling to withstand the acid!") + visible_message("[src.target] is struggling to withstand the acid!") if(0 to 1) - visible_message("[src.target] begins to crumble under the acid!") + visible_message("[src.target] begins to crumble under the acid!") spawn(rand(150, 200)) tick() /* diff --git a/code/game/objects/effects/chem/chemsmoke.dm b/code/game/objects/effects/chem/chemsmoke.dm index bcf24ac043d..2fd742704cd 100644 --- a/code/game/objects/effects/chem/chemsmoke.dm +++ b/code/game/objects/effects/chem/chemsmoke.dm @@ -29,8 +29,8 @@ var/datum/seed/seed /datum/effect_system/smoke_spread/chem/spores/New(seed_name) - if(seed_name && plant_controller) - seed = plant_controller.seeds[seed_name] + if(seed_name && SSplants) + seed = SSplants.seeds[seed_name] if(!seed) qdel(src) ..() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index d7af9328406..64a877fb23f 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -540,9 +540,10 @@ var/list/global/slot_flags_enumeration = list( return -//This proc is executed when someone clicks the on-screen UI button. To make the UI button show, set the 'icon_action_button' to the icon_state of the image of the button in screen1_action.dmi -//The default action is attack_self(). -//Checks before we get to here are: mob is alive, mob is not restrained, paralyzed, asleep, resting, laying, item is on the mob. +/** + *This proc is executed when someone clicks the on-screen UI button. + *The default action is attack_self(). + */ /obj/item/proc/ui_action_click() attack_self(usr) @@ -948,3 +949,7 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. // Like the above, but used for RPED sorting of parts. /obj/item/proc/rped_rating() return get_rating() + +/obj/item/interact(mob/user) + add_fingerprint(user) + ui_interact(user) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 6f8f2569e58..138c6ea92bf 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -5,12 +5,15 @@ icon_state = "flashlight" w_class = ITEMSIZE_SMALL slot_flags = SLOT_BELT - matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) + matter = list(DEFAULT_WALL_MATERIAL = 50, MAT_GLASS = 20) action_button_name = "Toggle Flashlight" - var/on = 0 - var/brightness_on = 4 //luminosity when on - var/flashlight_power = 0.8 //lighting power when on - var/flashlight_colour = LIGHT_COLOR_INCANDESCENT_FLASHLIGHT //lighting colour when on + var/on = FALSE + ///Luminosity when on + var/brightness_on = 4 + ///Lighting power when on + var/flashlight_power = 0.8 + ///Lighting colour when on + var/flashlight_colour = LIGHT_COLOR_INCANDESCENT_FLASHLIGHT var/obj/item/cell/cell var/cell_type = /obj/item/cell/device var/list/brightness_levels @@ -49,7 +52,7 @@ if(choice) brightness_level = choice power_usage = brightness_levels[choice] - to_chat(user, "You set the brightness level on \the [src] to [brightness_level].") + to_chat(user, SPAN_NOTICE("You set the brightness level on \the [src] to [brightness_level].")) update_icon() /obj/item/flashlight/process(delta_time) @@ -57,11 +60,11 @@ return PROCESS_KILL if(brightness_level && power_usage) - if(cell.use(power_usage) != power_usage) // we weren't able to use our full power_usage amount! - visible_message("\The [src] flickers before going dull.") - set_light(0) + if(cell.use(power_usage) != power_usage) //We weren't able to use our full power_usage amount! + visible_message(SPAN_WARNING("\The [src] flickers before going dull.")) + set_light(FALSE) playsound(src.loc, 'sound/effects/sparks3.ogg', 10, 1, -3) //Small cue that your light went dull in your pocket. - on = 0 + on = FALSE update_icon() return PROCESS_KILL @@ -102,10 +105,10 @@ if(power_use) if(!isturf(user.loc)) to_chat(user, "You cannot turn the light on while in this [user.loc].") //To prevent some lighting anomalities. - return 0 + return FALSE if(!cell || cell.charge == 0) to_chat(user, "You flick the switch on [src], but nothing happens.") - return 0 + return FALSE on = !on if(on && power_use) START_PROCESSING(SSobj, src) @@ -114,7 +117,7 @@ playsound(src.loc, 'sound/weapons/empty.ogg', 15, 1, -3) update_icon() user.update_action_buttons() - return 1 + return TRUE /obj/item/flashlight/emp_act(severity) for(var/obj/O in contents) @@ -132,38 +135,38 @@ if(istype(H)) for(var/obj/item/clothing/C in list(H.head,H.wear_mask,H.glasses)) if(istype(C) && (C.body_parts_covered & EYES)) - to_chat(user, "You're going to need to remove [C.name] first.") + to_chat(user, SPAN_WARNING("You're going to need to remove [C.name] first.")) return var/obj/item/organ/vision if(H.species.vision_organ) vision = H.internal_organs_by_name[H.species.vision_organ] if(!vision) - to_chat(user, "You can't find any [H.species.vision_organ ? H.species.vision_organ : "eyes"] on [H]!") + to_chat(user, SPAN_WARNING("You can't find any [H.species.vision_organ ? H.species.vision_organ : "eyes"] on [H]!")) - user.visible_message("\The [user] directs [src] to [M]'s eyes.", \ - "You direct [src] to [M]'s eyes.") + user.visible_message(SPAN_NOTICE("\The [user] directs [src] to [M]'s eyes."), \ + SPAN_NOTICE("You direct [src] to [M]'s eyes.")) if(H != user) //can't look into your own eyes buster if(M.stat == DEAD || M.blinded) //mob is dead or fully blind - to_chat(user, "\The [M]'s pupils do not react to the light!") + to_chat(user, SPAN_WARNING("\The [M]'s pupils do not react to the light!")) return if(XRAY in M.mutations) - to_chat(user, "\The [M] pupils give an eerie glow!") + to_chat(user, SPAN_NOTICE("\The [M] pupils give an eerie glow!")) if(vision.is_bruised()) - to_chat(user, "There's visible damage to [M]'s [vision.name]!") + to_chat(user, SPAN_WARNING("There's visible damage to [M]'s [vision.name]!")) else if(M.eye_blurry) - to_chat(user, "\The [M]'s pupils react slower than normally.") + to_chat(user, SPAN_NOTICE("\The [M]'s pupils react slower than normally.")) if(M.getBrainLoss() > 15) - to_chat(user, "There's visible lag between left and right pupils' reactions.") + to_chat(user, SPAN_NOTICE("There's visible lag between left and right pupils' reactions.")) var/list/pinpoint = list("oxycodone"=1,"tramadol"=5) var/list/dilating = list("space_drugs"=5,"mindbreaker"=1) if(M.reagents.has_any_reagent(pinpoint) || H.ingested.has_any_reagent(pinpoint)) - to_chat(user, "\The [M]'s pupils are already pinpoint and cannot narrow any more.") + to_chat(user, SPAN_NOTICE("\The [M]'s pupils are already pinpoint and cannot narrow any more.")) else if(M.reagents.has_any_reagent(dilating) || H.ingested.has_any_reagent(dilating)) - to_chat(user, "\The [M]'s pupils narrow slightly, but are still very dilated.") + to_chat(user, SPAN_NOTICE("\The [M]'s pupils narrow slightly, but are still very dilated.")) else - to_chat(user, "\The [M]'s pupils narrow.") + to_chat(user, SPAN_NOTICE("\The [M]'s pupils narrow.")) user.setClickCooldown(user.get_attack_speed(src)) //can be used offensively M.flash_eyes() @@ -176,9 +179,9 @@ cell.update_icon() user.put_in_hands(cell) cell = null - to_chat(user, "You remove the cell from the [src].") - playsound(src, 'sound/machines/button.ogg', 30, 1, 0) - on = 0 + to_chat(user, SPAN_NOTICE("You remove the cell from the [src].")) + playsound(src, 'sound/machines/button.ogg', 30, TRUE, 0) + on = FALSE update_icon() return ..() @@ -225,13 +228,13 @@ user.drop_item() W.loc = src cell = W - to_chat(user, "You install a cell in \the [src].") + to_chat(user, SPAN_NOTICE("You install a cell in \the [src].")) playsound(src, 'sound/machines/button.ogg', 30, 1, 0) update_icon() else - to_chat(user, "\The [src] already has a cell.") + to_chat(user, SPAN_NOTICE("\The [src] already has a cell.")) else - to_chat(user, "\The [src] cannot use that type of cell.") + to_chat(user, SPAN_NOTICE("\The [src] cannot use that type of cell.")) else ..() @@ -277,7 +280,7 @@ slot_flags = SLOT_BELT w_class = ITEMSIZE_SMALL attack_verb = list ("smacked", "thwacked", "thunked") - matter = list(DEFAULT_WALL_MATERIAL = 200,"glass" = 50) + matter = list(DEFAULT_WALL_MATERIAL = 200, MAT_GLASS = 50) hitsound = "swing_hit" /obj/item/flashlight/drone @@ -351,7 +354,7 @@ STOP_PROCESSING(SSobj, src) /obj/item/flashlight/flare/proc/turn_off() - on = 0 + on = FALSE src.force = initial(src.force) src.damtype = initial(src.damtype) update_icon() @@ -360,7 +363,7 @@ // Usual checks if(!fuel) - to_chat(user, "It's out of fuel.") + to_chat(user, SPAN_NOTICE("It's out of fuel.")) return if(on) return @@ -368,7 +371,7 @@ . = ..() // All good, turn it on. if(.) - user.visible_message("[user] activates the flare.", "You pull the cord on the flare, activating it!") + user.visible_message(SPAN_NOTICE("[user] activates the flare."), SPAN_NOTICE("You pull the cord on the flare, activating it!")) src.force = on_damage src.damtype = "fire" START_PROCESSING(SSobj, src) @@ -379,7 +382,7 @@ force = on_damage damtype = "fire" START_PROCESSING(SSobj, src) - return 1 + return TRUE //Glowsticks @@ -408,20 +411,20 @@ STOP_PROCESSING(SSobj, src) /obj/item/flashlight/glowstick/proc/turn_off() - on = 0 + on = FALSE update_icon() /obj/item/flashlight/glowstick/attack_self(mob/user) if(!fuel) - to_chat(user, "The glowstick has already been turned on.") + to_chat(user, SPAN_NOTICE("The glowstick has already been turned on.")) return if(on) return . = ..() if(.) - user.visible_message("[user] cracks and shakes the glowstick.", "You crack and shake the glowstick, turning it on!") + user.visible_message(SPAN_NOTICE("[user] cracks and shakes the glowstick."), SPAN_NOTICE("You crack and shake the glowstick, turning it on!")) START_PROCESSING(SSobj, src) /obj/item/flashlight/glowstick/red @@ -462,7 +465,7 @@ flashlight_colour = "#FFF423" w_class = ITEMSIZE_TINY brightness_on = 6 - on = 1 //Bio-luminesence has one setting, on. + on = TRUE //Bio-luminesence has one setting, on. power_use = 0 /obj/item/flashlight/slime/Initialize(mapload) diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 9ca057cd1f0..83533bbee1c 100755 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -83,6 +83,9 @@ return "[..()][append]" +/obj/item/radio/headset/ui_state(mob/user) + return GLOB.inventory_state + /obj/item/radio/headset/syndicate origin_tech = list(TECH_ILLEGAL = 3) syndie = 1 @@ -414,7 +417,7 @@ return -/obj/item/radio/headset/proc/recalculateChannels(var/setDescription = 0) +/obj/item/radio/headset/recalculateChannels(var/setDescription = 0) src.channels = list() src.translate_binary = 0 src.translate_hive = 0 diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 59bb43fd71a..001deeb410d 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -24,33 +24,42 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( )) /obj/item/radio - icon = 'icons/obj/radio.dmi' //VOREStation Edit - name = "shortwave radio" //VOREStation Edit + icon = 'icons/obj/radio.dmi' + name = "shortwave radio" suffix = "\[3\]" icon_state = "walkietalkie" item_state = "radio" - var/on = 1 // 0 for off + ///FALSE for off + var/on = TRUE var/last_transmission var/frequency = PUB_FREQ //common chat - var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies - var/canhear_range = 3 // the range which mobs can hear this radio from + ///Tune to frequency to unlock traitor supplies + var/traitor_frequency = 0 + ///The range which mobs can hear this radio from + var/canhear_range = 3 + ///Allows borgs to disable canhear_range. + var/loudspeaker = TRUE var/datum/wires/radio/wires = null var/b_stat = 0 - var/broadcasting = 0 - var/listening = 1 + var/broadcasting = FALSE + var/listening = TRUE var/list/channels = list() //see communications.dm for full list. First channel is a "default" for :h - var/subspace_transmission = 0 - var/adhoc_fallback = FALSE //Falls back to 'radio' mode if subspace not available - var/syndie = 0//Holder to see if it's a syndicate encrypted radio - var/centComm = 0//Holder to see if it's a CentCom encrypted radio + var/subspace_transmission = FALSE + var/subspace_switchable = FALSE + ///Falls back to 'radio' mode if subspace not available + var/adhoc_fallback = FALSE + ///Holder to see if it's a syndicate encrypted radio + var/syndie = FALSE + ///Holder to see if it's a CentCom encrypted radio + var/centComm = FALSE slot_flags = SLOT_BELT throw_speed = 2 throw_range = 9 w_class = ITEMSIZE_SMALL show_messages = 1 - // Bluespace radios talk directly to telecomms equipment + //Bluespace radios talk directly to telecomms equipment var/bluespace_radio = FALSE var/datum/weakref/bs_tx_weakref //Maybe misleading, this is the device to TRANSMIT TO // For mappers or subtypes, to start them prelinked to these devices @@ -117,6 +126,9 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( if(!found) stack_trace("A radio [src] at [x],[y],[z] specified bluespace prelink IDs, but the machines with corresponding IDs ([bs_tx_preload_id], [bs_rx_preload_id]) couldn't be found.") +/obj/item/radio/proc/recalculateChannels() + return + /obj/item/radio/Destroy() qdel(wires) wires = null @@ -138,15 +150,23 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( if(b_stat) wires.Interact(user) - return nano_ui_interact(user) + return ui_interact(user) -/obj/item/radio/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/item/radio/ui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Radio", name) + ui.open() + +/obj/item/radio/ui_data(mob/user) var/data[0] - data["mic_status"] = broadcasting - data["speaker"] = listening - data["freq"] = format_frequency(frequency) - data["rawfreq"] = num2text(frequency) + data["rawfreq"] = frequency + data["listening"] = listening + data["broadcasting"] = broadcasting + data["subspace"] = subspace_transmission + data["subspaceSwitchable"] = subspace_switchable + data["loudspeaker"] = loudspeaker data["mic_cut"] = (wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL)) data["spk_cut"] = (wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL)) @@ -154,16 +174,72 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( var/list/chanlist = list_channels(user) if(islist(chanlist) && chanlist.len) data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len + else + data["chan_list"] = null if(syndie) - data["useSyndMode"] = 1 + data["useSyndMode"] = TRUE - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430) - ui.set_initial_data(data) - ui.open() + data["minFrequency"] = PUBLIC_LOW_FREQ + data["maxFrequency"] = PUBLIC_HIGH_FREQ + + return data + +/obj/item/radio/ui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("setFrequency") + var/new_frequency = (text2num(params["freq"])) + if((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)) + new_frequency = sanitize_frequency(new_frequency) + set_frequency(new_frequency) + if(hidden_uplink) + if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency)) + usr << browse(null, "window=radio") + . = TRUE + if("broadcast") + ToggleBroadcast() + . = TRUE + if("listen") + ToggleReception() + . = TRUE + if("channel") + var/chan_name = params["channel"] + if(channels[chan_name] & FREQ_LISTENING) + channels[chan_name] &= ~FREQ_LISTENING + else + channels[chan_name] |= FREQ_LISTENING + . = TRUE + if("specFreq") + var/freq = params["channel"] + if(has_channel_access(usr, freq)) + set_frequency(text2num(freq)) + . = TRUE + if("subspace") + if(subspace_switchable) + subspace_transmission = !subspace_transmission + if(!subspace_transmission) + channels = list() + to_chat(usr, SPAN_NOTICE("Subspace Transmission is disabled")) + else + recalculateChannels() + to_chat(usr, SPAN_NOTICE("Subspace Transmission is enabled")) + . = TRUE + if("toggleLoudspeaker") + if(!subspace_switchable) + return + loudspeaker = !loudspeaker + + if(loudspeaker) + to_chat(usr, SPAN_NOTICE("Loadspeaker enabled.")) + else + to_chat(usr, SPAN_NOTICE("Loadspeaker disabled.")) + . = TRUE + + if(. && iscarbon(usr)) + playsound(src, "button", 10) /obj/item/radio/proc/list_channels(var/mob/user) return list_internal_channels(user) @@ -175,7 +251,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( var/chan_stat = channels[ch_name] var/listening = !!(chan_stat & FREQ_LISTENING) != 0 - dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "chan_span" = frequency_span_class(radiochannels[ch_name])))) + dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "freq" = radiochannels[ch_name]))) return dat @@ -183,7 +259,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( var/dat[0] for(var/internal_chan in internal_channels) if(has_channel_access(user, internal_chan)) - dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_name(text2num(internal_chan)), "chan_span" = frequency_span_class(text2num(internal_chan))))) + dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_name(text2num(internal_chan)), "freq" = text2num(internal_chan)))) return dat @@ -221,51 +297,6 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( return UI_CLOSE return ..() -/obj/item/radio/Topic(href, href_list) - if(..()) - return TRUE - - usr.set_machine(src) - if (href_list["track"]) - var/mob/target = locate(href_list["track"]) - var/mob/living/silicon/ai/A = locate(href_list["track2"]) - if(A && target) - A.ai_actual_track(target) - . = 1 - - else if (href_list["freq"]) - var/new_frequency = (frequency + text2num(href_list["freq"])) - if ((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)) - new_frequency = sanitize_frequency(new_frequency) - set_frequency(new_frequency) - if(hidden_uplink) - if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency)) - usr << browse(null, "window=radio") - . = 1 - else if (href_list["talk"]) - ToggleBroadcast() - . = 1 - else if (href_list["listen"]) - var/chan_name = href_list["ch_name"] - if (!chan_name) - ToggleReception() - else - if (channels[chan_name] & FREQ_LISTENING) - channels[chan_name] &= ~FREQ_LISTENING - else - channels[chan_name] |= FREQ_LISTENING - . = 1 - else if(href_list["spec_freq"]) - var freq = href_list["spec_freq"] - if(has_channel_access(usr, freq)) - set_frequency(text2num(freq)) - . = 1 - if(href_list["nowindow"]) // here for pAIs, maybe others will want it, idk - return TRUE - - if(.) - SSnanoui.update_uis(src) - /obj/item/radio/proc/autosay(var/message, var/from, var/channel, list/zlevels = list(0)) //BS12 EDIT var/datum/radio_frequency/connection = null if(channel && channels && channels.len > 0) @@ -288,25 +319,25 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( ///Interprets the message mode when talking into a radio, possibly returning a connection datum /obj/item/radio/proc/handle_message_mode(mob/living/M as mob, message, message_mode) - // If a channel isn't specified, send to common. + //If a channel isn't specified, send to common. if(!message_mode || message_mode == "headset") return radio_connection - // Otherwise, if a channel is specified, look for it. + //Otherwise, if a channel is specified, look for it. if(channels && channels.len > 0) - if (message_mode == "department") // Department radio shortcut + if (message_mode == "department") //Department radio shortcut message_mode = channels[1] if (channels[message_mode]) // only broadcast if the channel is set on return secure_radio_connections[message_mode] - // If we were to send to a channel we don't have, drop it. + //If we were to send to a channel we don't have, drop it. return null /obj/item/radio/talk_into(mob/living/M as mob, message, channel, var/verb = "says", var/datum/language/speaking = null) if(!on) - return FALSE // the device has to be on - // Fix for permacell radios, but kinda eh about actually fixing them. + return FALSE //The device has to be on + //Fix for permacell radios, but kinda eh about actually fixing them. if(!M || !message) return FALSE @@ -437,14 +468,14 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( if(bluespace_radio) //Nothing to transmit to if(!bs_tx_weakref) - to_chat(loc, "\The [src] buzzes to inform you of the lack of a functioning connection.") + to_chat(loc, SPAN_WARNING("\The [src] buzzes to inform you of the lack of a functioning connection.")) return FALSE var/obj/machinery/telecomms/tx_to = bs_tx_weakref.resolve() //Was linked, now destroyed or something if(!tx_to) bs_tx_weakref = null - to_chat(loc, "\The [src] buzzes to inform you of the lack of a functioning connection.") + to_chat(loc, SPAN_WARNING("\The [src] buzzes to inform you of the lack of a functioning connection.")) return FALSE //Transmitted in the blind. If we get a message back, cool. If not, oh well. @@ -456,7 +487,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( var/list/jamming = is_jammed(src) if(jamming) var/distance = jamming["distance"] - to_chat(M, "[icon2html(src, world)] You hear the [distance <= 2 ? "loud hiss" : "soft hiss"] of static.") + to_chat(M, SPAN_DANGER("[icon2html(src, world)] You hear the [distance <= 2 ? "loud hiss" : "soft hiss"] of static.")) return FALSE // First, we want to generate a new radio signal @@ -475,7 +506,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( return TRUE //Huzzah, sent via subspace else if(adhoc_fallback) //Less huzzah, we have to fallback - to_chat(loc, "\The [src] pings as it falls back to local radio transmission.") + to_chat(loc, SPAN_WARNING("\The [src] pings as it falls back to local radio transmission.")) subspace_transmission = FALSE else //Oh well @@ -503,7 +534,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( if(signal.data["done"] && (pos_z in signal.data["level"])) if(adhoc_fallback) - to_chat(loc, "\The [src] pings as it reestablishes subspace communications.") + to_chat(loc, SPAN_NOTICE("\The [src] pings as it reestablishes subspace communications.")) subspace_transmission = TRUE // we're done here. return TRUE @@ -581,9 +612,9 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( . = ..() if ((in_range(src, user) || loc == user)) if (b_stat) - . += "\The [src] can be attached and modified!" + . += SPAN_NOTICE("\The [src] can be attached and modified!") else - . += "\The [src] can not be modified or attached!" + . += SPAN_NOTICE("\The [src] can not be modified or attached!") return /obj/item/radio/attackby(obj/item/W as obj, mob/user as mob) @@ -594,15 +625,15 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( b_stat = !( b_stat ) if(!istype(src, /obj/item/radio/beacon)) if (b_stat) - user.show_message("\The [src] can now be attached and modified!") + user.show_message(SPAN_NOTICE("\The [src] can now be attached and modified!")) else - user.show_message("\The [src] can no longer be modified or attached!") + user.show_message(SPAN_NOTICE("\The [src] can no longer be modified or attached!")) updateDialog() return /obj/item/radio/emp_act(severity) - broadcasting = 0 - listening = 0 + broadcasting = FALSE + listening = FALSE for (var/ch_name in channels) channels[ch_name] = 0 ..() @@ -615,11 +646,11 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( /obj/item/radio/borg var/mob/living/silicon/robot/myborg = null // Cyborg which owns this radio. Used for power checks var/obj/item/encryptionkey/keyslot = null//Borg radios can handle a single encryption key - var/shut_up = 1 icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component. icon_state = "radio" canhear_range = 0 - subspace_transmission = 1 + subspace_transmission = TRUE + subspace_switchable = TRUE /obj/item/radio/borg/Destroy() myborg = null @@ -677,7 +708,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( return -/obj/item/radio/borg/proc/recalculateChannels() +/obj/item/radio/borg/recalculateChannels() src.channels = list() src.syndie = 0 @@ -707,71 +738,6 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( return -/obj/item/radio/borg/Topic(href, href_list) - if(..()) - return TRUE - if (href_list["mode"]) - var/enable_subspace_transmission = text2num(href_list["mode"]) - if(enable_subspace_transmission != subspace_transmission) - subspace_transmission = !subspace_transmission - if(subspace_transmission) - to_chat(usr, "Subspace Transmission is enabled") - else - to_chat(usr, "Subspace Transmission is disabled") - - if(subspace_transmission == 0)//Simple as fuck, clears the channel list to prevent talking/listening over them if subspace transmission is disabled - channels = list() - else - recalculateChannels() - . = 1 - if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. - var/do_shut_up = text2num(href_list["shutup"]) - if(do_shut_up != shut_up) - shut_up = !shut_up - if(shut_up) - canhear_range = 0 - to_chat(usr, "Loadspeaker disabled.") - else - canhear_range = 3 - to_chat(usr, "Loadspeaker enabled.") - . = 1 - - if(.) - SSnanoui.update_uis(src) - -/obj/item/radio/borg/interact(mob/user as mob) - if(!on) - return - - . = ..() - -/obj/item/radio/borg/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/data[0] - - data["mic_status"] = broadcasting - data["speaker"] = listening - data["freq"] = format_frequency(frequency) - data["rawfreq"] = num2text(frequency) - - var/list/chanlist = list_channels(user) - if(islist(chanlist) && chanlist.len) - data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len - - if(syndie) - data["useSyndMode"] = 1 - - data["has_loudspeaker"] = 1 - data["loudspeaker"] = !shut_up - data["has_subspace"] = 1 - data["subspace"] = subspace_transmission - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 430) - ui.set_initial_data(data) - ui.open() - /obj/item/radio/proc/config(op) if(radio_controller) for (var/ch_name in channels) @@ -784,15 +750,15 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( return /obj/item/radio/off - listening = 0 + listening = FALSE /obj/item/radio/phone - broadcasting = 0 icon = 'icons/obj/items.dmi' icon_state = "red_phone" - listening = 1 - name = "phone" anchored = FALSE + broadcasting = FALSE + listening = TRUE + name = "phone" /obj/item/radio/phone/medbay frequency = MED_I_FREQ diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index be77b6c557a..9d5bca3155e 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -1,64 +1,73 @@ /obj/item/transfer_valve name = "tank transfer valve" - desc = "Regulates the transfer of air between two tanks" + desc = "Regulates the transfer of air between two tanks." icon = 'icons/obj/assemblies.dmi' icon_state = "valve_1" + base_icon_state = "valve" + //inhand_icon_state = "ttv" + //lefthand_file = 'icons/mob/inhands/weapons/bombs_lefthand.dmi' + //righthand_file = 'icons/mob/inhands/weapons/bombs_righthand.dmi' + w_class = WEIGHT_CLASS_BULKY + var/obj/item/tank/tank_one var/obj/item/tank/tank_two - var/obj/item/attached_device + var/obj/item/assembly/attached_device var/mob/attacher = null - var/valve_open = 0 - var/toggle = 1 + var/valve_open = FALSE + var/toggle = TRUE flags = PROXMOVE -/obj/item/transfer_valve/proc/process_activation(var/obj/item/D) -/obj/item/transfer_valve/IsAssemblyHolder() - return 1 +/obj/item/transfer_valve/Destroy() + attached_device = null + return ..() -/obj/item/transfer_valve/attackby(obj/item/item, mob/user) +/obj/item/transfer_valve/attackby(obj/item/item, mob/user, params) var/turf/location = get_turf(src) // For admin logs if(istype(item, /obj/item/tank)) if(tank_one && tank_two) - to_chat(user, "There are already two tanks attached, remove one first.") + to_chat(user, SPAN_WARNING("There are already two tanks attached, remove one first!")) return if(!tank_one) + if(!user.transferItemToLoc(item, src)) + return tank_one = item - user.drop_item() - item.loc = src - to_chat(user, "You attach the tank to the transfer valve.") + to_chat(user, SPAN_NOTICE("You attach the tank to the transfer valve.")) + else if(!tank_two) + if(!user.transferItemToLoc(item, src)) + return tank_two = item - user.drop_item() - item.loc = src - to_chat(user, "You attach the tank to the transfer valve.") + to_chat(user, SPAN_NOTICE("You attach the tank to the transfer valve.")) + message_admins("[key_name_admin(user)] attached both tanks to a transfer valve. (JMP)") log_game("[key_name_admin(user)] attached both tanks to a transfer valve.") - update_icon() - SSnanoui.update_uis(src) // update all UIs attached to src + update_appearance() + SStgui.update_uis(src) // update all UIs attached to src //TODO: Have this take an assemblyholder else if(isassembly(item)) var/obj/item/assembly/A = item if(A.secured) - to_chat(user, "The device is secured.") + to_chat(user, SPAN_NOTICE("The device is secured.")) return if(attached_device) - to_chat(user, "There is already an device attached to the valve, remove it first.") + to_chat(user, SPAN_WARNING("There is already a device attached to the valve, remove it first!")) + return + if(!user.transferItemToLoc(item, src)) return - user.remove_from_mob(item) attached_device = A - A.loc = src - to_chat(user, "You attach the [item] to the valve controls and secure it.") + to_chat(user, SPAN_NOTICE("You attach the [item] to the valve controls and secure it.")) + //A.on_attach() A.holder = src - A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb). + A.toggle_secure() //This calls update_appearance(), which calls update_appearance() on the holder (i.e. the bomb). bombers += "[key_name(user)] attached a [item] to a transfer valve." message_admins("[key_name_admin(user)] attached a [item] to a transfer valve. (JMP)") log_game("[key_name_admin(user)] attached a [item] to a transfer valve.") attacher = user - SSnanoui.update_uis(src) // update all UIs attached to src + SStgui.update_uis(src) //Update all UIs attached to src return @@ -67,78 +76,88 @@ attached_device.HasProximity(AM) return +/obj/item/transfer_valve/attack_self(mob/user) + ui_interact(user) -/obj/item/transfer_valve/attack_self(mob/user as mob) - nano_ui_interact(user) +/obj/item/transfer_valve/ui_state(mob/user) + return GLOB.inventory_state -/obj/item/transfer_valve/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - - // this is the data which will be sent to the ui - var/data[0] - data["attachmentOne"] = tank_one ? tank_one.name : null - data["attachmentTwo"] = tank_two ? tank_two.name : null - data["valveAttachment"] = attached_device ? attached_device.name : null - data["valveOpen"] = valve_open ? 1 : 0 - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "transfer_valve.tmpl", "Tank Transfer Valve", 460, 280) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window +/obj/item/transfer_valve/ui_interact(mob/user, datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "TransferValve", name) // 460, 320 ui.open() - // auto update every Master Controller tick - //ui.set_auto_update(1) -/obj/item/transfer_valve/Topic(href, href_list) - ..() - if ( usr.stat || usr.restrained() ) - return 0 - if (src.loc != usr) - return 0 - if(tank_one && href_list["tankone"]) - remove_tank(tank_one) - else if(tank_two && href_list["tanktwo"]) - remove_tank(tank_two) - else if(href_list["open"]) - toggle_valve() - else if(attached_device) - if(href_list["rem_device"]) - attached_device.loc = get_turf(src) - attached_device:holder = null - attached_device = null - update_icon() - if(href_list["device"]) - attached_device.attack_self(usr) - return 1 // Returning 1 sends an update to attached UIs +/obj/item/transfer_valve/ui_data(mob/user) + var/list/data = list() + data["tank_one"] = tank_one ? tank_one.name : null + data["tank_two"] = tank_two ? tank_two.name : null + data["attached_device"] = attached_device ? attached_device.name : null + data["valve"] = valve_open + return data -/obj/item/transfer_valve/process_activation(var/obj/item/D) - if(toggle) - toggle = 0 - toggle_valve() - spawn(50) // To stop a signal being spammed from a proxy sensor constantly going off or whatever - toggle = 1 - -/obj/item/transfer_valve/update_icon() - overlays.Cut() - underlays = null - - if(!tank_one && !tank_two && !attached_device) - icon_state = "valve_1" +/obj/item/transfer_valve/ui_act(action, params) + if(..()) return - icon_state = "valve" + . = TRUE + switch(action) + if("tankone") + remove_tank(tank_one) + if("tanktwo") + remove_tank(tank_two) + if("toggle") + toggle_valve() + if("device") + if(attached_device) + attached_device.attack_self(usr) + if("remove_device") + if(attached_device) + attached_device.forceMove(get_turf(src)) + attached_device.holder = null + attached_device = null + update_appearance() + else + . = FALSE + if(.) + update_appearance() + add_fingerprint(usr) +/obj/item/transfer_valve/proc/process_activation(var/obj/item/D) + if(toggle) + toggle = FALSE + toggle_valve() + VARSET_IN(src, toggle, TRUE, 5 SECONDS) + +///obj/item/transfer_valve/proc/toggle_off() +// toggle = TRUE + +/obj/item/transfer_valve/update_icon_state() + icon_state = "[base_icon_state][(!tank_one && !tank_two && !attached_device) ? "_1" : null]" + return ..() + +/obj/item/transfer_valve/update_overlays() + . = ..() if(tank_one) - overlays += "[tank_one.icon_state]" - if(tank_two) - var/icon/J = new(icon, icon_state = "[tank_two.icon_state]") - J.Shift(WEST, 13) - underlays += J - if(attached_device) - overlays += "device" + . += "[tank_one.icon_state]" + + if(!tank_two) + underlays = null + else + var/mutable_appearance/J = mutable_appearance(icon, icon_state = "[tank_two.icon_state]") + var/matrix/T = matrix() + T.Translate(-13, 0) + J.transform = T + underlays = list(J) + + if(!attached_device) + return + + . += "device" + if(!istype(attached_device, /obj/item/assembly/infra)) + return + var/obj/item/assembly/infra/sensor = attached_device + if(sensor.on && sensor.visible) + . += "proxy_beam" /obj/item/transfer_valve/proc/remove_tank(obj/item/tank/T) if(tank_one == T) @@ -151,7 +170,7 @@ return T.loc = get_turf(src) - update_icon() + update_appearance() /obj/item/transfer_valve/proc/merge_gases() if(valve_open) @@ -214,7 +233,7 @@ else if(valve_open==1 && (tank_one && tank_two)) split_gases() - src.update_icon() + update_appearance() // this doesn't do anything but the timer etc. expects it to be here // eventually maybe have it update icon to show state (timer, prox etc.) like old bombs diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 1f7f164172a..585a77a2be3 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -8,15 +8,15 @@ icon_state = "cyborg_upgrade" /// Bitflags listing module compatibility. Used in the exosuit fabricator for creating sub-categories. var/list/module_flags = NONE - var/locked = 0 - var/require_module = 0 - var/installed = 0 + var/locked = FALSE + var/require_module = FALSE + var/installed = FALSE /obj/item/borg/upgrade/proc/action(var/mob/living/silicon/robot/R) if(R.stat == DEAD) - to_chat(usr, "The [src] will not function on a deceased robot.") - return 1 - return 0 + to_chat(usr, SPAN_WARNING("The [src] will not function on a deceased robot.")) + return TRUE + return FALSE /obj/item/borg/upgrade/reset @@ -24,13 +24,13 @@ desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the robot." icon_state = "cyborg_upgrade1" item_state = "cyborg_upgrade" - require_module = 1 + require_module = TRUE /obj/item/borg/upgrade/reset/action(var/mob/living/silicon/robot/R) if(..()) - return 0 + return FALSE R.module_reset() - return 1 + return TRUE /obj/item/borg/upgrade/rename name = "robot reclassification board" @@ -43,13 +43,14 @@ heldname = sanitizeSafe(input(user, "Enter new robot name", "Robot Reclassification", heldname), MAX_NAME_LEN) /obj/item/borg/upgrade/rename/action(var/mob/living/silicon/robot/R) - if(..()) return 0 + if(..()) + return FALSE R.notify_ai(ROBOT_NOTIFICATION_NEW_NAME, R.name, heldname) R.name = heldname R.custom_name = heldname R.real_name = heldname - return 1 + return TRUE /obj/item/borg/upgrade/restart name = "robot emergency restart module" @@ -61,7 +62,7 @@ /obj/item/borg/upgrade/restart/action(var/mob/living/silicon/robot/R) if(R.health < 0) to_chat(usr, "You have to repair the robot before using this module!") - return 0 + return FALSE if(!R.key) for(var/mob/observer/dead/ghost in player_list) @@ -72,7 +73,7 @@ dead_mob_list -= R living_mob_list |= R R.notify_ai(ROBOT_NOTIFICATION_NEW_UNIT) - return 1 + return TRUE /obj/item/borg/upgrade/vtec @@ -80,16 +81,17 @@ desc = "Used to kick in a robot's VTEC systems, increasing their speed." icon_state = "cyborg_upgrade2" item_state = "cyborg_upgrade" - require_module = 1 + require_module = TRUE /obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/R) - if(..()) return 0 + if(..()) + return FALSE if(R.speed == -1) - return 0 + return FALSE R.speed-- - return 1 + return TRUE /obj/item/borg/upgrade/tasercooler @@ -98,16 +100,17 @@ icon_state = "cyborg_upgrade3" item_state = "cyborg_upgrade" module_flags = BORG_MODULE_SECURITY - require_module = 1 + require_module = TRUE /obj/item/borg/upgrade/tasercooler/action(var/mob/living/silicon/robot/R) - if(..()) return 0 + if(..()) + return FALSE if(!R.module || !(type in R.module.supported_upgrades)) to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") to_chat(usr, "There's no mounting point for the module!") - return 0 + return FALSE var/obj/item/gun/energy/taser/mounted/cyborg/T = locate() in R.module if(!T) @@ -115,28 +118,29 @@ if(!T) T = locate() in R.module.modules if(!T) - to_chat(usr, "This robot has had its taser removed!") - return 0 + to_chat(usr, SPAN_WARNING("This robot has had its taser removed!")) + return FALSE if(T.recharge_time <= 2) to_chat(R, "Maximum cooling achieved for this hardpoint!") to_chat(usr, "There's no room for another cooling unit!") - return 0 + return FALSE else T.recharge_time = max(2 , T.recharge_time - 4) - return 1 + return TRUE /obj/item/borg/upgrade/jetpack name = "robot jetpack" desc = "A carbon dioxide jetpack suitable for low-gravity operations." icon_state = "cyborg_upgrade3" item_state = "cyborg_upgrade" - require_module = 1 + require_module = TRUE /obj/item/borg/upgrade/jetpack/action(var/mob/living/silicon/robot/R) - if(..()) return 0 + if(..()) + return FALSE var/obj/item/tank/jetpack/carbondioxide/T = locate() in R.module if(!T) @@ -147,21 +151,22 @@ R.module.modules += new/obj/item/tank/jetpack/carbondioxide(R.module) for(var/obj/item/tank/jetpack/carbondioxide in R.module.modules) R.internals = src - return 1 + return TRUE if(T) to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") to_chat(usr, "There's no mounting point for the module!") - return 0 + return FALSE /obj/item/borg/upgrade/advhealth name = "advanced health analyzer module" desc = "A carbon dioxide jetpack suitable for low-gravity operations." icon_state = "cyborg_upgrade3" item_state = "cyborg_upgrade" - require_module = 1 + require_module = TRUE /obj/item/borg/upgrade/advhealth/action(var/mob/living/silicon/robot/R) - if(..()) return 0 + if(..()) + return FALSE var/obj/item/healthanalyzer/advanced/T = locate() in R.module if(!T) @@ -170,27 +175,28 @@ T = locate() in R.module.modules if(!T) R.module.modules += new/obj/item/healthanalyzer/advanced(R.module) - return 1 + return TRUE if(T) to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") to_chat(usr, "There's no mounting point for the module!") - return 0 + return FALSE /obj/item/borg/upgrade/syndicate/ name = "scrambled equipment module" desc = "Unlocks new and often deadly module specific items of a robot" icon_state = "cyborg_upgrade3" item_state = "cyborg_upgrade" - require_module = 1 + require_module = TRUE /obj/item/borg/upgrade/syndicate/action(var/mob/living/silicon/robot/R) - if(..()) return 0 + if(..()) + return FALSE if(R.emag_items == 1) - return 0 + return FALSE R.emag_items = 1 - return 1 + return TRUE /obj/item/borg/upgrade/language name = "language module" @@ -199,7 +205,8 @@ item_state = "cyborg_upgrade" /obj/item/borg/upgrade/language/action(var/mob/living/silicon/robot/R) - if(..()) return 0 + if(..()) + return FALSE R.add_language(LANGUAGE_SOL_COMMON, 1) R.add_language(LANGUAGE_TRADEBAND, 1) @@ -214,4 +221,4 @@ R.add_language(LANGUAGE_TERMINUS, 1) R.add_language(LANGUAGE_ZADDAT, 1) - return 1 + return TRUE diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 1a81b07f9d2..93003b64330 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -475,3 +475,24 @@ New(title, recipes) src.title = title src.recipes = recipes + +/obj/item/stack/proc/set_amount(var/new_amount, var/no_limits = FALSE) + if(new_amount < 0 || new_amount % 1) + stack_trace("Tried to set a bad stack amount: [new_amount]") + return 0 + + // Clean up the new amount + new_amount = max(round(new_amount), 0) + + // Can exceed max if you really want + if(new_amount > max_amount && !no_limits) + new_amount = max_amount + + amount = new_amount + + // Can set it to 0 without qdel if you really want + if(amount == 0 && !no_limits) + qdel(src) + return FALSE + + return TRUE diff --git a/code/game/objects/items/uav.dm b/code/game/objects/items/uav.dm new file mode 100644 index 00000000000..0cb9776a658 --- /dev/null +++ b/code/game/objects/items/uav.dm @@ -0,0 +1,360 @@ +#define UAV_OFF 0 +#define UAV_ON 1 +#define UAV_PAIRING 2 +#define UAV_PACKED 3 + +/obj/item/uav + name = "recon skimmer" + desc = "A semi-portable reconisance drone that folds into a backpack-sized carrying case." + icon = 'icons/obj/uav.dmi' + icon_state = "uav" + + var/obj/item/cell/cell + var/cell_type = null //Can put a starting cell here + + density = 1 //Is dense, but not anchored, so you can swap with it + slowdown = 3 //Heevvee. + + health = 100 + + //light_system = MOVABLE_LIGHT_DIRECTIONAL + //light_cone_y_offset = 5 + light_range = 4 + light_power = 4 + + var/power_per_process = 50 // About 6.5 minutes of use on a high-cell (10,000) + var/state = UAV_OFF + + var/datum/effect_system/ion_trail_follow/ion_trail + + var/list/mob/living/masters + + // So you know which is which + var/nickname = "Unnamed UAV" + + // Radial menu + var/static/image/radial_pickup = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_pickup") + var/static/image/radial_wrench = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_wrench") + var/static/image/radial_power = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_power") + var/static/image/radial_pair = image(icon = 'icons/mob/radial.dmi', icon_state = "radial_pair") + + // Movement cooldown + var/next_move = 0 + + // Idle shutdown time + var/no_masters_time = 0 + +/obj/item/uav/loaded + cell_type = /obj/item/cell/high + +/obj/item/uav/Initialize(mapload) + . = ..() + + if(!cell && cell_type) + cell = new cell_type + + ion_trail = new /datum/effect_system/ion_trail_follow() + ion_trail.set_up(src) + ion_trail.stop() + +/obj/item/uav/Destroy() + QDEL_NULL(cell) + QDEL_NULL(ion_trail) + LAZYCLEARLIST(masters) + STOP_PROCESSING(SSobj, src) + return ..() + +/obj/item/uav/attack_hand(var/mob/user) + //Has to be on the ground to work with it properly + if(!isturf(loc)) + return ..() + + var/list/options = list( + "Pick Up" = radial_pickup, + "(Dis)Assemble" = radial_wrench, + "Toggle Power" = radial_power, + "Pairing Mode" = radial_pair) + var/choice = show_radial_menu(user, src, options, require_near = !issilicon(user)) + + switch(choice) + // Can pick up when off or packed + if("Pick Up") + if(state == UAV_OFF || state == UAV_PACKED) + return ..() + else + to_chat(user, SPAN_WARNING("Turn [nickname] off or pack it first!")) + return + // Can disasemble or reassemble from packed or off (and this one takes time) + if("(Dis)Assemble") + if(can_transition_to(state == UAV_PACKED ? UAV_OFF : UAV_PACKED, user)) + user.visible_message("[user] starts [state == UAV_PACKED ? "unpacking" : "packing"] [src].", "You start [state == UAV_PACKED ? "unpacking" : "packing"] [src].") + if(do_after(user, 10 SECONDS, src)) + return toggle_packed(user) + // Can toggle power from on and off + if("Toggle Power") + if(can_transition_to(state == UAV_ON ? UAV_OFF : UAV_ON, user)) + return toggle_power(user) + // Can pair when off + if("Pairing Mode") + if(can_transition_to(state == UAV_PAIRING ? UAV_OFF : UAV_PAIRING, user)) + return toggle_pairing(user) + +/obj/item/uav/attackby(var/obj/item/I, var/mob/user) + if(istype(I, /obj/item/modular_computer) && state == UAV_PAIRING) + var/obj/item/modular_computer/MC = I + LAZYDISTINCTADD(MC.paired_uavs, WEAKREF(src)) + playsound(src, 'sound/machines/buttonbeep.ogg', 50, 1) + visible_message(SPAN_NOTICE("[user] pairs [I] to [nickname]")) + toggle_pairing() + + else if(I.is_screwdriver() && cell) + if(do_after(user, 3 SECONDS, src)) + to_chat(user, SPAN_NOTICE("You remove [cell] into [nickname].")) + playsound(src, I.usesound, 50, 1) + power_down() + cell.forceMove(get_turf(src)) + cell = null + + else if(istype(I, /obj/item/cell) && !cell) + if(do_after(user, 3 SECONDS, src)) + to_chat(user, SPAN_NOTICE("You insert [I] into [nickname].")) + playsound(src, 'sound/items/deconstruct.ogg', 50, 1) + power_down() + user.remove_from_mob(I) + I.forceMove(src) + cell = I + + else if(istype(I, /obj/item/pen) || istype(I, /obj/item/flashlight/pen)) + var/tmp_label = sanitizeSafe(input(user, "Enter a nickname for [src]", "Nickname", nickname), MAX_NAME_LEN) + if(length(tmp_label) > 50 || length(tmp_label) < 3) + to_chat(user, SPAN_NOTICE("The nickname must be between 3 and 50 characters.")) + else + to_chat(user, SPAN_NOTICE("You scribble your new nickname on the side of [src].")) + nickname = tmp_label + desc = initial(desc) + " This one has '[nickname]' scribbled on the side." + else + return ..() + +/obj/item/uav/proc/can_transition_to(var/new_state, var/mob/user) + switch(state) //Current one + if(UAV_ON) + if(new_state == UAV_OFF || new_state == UAV_PACKED) + . = TRUE + if(UAV_OFF) + if(new_state == UAV_ON || new_state == UAV_PACKED || new_state == UAV_PAIRING) + . = TRUE + if(UAV_PAIRING) + if(new_state == UAV_OFF) + . = TRUE + if(UAV_PACKED) + if(new_state == UAV_OFF) + . = TRUE + + if(!.) + if(user) + to_chat(user, "You can't do that while [nickname] is in this state.") + return FALSE + +/obj/item/uav/update_icon() + cut_overlays() + switch(state) + if(UAV_PAIRING) + add_overlay("[initial(icon_state)]_pairing") + icon_state = "[initial(icon_state)]" + if(UAV_ON) + icon_state = "[initial(icon_state)]_on" + if(UAV_OFF) + icon_state = "[initial(icon_state)]" + if(UAV_PACKED) + icon_state = "[initial(icon_state)]_packed" + +/obj/item/uav/process() + if(cell?.use(power_per_process) != power_per_process) + visible_message("[src] sputters and thuds to the ground, inert.") + playsound(src, 'sound/items/drop/metalboots.ogg', 75, 1) + power_down() + health -= initial(health)*0.25 //Lose 25% of your original health + + if(LAZYLEN(masters)) + no_masters_time = 0 + else if(no_masters_time++ > 50) + power_down() + +/obj/item/uav/proc/toggle_pairing() + switch(state) + if(UAV_PAIRING) + state = UAV_OFF + update_icon() + return TRUE + if(UAV_OFF) + state = UAV_PAIRING + update_icon() + return TRUE + return FALSE + +/obj/item/uav/proc/toggle_power() + switch(state) + if(UAV_OFF) + power_up() + return TRUE + if(UAV_ON) + power_down() + return TRUE + return FALSE + +/obj/item/uav/proc/toggle_packed() + if(state == UAV_ON) + power_down() + switch(state) + if(UAV_OFF) //Packing + state = UAV_PACKED + w_class = ITEMSIZE_LARGE + slowdown = 1 + density = FALSE + update_icon() + return TRUE + if(UAV_PACKED) //Unpacking + state = UAV_OFF + w_class = ITEMSIZE_HUGE + slowdown = 3 + density = TRUE + update_icon() + return TRUE + return FALSE + +/obj/item/uav/proc/power_up() + if(state != UAV_OFF || !isturf(loc)) + return + if(cell?.use(power_per_process) != power_per_process) + visible_message(SPAN_WARNING("[src] sputters and chugs as it tries, and fails, to power up.")) + return + + state = UAV_ON + update_icon() + start_hover() + set_light("#ffffff") + START_PROCESSING(SSobj, src) + no_masters_time = 0 + visible_message(SPAN_NOTICE("[nickname] buzzes and lifts into the air.")) + +/obj/item/uav/proc/power_down() + if(state != UAV_ON) + return + + state = UAV_OFF + update_icon() + stop_hover() + set_light(0) + LAZYCLEARLIST(masters) + STOP_PROCESSING(SSobj, src) + visible_message(SPAN_NOTICE("[nickname] gracefully settles onto the ground.")) + +//////////////// Helpers +/obj/item/uav/get_cell() + return cell + +/obj/item/uav/relaymove(var/mob/user, direction, signal = 1) + if(signal && state == UAV_ON && (WEAKREF(user) in masters)) + if(next_move <= world.time) + next_move = world.time + (1 SECOND/signal) + step(src, direction) + return TRUE // Even if we couldn't step, we're taking credit for absorbing the move + return FALSE + +/obj/item/uav/proc/get_status_string() + return "[nickname] - [get_x(src)],[get_y(src)],[get_z(src)] - I:[health]/[initial(health)] - C:[cell ? "[cell.charge]/[cell.maxcharge]" : "Not Installed"]" + +/obj/item/uav/proc/add_master(var/mob/living/M) + LAZYDISTINCTADD(masters, WEAKREF(M)) + +/obj/item/uav/proc/remove_master(var/mob/living/M) + LAZYREMOVE(masters, WEAKREF(M)) + +/obj/item/uav/check_eye() + if(state == UAV_ON) + return 0 + else + return -1 + +/obj/item/uav/proc/start_hover() + if(!ion_trail.on) //We'll just use this to store if we're floating or not + ion_trail.start() + var/amplitude = 2 //maximum displacement from original position + var/period = 36 //time taken for the mob to go up >> down >> original position, in deciseconds. Should be multiple of 4 + + var/top = old_y + amplitude + var/bottom = old_y - amplitude + var/half_period = period / 2 + var/quarter_period = period / 4 + + animate(src, pixel_y = top, time = quarter_period, easing = SINE_EASING | EASE_OUT, loop = -1) //up + animate(pixel_y = bottom, time = half_period, easing = SINE_EASING, loop = -1) //down + animate(pixel_y = old_y, time = quarter_period, easing = SINE_EASING | EASE_IN, loop = -1) //back + +/obj/item/uav/proc/stop_hover() + if(ion_trail.on) + ion_trail.stop() + animate(src, pixel_y = old_y, time = 5, easing = SINE_EASING | EASE_IN) //halt animation + +/obj/item/uav/hear_talk(var/mob/living/M, message, verb) + var/name_used = M.GetVoice() + for(var/wr_master in masters) + var/datum/weakref/wr = wr_master + var/mob/master = wr.resolve() + var/rendered = "UAV received: [name_used] [message]" + master.show_message(rendered, 2) + +/obj/item/radio/hear_talk(mob/M as mob, msg, var/verb = "says", var/datum/language/speaking = null) + if (broadcasting) + if(get_dist(src, M) <= canhear_range) + talk_into(M, msg,null,verb,speaking) + +/obj/item/uav/see_emote(var/mob/living/M, text) + for(var/wr_master in masters) + var/datum/weakref/wr = wr_master + var/mob/master = wr.resolve() + var/rendered = "UAV received, [text]" + master.show_message(rendered, 2) + +/obj/item/uav/show_message(msg, type, alt, alt_type) + for(var/wr_master in masters) + var/datum/weakref/wr = wr_master + var/mob/master = wr.resolve() + var/rendered = "UAV received, [msg]" + master.show_message(rendered, type) + +/obj/item/uav/take_damage(var/damage) + health -= damage + CheckHealth() + return + +/obj/item/uav/attack_generic(var/mob/user, var/damage, var/attack_verb) + visible_message(SPAN_DANGER("[user] [attack_verb] the [src]!")) + playsound(src, 'sound/weapons/smash.ogg', 50, 1) + user.do_attack_animation(src) + health -= damage + CheckHealth() + return + +/obj/item/uav/ex_act(severity) + switch(severity) + if(1.0) + die() + if(2.0) + health -= 25 + CheckHealth() + +/obj/item/uav/proc/CheckHealth() + if(health <= 0) + die() + +/obj/item/uav/proc/die() + visible_message(SPAN_DANGER("[src] shorts out and explodes!")) + power_down() + var/turf/T = get_turf(src) + qdel(src) + explosion(T, -1, 0, 1, 2) //Not very large + +#undef UAV_OFF +#undef UAV_ON +#undef UAV_PACKED diff --git a/code/game/objects/items/weapons/RPD.dm b/code/game/objects/items/weapons/RPD.dm index 6898464a0b1..61a730f1392 100644 --- a/code/game/objects/items/weapons/RPD.dm +++ b/code/game/objects/items/weapons/RPD.dm @@ -1,226 +1,222 @@ -#define PAINT_MODE -2 -#define EATING_MODE -1 -#define ATMOS_MODE 0 -#define DISPOSALS_MODE 1 -#define TRANSIT_MODE 2 +#define ATMOS_CATEGORY 0 +#define DISPOSALS_CATEGORY 1 +#define TRANSIT_CATEGORY 2 + +#define BUILD_MODE (1<<0) +#define WRENCH_MODE (1<<1) +#define DESTROY_MODE (1<<2) +#define PAINT_MODE (1<<3) /obj/item/pipe_dispenser name = "Rapid Piping Device (RPD)" desc = "A device used to rapidly pipe things." - icon = 'icons/obj/tools.dmi' + icon = 'icons/obj/tools_vr.dmi' icon_state = "rpd" + item_state = "rpd" + item_icons = list( + slot_l_hand_str = 'icons/mob/items/lefthand_vr.dmi', + slot_r_hand_str = 'icons/mob/items/righthand_vr.dmi', + ) flags = NOBLUDGEON force = 10 throwforce = 10 throw_speed = 1 throw_range = 5 w_class = ITEMSIZE_NORMAL - matter = list(DEFAULT_WALL_MATERIAL = 50000, "glass" = 25000) - var/datum/effect_system/spark_spread/spark_system - var/working = 0 - var/mode = ATMOS_MODE + slot_flags = SLOT_BELT + matter = list(MAT_STEEL = 50000, MAT_GLASS = 25000) + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 100, ACID = 50) + ///Sparks system used when changing device in the UI + var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread + ///Direction of the device we are going to spawn, set up in the UI var/p_dir = NORTH + ///Initial direction of the smart pipe we are going to spawn, set up in the UI + var/p_init_dir = ALL_CARDINALS + ///Is the device of the flipped type? var/p_flipped = FALSE - var/paint_color="grey" - var/screen = ATMOS_MODE //Starts on the atmos tab. + ///Color of the device we are going to spawn + var/paint_color = "grey" + ///Category currently active (Atmos, disposal, transit) + var/category = ATMOS_CATEGORY + ///Piping layer we are going to spawn the atmos device in var/piping_layer = PIPING_LAYER_DEFAULT - var/wrench_mode = FALSE var/obj/item/tool/wrench/tool - var/datum/pipe_recipe/recipe - var/static/datum/pipe_recipe/first_atmos - var/static/datum/pipe_recipe/first_disposal + ///Stores the current device to spawn + var/datum/pipe_info/recipe + ///Stores the first atmos device + var/static/datum/pipe_info/first_atmos + ///Stores the first disposal device + var/static/datum/pipe_info/first_disposal + ///Stores the first transit device + //var/static/datum/pipe_info/first_transit + ///The modes that are allowed for the RPD + var/mode = BUILD_MODE | DESTROY_MODE | WRENCH_MODE //| REPROGRAM_MODE + var/static/list/pipe_layers = list( + "Regular" = PIPING_LAYER_REGULAR, + "Supply" = PIPING_LAYER_SUPPLY, + "Scrubber" = PIPING_LAYER_SCRUBBER, + "Fuel" = PIPING_LAYER_FUEL, + "Aux" = PIPING_LAYER_AUX + ) /obj/item/pipe_dispenser/Initialize(mapload) . = ..() - src.spark_system = new /datum/effect_system/spark_spread spark_system.set_up(5, 0, src) spark_system.attach(src) + tool = new /obj/item/tool/wrench/cyborg(src) + +/obj/item/pipe_dispenser/proc/SetupPipes() if(!first_atmos) - first_atmos = atmos_pipe_recipes[atmos_pipe_recipes[1]][1] + first_atmos = GLOB.atmos_pipe_recipes[GLOB.atmos_pipe_recipes[1]][1] if(!first_disposal) - first_disposal = disposal_pipe_recipes[disposal_pipe_recipes[1]][1] - recipe = first_atmos - tool = new /obj/item/tool/wrench/cyborg(src) // RPDs have wrenches inside of them, so that they can wrench down spawned pipes without being used as superior wrenches themselves. + first_disposal = GLOB.disposal_pipe_recipes[GLOB.disposal_pipe_recipes[1]][1] + //if(!first_transit) + // first_transit = GLOB.transit_tube_recipes[GLOB.transit_tube_recipes[1]][1] + if(!recipe) + recipe = first_atmos /obj/item/pipe_dispenser/Destroy() - qdel(spark_system) - spark_system = null + QDEL_NULL(spark_system) + QDEL_NULL(tool) return ..() - +/* /obj/item/pipe_dispenser/suicide_act(mob/user) var/datum/gender/TU = gender_datums[user.get_visible_gender()] - user.visible_message("[user] points the end of the RPD down [TU.his] throat and presses a button! It looks like [TU.hes] trying to commit suicide...") - playsound(get_turf(user), 'sound/machines/click.ogg', 50, 1) - playsound(get_turf(user), 'sound/items/deconstruct.ogg', 50, 1) + user.visible_message(SPAN_SUICIDE("[user] points the end of the RPD down [TU.his] throat and presses a button! It looks like [TU.hes] trying to commit suicide...")) + playsound(src, 'sound/machines/click.ogg', 50, TRUE) + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) return(BRUTELOSS) +*/ + +/obj/item/pipe_dispenser/examine(mob/user) + . = ..() + . += "You can scroll your mouse wheel to change the piping layer." + +/obj/item/pipe_dispenser/equipped(mob/user, slot, initial) + . = ..() + if(slot == slot_r_hand || slot_l_hand) + RegisterSignal(user, COMSIG_MOUSE_SCROLL_ON, .proc/mouse_wheeled) + else + UnregisterSignal(user, COMSIG_MOUSE_SCROLL_ON) + +/obj/item/pipe_dispenser/dropped(mob/user) + UnregisterSignal(user, COMSIG_MOUSE_SCROLL_ON) + return ..() + +///obj/item/pipe_dispenser/cyborg_unequip(mob/user) +// UnregisterSignal(user, COMSIG_MOUSE_SCROLL_ON) +// return ..() /obj/item/pipe_dispenser/attack_self(mob/user) - src.interact(user) + ui_interact(user) -/obj/item/pipe_dispenser/interact(mob/user) - var/list/lines = list() - if(mode >= ATMOS_MODE) - lines += "

Direction:

" - var/icon/preview = null - var/icon/previewm = null - if(recipe.icon && recipe.icon_state) - preview = new /icon(recipe.icon, recipe.icon_state) - if (recipe.icon_state_m) - previewm = new /icon(recipe.icon, recipe.icon_state_m) - switch(recipe.dirtype) +/obj/item/pipe_dispenser/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/spritesheet/pipes), + ) - if(PIPE_STRAIGHT) // Straight, N-S, W-E - lines += render_dir_img(preview,user,NORTH,"Vertical","↕") - lines += render_dir_img(preview,user,EAST,"Horizontal","↔") +/obj/item/pipe_dispenser/ui_state(mob/user) + return GLOB.inventory_state - if(PIPE_BENDABLE) // Bent, N-W, N-E etc - lines += render_dir_img(preview,user,NORTH,"Vertical","↕") - lines += render_dir_img(preview,user,EAST,"Horizontal","↔") - lines += "
" - lines += render_dir_img(preview,user,NORTHWEST,"West to North","╝") - lines += render_dir_img(preview,user,NORTHEAST,"North to East","╚") - lines += "
" - lines += render_dir_img(preview,user,SOUTHWEST,"South to West","╗") - lines += render_dir_img(preview,user,SOUTHEAST,"East to South","╔") +/obj/item/pipe_dispenser/ui_interact(mob/user, datum/tgui/ui) + SetupPipes() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "RapidPipeDispenser", name) + ui.open() - if(PIPE_TRINARY) // Manifold - lines += render_dir_img(preview,user,NORTH,"West South East","╦") - lines += render_dir_img(preview,user,EAST,"North West South","╣") - lines += "
" - lines += render_dir_img(preview,user,SOUTH,"East North West","╩") - lines += render_dir_img(preview,user,WEST,"South East North","╠") +/obj/item/pipe_dispenser/ui_static_data(mob/user) + var/list/data = list("paint_colors" = GLOB.pipe_paint_colors) + return data - if(PIPE_TRIN_M) // Mirrored ones - //each mirror icon is 45 anticlockwise from it's real direction - lines += render_dir_img(preview,user,NORTH,"West South East","╦") - lines += render_dir_img(preview,user,EAST,"North West South","╣") - lines += "
" - lines += render_dir_img(preview,user,SOUTH,"East North West","╩") - lines += render_dir_img(preview,user,WEST,"South East North","╠") - lines += "
" - lines += render_dir_img(previewm,user,SOUTH,"West South East","╦", 1) - lines += render_dir_img(previewm,user,EAST,"North West South","╣", 1) - lines += "
" - lines += render_dir_img(previewm,user,NORTH,"East North West","╩", 1) - lines += render_dir_img(previewm,user,WEST,"South East North","╠", 1) +/obj/item/pipe_dispenser/ui_data(mob/user) + var/list/data = list( + "category" = category, + "piping_layer" = piping_layer, + //"ducting_layer" = ducting_layer, + "preview_rows" = recipe.get_preview(p_dir), + "categories" = list(), + "selected_color" = paint_color, + "mode" = mode + ) - if(PIPE_DIRECTIONAL) // Stuff with four directions - includes pumps etc. - lines += render_dir_img(preview,user,NORTH,"North","↑") - lines += render_dir_img(preview,user,EAST,"East","→") - lines += render_dir_img(preview,user,SOUTH,"South","↓") - lines += render_dir_img(preview,user,WEST,"West","←") + var/list/recipes + switch(category) + if(ATMOS_CATEGORY) + recipes = GLOB.atmos_pipe_recipes + if(DISPOSALS_CATEGORY) + recipes = GLOB.disposal_pipe_recipes + //if(TRANSIT_CATEGORY) + // recipes = GLOB.transit_tube_recipes + for(var/c in recipes) + var/list/cat = recipes[c] + var/list/r = list() + for(var/i in 1 to cat.len) + var/datum/pipe_info/info = cat[i] + r += list(list("pipe_name" = info.name, "pipe_index" = i, "selected" = (info == recipe), "all_layers" = info.all_layers)) + data["categories"] += list(list("cat_name" = c, "recipes" = r)) - if(PIPE_ONEDIR) // Single icon_state (eg 4-way manifolds) - lines += render_dir_img(preview,user,SOUTH,"Pipe","↕") - lines += "
" + var/list/init_directions = list("north" = FALSE, "south" = FALSE, "east" = FALSE, "west" = FALSE) + for(var/direction in ALL_CARDINALS) + if(p_init_dir & direction) + init_directions[dir2text(direction)] = TRUE + data["init_directions"] = init_directions + return data - if(mode == ATMOS_MODE || mode == PAINT_MODE) - lines += "

Color:

" - var/i = 0 - for(var/c in pipe_colors) - ++i - lines += "[c]" - if(i == 4) - lines += "
" - i = 0 - lines += "
" - - lines += "

Utilities:

" - lines += "Lay Pipes" - lines += "Eat Pipes" - lines += "Paint Pipes" - lines += "
" - - lines += "

Catagory:

" - lines += "Atmospherics" - lines += "Disposals" - //lines += "Transit Tube" - lines += "
Wrench Mode" - lines += "
" - - if(screen == ATMOS_MODE) - for(var/category in atmos_pipe_recipes) - lines += "

[category]:

" - if(category == "Pipes") - lines += "
" - lines += "Regular " - lines += "Supply " - lines += "Scrubber " - lines += "
" - var/list/L = atmos_pipe_recipes[category] - for(var/i in 1 to L.len) - var/datum/pipe_recipe/PI = L[i] - lines += "
" - lines += "[PI.name]" - lines += "
" - lines += "
" - else if(screen == DISPOSALS_MODE) - for(var/category in disposal_pipe_recipes) - lines += "

[category]:

" - var/list/L = disposal_pipe_recipes[category] - for(var/i in 1 to L.len) - var/datum/pipe_recipe/PI = L[i] - lines += "
" - lines += "[PI.name]" - lines += "
" - lines += "
" - - var/dat = lines.Join() - var/datum/browser/popup = new(user, "rpd", name, 300, 800, src) - popup.set_content("[dat]") - popup.open() - -/obj/item/pipe_dispenser/Topic(href,href_list) - if(..()) +/obj/item/pipe_dispenser/ui_act(action, params) + . = ..() + if(.) return if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - return - var/playeffect = TRUE // Do we spark the device - var/anyclicked = FALSE // Tells us if we need to refresh the window. - if(href_list["paint_color"]) - paint_color = href_list["paint_color"] - playeffect = FALSE - anyclicked = TRUE - if(href_list["mode"]) - mode = text2num(href_list["mode"]) - anyclicked = TRUE - if(href_list["screen"]) - if(mode == screen) - mode = text2num(href_list["screen"]) - screen = text2num(href_list["screen"]) - switch(screen) - if(DISPOSALS_MODE) - recipe = first_disposal - if(ATMOS_MODE) - recipe = first_atmos - p_dir = NORTH - playeffect = FALSE - anyclicked = TRUE - if(href_list["piping_layer"]) - piping_layer = text2num(href_list["piping_layer"]) - playeffect = FALSE - anyclicked = TRUE - if(href_list["pipe_type"]) - recipe = all_pipe_recipes[href_list["category"]][text2num(href_list["pipe_type"])] - if(recipe.dirtype == PIPE_ONEDIR) // One hell of a hack for the fact that the image previews for the onedir types only show on the south, but the default pipe type is north. - p_dir = SOUTH // Did I fuck this up? Maybe. Or maybe it's just the icon files not being ready for an RPD. - else // If going to try and fix this hack, be aware the pipe dispensers might rely on pipes defaulting south instead of north. + return TRUE + var/playeffect = TRUE + switch(action) + if("color") + paint_color = params["paint_color"] + if("category") + category = text2num(params["category"]) + switch(category) + if(DISPOSALS_CATEGORY) + recipe = first_disposal + if(ATMOS_CATEGORY) + recipe = first_atmos + //if(TRANSIT_CATEGORY) + // recipe = first_transit p_dir = NORTH - p_flipped = FALSE - anyclicked = TRUE - if(href_list["dir"]) - p_dir = text2dir(href_list["dir"]) - p_flipped = text2num(href_list["flipped"]) - playeffect = FALSE - anyclicked = TRUE - if(href_list["switch_wrench"]) - wrench_mode = text2num(href_list["wrench_mode"]) - anyclicked = TRUE - if(anyclicked) - if(playeffect) - spark_system.start() - playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0) - src.interact(usr) + playeffect = FALSE + if("piping_layer") + piping_layer = text2num(params["piping_layer"]) + playeffect = FALSE + //if("ducting_layer") + // ducting_layer = text2num(params["ducting_layer"]) + // playeffect = FALSE + if("pipe_type") + var/static/list/recipes + if(!recipes) + recipes = GLOB.disposal_pipe_recipes + GLOB.atmos_pipe_recipes //+ GLOB.transit_tube_recipes + recipe = recipes[params["category"]][text2num(params["pipe_type"])] + p_dir = NORTH + if("setdir") + p_dir = text2dir(params["dir"]) + p_flipped = text2num(params["flipped"]) + playeffect = FALSE + if("mode") + var/n = text2num(params["mode"]) + mode ^= n + if("init_dir_setting") + var/target_dir = p_init_dir ^ text2dir(params["dir_flag"]) + // Refuse to create a smart pipe that can only connect in one direction (it would act weirdly and lack an icon) + if (ISNOTSTUB(target_dir)) + p_init_dir = target_dir + else + to_chat(usr, SPAN_WARNING("\The [src]'s screen flashes a warning: Can't configure a pipe to only connect in one direction.")) + playeffect = FALSE + if("init_reset") + p_init_dir = ALL_CARDINALS + if(playeffect) + spark_system.start() + playsound(get_turf(src), 'sound/effects/pop.ogg', 50, FALSE) + return TRUE /obj/item/pipe_dispenser/afterattack(atom/A, mob/user as mob, proximity) if(!user.IsAdvancedToolUser() || istype(A, /turf/space/transit) || !proximity) @@ -228,118 +224,155 @@ //So that changing the menu settings doesn't affect the pipes already being built. var/queued_piping_layer = piping_layer - var/queued_p_type = recipe.pipe_type var/queued_p_dir = p_dir var/queued_p_flipped = p_flipped - var/queued_p_subtype = recipe.subtype - var/queued_p_paintable = recipe.paintable - //make sure what we're clicking is valid for the current mode - var/static/list/make_pipe_whitelist // This should probably be changed to be in line with polaris standards. Oh well. + //Make sure what we're clicking is valid for the current mode + var/static/list/make_pipe_whitelist if(!make_pipe_whitelist) make_pipe_whitelist = typecacheof(list(/obj/structure/lattice, /obj/structure/girder, /obj/item/pipe)) var/can_make_pipe = (isturf(A) || is_type_in_typecache(A, make_pipe_whitelist)) - . = FALSE - switch(mode) //if we've gotten this var, the target is valid - if(PAINT_MODE) //Paint pipes - if(!istype(A, /obj/machinery/atmospherics/pipe)) - return ..() + var/can_destroy_pipe = istype(A, /obj/item/pipe) || istype(A, /obj/item/pipe_meter) || istype(A, /obj/structure/disposalconstruct) + + . = TRUE + if((mode & DESTROY_MODE) && can_destroy_pipe) + to_chat(user, SPAN_NOTICE("You start destroying a pipe...")) + playsound(src, 'sound/machines/click.ogg', 50, 1) + if(do_after(user, 2, target = A)) + activate() + animate_deletion(A) + return + + //Painting pipes + if((mode & PAINT_MODE)) + if(istype(A, /obj/machinery/atmospherics/pipe)) var/obj/machinery/atmospherics/pipe/P = A - playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) + playsound(src, 'sound/machines/click.ogg', 50, 1) P.change_color(pipe_colors[paint_color]) - user.visible_message("[user] paints \the [P] [paint_color].","You paint \the [P] [paint_color].") + user.visible_message(SPAN_NOTICE("[user] paints \the [P] [paint_color]."), SPAN_NOTICE("You paint \the [P] [paint_color].")) return - if(EATING_MODE) //Eating pipes - if(!(istype(A, /obj/item/pipe) || istype(A, /obj/item/pipe_meter) || istype(A, /obj/structure/disposalconstruct))) - return ..() - to_chat(user, "You start destroying a pipe...") - playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) - if(do_after(user, 2, target = A)) - activate() - qdel(A) + //Making pipes + if(mode & BUILD_MODE) + switch(category) + if(ATMOS_CATEGORY) + if(!can_make_pipe) + return ..() + playsound(src, 'sound/machines/click.ogg', 50, 1) + if(istype(recipe, /datum/pipe_info/meter)) + to_chat(user, SPAN_NOTICE("You start building a meter...")) + if(do_after(user, 2, target = A)) + activate() + var/obj/item/pipe_meter/PM = new /obj/item/pipe_meter(get_turf(A)) + PM.setAttachLayer(queued_piping_layer) + if(mode & WRENCH_MODE) + do_wrench(PM, user) + else if(istype(recipe, /datum/pipe_info/pipe)) + if(recipe.all_layers == FALSE && (piping_layer == 1 || piping_layer == 5)) + to_chat(user, SPAN_NOTICE("You can't build this object on the layer...")) + return ..() + else + var/datum/pipe_info/pipe/R = recipe + to_chat(user, SPAN_NOTICE("You start building a pipe...")) + if(do_after(user, 2, target = A)) + if(recipe.all_layers == FALSE && (piping_layer == 1 || piping_layer == 5))//double check to stop cheaters (and to not waste time waiting for something that can't be placed) + to_chat(user, SPAN_NOTICE("You can't build this object on the layer...")) + return ..() + activate() + var/obj/machinery/atmospherics/path = R.pipe_type + var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe + var/obj/item/pipe/P = new pipe_item_type(get_turf(A), path, queued_p_dir) - if(ATMOS_MODE) //Making pipes - if(!can_make_pipe) - return ..() - playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) - if (istype(recipe, /datum/pipe_recipe/meter)) - to_chat(user, "You start building a meter...") - if(do_after(user, 2, target = A)) - activate() - var/obj/item/pipe_meter/PM = new /obj/item/pipe_meter(get_turf(A)) - PM.setAttachLayer(queued_piping_layer) - if(wrench_mode) - do_wrench(PM, user) - else - to_chat(user, "You start building a pipe...") - if(do_after(user, 2, target = A)) - activate() - var/obj/machinery/atmospherics/path = queued_p_type - var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe - var/obj/item/pipe/P = new pipe_item_type(get_turf(A), queued_p_type, queued_p_dir) + P.update() + P.add_fingerprint(usr) + if(R.paintable) + P.color = pipe_colors[paint_color] + P.setPipingLayer(queued_piping_layer) + if(queued_p_flipped) + P.do_a_flip() + if(mode & WRENCH_MODE) + do_wrench(P, user) + else + build_effect(P) - P.update() - P.add_fingerprint(usr) - P.setPipingLayer(queued_piping_layer) - if (queued_p_paintable) - P.color = pipe_colors[paint_color] - if(queued_p_flipped) - P.do_a_flip() - if(wrench_mode) - do_wrench(P, user) - - if(DISPOSALS_MODE) //Making disposals pipes - if(!can_make_pipe) - return ..() - A = get_turf(A) - if(istype(A, /turf/unsimulated)) - to_chat(user, "[src]'s error light flickers; there's something in the way!") - return - to_chat(user, "You start building a disposals pipe...") - playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1) - if(do_after(user, 4, target = A)) - var/obj/structure/disposalconstruct/C = new(A, queued_p_type, queued_p_dir, queued_p_flipped, queued_p_subtype) - - if(!C.can_place()) - to_chat(user, "There's not enough room to build that here!") - qdel(C) + //Making disposals pipes + if(DISPOSALS_CATEGORY) + var/datum/pipe_info/disposal/R = recipe + if(!istype(R) || !can_make_pipe) + return ..() + A = get_turf(A) + if(istype(A, /turf/unsimulated)) + to_chat(user, SPAN_WARNING("[src]'s error light flickers; there's something in the way!")) return + to_chat(user, SPAN_NOTICE("You start building a disposals pipe...")) + playsound(src, 'sound/machines/click.ogg', 50, 1) + if(do_after(user, 4, target = A)) + var/obj/structure/disposalconstruct/C = new(A, R.pipe_type, queued_p_dir, queued_p_flipped, R.subtype) - activate() + if(!C.can_place()) + to_chat(user, SPAN_WARNING("There's not enough room to build that here!")) + qdel(C) + return - C.add_fingerprint(usr) - C.update_icon() - if(wrench_mode) - do_wrench(C, user) - return + activate() - else - return ..() + C.add_fingerprint(usr) + C.update_icon() + if(mode & WRENCH_MODE) + do_wrench(C, user) + else + build_effect(C) + else + return ..() + +/obj/item/pipe_dispenser/proc/build_effect(var/obj/P, var/time = 1.5) + set waitfor = FALSE + P.filters += filter(type = "angular_blur", size = 30) + animate(P.filters[P.filters.len], size = 0, time = time) + var/outline = filter(type = "outline", size = 1, color = "#22AAFF") + P.filters += outline + sleep(time) + P.filters -= outline + P.filters -= filter(type = "angular_blur", size = 0) + +/obj/item/pipe_dispenser/proc/animate_deletion(var/obj/P, var/time = 1.5) + set waitfor = FALSE + P.filters += filter(type = "angular_blur", size = 0) + animate(P.filters[P.filters.len], size = 30, time = time) + sleep(time) + if(!QDELETED(P)) + P.filters -= filter(type = "angular_blur", size = 30) + qdel(P) /obj/item/pipe_dispenser/proc/activate() - playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1) + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) /obj/item/pipe_dispenser/proc/do_wrench(var/atom/target, mob/user) var/resolved = target.attackby(tool,user) if(!resolved && tool && target) tool.afterattack(target,user,1) -/obj/item/pipe_dispenser/proc/render_dir_img(preview,user,_dir,title,noimg,flipped=0) - var/dirtext = dir2text(_dir) - var/selected = " style=\"height:34px;width:34px;display:inline-block\"" - if(_dir == p_dir && flipped == p_flipped) - selected += " class=\"linkOn\"" - if(preview) - user << browse_rsc(new /icon(preview, dir=_dir), "[dirtext][flipped ? "m" : ""].png") - return "" +/obj/item/pipe_dispenser/proc/mouse_wheeled(mob/user, atom/A, delta_x, delta_y, params) + SIGNAL_HANDLER + if(user.incapacitated(INCAPACITATION_RESTRAINED)) + return + + if(delta_y < 0) + piping_layer = min(PIPING_LAYER_MAX, piping_layer + 1) + else if(delta_y > 0) + piping_layer = max(PIPING_LAYER_MIN, piping_layer - 1) else - return "[noimg]" + return + SStgui.update_uis(src) + to_chat(user, SPAN_NOTICE("You set the layer to [piping_layer].")) +#undef ATMOS_CATEGORY +#undef DISPOSALS_CATEGORY +#undef TRANSIT_CATEGORY +#undef BUILD_MODE +#undef WRENCH_MODE +#undef DESTROY_MODE #undef PAINT_MODE -#undef EATING_MODE -#undef ATMOS_MODE -#undef DISPOSALS_MODE diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index e41dc59ab52..bf83758a442 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -1,6 +1,12 @@ var/list/global/tank_gauge_cache = list() +/** + * # Gas Tank + * + * Handheld gas canisters + * Can rupture explosively if overpressurized + */ /obj/item/tank name = "tank" icon = 'icons/obj/tank.dmi' @@ -25,7 +31,7 @@ var/list/global/tank_gauge_cache = list() var/datum/gas_mixture/air_contents = null var/distribute_pressure = ONE_ATMOSPHERE var/integrity = 20 - var/maxintegrity = 20 + var/max_integrity = 20 var/valve_welded = 0 var/obj/item/tankassemblyproxy/proxyassembly @@ -196,8 +202,8 @@ var/list/global/tank_gauge_cache = list() message_admins("[key_name_admin(user)] attempted to weld a [src]. [src.air_contents.temperature-T0C]") if(WT.welding) to_chat(user, "You accidentally rake \the [W] across \the [src]!") - maxintegrity -= rand(2,6) - integrity = min(integrity,maxintegrity) + max_integrity -= rand(2,6) + integrity = min(integrity,max_integrity) src.air_contents.add_thermal_energy(rand(2000,50000)) WT.eyecheck(user) else @@ -210,90 +216,77 @@ var/list/global/tank_gauge_cache = list() add_fingerprint(user) if (!(src.air_contents)) return - nano_ui_interact(user) + ui_interact(user) // There's GOT to be a better way to do this if (src.proxyassembly.assembly) src.proxyassembly.assembly.attack_self(user) +/obj/item/weapon/tank/ui_state(mob/user) + return GLOB.deep_inventory_state -/obj/item/tank/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - var/mob/living/carbon/location = null - - if(istype(loc, /obj/item/rig)) // check for tanks in rigs - if(istype(loc.loc, /mob/living/carbon)) - location = loc.loc - else if(istype(loc, /mob/living/carbon)) - location = loc - - var/using_internal - if(istype(location)) - if(location.internal==src) - using_internal = 1 - - // this is the data which will be sent to the ui - var/data[0] - data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) - data["releasePressure"] = round(distribute_pressure ? distribute_pressure : 0) - data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE) - data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE) - data["valveOpen"] = using_internal ? 1 : 0 - data["maskConnected"] = 0 - - if(istype(location)) - var/mask_check = 0 - - if(location.internal == src) // if tank is current internal - mask_check = 1 - else if(src in location) // or if tank is in the mobs possession - if(!location.internal) // and they do not have any active internals - mask_check = 1 - else if(istype(src.loc, /obj/item/rig) && (src.loc in location)) // or the rig is in the mobs possession - if(!location.internal) // and they do not have any active internals - mask_check = 1 - - if(mask_check) - if(location.wear_mask && (location.wear_mask.item_flags & ALLOWINTERNALS)) - data["maskConnected"] = 1 - else if(istype(location, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = location - if(H.head && (H.head.item_flags & ALLOWINTERNALS)) - data["maskConnected"] = 1 - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "tanks.tmpl", "Tank", 500, 300) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window +/obj/item/tank/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Tank", name) ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) -/obj/item/tank/Topic(href, href_list) - ..() - if (usr.stat|| usr.restrained()) - return 0 - if (src.loc != usr) - return 0 +/obj/item/tank/ui_static_data(mob/user) + . = list ( + "defaultReleasePressure" = round(TANK_DEFAULT_RELEASE_PRESSURE), + "minReleasePressure" = round(TANK_MIN_RELEASE_PRESSURE), + "maxReleasePressure" = round(TANK_MAX_RELEASE_PRESSURE), + "leakPressure" = round(TANK_LEAK_PRESSURE), + "fragmentPressure" = round(TANK_FRAGMENT_PRESSURE) + ) - if (href_list["dist_p"]) - if (href_list["dist_p"] == "reset") - src.distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE - else if (href_list["dist_p"] == "max") - src.distribute_pressure = TANK_MAX_RELEASE_PRESSURE - else - var/cp = text2num(href_list["dist_p"]) - src.distribute_pressure += cp - src.distribute_pressure = min(max(round(src.distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE) - if (href_list["stat"]) - toggle_valve(usr) +/obj/item/tank/ui_data(mob/user) + . = list( + "tankPressure" = round(air_contents.return_pressure()), + "releasePressure" = round(distribute_pressure) + ) - src.add_fingerprint(usr) - return 1 + var/mob/living/carbon/C = user + if(!istype(C)) + C = loc.loc + if(C.internal == src) + .["connected"] = TRUE + else + .["connected"] = FALSE + + .["maskConnected"] = FALSE + if(C.wear_mask && (C.wear_mask.item_flags & ALLOWINTERNALS)) + .["maskConnected"] = TRUE + else if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(H.head && (H.head.item_flags & ALLOWINTERNALS)) + .["maskConnected"] = TRUE + + return . + +/obj/item/tank/ui_act(action, params) + if(..()) + return TRUE + switch(action) + if("pressure") + var/pressure = params["pressure"] + if(pressure == "reset") + pressure = TANK_DEFAULT_RELEASE_PRESSURE + . = TRUE + else if(pressure == "min") + pressure = TANK_MIN_RELEASE_PRESSURE + . = TRUE + else if(pressure == "max") + pressure = TANK_MAX_RELEASE_PRESSURE + . = TRUE + else if(text2num(pressure) != null) + pressure = text2num(pressure) + . = TRUE + if(.) + distribute_pressure = clamp(round(pressure), TANK_MIN_RELEASE_PRESSURE, TANK_MAX_RELEASE_PRESSURE) + if("toggle") + toggle_valve(usr) + . = TRUE /obj/item/tank/proc/toggle_valve(var/mob/user) if(istype(loc,/mob/living/carbon)) @@ -321,23 +314,25 @@ var/list/global/tank_gauge_cache = list() else to_chat(user, "You need something to connect to \the [src].") - - /obj/item/tank/remove_air(amount) + START_PROCESSING(SSobj, src) return air_contents.remove(amount) +/obj/item/tank/return_air() + START_PROCESSING(SSobj, src) + return air_contents + + +/obj/item/tank/assume_air(datum/gas_mixture/giver) + START_PROCESSING(SSobj, src) + air_contents.merge(giver) + //handle_tolerances(ASSUME_AIR_DT_FACTOR) + check_status() + return TRUE + /obj/item/tank/proc/remove_air_by_flag(flag, amount) return air_contents.remove_by_flag(flag, amount) -/obj/item/tank/return_air() - return air_contents - -/obj/item/tank/assume_air(datum/gas_mixture/giver) - air_contents.merge(giver) - - check_status() - return 1 - /obj/item/tank/proc/remove_air_volume(volume_to_return) if(!air_contents) return null @@ -516,18 +511,14 @@ var/list/global/tank_gauge_cache = list() #ifdef FIREDBG log_debug("[x],[y] tank is leaking: [pressure] kPa, integrity [integrity]") #endif - - else integrity-= 1 - - else - if(integrity < maxintegrity) + if(integrity < max_integrity) integrity++ if(leaking) integrity++ - if(integrity == maxintegrity) + if(integrity == max_integrity) leaking = 0 ///////////////////////////////// @@ -641,9 +632,8 @@ var/list/global/tank_gauge_cache = list() return - -/obj/item/tank/proc/ignite() //This happens when a bomb is told to explode - +///This happens when a bomb is told to explode +/obj/item/tank/proc/ignite() var/obj/item/assembly_holder/assy = src.proxyassembly.assembly var/ign = assy.a_right var/obj/item/other = assy.a_left diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index c5840c19c02..cb7f5844d66 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -119,6 +119,7 @@ ..() /mob/proc/unset_machine() + machine?.remove_visual(src) src.machine = null /mob/proc/set_machine(var/obj/O) diff --git a/code/game/world.dm b/code/game/world.dm index 7cfde37b250..7098b38e430 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -66,9 +66,6 @@ GLOBAL_LIST(topic_status_cache) . = ..() - // Set up roundstart seed list. - plant_controller = new - // *sighs* job_master = new job_master.SetupOccupations() diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 25245b30cd6..5f4d35f25e4 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -1019,16 +1019,16 @@ var/datum/announcement/minor/admin_min_announcer = new return 0 -/datum/admins/proc/spawn_fruit(seedtype in plant_controller.seeds) +/datum/admins/proc/spawn_fruit(seedtype in SSplants.seeds) set category = "Debug" set desc = "Spawn the product of a seed." set name = "Spawn Fruit" if(!check_rights(R_SPAWN)) return - if(!seedtype || !plant_controller.seeds[seedtype]) + if(!seedtype || !SSplants.seeds[seedtype]) return - var/datum/seed/S = plant_controller.seeds[seedtype] + var/datum/seed/S = SSplants.seeds[seedtype] S.harvest(usr,0,0,1) log_admin("[key_name(usr)] spawned [seedtype] fruit at ([usr.x],[usr.y],[usr.z])") @@ -1072,16 +1072,16 @@ var/datum/announcement/minor/admin_min_announcer = new for(var/datum/custom_item/item in current_items) to_chat(usr, "- name: [item.name] icon: [item.item_icon] path: [item.item_path] desc: [item.item_desc]") -/datum/admins/proc/spawn_plant(seedtype in plant_controller.seeds) +/datum/admins/proc/spawn_plant(seedtype in SSplants.seeds) set category = "Debug" set desc = "Spawn a spreading plant effect." set name = "Spawn Plant" if(!check_rights(R_SPAWN)) return - if(!seedtype || !plant_controller.seeds[seedtype]) + if(!seedtype || !SSplants.seeds[seedtype]) return - new /obj/effect/plant(get_turf(usr), plant_controller.seeds[seedtype]) + new /obj/effect/plant(get_turf(usr), SSplants.seeds[seedtype]) log_admin("[key_name(usr)] spawned [seedtype] vines at ([usr.x],[usr.y],[usr.z])") /datum/admins/proc/spawn_atom(var/object as text) diff --git a/code/modules/alarm/alarm_handler.dm b/code/modules/alarm/alarm_handler.dm index 8f6686e3dec..b3b775d2272 100644 --- a/code/modules/alarm/alarm_handler.dm +++ b/code/modules/alarm/alarm_handler.dm @@ -47,24 +47,24 @@ existing.clear(source) return check_alarm_cleared(existing) -/datum/alarm_handler/proc/major_alarms() - return visible_alarms() +/datum/alarm_handler/proc/major_alarms(var/z) + return visible_alarms(z) -/datum/alarm_handler/proc/has_major_alarms() - if(alarms && alarms.len) - return 1 - return 0 +/datum/alarm_handler/proc/has_major_alarms(var/z) + if(!LAZYLEN(alarms)) + return FALSE + return LAZYLEN(major_alarms(z)) -/datum/alarm_handler/proc/minor_alarms() - return visible_alarms() +/datum/alarm_handler/proc/minor_alarms(var/z) + return visible_alarms(z) /datum/alarm_handler/proc/check_alarm_cleared(var/datum/alarm/alarm) if ((alarm.end_time && world.time > alarm.end_time) || !alarm.sources.len) alarms -= alarm alarms_assoc -= alarm.origin on_alarm_change(alarm, ALARM_CLEARED) - return 1 - return 0 + return TRUE + return FALSE /datum/alarm_handler/proc/on_alarm_change(var/datum/alarm/alarm, var/was_raised) for(var/obj/machinery/camera/C in alarm.cameras()) @@ -101,9 +101,13 @@ for(var/listener in listeners) call(listener, listeners[listener])(src, alarm, was_raised) -/datum/alarm_handler/proc/visible_alarms() +/datum/alarm_handler/proc/visible_alarms(var/z) + if(!LAZYLEN(alarms)) + return list() + var/list/map_levels = GLOB.using_map.get_map_levels(z) var/list/visible_alarms = new() for(var/datum/alarm/A in alarms) - if(!A.hidden) - visible_alarms.Add(A) + if(A.hidden || (z && !(A.origin?.z in map_levels))) + continue + visible_alarms.Add(A) return visible_alarms diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm index a87abd336fc..92e923dfdb7 100644 --- a/code/modules/assembly/assembly.dm +++ b/code/modules/assembly/assembly.dm @@ -1,3 +1,10 @@ +#define WIRE_RECEIVE (1<<0) +#define WIRE_PULSE (1<<1) +#define WIRE_PULSE_SPECIAL (1<<2) +#define WIRE_RADIO_RECEIVE (1<<3) +#define WIRE_RADIO_PULSE (1<<4) +#define ASSEMBLY_BEEP_VOLUME 5 + /obj/item/assembly name = "assembly" desc = "A small electronic device that should never exist." @@ -15,87 +22,52 @@ var/secured = 1 var/list/attached_overlays = null var/obj/item/assembly_holder/holder = null - var/cooldown = 0//To prevent spam + var/cooldown = FALSE //To prevent spam var/wires = WIRE_RECEIVE | WIRE_PULSE - var/const/WIRE_RECEIVE = 1 //Allows Pulsed(0) to call Activate() - var/const/WIRE_PULSE = 2 //Allows Pulse(0) to act on the holder - var/const/WIRE_PULSE_SPECIAL = 4 //Allows Pulse(0) to act on the holders special assembly - var/const/WIRE_RADIO_RECEIVE = 8 //Allows Pulsed(1) to call Activate() - var/const/WIRE_RADIO_PULSE = 16 //Allows Pulse(1) to send a radio message +/obj/item/assembly/Destroy() + holder = null + return ..() -/obj/item/assembly/proc/activate() //What the device does when turned on +/obj/item/assembly/proc/holder_movement() return -/obj/item/assembly/proc/pulsed(var/radio = 0) //Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs - return +/obj/item/assembly/proc/process_cooldown() + if(cooldown) + return FALSE + cooldown = TRUE + VARSET_IN(src, cooldown, FALSE, 2 SECONDS) + return TRUE -/obj/item/assembly/proc/pulse(var/radio = 0) //Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct - return - -/obj/item/assembly/proc/toggle_secure() //Code that has to happen when the assembly is un\secured goes here - return - -/obj/item/assembly/proc/attach_assembly(var/obj/A, var/mob/user) //Called when an assembly is attacked by another - return - -/obj/item/assembly/proc/process_cooldown() //Called via spawn(10) to have it count down the cooldown var - return - -/obj/item/assembly/proc/holder_movement() //Called when the holder is moved - return - -/obj/item/assembly/interact(mob/user as mob) //Called when attack_self is called - return - - -/obj/item/assembly/process_cooldown() - cooldown-- - if(cooldown <= 0) return 0 - spawn(10) - process_cooldown() - return 1 - - -/obj/item/assembly/pulsed(var/radio = 0) +/obj/item/assembly/proc/pulsed(var/radio = 0) if(holder && (wires & WIRE_RECEIVE)) activate() if(radio && (wires & WIRE_RADIO_RECEIVE)) activate() - return 1 + return TRUE - -/obj/item/assembly/pulse(var/radio = 0) +/obj/item/assembly/proc/pulse(var/radio = 0) if(holder && (wires & WIRE_PULSE)) holder.process_activation(src, 1, 0) if(holder && (wires & WIRE_PULSE_SPECIAL)) holder.process_activation(src, 0, 1) -// if(radio && (wires & WIRE_RADIO_PULSE)) - //Not sure what goes here quite yet send signal? - return 1 + return TRUE +/obj/item/assembly/proc/activate() + if(!secured || !process_cooldown()) + return FALSE + return TRUE -/obj/item/assembly/activate() - if(!secured || (cooldown > 0)) return 0 - cooldown = 2 - spawn(10) - process_cooldown() - return 1 - - -/obj/item/assembly/toggle_secure() +/obj/item/assembly/proc/toggle_secure() secured = !secured update_icon() return secured - -/obj/item/assembly/attach_assembly(var/obj/item/assembly/A, var/mob/user) +/obj/item/assembly/proc/attach_assembly(var/obj/item/assembly/A, var/mob/user) holder = new/obj/item/assembly_holder(get_turf(src)) if(holder.attach(A,src,user)) - to_chat(user, "You attach \the [A] to \the [src]!") - return 1 - return 0 - + to_chat(user, SPAN_NOTICE("You attach \the [A] to \the [src]!")) + return TRUE /obj/item/assembly/attackby(obj/item/W as obj, mob/user as mob) if(isassembly(W)) @@ -105,18 +77,14 @@ return if(W.is_screwdriver()) if(toggle_secure()) - to_chat(user, "\The [src] is ready!") + to_chat(user, SPAN_NOTICE("\The [src] is ready!")) else - to_chat(user, "\The [src] can now be attached!") + to_chat(user, SPAN_NOTICE("\The [src] can now be attached!")) return - ..() - return - + return ..() /obj/item/assembly/process(delta_time) - STOP_PROCESSING(SSobj, src) - return - + return PROCESS_KILL /obj/item/assembly/examine(mob/user) . = ..() @@ -129,54 +97,19 @@ /obj/item/assembly/attack_self(mob/user as mob) - if(!user) return 0 + if(!user) + return FALSE user.set_machine(src) - interact(user) - return 1 + ui_interact(user) + return TRUE +/obj/item/device/assembly/ui_state(mob/user) + return GLOB.deep_inventory_state -/obj/item/assembly/interact(mob/user as mob) - return //HTML MENU FOR WIRES GOES HERE +/obj/item/device/assembly/ui_interact(mob/user, datum/tgui/ui) + return // tgui goes here -/obj/item/assembly/nano_host() - if(istype(loc, /obj/item/assembly_holder)) - return loc.nano_host() - return ..() - -/* - var/small_icon_state = null//If this obj will go inside the assembly use this for icons - var/list/small_icon_state_overlays = null//Same here - var/obj/holder = null - var/cooldown = 0//To prevent spam - - proc - Activate()//Called when this assembly is pulsed by another one - Process_cooldown()//Call this via spawn(10) to have it count down the cooldown var - Attach_Holder(var/obj/H, var/mob/user)//Called when an assembly holder attempts to attach, sets src's loc in here - - - Activate() - if(cooldown > 0) - return 0 - cooldown = 2 - spawn(10) - Process_cooldown() - //Rest of code here - return 0 - - - Process_cooldown() - cooldown-- - if(cooldown <= 0) return 0 - spawn(10) - Process_cooldown() - return 1 - - - Attach_Holder(var/obj/H, var/mob/user) - if(!H) return 0 - if(!H.IsAssemblyHolder()) return 0 - //Remember to have it set its loc somewhere in here - - -*/ +/obj/item/device/assembly/ui_host() + if(istype(loc, /obj/item/assembly_holder)) + return loc.ui_host() + return ..() diff --git a/code/modules/assembly/helpers.dm b/code/modules/assembly/helpers.dm index db72e5f8fcb..c5afef9b795 100644 --- a/code/modules/assembly/helpers.dm +++ b/code/modules/assembly/helpers.dm @@ -27,18 +27,3 @@ if(istype(O, /obj/item/assembly/timer)) return 1 return 0 - -/* -Name: IsSpecialAssembly -Desc: If true is an object that can be attached to an assembly holder but is a special thing like a phoron can or door -*/ - -/obj/proc/IsSpecialAssembly() - return 0 - -/* -Name: IsAssemblyHolder -Desc: If true is an object that can hold an assemblyholder object -*/ -/obj/proc/IsAssemblyHolder() - return 0 diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index be3af9123a1..8790dc9ac38 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -14,76 +14,49 @@ var/obj/item/assembly/a_right = null var/obj/special_assembly = null -/obj/item/assembly_holder/proc/attach(var/obj/item/D, var/obj/item/D2, var/mob/user) - return +/obj/item/assembly_holder/proc/attach(var/obj/item/assembly/D, var/obj/item/assembly/D2, var/mob/user) + if(!D || !D2) + return FALSE -/obj/item/assembly_holder/proc/attach_special(var/obj/O, var/mob/user) - return + if(!istype(D) || !istype(D2)) + return FALSE -/obj/item/assembly_holder/proc/process_activation(var/obj/item/D) - return - -/obj/item/assembly_holder/proc/detached() - return + if(D.secured || D2.secured) + return FALSE -/obj/item/assembly_holder/IsAssemblyHolder() - return 1 - - -/obj/item/assembly_holder/attach(var/obj/item/D, var/obj/item/D2, var/mob/user) - if((!D)||(!D2)) return 0 - if((!isassembly(D))||(!isassembly(D2))) return 0 - if((D:secured)||(D2:secured)) return 0 if(user) user.remove_from_mob(D) user.remove_from_mob(D2) - D:holder = src - D2:holder = src - D.loc = src - D2.loc = src + + D.holder = src + D2.holder = src + D.forceMove(src) + D2.forceMove(src) a_left = D a_right = D2 name = "[D.name]-[D2.name] assembly" update_icon() - usr.put_in_hands(src) + user.put_in_hands(src) - return 1 + return TRUE - -/obj/item/assembly_holder/attach_special(var/obj/O, var/mob/user) - if(!O) return - if(!O.IsSpecialAssembly()) return 0 - -/* if(O:Attach_Holder()) - special_assembly = O - update_icon() - src.name = "[a_left.name] [a_right.name] [special_assembly.name] assembly" -*/ +/obj/item/assembly_holder/proc/detached() return - /obj/item/assembly_holder/update_icon() - overlays.Cut() + cut_overlays() if(a_left) - overlays += "[a_left.icon_state]_left" + add_overlay("[a_left.icon_state]_left") for(var/O in a_left.attached_overlays) - overlays += "[O]_l" + add_overlay("[O]_l") if(a_right) - src.overlays += "[a_right.icon_state]_right" + add_overlay("[a_right.icon_state]_right") for(var/O in a_right.attached_overlays) - overlays += "[O]_r" + add_overlay("[O]_r") if(master) master.update_icon() -/* if(special_assembly) - special_assembly.update_icon() - if(special_assembly:small_icon_state) - src.overlays += special_assembly:small_icon_state - for(var/O in special_assembly:small_icon_state_overlays) - src.overlays += O -*/ - /obj/item/assembly_holder/examine(mob/user) . = ..() if ((in_range(src, user) || src.loc == user)) @@ -91,17 +64,12 @@ . += "\The [src] is ready!" else . += "\The [src] can be attached!" - return - /obj/item/assembly_holder/HasProximity(atom/movable/AM as mob|obj) if(a_left) a_left.HasProximity(AM) if(a_right) a_right.HasProximity(AM) - if(special_assembly) - special_assembly.HasProximity(AM) - /obj/item/assembly_holder/Crossed(atom/movable/AM) . = ..() @@ -111,41 +79,27 @@ a_left.Crossed(AM) if(a_right) a_right.Crossed(AM) - if(special_assembly) - special_assembly.Crossed(AM) /obj/item/assembly_holder/on_found(mob/finder as mob) if(a_left) a_left.on_found(finder) if(a_right) a_right.on_found(finder) - if(special_assembly) - if(istype(special_assembly, /obj/item)) - var/obj/item/S = special_assembly - S.on_found(finder) - /obj/item/assembly_holder/Move() ..() if(a_left && a_right) a_left.holder_movement() a_right.holder_movement() -// if(special_assembly) -// special_assembly:holder_movement() - return /obj/item/assembly_holder/attack_hand()//Perhapse this should be a holder_pickup proc instead, can add if needbe I guess if(a_left && a_right) a_left.holder_movement() a_right.holder_movement() -// if(special_assembly) -// special_assembly:Holder_Movement() ..() - return - -/obj/item/assembly_holder/attackby(obj/item/W as obj, mob/user as mob) +/obj/item/assembly_holder/attackby(var/obj/item/W, var/mob/user) if(W.is_screwdriver()) if(!a_left || !a_right) to_chat(user, " BUG:Assembly part missing, please report this!") @@ -159,14 +113,10 @@ to_chat(user, "\The [src] can now be taken apart!") update_icon() return - else if(W.IsSpecialAssembly()) - attach_special(W, user) else ..() - return - -/obj/item/assembly_holder/attack_self(mob/user as mob) +/obj/item/assembly_holder/attack_self(var/mob/user) src.add_fingerprint(user) if(src.secured) if(!a_left || !a_right) @@ -184,20 +134,20 @@ a_right.attack_self(user) else var/turf/T = get_turf(src) - if(!T) return 0 + if(!T) + return FALSE if(a_left) - a_left:holder = null - a_left.loc = T + a_left.holder = null + a_left.forceMove(T) if(a_right) - a_right:holder = null - a_right.loc = T - spawn(0) - qdel(src) - return + a_right.holder = null + a_right.forceMove(T) + qdel(src) -/obj/item/assembly_holder/process_activation(var/obj/D, var/normal = 1, var/special = 1) - if(!D) return 0 +/obj/item/assembly_holder/proc/process_activation(var/obj/D, var/normal = 1) + if(!D) + return FALSE if(!secured) visible_message("[icon2html(thing = src, target = world)] *beep* *beep*", "*beep* *beep*") if((normal) && (a_right) && (a_left)) @@ -207,42 +157,35 @@ a_left.pulsed(0) if(master) master.receive_signal() -// if(special && special_assembly) -// if(!special_assembly == D) -// special_assembly.dothings() - return 1 - + return TRUE /obj/item/assembly_holder/hear_talk(mob/living/M as mob, msg, verb, datum/language/speaking) if(a_right) a_right.hear_talk(M,msg,verb,speaking) if(a_left) a_left.hear_talk(M,msg,verb,speaking) - - - - /obj/item/assembly_holder/timer_igniter name = "timer-igniter assembly" - New() - ..() +/obj/item/assembly_holder/timer_igniter/New() + ..() - var/obj/item/assembly/igniter/ign = new(src) - ign.secured = 1 - ign.holder = src - var/obj/item/assembly/timer/tmr = new(src) - tmr.time=5 - tmr.secured = 1 - tmr.holder = src - START_PROCESSING(SSobj, tmr) - a_left = tmr - a_right = ign - secured = 1 - update_icon() - name = initial(name) + " ([tmr.time] secs)" + var/obj/item/assembly/igniter/ign = new(src) + ign.secured = 1 + ign.holder = src - loc.verbs += /obj/item/assembly_holder/timer_igniter/verb/configure + var/obj/item/assembly/timer/tmr = new(src) + tmr.time = 5 + tmr.secured = 1 + tmr.holder = src + + a_left = tmr + a_right = ign + secured = 1 + update_icon() + name = initial(name) + " ([tmr.time] secs)" + + loc.verbs += /obj/item/assembly_holder/timer_igniter/verb/configure /obj/item/assembly_holder/timer_igniter/detached() loc.verbs -= /obj/item/assembly_holder/timer_igniter/verb/configure diff --git a/code/modules/assembly/igniter.dm b/code/modules/assembly/igniter.dm index b5fdc79157a..846b9467dad 100644 --- a/code/modules/assembly/igniter.dm +++ b/code/modules/assembly/igniter.dm @@ -5,11 +5,12 @@ origin_tech = list(TECH_MAGNET = 1) matter = list(DEFAULT_WALL_MATERIAL = 500, "glass" = 50) - secured = 1 + secured = TRUE wires = WIRE_RECEIVE /obj/item/assembly/igniter/activate() - if(!..()) return 0//Cooldown check + if(!..()) + return FALSE if(holder && istype(holder.loc,/obj/item/grenade/chem_grenade)) var/obj/item/grenade/chem_grenade/grenade = holder.loc @@ -28,13 +29,12 @@ s.set_up(3, 1, src) s.start() - return 1 + return TRUE -/obj/item/assembly/igniter/attack_self(mob/user as mob) +/obj/item/assembly/igniter/attack_self(var/mob/user) activate() add_fingerprint(user) - return /obj/item/assembly/igniter/is_hot() return TRUE diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index 043fa6bbc7b..f498b81459f 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -1,5 +1,3 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - /obj/item/assembly/infra name = "infrared emitter" desc = "Emits a visible or invisible beam and is triggered when the beam is interrupted." @@ -23,11 +21,7 @@ var/dirty = FALSE /// current atom listening to var/atom/movable/listening - -/obj/item/assembly/infra/Destroy() - if(on) - turn_off() - return ..() + var/hearing_range = 3 /obj/item/assembly/infra/activate() . = ..() @@ -159,45 +153,44 @@ return FALSE pulse(0) if(!holder) - visible_message("[icon2html(thing = src, target = world)] *beep* *beep*") + audible_message(SPAN_INFOPLAIN("[icon2html(src, hearers(src))] *beep* *beep* *beep*"), null, hearing_range) + for(var/mob/hearing_mob in get_hearers_in_view(hearing_range, src)) + hearing_mob.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE) cooldown = 2 addtimer(CALLBACK(src, /obj/item/assembly/proc/process_cooldown), 10) -/obj/item/assembly/infra/interact(mob/user as mob)//TODO: change this this to the wire control panel +/obj/item/assembly/infra/ui_interact(mob/user, datum/tgui/ui) if(!secured) - return - user.set_machine(src) - var/dat = text("Infrared Laser\nStatus: []
\nVisibility: []
\n
", (on ? text("On", src) : text("Off", src)), (src.visible ? text("Visible", src) : text("Invisible", src))) - dat += "

Refresh" - dat += "

Close" - user << browse(dat, "window=infra") - onclose(user, "infra") + to_chat(user, SPAN_WARNING("[src] is unsecured!")) + return FALSE + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AssemblyInfrared", name) + ui.open() -/obj/item/assembly/infra/Topic(href, href_list, state = deep_inventory_state) - . = ..() - if(.) - return - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=infra") - onclose(usr, "infra") - return +/obj/item/assembly/infra/ui_data(mob/user) + var/list/data = ..() - if(href_list["state"]) - if(on) - turn_off() - else - turn_on() - interact(usr) - return + data["on"] = on + data["visible"] = visible - if(href_list["visible"]) - toggle_visible() - interact(usr) - return + return data - if(href_list["close"]) - usr << browse(null, "window=infra") - return +/obj/item/assembly/infra/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE + + switch(action) + if("state") + activate() + return TRUE + if("visible") + visible = !visible + for(var/ibeam in head) + var/obj/effect/beam/i_beam/I = ibeam + I.visible = visible + CHECK_TICK + return TRUE /obj/item/assembly/infra/verb/rotate_clockwise() set name = "Rotate Infrared Laser Clockwise" diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 3dc63fd2b43..9022a8dd1f7 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -7,7 +7,7 @@ var/armed = 0 -/obj/item/assembly/mousetrap/examine(mob/user) +/obj/item/assembly/mousetrap/examine(var/mob/user) . = ..() if(armed) . += "It looks like it's armed." @@ -20,7 +20,7 @@ if(holder) holder.update_icon() -/obj/item/assembly/mousetrap/proc/triggered(mob/target as mob, var/type = "feet") +/obj/item/assembly/mousetrap/proc/triggered(var/mob/target, var/type = "feet") if(!armed) return var/obj/item/organ/external/affecting = null @@ -49,8 +49,7 @@ update_icon() pulse(0) - -/obj/item/assembly/mousetrap/attack_self(mob/living/user as mob) +/obj/item/assembly/mousetrap/attack_self(var/mob/living/user) if(!armed) to_chat(user, "You arm [src].") else @@ -69,7 +68,7 @@ playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3) -/obj/item/assembly/mousetrap/attack_hand(mob/living/user as mob) +/obj/item/assembly/mousetrap/attack_hand(var/mob/living/user) if(armed) if((CLUMSY in user.mutations) && prob(50)) var/which_hand = "l_hand" @@ -82,7 +81,7 @@ ..() -/obj/item/assembly/mousetrap/Crossed(atom/movable/AM as mob|obj) +/obj/item/assembly/mousetrap/Crossed(var/atom/movable/AM) if(AM.is_incorporeal()) return if(armed) @@ -97,7 +96,7 @@ ..() -/obj/item/assembly/mousetrap/on_found(mob/living/finder as mob) +/obj/item/assembly/mousetrap/on_found(var/mob/living/finder) if(armed) finder.visible_message("[finder] accidentally sets off [src], breaking their fingers.", \ "You accidentally trigger [src]!") @@ -106,18 +105,16 @@ return 0 -/obj/item/assembly/mousetrap/hitby(A as mob|obj) +/obj/item/assembly/mousetrap/hitby(var/atom/movable/A) if(!armed) return ..() visible_message("[src] is triggered by [A].") triggered(null) - /obj/item/assembly/mousetrap/armed icon_state = "mousetraparmed" armed = 1 - /obj/item/assembly/mousetrap/verb/hide_under() set src in oview(1) set name = "Hide" @@ -126,5 +123,5 @@ if(usr.stat) return - layer = TURF_LAYER+0.2 + layer = HIDING_LAYER to_chat(usr, "You hide [src].") diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 272fe0baf4f..462f75245d8 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -12,15 +12,15 @@ var/scanning = 0 var/timing = 0 var/time = 10 - + var/hearing_range = 3 var/range = 2 /obj/item/assembly/prox_sensor/activate() - if(!..()) return 0//Cooldown check + if(!..()) + return FALSE timing = !timing update_icon() - return 0 - + return FALSE /obj/item/assembly/prox_sensor/toggle_secure() secured = !secured @@ -33,29 +33,25 @@ update_icon() return secured - /obj/item/assembly/prox_sensor/HasProximity(atom/movable/AM as mob|obj) if(!istype(AM)) log_debug("DEBUG: HasProximity called with [AM] on [src] ([usr]).") return - if (istype(AM, /obj/effect/beam)) return - if (!isobserver(AM) && AM.move_speed < 12) sense() - return - + if (istype(AM, /obj/effect/beam)) + return + if (!isobserver(AM) && AM.move_speed < 12) + sense() /obj/item/assembly/prox_sensor/proc/sense() - var/turf/mainloc = get_turf(src) -// if(scanning && cooldown <= 0) -// mainloc.visible_message("[icon2html(thing = src, target = world)] *boop* *boop*", "*boop* *boop*") - if((!holder && !secured)||(!scanning)||(cooldown > 0)) return 0 - pulse(0) - if(!holder) - mainloc.visible_message("[icon2html(thing = src, target = world)] *beep* *beep*", "*beep* *beep*") - cooldown = 2 - spawn(10) - process_cooldown() - return - + if((!holder && !secured) || !scanning || !process_cooldown()) + return FALSE + pulse(FALSE) + audible_message(SPAN_INFOPLAIN("[icon2html(src, hearers(src))] *beep* *beep* *beep*"), null, hearing_range) + for(var/CHM in get_hearers_in_view(hearing_range, src)) + if(ismob(CHM)) + var/mob/LM = CHM + LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE) + return TRUE /obj/item/assembly/prox_sensor/process(delta_time) if(scanning) @@ -69,90 +65,80 @@ if(timing && time <= 0) timing = 0 toggle_scan() - time = 10 - return - + time = initial(time) /obj/item/assembly/prox_sensor/dropped() . = ..() INVOKE_ASYNC(src, .proc/sense) /obj/item/assembly/prox_sensor/proc/toggle_scan() - if(!secured) return 0 + if(!secured) + return FALSE scanning = !scanning update_icon() - return - /obj/item/assembly/prox_sensor/update_icon() - overlays.Cut() - attached_overlays = list() + cut_overlays() + LAZYCLEARLIST(attached_overlays) if(timing) - overlays += "prox_timing" - attached_overlays += "prox_timing" + add_overlay("prox_timing") + LAZYADD(attached_overlays, "prox_timing") if(scanning) - overlays += "prox_scanning" - attached_overlays += "prox_scanning" + add_overlay("prox_scanning") + LAZYADD(attached_overlays, "prox_scanning") if(holder) holder.update_icon() if(holder && istype(holder.loc,/obj/item/grenade/chem_grenade)) var/obj/item/grenade/chem_grenade/grenade = holder.loc grenade.primed(scanning) - return - /obj/item/assembly/prox_sensor/Move() ..() sense() - return - -/obj/item/assembly/prox_sensor/interact(mob/user as mob)//TODO: Change this to the wires thingy +/obj/item/assembly/prox_sensor/ui_interact(mob/user, datum/tgui/ui) if(!secured) - user.show_message("The [name] is unsecured!") - return 0 - var/second = time % 60 - var/minute = (time - second) / 60 - var/dat = text("Proximity Sensor\n[] []:[]\n- - + +\n", (timing ? text("Arming", src) : text("Not Arming", src)), minute, second, src, src, src, src) - dat += text("
Range: - [] +", src, range, src) - dat += "
[scanning?"Armed":"Unarmed"] (Movement sensor active when armed!)" - dat += "

Refresh" - dat += "

Close" - user << browse(dat, "window=prox") - onclose(user, "prox") - return + to_chat(user, SPAN_WARNING("[src] is unsecured!")) + return FALSE + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AssemblyProx", name) + ui.open() +/obj/item/assembly/prox_sensor/ui_data(mob/user) + var/list/data = ..() -/obj/item/assembly/prox_sensor/Topic(href, href_list, state = deep_inventory_state) - if(..()) return 1 - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=prox") - onclose(usr, "prox") - return + data["time"] = time * 10 + data["timing"] = timing + data["range"] = range + data["maxRange"] = 5 + data["scanning"] = scanning - if(href_list["scanning"]) - toggle_scan() + return data - if(href_list["time"]) - timing = text2num(href_list["time"]) - update_icon() +/obj/item/assembly/prox_sensor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE - if(href_list["tp"]) - var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 0), 600) - - if(href_list["range"]) - var/r = text2num(href_list["range"]) - range += r - range = min(max(range, 1), 5) - - if(href_list["close"]) - usr << browse(null, "window=prox") - return - - if(usr) - attack_self(usr) - - - return + switch(action) + if("scanning") + toggle_scan() + return TRUE + if("timing") + timing = !timing + update_icon() + return TRUE + if("set_time") + var/real_new_time = 0 + var/new_time = params["time"] + var/list/L = splittext(new_time, ":") + if(LAZYLEN(L)) + for(var/i in 1 to LAZYLEN(L)) + real_new_time += text2num(L[i]) * (60 ** (LAZYLEN(L) - i)) + else + real_new_time = text2num(new_time) + time = clamp(real_new_time, 0, 600) + return TRUE + if("range") + range = clamp(params["range"], 1, 5) + return TRUE diff --git a/code/modules/assembly/shock_kit.dm b/code/modules/assembly/shock_kit.dm index 341fb030e97..3441d945ea0 100644 --- a/code/modules/assembly/shock_kit.dm +++ b/code/modules/assembly/shock_kit.dm @@ -13,7 +13,7 @@ ..() return -/obj/item/assembly/shock_kit/attackby(obj/item/W as obj, mob/user as mob) +/obj/item/assembly/shock_kit/attackby(var/obj/item/W, var/mob/user) if(W.is_wrench() && !status) var/turf/T = loc if(ismob(T)) diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index f51fe59a78c..3d15932445b 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -12,6 +12,7 @@ var/code = 30 var/frequency = 1457 var/delay = 0 + var/hearing_range = 1 var/airlock_wire = null var/datum/wires/connected = null var/datum/radio_frequency/radio_connection @@ -26,79 +27,54 @@ set_frequency(frequency) /obj/item/assembly/signaler/activate() - if(cooldown > 0) return FALSE - cooldown = 2 - spawn(10) - process_cooldown() - + if(!process_cooldown()) + return FALSE signal() return TRUE /obj/item/assembly/signaler/update_icon() if(holder) holder.update_icon() - return -/obj/item/assembly/signaler/interact(mob/user as mob, flag1) - var/t1 = "-------" -// if ((src.b_stat && !( flag1 ))) -// t1 = text("-------
\nGreen Wire: []
\nRed Wire: []
\nBlue Wire: []
\n", (src.wires & 4 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 2 ? text("Cut Wire", src) : text("Mend Wire", src)), (src.wires & 1 ? text("Cut Wire", src) : text("Mend Wire", src))) -// else -// t1 = "-------" Speaker: [src.listening ? "Engaged" : "Disengaged"]
- var/dat = {" - +/obj/item/assembly/signaler/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Signaler", name) + ui.open() -Send Signal
-Frequency/Code for signaler:
-Frequency: -- -- -[format_frequency(src.frequency)] -+ -+
+/obj/item/assembly/signaler/ui_data(mob/user) + var/list/data = list() + data["frequency"] = frequency + data["code"] = code + data["minFrequency"] = RADIO_LOW_FREQ + data["maxFrequency"] = RADIO_HIGH_FREQ + return data -Code: -- -- -[src.code] -+ -+
-[t1] -
"} - user << browse(dat, "window=radio") - onclose(user, "radio") - return - - -/obj/item/assembly/signaler/Topic(href, href_list, state = deep_inventory_state) +/obj/item/assembly/signaler/ui_act(action, params) if(..()) return TRUE - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=radio") - onclose(usr, "radio") - return + switch(action) + if("signal") + INVOKE_ASYNC(src, .proc/signal) + . = TRUE + if("freq") + frequency = unformat_frequency(params["freq"]) + frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) + set_frequency(frequency) + . = TRUE + if("code") + code = text2num(params["code"]) + code = clamp(round(code), 1, 100) + . = TRUE + if("reset") + if(params["reset"] == "freq") + set_frequency(initial(frequency)) + else + code = initial(code) + . = TRUE - if (href_list["freq"]) - var/new_frequency = (frequency + text2num(href_list["freq"])) - if(new_frequency < RADIO_LOW_FREQ || new_frequency > RADIO_HIGH_FREQ) - new_frequency = sanitize_frequency(new_frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) - set_frequency(new_frequency) - - if(href_list["code"]) - src.code += text2num(href_list["code"]) - src.code = round(src.code) - src.code = min(100, src.code) - src.code = max(1, src.code) - - if(href_list["send"]) - spawn( 0 ) - signal() - - if(usr) - attack_self(usr) - - return + update_icon() /obj/item/assembly/signaler/attackby(obj/item/W, mob/user, params) if(issignaler(W)) @@ -121,8 +97,6 @@ Code: signal.encryption = code signal.data["message"] = "ACTIVATE" radio_connection.post_signal(src, signal) - return - /obj/item/assembly/signaler/pulse(var/radio = 0) if(is_jammed(src)) @@ -135,7 +109,6 @@ Code: ..(radio) return TRUE - /obj/item/assembly/signaler/receive_signal(datum/signal/signal) if(!signal) return FALSE @@ -145,13 +118,14 @@ Code: return FALSE if(is_jammed(src)) return FALSE - pulse(1) - - if(!holder) - for(var/mob/O in hearers(1, src.loc)) - to_chat(O,"[icon2html(thing = src, target = O)] *beep beep*") - return + pulse(TRUE) + audible_message(SPAN_INFOPLAIN("[icon2html(src, hearers(src))] *beep* *beep* *beep*"), null, hearing_range) + for(var/CHM in get_hearers_in_view(hearing_range, src)) + if(ismob(CHM)) + var/mob/LM = CHM + LM.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE) + return TRUE /obj/item/assembly/signaler/proc/set_frequency(new_frequency) if(!frequency) @@ -164,7 +138,6 @@ Code: radio_controller.remove_object(src, frequency) frequency = new_frequency radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) - return /obj/item/assembly/signaler/process(delta_time) if(!deadman) @@ -177,7 +150,6 @@ Code: STOP_PROCESSING(SSobj, src) else if(prob(5)) M.visible_message("[M]'s finger twitches a bit over [src]'s signal button!") - return /obj/item/assembly/signaler/verb/deadman_it() set src in usr diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 4562c69a2c9..97b402decc1 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -7,99 +7,101 @@ wires = WIRE_PULSE - secured = 0 + secured = FALSE - var/timing = 0 + drop_sound = 'sound/items/handling/component_drop.ogg' + pickup_sound = 'sound/items/handling/component_pickup.ogg' + var/timing = FALSE var/time = 10 + var/saved_time = 10 + var/loop = FALSE + var/hearing_range = 3 /obj/item/assembly/timer/activate() - if(!..()) return 0//Cooldown check - + if(!..()) + return FALSE //Cooldown check timing = !timing - - update_icon() - return 0 - + update_appearance() + return TRUE /obj/item/assembly/timer/toggle_secure() secured = !secured if(secured) - START_PROCESSING(SSprocessing, src) + START_PROCESSING(SSobj, src) else - timing = 0 - STOP_PROCESSING(SSprocessing, src) - update_icon() + timing = FALSE + STOP_PROCESSING(SSobj, src) + update_appearance() return secured - /obj/item/assembly/timer/proc/timer_end() - if(!secured) return 0 - pulse(0) - if(!holder) - visible_message("[icon2html(thing = src, target = world)] *beep* *beep*", "*beep* *beep*") - cooldown = 2 - spawn(10) - process_cooldown() - return - + if(!secured) + return FALSE + pulse(FALSE) + audible_message(SPAN_INFOPLAIN("[icon2html(src, hearers(src))] *beep* *beep* *beep*"), null, hearing_range) + for(var/mob/hearing_mob in get_hearers_in_view(hearing_range, src)) + hearing_mob.playsound_local(get_turf(src), 'sound/machines/triple_beep.ogg', ASSEMBLY_BEEP_VOLUME, TRUE) + if(loop) + timing = TRUE + update_appearance() /obj/item/assembly/timer/process(delta_time) - if(timing && (time > 0)) - time-- - if(timing && time <= 0) - timing = 0 + if(!timing) + return + time -= delta_time + if(time <= 0) + timing = FALSE timer_end() - time = 10 - return + time = saved_time +/obj/item/assembly/timer/update_appearance() + . = ..() + holder?.update_appearance() -/obj/item/assembly/timer/update_icon() - overlays.Cut() +/obj/item/assembly/timer/update_overlays() + . = ..() attached_overlays = list() if(timing) - overlays += "timer_timing" + . += "timer_timing" attached_overlays += "timer_timing" - if(holder) - holder.update_icon() - return - -/obj/item/assembly/timer/interact(mob/user as mob)//TODO: Have this use the wires +/obj/item/assembly/timer/ui_interact(mob/user, datum/tgui/ui) if(!secured) - user.show_message("The [name] is unsecured!") - return 0 - var/second = time % 60 - var/minute = (time - second) / 60 - var/dat = text("Timing Unit\n[] []:[]\n- - + +\n", (timing ? text("Timing", src) : text("Not Timing", src)), minute, second, src, src, src, src) - dat += "

Refresh" - dat += "

Close" - user << browse(dat, "window=timer") - onclose(user, "timer") - return + to_chat(user, SPAN_WARNING("[src] is unsecured!")) + return FALSE + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AssemblyTimer", name) + ui.open() +/obj/item/assembly/timer/ui_data(mob/user) + var/list/data = ..() + var/time_left = time + data["seconds"] = round(time_left % 60) + data["minutes"] = round((time_left - data["seconds"]) / 60) + data["timing"] = timing + data["loop"] = loop + return data -/obj/item/assembly/timer/Topic(href, href_list, state = deep_inventory_state) - if(..()) return 1 - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=timer") - onclose(usr, "timer") - return +/obj/item/assembly/timer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE - if(href_list["time"]) - timing = text2num(href_list["time"]) - update_icon() - - if(href_list["tp"]) - var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 0), 600) - - if(href_list["close"]) - usr << browse(null, "window=timer") - return - - if(usr) - attack_self(usr) - - return + switch(action) + if("time") + timing = !timing + //if(timing && istype(holder, /obj/item/transfer_valve)) + //log_bomber(usr, "activated a", src, "attachment on [holder]") + update_appearance() + . = TRUE + if("repeat") + loop = !loop + . = TRUE + if("input") + var/value = text2num(params["adjust"]) + if(value) + value = round(time + value) + time = clamp(value, 1, 600) + saved_time = time + . = TRUE diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm index 52f2a259d38..13c85b23e18 100644 --- a/code/modules/assembly/voice.dm +++ b/code/modules/assembly/voice.dm @@ -26,10 +26,10 @@ /obj/item/assembly/voice/attack_self(mob/user) - if(!user) return 0 + if(!user) + return FALSE activate() - return 1 - + return TRUE /obj/item/assembly/voice/toggle_secure() . = ..() diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index f5542b80af4..53c58dcf1a0 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -3,12 +3,6 @@ //DEFINITIONS FOR ASSET DATUMS START HERE. -/datum/asset/simple/tgui_common - keep_local_name = TRUE - assets = list( - "tgui-common.chunk.js" = 'tgui/public/tgui-common.bundle.js', - ) - /datum/asset/simple/tgui keep_local_name = TRUE assets = list( @@ -71,9 +65,9 @@ "blank" = 'icons/pda_icons/pda_blank.png', "boom" = 'icons/pda_icons/pda_boom.png', "bucket" = 'icons/pda_icons/pda_bucket.png', - //"medibot" = 'icons/pda_icons/pda_medbot.png', - //"floorbot" = 'icons/pda_icons/pda_floorbot.png', - //"cleanbot" = 'icons/pda_icons/pda_cleanbot.png', + "medibot" = 'icons/pda_icons/pda_medibot.png', + "floorbot" = 'icons/pda_icons/pda_floorbot.png', + "cleanbot" = 'icons/pda_icons/pda_cleanbot.png', "crate" = 'icons/pda_icons/pda_crate.png', "cuffs" = 'icons/pda_icons/pda_cuffs.png', "eject" = 'icons/pda_icons/pda_eject.png', @@ -90,10 +84,10 @@ "refresh" = 'icons/pda_icons/pda_refresh.png', "scanner" = 'icons/pda_icons/pda_scanner.png', "signaler" = 'icons/pda_icons/pda_signaler.png', - // "skills" = 'icons/pda_icons/pda_skills.png', - "status" = 'icons/pda_icons/pda_status.png' - //"dronephone" = 'icons/pda_icons/pda_dronephone.png', - //"emoji" = 'icons/pda_icons/pda_emoji.png' + "skills" = 'icons/pda_icons/pda_skills.png', + "status" = 'icons/pda_icons/pda_status.png', + "dronephone" = 'icons/pda_icons/pda_dronephone.png', + "emoji" = 'icons/pda_icons/pda_emoji.png' ) /* /datum/asset/spritesheet/simple/paper @@ -397,15 +391,15 @@ set waitfor = FALSE var/datum/language/L = new path () L.get_icon() - +*/ /datum/asset/spritesheet/pipes name = "pipes" /datum/asset/spritesheet/pipes/register() - for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi', 'icons/obj/plumbing/fluid_ducts.dmi')) + for(var/each in list('icons/obj/pipe-item.dmi', 'icons/obj/pipes/disposal.dmi')) InsertAll("", each, GLOB.alldirs) ..() - +/* // Representative icons for each research design /datum/asset/spritesheet/research_designs name = "design" diff --git a/code/modules/atmospherics/atmospherics.dm b/code/modules/atmospherics/atmospherics.dm index ba9d40bc3cb..f95aadc6e1d 100644 --- a/code/modules/atmospherics/atmospherics.dm +++ b/code/modules/atmospherics/atmospherics.dm @@ -10,25 +10,34 @@ Pipelines + Other Objects -> Pipe network */ /obj/machinery/atmospherics - anchored = 1 + anchored = TRUE idle_power_usage = 0 active_power_usage = 0 power_channel = ENVIRON - var/nodealert = 0 - var/power_rating //the maximum amount of power the machine can use to do work, affects how powerful the machine is, in Watts - layer = ATMOS_LAYER plane = PLATING_PLANE + obj_flags = CAN_BE_HIT | ON_BLUEPRINTS - var/pipe_flags = PIPING_DEFAULT_LAYER_ONLY // Allow other layers by exception basis. - var/connect_types = CONNECT_TYPE_REGULAR - var/piping_layer = PIPING_LAYER_DEFAULT // This will replace icon_connect_type at some point ~Leshana - var/icon_connect_type = "" //"-supply" or "-scrubbers" - var/construction_type = null // Type path of the pipe item when this is deconstructed. - var/pipe_state // icon_state as a pipe item - - var/initialize_directions = 0 + ///The color of the pipe var/pipe_color + ///The maximum amount of power the machine can use to do work, affects how powerful the machine is, in Watts + var/power_rating + ///The flags of the pipe/component (PIPING_ALL_LAYER | PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY | PIPING_CARDINAL_AUTONORMALIZE) + var/pipe_flags = PIPING_DEFAULT_LAYER_ONLY + ///What pipe layer can this connect to. + var/connect_types = CONNECT_TYPE_REGULAR + ///What layer the pipe is in (from 1 to 5, default 3) + var/piping_layer = PIPING_LAYER_DEFAULT + ///"-supply" or "-scrubbers" + var/icon_connect_type = "" + ///The type path of the pipe item when this is deconstructed. + var/construction_type = null + ///icon_state as a pipe item + var/pipe_state + ///Bitflag of the initialized directions (NORTH | SOUTH | EAST | WEST) + var/initialize_directions = 0 + + var/nodealert = 0 //Apparently this is used only for plumbing or something??? var/global/datum/pipe_icon_manager/icon_manager var/obj/machinery/atmospherics/node1 diff --git a/code/modules/atmospherics/components/binary_devices/algae_generator_vr.dm b/code/modules/atmospherics/components/binary_devices/algae_generator_vr.dm index ecb6378fe98..986578ee417 100644 --- a/code/modules/atmospherics/components/binary_devices/algae_generator_vr.dm +++ b/code/modules/atmospherics/components/binary_devices/algae_generator_vr.dm @@ -122,7 +122,7 @@ icon_state = "algae-full" else icon_state = "algae-on" - return 1 + return TRUE /obj/machinery/atmospherics/binary/algae_farm/attackby(obj/item/W as obj, mob/user as mob) add_fingerprint(user) @@ -135,13 +135,13 @@ if(try_load_materials(user, W)) return else - to_chat(user, "You cannot insert this item into \the [src]!") + to_chat(user, SPAN_NOTICE("You cannot insert this item into \the [src]!")) return /obj/machinery/atmospherics/binary/algae_farm/attack_hand(mob/user) if(..()) - return 1 - nano_ui_interact(user) + return TRUE + ui_interact(user) /obj/machinery/atmospherics/binary/algae_farm/RefreshParts() ..() @@ -166,8 +166,15 @@ moles_per_tick = initial(moles_per_tick) + (manip_rating**2 - 1) -/obj/machinery/atmospherics/binary/algae_farm/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nanoui/master_ui = null, var/datum/topic_state/state = default_state) - var/data[0] +/obj/machinery/atmospherics/binary/algae_farm/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AlgaeFarm", name) + ui.open() + +/obj/machinery/atmospherics/binary/algae_farm/ui_data(mob/user) + var/list/data = list() + data["panelOpen"] = panel_open var/materials_ui[0] @@ -199,44 +206,30 @@ "percent" = air2.total_moles ? round((air2.gas[output_gas] / air2.total_moles) * 100) : 0, "moles" = round(air2.gas[output_gas], 0.01)) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "algae_farm_vr.tmpl", "Algae Farm Control Panel", 500, 600) - ui.set_initial_data(data) - ui.set_auto_update(TRUE) - ui.open() + return data -/obj/machinery/atmospherics/binary/algae_farm/Topic(href, href_list) +/obj/machinery/atmospherics/binary/algae_farm/ui_act(action, params) if(..()) - return 1 - usr.set_machine(src) - add_fingerprint(usr) + return TRUE - // Queue management can be done even while busy - if(href_list["activate"]) - update_use_power(USE_POWER_ACTIVE) - update_icon() - updateUsrDialog() - return + switch(action) + if("toggle") + if(use_power == USE_POWER_IDLE) + update_use_power(USE_POWER_ACTIVE) + else + update_use_power(USE_POWER_IDLE) + update_icon() + . = TRUE - if(href_list["deactivate"]) - update_use_power(USE_POWER_IDLE) - update_icon() - updateUsrDialog() - return - - if(href_list["ejectMaterial"]) - var/matName = href_list["ejectMaterial"] - if(!(matName in stored_material)) - return - eject_materials(matName, 0) - updateUsrDialog() - return + if("ejectMaterial") + var/matName = params["mat"] + if(!(matName in stored_material)) + return + eject_materials(matName, 0) + . = TRUE // TODO - These should be replaced with materials datum. - // 0 amount = 0 means ejecting a full stack; -1 means eject everything /obj/machinery/atmospherics/binary/algae_farm/proc/eject_materials(var/material_name, var/amount) var/recursive = amount == -1 ? 1 : 0 diff --git a/code/modules/atmospherics/components/binary_devices/heat_pump.dm b/code/modules/atmospherics/components/binary_devices/heat_pump.dm index 3a81673654b..7bab68c165f 100644 --- a/code/modules/atmospherics/components/binary_devices/heat_pump.dm +++ b/code/modules/atmospherics/components/binary_devices/heat_pump.dm @@ -5,80 +5,83 @@ #define EFFICENCY_LIMIT_MULT 1 /obj/machinery/atmospherics/binary/heat_pump - name = "heat pump" - desc = "A heat pump, used to transfer heat between two pipe systems." + name = "heat pump" + desc = "A heat pump, used to transfer heat between two pipe systems." - level = 1 + level = 1 - icon = 'icons/atmos/heat_pump.dmi' - icon_state = "map_off" - construction_type = /obj/item/pipe/directional - pipe_state = "pump" - var/base_icon = "heat_pump" + icon = 'icons/atmos/heat_pump.dmi' + icon_state = "map_off" + construction_type = /obj/item/pipe/directional + pipe_state = "pump" - use_power = USE_POWER_OFF - idle_power_usage = 150//internal circuitry, friction losses and stuff - power_rating = 15000//15000 W ~ 20 HP - var/max_power_rating = 15000 - /*can be used for radio stuff later - var/frequency = 0 + use_power = USE_POWER_OFF + //Internal circuitry, friction losses and stuff + idle_power_usage = 150 + //15000 W ~ 20 HP + power_rating = 15000 + var/max_power_rating = 15000 + /*can be used for radio stuff later + var/frequency = 0 var/id = null var/datum/radio_frequency/radio_connection - */ - var/target_temp = T20C - var/lowest_temp = TCMB - var/max_temp = 99999999//Need to bottle it somewhere, the sun's core has 15 million kelvin + */ + var/target_temp = T20C + var/lowest_temp = TCMB + ///Need to bottle it somewhere, the sun's core has 15 million kelvin + var/max_temp = 99999999 - var/on = 0 - var/efficiency = 0 + var/on = FALSE + var/efficiency = 0 /obj/machinery/atmospherics/binary/heat_pump/CtrlClick(mob/user) - if (Adjacent(user)) - add_hiddenprint(user) - if(powered()) - to_chat(user, "You toggle the power to the [src] [on ? "Off" : "On"].") - update_use_power(!use_power) - on = !on - update_icon() - else - to_chat(user, "There doesn't seem to be any power.") + if(Adjacent(user)) + add_hiddenprint(user) + if(powered()) + to_chat(user, "You toggle the power to the [src] [on ? "Off" : "On"].") + update_use_power(!use_power) + on = !on + update_icon() + else + to_chat(user, SPAN_WARNING("There doesn't seem to be any power.")) /obj/machinery/atmospherics/binary/heat_pump/CtrlShiftClick(mob/user) - if(Adjacent(user)) - add_hiddenprint(user) - if (powered()) - to_chat(user, "You set the target temperature of the [src] to default.") - target_temp = T20C - else - to_chat(user, "There doesn't seem to be any power.") + if(Adjacent(user)) + add_hiddenprint(user) + if (powered()) + to_chat(user, "You set the target temperature of the [src] to default.") + target_temp = T20C + else + to_chat(user, SPAN_WARNING("There doesn't seem to be any power.")) /obj/machinery/atmospherics/binary/heat_pump/AltClick(mob/user) - if(Adjacent(user)) - add_hiddenprint(user) - if (powered()) - to_chat(user, "You set the target temperature of the [src] to [TCMB] Kelvin.") - target_temp = TCMB - else - to_chat(user, "There doesn't seem to be any power.") + if(Adjacent(user)) + add_hiddenprint(user) + if (powered()) + to_chat(user, "You set the target temperature of the [src] to [TCMB] Kelvin.") + target_temp = TCMB + else + to_chat(user, SPAN_WARNING("There doesn't seem to be any power.")) /obj/machinery/atmospherics/binary/heat_pump/Initialize(mapload) - . = ..() - air1.volume = ATMOS_DEFAULT_VOLUME_PUMP - air2.volume = ATMOS_DEFAULT_VOLUME_PUMP + . = ..() + air1.volume = ATMOS_DEFAULT_VOLUME_PUMP + air2.volume = ATMOS_DEFAULT_VOLUME_PUMP /obj/machinery/atmospherics/binary/passive_gate/Destroy() unregister_radio(src, frequency) . = ..() /obj/machinery/atmospherics/binary/heat_pump/update_icon() - if(!powered() || !on) - icon_state = "off" - else if(air1.temperature < target_temp) - icon_state = "cool_1" - else if(air1.temperature > target_temp) - icon_state = "cool_2" - else - icon_state = "off" + . = ..() + if(!powered() || !on) + icon_state = "off" + else if(air1.temperature < target_temp) + icon_state = "cool_1" + else if(air1.temperature > target_temp) + icon_state = "cool_2" + else + icon_state = "off" /obj/machinery/atmospherics/binary/heat_pump/update_underlays() if(..()) @@ -93,136 +96,138 @@ update_underlays() /obj/machinery/atmospherics/binary/heat_pump/attackby(obj/item/W, mob/user) - if(istype(W, /obj/item/pen)) - var/new_name = input(user, "Please enter the new name for this device:", "New Name") as text|null - new_name = trim(new_name) - name = (new_name? new_name : name) - return - if (!W.is_wrench()) - return ..() - if (!(stat & NOPOWER) && use_power) - to_chat(user, "You cannot unwrench this [src], turn it off first.") - return 1 - add_fingerprint(user) - playsound(src, W.usesound, 50, 1) - to_chat(user, "You begin to unfasten \the [src]...") - if (do_after(user, 40 * W.toolspeed)) - user.visible_message( \ - "\The [user] unfastens \the [src].", \ - "You have unfastened \the [src].", \ - "You hear ratchet.") - deconstruct() + if(istype(W, /obj/item/pen)) + var/new_name = input(user, "Please enter the new name for this device:", "New Name") as text|null + new_name = trim(new_name) + name = (new_name? new_name : name) + return + if (!W.is_wrench()) + return ..() + if (!(stat & NOPOWER) && use_power) + to_chat(user, SPAN_WARNING("You cannot unwrench this [src], turn it off first.")) + return TRUE + add_fingerprint(user) + playsound(src, W.usesound, 50, 1) + to_chat(user, SPAN_NOTICE("You begin to unfasten \the [src]...")) + if (do_after(user, 40 * W.toolspeed)) + user.visible_message( \ + SPAN_NOTICE("\The [user] unfastens \the [src]."), \ + SPAN_NOTICE("You have unfastened \the [src]."), \ + "You hear ratchet.") + deconstruct() /obj/machinery/atmospherics/binary/heat_pump/attack_hand(user as mob) if(..()) return src.add_fingerprint(usr) if(!src.allowed(user)) - to_chat(user, "Access denied.") + to_chat(user, SPAN_BOLDWARNING("Access denied.")) return usr.set_machine(src) ui_interact(user) return /obj/machinery/atmospherics/binary/heat_pump/process(delta_time) - update_icon() - if((stat & (NOPOWER|BROKEN)) || !use_power) - return + update_icon() + if((stat & (NOPOWER|BROKEN)) || !use_power) + return - if(!air1 || !air2) - return + if(!air1 || !air2) + return - if( (air1.temperature < 1) || (air2.temperature < 1))//If there is no air1 or 2 the temperature is assumed 0 Kelvin which allows for - return + //If there is no air1 or 2 the temperature is assumed 0 Kelvin which allows for + if( (air1.temperature < 1) || (air2.temperature < 1)) + return - if((air2.temperature <= target_temp+0.1) && (air2.temperature >= target_temp-0.1)) - return//We are close enough to our target temp that its not worth the hassle - - if(check_passive_opportunity()) - handle_passive_flow() - return//No need to pump while there is passive flow occuring + if((air2.temperature <= target_temp+0.1) && (air2.temperature >= target_temp-0.1)) + return //We are close enough to our target temp that its not worth the hassle - //Now we are at the point where we need to actively pump - efficiency = get_thermal_efficency() - var/energy_transfered = 0 - CACHE_VSC_PROP(atmos_vsc, /atmos/heatpump/performance_factor, performance_factor) + if(check_passive_opportunity()) + handle_passive_flow() + return //No need to pump while there is passive flow occuring - energy_transfered = clamp(air2.get_thermal_energy_change(target_temp),performance_factor*power_rating,-performance_factor*power_rating) - - var/power_draw = abs(energy_transfered/performance_factor) - air2.add_thermal_energy(-air1.add_thermal_energy(-energy_transfered*efficiency))//only adds the energy actually removed from air one to air two(- infront of air1 because energy was removed) - if (power_draw >= 0) - last_power_draw = power_draw - use_power(power_draw) - if(network1) - network1.update = 1 - if(network2) - network2.update = 1 + //Now we are at the point where we need to actively pump + efficiency = get_thermal_efficency() + var/energy_transfered = 0 + CACHE_VSC_PROP(atmos_vsc, /atmos/heatpump/performance_factor, performance_factor) + + energy_transfered = clamp(air2.get_thermal_energy_change(target_temp),performance_factor*power_rating,-performance_factor*power_rating) + + var/power_draw = abs(energy_transfered/performance_factor) + //Only adds the energy actually removed from air one to air two(- infront of air1 because energy was removed) + air2.add_thermal_energy(-air1.add_thermal_energy(-energy_transfered*efficiency)) + if(power_draw >= 0) + last_power_draw = power_draw + use_power(power_draw) + if(network1) + network1.update = TRUE + if(network2) + network2.update = TRUE /obj/machinery/atmospherics/binary/heat_pump/proc/get_thermal_efficency() - if((target_temp < air2.temperature)) - return clamp((air2.temperature/air1.temperature)*EFFICENCY_MULT,0,1*EFFICENCY_LIMIT_MULT) - else if((target_temp > air2.temperature)) - return clamp((air1.temperature/air2.temperature)*EFFICENCY_MULT,0,1*EFFICENCY_LIMIT_MULT) + if((target_temp < air2.temperature)) + return clamp((air2.temperature / air1.temperature) * EFFICENCY_MULT, 0, 1 * EFFICENCY_LIMIT_MULT) + else if((target_temp > air2.temperature)) + return clamp((air1.temperature / air2.temperature) * EFFICENCY_MULT, 0, 1 * EFFICENCY_LIMIT_MULT) /obj/machinery/atmospherics/binary/heat_pump/proc/handle_passive_flow() - var/air_heat_capacity = air1.heat_capacity() - var/other_air_heat_capacity = air2.heat_capacity() - var/combined_heat_capacity = other_air_heat_capacity + air_heat_capacity + var/air_heat_capacity = air1.heat_capacity() + var/other_air_heat_capacity = air2.heat_capacity() + var/combined_heat_capacity = other_air_heat_capacity + air_heat_capacity - if(combined_heat_capacity > 0) - var/combined_energy = air1.temperature*other_air_heat_capacity + air_heat_capacity*air2.temperature + if(combined_heat_capacity > 0) + var/combined_energy = air1.temperature*other_air_heat_capacity + air_heat_capacity*air2.temperature - var/new_temperature = combined_energy/combined_heat_capacity - air1.temperature = new_temperature - air2.temperature = new_temperature + var/new_temperature = combined_energy/combined_heat_capacity + air1.temperature = new_temperature + air2.temperature = new_temperature /obj/machinery/atmospherics/binary/heat_pump/proc/check_passive_opportunity() - if((target_temp < air2.temperature) && (air1.temperature < air2.temperature - 5))//Little offsets to prevent just constant passive flow for minor temperature differences - return TRUE - if((target_temp > air2.temperature) && (air1.temperature > air2.temperature + 5)) - return TRUE - return FALSE - + //Little offsets to prevent just constant passive flow for minor temperature differences + if((target_temp < air2.temperature) && (air1.temperature < air2.temperature - 5)) + return TRUE + if((target_temp > air2.temperature) && (air1.temperature > air2.temperature + 5)) + return TRUE + return FALSE + /obj/machinery/atmospherics/binary/heat_pump/ui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "heat_pump", name) - ui.open() + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "heat_pump", name) + ui.open() /obj/machinery/atmospherics/binary/heat_pump/ui_data(mob/user) - var/list/data = list() - data["target_temp"] = target_temp - data["current_temp"] = air2.temperature - data["sink_temp"] = air1.temperature - data["on"] = on - data["lowest_temp"] = lowest_temp - data["highest_temp"] = max_temp - data["efficency"] = efficiency + var/list/data = list() + data["target_temp"] = target_temp + data["current_temp"] = air2.temperature + data["sink_temp"] = air1.temperature + data["on"] = on + data["lowest_temp"] = lowest_temp + data["highest_temp"] = max_temp + data["efficency"] = efficiency - - return data + return data /obj/machinery/atmospherics/binary/heat_pump/ui_state(mob/user) - return GLOB.physical_state + return GLOB.physical_state /obj/machinery/atmospherics/binary/heat_pump/ui_act(action, params) - if(..()) - return TRUE - switch(action) - if("power") - on = !on - if(on) - use_power = USE_POWER_ACTIVE - else - use_power = USE_POWER_OFF - if("target_temp") - var/newValue = params["temperature"] - if(text2num(newValue) != null) - target_temp = text2num(newValue) - . = TRUE - if(.) - target_temp = max(newValue,lowest_temp) + if(..()) + return TRUE + switch(action) + if("power") + on = !on + if(on) + use_power = USE_POWER_ACTIVE + else + use_power = USE_POWER_OFF + if("target_temp") + var/newValue = params["temperature"] + if(text2num(newValue) != null) + target_temp = text2num(newValue) + . = TRUE + if(.) + target_temp = max(newValue,lowest_temp) #undef EFFICENCY_MULT diff --git a/code/modules/atmospherics/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/components/binary_devices/passive_gate.dm index 923c2af4c88..5267aa83a03 100644 --- a/code/modules/atmospherics/components/binary_devices/passive_gate.dm +++ b/code/modules/atmospherics/components/binary_devices/passive_gate.dm @@ -170,20 +170,23 @@ /obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) - to_chat(user, "Access denied.") + add_fingerprint(usr) + if(!allowed(user)) + to_chat(user, SPAN_WARNING("Access denied.")) return - usr.set_machine(src) - nano_ui_interact(user) - return + ui_interact(user) -/obj/machinery/atmospherics/binary/passive_gate/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, datum/tgui/ui) if(stat & (BROKEN|NOPOWER)) - return + return FALSE + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PressureRegulator", name) + ui.open() - // this is the data which will be sent to the ui - var/data[0] +//This is the data which will be sent to the ui +/obj/machinery/atmospherics/binary/passive_gate/ui_data(mob/user) + var/list/data = list() data = list( "on" = unlocked, @@ -196,51 +199,46 @@ "last_flow_rate" = round(last_flow_rate*10), ) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "pressure_regulator.tmpl", name, 470, 370) - ui.set_initial_data(data) // when the ui is first opened this is the data it will use - ui.open() // open the new ui window - ui.set_auto_update(1) // auto update every Master Controller tick + return data +/obj/machinery/atmospherics/binary/passive_gate/ui_act(action, params) + if(..()) + return TRUE -/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list) - if(..()) return 1 + switch(action) + if("toggle_valve") + . = TRUE + unlocked = !unlocked + if("regulate_mode") + . = TRUE + switch(params["mode"]) + if("off") regulate_mode = REGULATE_NONE + if("input") regulate_mode = REGULATE_INPUT + if("output") regulate_mode = REGULATE_OUTPUT - if(href_list["toggle_valve"]) - unlocked = !unlocked + if("set_press") + . = TRUE + switch(params["press"]) + if("min") + target_pressure = 0 + if("max") + target_pressure = max_pressure_setting + if("set") + var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure) as num + src.target_pressure = between(0, new_pressure, max_pressure_setting) - if(href_list["regulate_mode"]) - switch(href_list["regulate_mode"]) - if ("off") regulate_mode = REGULATE_NONE - if ("input") regulate_mode = REGULATE_INPUT - if ("output") regulate_mode = REGULATE_OUTPUT + if("set_flow_rate") + . = TRUE + switch(params["press"]) + if("min") + set_flow_rate = 0 + if("max") + set_flow_rate = air1.volume + if("set") + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate) as num + src.set_flow_rate = between(0, new_flow_rate, air1.volume) - switch(href_list["set_press"]) - if ("min") - target_pressure = 0 - if ("max") - target_pressure = max_pressure_setting - if ("set") - var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure) as num - src.target_pressure = between(0, new_pressure, max_pressure_setting) - - switch(href_list["set_flow_rate"]) - if ("min") - set_flow_rate = 0 - if ("max") - set_flow_rate = air1.volume - if ("set") - var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[air1.volume]kPa)","Flow Rate Control",src.set_flow_rate) as num - src.set_flow_rate = between(0, new_flow_rate, air1.volume) - - usr.set_machine(src) //Is this even needed with NanoUI? - src.update_icon() - src.add_fingerprint(usr) - return + update_icon() /obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/W as obj, var/mob/user as mob) if(istype(W, /obj/item/pen)) @@ -268,3 +266,8 @@ #undef REGULATE_NONE #undef REGULATE_INPUT #undef REGULATE_OUTPUT + + +/obj/machinery/atmospherics/binary/passive_gate/on + unlocked = TRUE + icon_state = "on" diff --git a/code/modules/atmospherics/components/binary_devices/passive_gate_vr.dm b/code/modules/atmospherics/components/binary_devices/passive_gate_vr.dm deleted file mode 100644 index f1b2603c235..00000000000 --- a/code/modules/atmospherics/components/binary_devices/passive_gate_vr.dm +++ /dev/null @@ -1,3 +0,0 @@ -/obj/machinery/atmospherics/binary/passive_gate/on - unlocked = 1 - icon_state = "on" diff --git a/code/modules/atmospherics/components/binary_devices/pump.dm b/code/modules/atmospherics/components/binary_devices/pump.dm index c0cee9bd8c9..5b7d438c8b8 100644 --- a/code/modules/atmospherics/components/binary_devices/pump.dm +++ b/code/modules/atmospherics/components/binary_devices/pump.dm @@ -172,31 +172,28 @@ Thus, the two variables affect pump operation are set in New(): return 1 -/obj/machinery/atmospherics/binary/pump/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, datum/tgui/ui) if(stat & (BROKEN|NOPOWER)) - return + return FALSE + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GasPump", name) + ui.open() - // this is the data which will be sent to the ui - var/data[0] +//This is the data which will be sent to the ui +/obj/machinery/atmospherics/binary/pump/ui_data(mob/user) + var/list/data = list() data = list( "on" = use_power, - "pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently. + "pressure_set" = round(target_pressure*100), "max_pressure" = max_pressure_setting, "last_flow_rate" = round(last_flow_rate*10), "last_power_draw" = round(last_power_draw), "max_power_draw" = power_rating, ) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "gas_pump.tmpl", name, 470, 290) - ui.set_initial_data(data) // when the ui is first opened this is the data it will use - ui.open() // open the new ui window - ui.set_auto_update(1) // auto update every Master Controller tick + return data /obj/machinery/atmospherics/binary/pump/Initialize(mapload) . = ..() @@ -205,7 +202,7 @@ Thus, the two variables affect pump operation are set in New(): /obj/machinery/atmospherics/binary/pump/receive_signal(datum/signal/signal) if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command")) - return 0 + return FALSE if(signal.data["power"]) if(text2num(signal.data["power"])) @@ -233,36 +230,39 @@ Thus, the two variables affect pump operation are set in New(): update_icon() return -/obj/machinery/atmospherics/binary/pump/attack_hand(user as mob) +/obj/machinery/atmospherics/binary/pump/attack_ghost(mob/user) + ui_interact(user) + +/obj/machinery/atmospherics/binary/pump/attack_hand(mob/user) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) - to_chat(user, "Access denied.") + add_fingerprint(usr) + if(!allowed(user)) + to_chat(user, SPAN_WARNING("Access denied.")) return - usr.set_machine(src) - nano_ui_interact(user) - return + ui_interact(user) -/obj/machinery/atmospherics/binary/pump/Topic(href,href_list) - if(..()) return 1 +/obj/machinery/atmospherics/binary/pump/ui_act(action, params) + if(..()) + return TRUE - if(href_list["power"]) - update_use_power(!use_power) + switch(action) + if("power") + update_use_power(!use_power) + . = TRUE + if("set_press") + var/press = params["press"] + switch(press) + if("min") + target_pressure = 0 + if("max") + target_pressure = max_pressure_setting + if("set") + var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure) as num + src.target_pressure = between(0, new_pressure, max_pressure_setting) + . = TRUE - switch(href_list["set_press"]) - if ("min") - target_pressure = 0 - if ("max") - target_pressure = max_pressure_setting - if ("set") - var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure) as num - src.target_pressure = between(0, new_pressure, max_pressure_setting) - - usr.set_machine(src) - src.add_fingerprint(usr) - - src.update_icon() + update_icon() /obj/machinery/atmospherics/binary/pump/power_change() var/old_stat = stat diff --git a/code/modules/atmospherics/components/valve.dm b/code/modules/atmospherics/components/binary_devices/valve.dm similarity index 100% rename from code/modules/atmospherics/components/valve.dm rename to code/modules/atmospherics/components/binary_devices/valve.dm diff --git a/code/modules/atmospherics/components/omni_devices/filter.dm b/code/modules/atmospherics/components/omni_devices/filter.dm index fdf5d0d05cb..09f49aea93b 100644 --- a/code/modules/atmospherics/components/omni_devices/filter.dm +++ b/code/modules/atmospherics/components/omni_devices/filter.dm @@ -84,25 +84,17 @@ if(P.network) P.network.update = 1 - return 1 + return TRUE -/obj/machinery/atmospherics/omni/atmos_filter/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - usr.set_machine(src) - - var/list/data = new() - - data = build_uidata() - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330) - ui.set_initial_data(data) +/obj/machinery/atmospherics/omni/atmos_filter/ui_interact(mob/user,datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "OmniFilter", name) ui.open() -/obj/machinery/atmospherics/omni/atmos_filter/proc/build_uidata() - var/list/data = new() +/obj/machinery/atmospherics/omni/atmos_filter/ui_data(mob/user) + var/list/data = list() data["power"] = use_power data["config"] = configuring @@ -155,34 +147,41 @@ else return null -/obj/machinery/atmospherics/omni/atmos_filter/Topic(href, href_list) - if(..()) return 1 - switch(href_list["command"]) +/obj/machinery/atmospherics/omni/atmos_filter/ui_act(action, params) + if(..()) + return TRUE + + switch(action) if("power") if(!configuring) update_use_power(!use_power) else update_use_power(USE_POWER_OFF) + . = TRUE if("configure") configuring = !configuring if(configuring) update_use_power(USE_POWER_OFF) - - //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on - if(configuring && !use_power) - switch(href_list["command"]) - if("set_flow_rate") - var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num - set_flow_rate = between(0, new_flow_rate, max_flow_rate) - if("switch_mode") - switch_mode(dir_flag(href_list["dir"]), mode_return_switch(href_list["mode"])) - if("switch_filter") - var/new_filter = input(usr,"Select filter mode:","Change filter",href_list["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Phoron", "Nitrous Oxide") - switch_filter(dir_flag(href_list["dir"]), mode_return_switch(new_filter)) + . = TRUE + if("set_flow_rate") + if(!configuring || use_power) + return + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num + set_flow_rate = between(0, new_flow_rate, max_flow_rate) + . = TRUE + if("switch_mode") + if(!configuring || use_power) + return + switch_mode(dir_flag(params["dir"]), mode_return_switch(params["mode"])) + . = TRUE + if("switch_filter") + if(!configuring || use_power) + return + var/new_filter = input(usr,"Select filter mode:","Change filter",params["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Phoron", "Nitrous Oxide") + switch_filter(dir_flag(params["dir"]), mode_return_switch(new_filter)) + . = TRUE update_icon() - SSnanoui.update_uis(src) - return /obj/machinery/atmospherics/omni/atmos_filter/proc/mode_return_switch(var/mode) switch(mode) diff --git a/code/modules/atmospherics/components/omni_devices/mixer.dm b/code/modules/atmospherics/components/omni_devices/mixer.dm index 9328813d881..77a18610864 100644 --- a/code/modules/atmospherics/components/omni_devices/mixer.dm +++ b/code/modules/atmospherics/components/omni_devices/mixer.dm @@ -124,22 +124,13 @@ return 1 -/obj/machinery/atmospherics/omni/mixer/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - usr.set_machine(src) - - var/list/data = new() - - data = build_uidata() - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - - if (!ui) - ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330) - ui.set_initial_data(data) - +/obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user,datum/tgui/ui = null) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "OmniMixer", name) ui.open() -/obj/machinery/atmospherics/omni/mixer/proc/build_uidata() +/obj/machinery/atmospherics/omni/mixer/ui_data(mob/user) var/list/data = new() data["power"] = use_power @@ -172,36 +163,45 @@ return data -/obj/machinery/atmospherics/omni/mixer/Topic(href, href_list) - if(..()) return 1 +/obj/machinery/atmospherics/omni/mixer/ui_act(action, params) + if(..()) + return TRUE - switch(href_list["command"]) + switch(action) if("power") + . = TRUE if(!configuring) update_use_power(!use_power) else update_use_power(USE_POWER_OFF) if("configure") + . = TRUE configuring = !configuring if(configuring) update_use_power(USE_POWER_OFF) - - //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on - if(configuring && !use_power) - switch(href_list["command"]) - if("set_flow_rate") - var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num - set_flow_rate = between(0, new_flow_rate, max_flow_rate) - if("switch_mode") - switch_mode(dir_flag(href_list["dir"]), href_list["mode"]) - if("switch_con") - change_concentration(dir_flag(href_list["dir"])) - if("switch_conlock") - con_lock(dir_flag(href_list["dir"])) + if("set_flow_rate") + . = TRUE + if(!configuring || use_power) + return + var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num + set_flow_rate = between(0, new_flow_rate, max_flow_rate) + if("switch_mode") + . = TRUE + if(!configuring || use_power) + return + switch_mode(dir_flag(params["dir"]), params["mode"]) + if("switch_con") + . = TRUE + if(!configuring || use_power) + return + change_concentration(dir_flag(params["dir"])) + if("switch_conlock") + . = TRUE + if(!configuring || use_power) + return + con_lock(dir_flag(params["dir"])) update_icon() - SSnanoui.update_uis(src) - return /obj/machinery/atmospherics/omni/mixer/proc/switch_mode(var/port = NORTH, var/mode = ATM_NONE) if(mode != ATM_INPUT && mode != ATM_OUTPUT) diff --git a/code/modules/atmospherics/components/omni_devices/omni_base.dm b/code/modules/atmospherics/components/omni_devices/omni_base.dm index 4c46789213b..9a2fd657a6e 100644 --- a/code/modules/atmospherics/components/omni_devices/omni_base.dm +++ b/code/modules/atmospherics/components/omni_devices/omni_base.dm @@ -109,7 +109,7 @@ return src.add_fingerprint(usr) - nano_ui_interact(user) + ui_interact(user) return /obj/machinery/atmospherics/omni/proc/build_icons() diff --git a/code/modules/atmospherics/components/trinary_devices/filter.dm b/code/modules/atmospherics/components/trinary_devices/filter.dm index c15fa55fd13..ff5519ab489 100644 --- a/code/modules/atmospherics/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/components/trinary_devices/filter.dm @@ -111,89 +111,73 @@ if(frequency) set_frequency(frequency) -/obj/machinery/atmospherics/trinary/atmos_filter/attack_hand(user as mob) // -- TLE +/obj/machinery/atmospherics/trinary/atmos_filter/attack_hand(user) if(..()) return - if(!src.allowed(user)) - to_chat(user, "Access denied.") + to_chat(user, SPAN_WARNING("Access denied.")) return + ui_interact(user) - var/dat - var/current_filter_type - switch(filter_type) - if(0) - current_filter_type = "Phoron" - if(1) - current_filter_type = "Oxygen" - if(2) - current_filter_type = "Nitrogen" - if(3) - current_filter_type = "Carbon Dioxide" - if(4) - current_filter_type = "Nitrous Oxide" - if(-1) - current_filter_type = "Nothing" - else - current_filter_type = "ERROR - Report this bug to the admin, please!" +/obj/machinery/atmospherics/trinary/atmos_filter/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AtmosFilter", name) + ui.open() - dat += {" - Power: [use_power?"On":"Off"]
- Filtering: [current_filter_type]

-

Set Filter Type:

- Phoron
- Oxygen
- Nitrogen
- Carbon Dioxide
- Nitrous Oxide
- Nothing
-
- Set Flow Rate Limit: - [src.set_flow_rate]L/s | Change
- Flow rate: [round(last_flow_rate, 0.1)]L/s - "} +/obj/machinery/atmospherics/trinary/atmos_filter/ui_data(mob/user) + var/list/data = list() - user << browse("[src.name] control[dat]", "window=atmos_filter") - onclose(user, "atmos_filter") - return + data["on"] = use_power + data["rate"] = set_flow_rate + data["max_rate"] = air1.volume -/obj/machinery/atmospherics/trinary/atmos_filter/Topic(href, href_list) // -- TLE + data["filter_types"] = list() + data["filter_types"] += list(list("name" = "Nothing", "f_type" = -1, "selected" = filter_type == -1)) + data["filter_types"] += list(list("name" = "Phoron", "f_type" = 0, "selected" = filter_type == 0)) + data["filter_types"] += list(list("name" = "Oxygen", "f_type" = 1, "selected" = filter_type == 1)) + data["filter_types"] += list(list("name" = "Nitrogen", "f_type" = 2, "selected" = filter_type == 2)) + data["filter_types"] += list(list("name" = "Carbon Dioxide", "f_type" = 3, "selected" = filter_type == 3)) + data["filter_types"] += list(list("name" = "Nitrous Oxide", "f_type" = 4, "selected" = filter_type == 4)) + + return data + +/obj/machinery/atmospherics/trinary/atmos_filter/ui_act(action, params) if(..()) - return 1 - usr.set_machine(src) - src.add_fingerprint(usr) - if(href_list["filterset"]) - filter_type = text2num(href_list["filterset"]) + return TRUE - filtered_out.Cut() //no need to create new lists unnecessarily - switch(filter_type) - if(0) //removing hydrocarbons - filtered_out += /datum/gas/phoron - filtered_out += /datum/gas/volatile_fuel - if(1) //removing O2 - filtered_out += /datum/gas/oxygen - if(2) //removing N2 - filtered_out += /datum/gas/nitrogen - if(3) //removing CO2 - filtered_out += /datum/gas/carbon_dioxide - if(4)//removing N2O - filtered_out += /datum/gas/nitrous_oxide + switch(action) + if("power") + update_use_power(!use_power) + if("rate") + var/rate = params["rate"] + if(rate == "max") + rate = air1.volume + . = TRUE + else if(text2num(rate) != null) + rate = text2num(rate) + . = TRUE + if(.) + set_flow_rate = clamp(rate, 0, air1.volume) + if("filter") + . = TRUE + filter_type = text2num(params["filterset"]) + filtered_out.Cut() //no need to create new lists unnecessarily + switch(filter_type) + if(0) //removing hydrocarbons + filtered_out += "phoron" + filtered_out += "oxygen_agent_b" + if(1) //removing O2 + filtered_out += "oxygen" + if(2) //removing N2 + filtered_out += "nitrogen" + if(3) //removing CO2 + filtered_out += "carbon_dioxide" + if(4)//removing N2O + filtered_out += "sleeping_agent" - if (href_list["temp"]) - src.temp = null - if(href_list["set_flow_rate"]) - var/new_flow_rate = input(usr,"Enter new flow rate (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate) as num - src.set_flow_rate = max(0, min(air1.volume, new_flow_rate)) - if(href_list["power"]) - use_power=!use_power - src.update_icon() - src.updateUsrDialog() -/* - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) -*/ - return + add_fingerprint(usr) + update_icon() // // Mirrored Orientation - Flips the output dir to opposite side from normal. diff --git a/code/modules/atmospherics/components/trinary_devices/mixer.dm b/code/modules/atmospherics/components/trinary_devices/mixer.dm index 15ff51e61b8..75c45006079 100644 --- a/code/modules/atmospherics/components/trinary_devices/mixer.dm +++ b/code/modules/atmospherics/components/trinary_devices/mixer.dm @@ -77,59 +77,58 @@ return 1 +/obj/machinery/atmospherics/trinary/mixer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "AtmosMixer", name) + ui.open() + +/obj/machinery/atmospherics/trinary/mixer/ui_data(mob/user) + var/list/data = list() + data["on"] = use_power + data["set_pressure"] = round(set_flow_rate) + data["max_pressure"] = min(air1.volume, air2.volume) + data["node1_concentration"] = round(mixing_inputs[air1]*100, 1) + data["node2_concentration"] = round(mixing_inputs[air2]*100, 1) + var/list/node_connects = get_node_connect_dirs() + data["node1_dir"] = dir_name(node_connects[1],TRUE) + data["node2_dir"] = dir_name(node_connects[2],TRUE) + return data + /obj/machinery/atmospherics/trinary/mixer/attack_hand(user as mob) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) - to_chat(user, "Access denied.") - return - usr.set_machine(src) - var/list/node_connects = get_node_connect_dirs() - var/dat = {"Power: [use_power?"On":"Off"]
- Set Flow Rate Limit: - [set_flow_rate]L/s | Change -
- Flow Rate: [round(last_flow_rate, 0.1)]L/s -

- Node 1 ([dir_name(node_connects[1],TRUE)]) Concentration: - - - - - [mixing_inputs[air1]]([mixing_inputs[air1]*100]%) - + - + -
- Node 2 ([dir_name(node_connects[2],TRUE)]) Concentration: - - - - - [mixing_inputs[air2]]([mixing_inputs[air2]*100]%) - + - + - "} + ui_interact(user) - user << browse("[src.name] control[dat]", "window=atmo_mixer") - onclose(user, "atmo_mixer") - return +/obj/machinery/atmospherics/trinary/mixer/ui_act(action, params) + if(..()) + return TRUE -/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list) - if(..()) return 1 - if(href_list["power"]) - update_use_power(!use_power) - if(href_list["set_press"]) - var/max_flow_rate = min(air1.volume, air2.volume) - var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",src.set_flow_rate) as num - src.set_flow_rate = max(0, min(max_flow_rate, new_flow_rate)) - if(href_list["node1_c"]) - var/value = text2num(href_list["node1_c"]) - src.mixing_inputs[air1] = max(0, min(1, src.mixing_inputs[air1] + value)) - src.mixing_inputs[air2] = 1.0 - mixing_inputs[air1] - if(href_list["node2_c"]) - var/value = text2num(href_list["node2_c"]) - src.mixing_inputs[air2] = max(0, min(1, src.mixing_inputs[air2] + value)) - src.mixing_inputs[air1] = 1.0 - mixing_inputs[air2] - src.update_icon() - src.updateUsrDialog() - return + switch(action) + if("power") + update_use_power(!use_power) + . = TRUE + if("pressure") + var/pressure = params["pressure"] + if(pressure == "max") + pressure = min(air1.volume, air2.volume) + . = TRUE + else if(text2num(pressure) != null) + pressure = text2num(pressure) + . = TRUE + if(.) + set_flow_rate = clamp(pressure, 0, min(air1.volume, air2.volume)) + if("node1") + var/value = text2num(params["concentration"]) + mixing_inputs[air1] = max(0, min(1, value / 100)) + mixing_inputs[air2] = 1.0 - mixing_inputs[air1] + . = TRUE + if("node2") + var/value = text2num(params["concentration"]) + mixing_inputs[air2] = max(0, min(1, value / 100)) + mixing_inputs[air1] = 1.0 - mixing_inputs[air2] + . = TRUE + update_icon() // // "T" Orientation - Inputs are on oposite sides instead of adjacent diff --git a/code/modules/atmospherics/components/tvalve.dm b/code/modules/atmospherics/components/trinary_devices/tvalve.dm similarity index 100% rename from code/modules/atmospherics/components/tvalve.dm rename to code/modules/atmospherics/components/trinary_devices/tvalve.dm diff --git a/code/modules/atmospherics/components/unary/cold_sink.dm b/code/modules/atmospherics/components/unary/cold_sink.dm index 71e012df088..5aefb5e8bd3 100644 --- a/code/modules/atmospherics/components/unary/cold_sink.dm +++ b/code/modules/atmospherics/components/unary/cold_sink.dm @@ -59,12 +59,18 @@ return /obj/machinery/atmospherics/unary/freezer/attack_ai(mob/user as mob) - nano_ui_interact(user) + ui_interact(user) /obj/machinery/atmospherics/unary/freezer/attack_hand(mob/user as mob) - nano_ui_interact(user) + ui_interact(user) -/obj/machinery/atmospherics/unary/freezer/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/atmospherics/unary/freezer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GasTemperatureSystem", name) + ui.open() + +/obj/machinery/atmospherics/unary/freezer/ui_data(mob/user) // this is the data which will be sent to the ui var/data[0] data["on"] = use_power ? 1 : 0 @@ -82,36 +88,26 @@ temp_class = "average" data["gasTemperatureClass"] = temp_class - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "freezer.tmpl", "Gas Cooling System", 440, 300) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + return data -/obj/machinery/atmospherics/unary/freezer/Topic(href, href_list) +/obj/machinery/atmospherics/unary/freezer/ui_act(action, params) if(..()) - return 1 - if(href_list["toggleStatus"]) - update_use_power(!use_power) - update_icon() - if(href_list["temp"]) - var/amount = text2num(href_list["temp"]) - if(amount > 0) - set_temperature = min(set_temperature + amount, 1000) - else - set_temperature = max(set_temperature + amount, 0) - if(href_list["setPower"]) //setting power to 0 is redundant anyways - var/new_setting = between(0, text2num(href_list["setPower"]), 100) - set_power_level(new_setting) + return TRUE - add_fingerprint(usr) + . = TRUE + switch(action) + if("toggleStatus") + update_use_power(!use_power) + update_icon() + if("setGasTemperature") + var/amount = text2num(params["temp"]) + if(amount > 0) + set_temperature = min(amount, 1000) + else + set_temperature = max(amount, 0) + if("setPower") //setting power to 0 is redundant anyways + var/new_setting = between(0, text2num(params["value"]), 100) + set_power_level(new_setting) /obj/machinery/atmospherics/unary/freezer/process(delta_time) ..() diff --git a/code/modules/atmospherics/components/unary/heat_source.dm b/code/modules/atmospherics/components/unary/heat_source.dm index 0fc38525ac0..1e7022e9b20 100644 --- a/code/modules/atmospherics/components/unary/heat_source.dm +++ b/code/modules/atmospherics/components/unary/heat_source.dm @@ -6,8 +6,8 @@ desc = "Heats gas when connected to a pipe network" icon = 'icons/obj/Cryogenic2.dmi' icon_state = "heater_0" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE use_power = USE_POWER_OFF idle_power_usage = 5 //5 Watts for thermostat related circuitry circuit = /obj/item/circuitboard/unary_atmos/heater @@ -23,12 +23,7 @@ /obj/machinery/atmospherics/unary/heater/Initialize(mapload) . = ..() - component_parts = list() - component_parts += new /obj/item/stock_parts/matter_bin(src) - component_parts += new /obj/item/stock_parts/capacitor(src) - component_parts += new /obj/item/stock_parts/capacitor(src) - component_parts += new /obj/item/stack/cable_coil(src, 5) - + default_apply_parts() RefreshParts() /obj/machinery/atmospherics/unary/heater/atmos_init() @@ -82,14 +77,20 @@ update_icon() /obj/machinery/atmospherics/unary/heater/attack_ai(mob/user as mob) - nano_ui_interact(user) + ui_interact(user) /obj/machinery/atmospherics/unary/heater/attack_hand(mob/user as mob) - nano_ui_interact(user) + ui_interact(user) + +/obj/machinery/atmospherics/unary/heater/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "GasTemperatureSystem", name) + ui.open() + +/obj/machinery/atmospherics/unary/heater/ui_data(mob/user) + var/list/data = list() -/obj/machinery/atmospherics/unary/heater/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - // this is the data which will be sent to the ui - var/data[0] data["on"] = use_power ? 1 : 0 data["gasPressure"] = round(air_contents.return_pressure()) data["gasTemperature"] = round(air_contents.temperature) @@ -98,41 +99,31 @@ data["targetGasTemperature"] = round(set_temperature) data["powerSetting"] = power_setting - var/temp_class = "normal" + var/temp_class = "average" if(air_contents.temperature > (T20C+40)) temp_class = "bad" data["gasTemperatureClass"] = temp_class - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "freezer.tmpl", "Gas Heating System", 440, 300) - // when the ui is first opened this is the data it will use - ui.set_initial_data(data) - // open the new ui window - ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + return data -/obj/machinery/atmospherics/unary/heater/Topic(href, href_list) +/obj/machinery/atmospherics/unary/heater/ui_act(action, params) if(..()) - return 1 - if(href_list["toggleStatus"]) - update_use_power(!use_power) - update_icon() - if(href_list["temp"]) - var/amount = text2num(href_list["temp"]) - if(amount > 0) - set_temperature = min(set_temperature + amount, max_temperature) - else - set_temperature = max(set_temperature + amount, 0) - if(href_list["setPower"]) //setting power to 0 is redundant anyways - var/new_setting = between(0, text2num(href_list["setPower"]), 100) - set_power_level(new_setting) + return TRUE - add_fingerprint(usr) + . = TRUE + switch(action) + if("toggleStatus") + update_use_power(!use_power) + update_icon() + if("setGasTemperature") + var/amount = text2num(params["temp"]) + if(amount > 0) + set_temperature = min(amount, max_temperature) + else + set_temperature = max(amount, 0) + if("setPower") //setting power to 0 is redundant anyways + var/new_setting = between(0, text2num(params["value"]), 100) + set_power_level(new_setting) //upgrading parts /obj/machinery/atmospherics/unary/heater/RefreshParts() diff --git a/code/modules/atmospherics/components/portables_connector.dm b/code/modules/atmospherics/components/unary/portables_connector.dm similarity index 100% rename from code/modules/atmospherics/components/portables_connector.dm rename to code/modules/atmospherics/components/unary/portables_connector.dm diff --git a/code/modules/atmospherics/components/unary/vent_pump.dm b/code/modules/atmospherics/components/unary/vent_pump.dm index c8bb891f31b..020d324f24d 100644 --- a/code/modules/atmospherics/components/unary/vent_pump.dm +++ b/code/modules/atmospherics/components/unary/vent_pump.dm @@ -370,6 +370,12 @@ ONE_ATMOSPHERE*50 ) + if("reset_external_pressure" in signal.data) + external_pressure_bound = ONE_ATMOSPHERE + + if("reset_internal_pressure" in signal.data) + internal_pressure_bound = 0 + if(signal.data["init"] != null) name = signal.data["init"] return diff --git a/code/modules/client/preference_setup/global/01_ui.dm b/code/modules/client/preference_setup/global/01_ui.dm index a346df0d92e..5173f94527b 100644 --- a/code/modules/client/preference_setup/global/01_ui.dm +++ b/code/modules/client/preference_setup/global/01_ui.dm @@ -30,15 +30,15 @@ . = "UI Style: [pref.UI_style]
" . += "Custom UI (recommended for White UI):
" . += "-Color: [pref.UI_style_color] [color_square(hex = pref.UI_style_color)] reset
" - . += "-Alpha(transparency): [pref.UI_style_alpha] reset
" + . += "-Alpha(transparency): [pref.UI_style_alpha]�reset
" . += "Tooltip Style: [pref.tooltipstyle]
" . += "Client FPS: [pref.client_fps]
" if(can_select_ooc_color(user)) - . += "OOC Color: " + . += "OOC Color:" if(pref.ooccolor == initial(pref.ooccolor)) . += "Using Default
" else - . += "[pref.ooccolor]
__
 reset
" + . += "[pref.ooccolor]
__
�reset
" /datum/category_item/player_setup_item/player_global/ui/OnTopic(var/href,var/list/href_list, var/mob/user) if(href_list["select_style"]) diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm index 613690c1c22..6588d824564 100644 --- a/code/modules/ghosttrap/trap.dm +++ b/code/modules/ghosttrap/trap.dm @@ -107,7 +107,7 @@ proc/populate_ghost_traps() ghost_trap_role = "Plant" /datum/ghosttrap/plant/welcome_candidate(var/mob/target) - to_chat(target, "You awaken slowly, stirring into sluggish motion as the air caresses you.") + to_chat(target, "You awaken slowly, stirring into sluggish motion as the air caresses you.") // This is a hack, replace with some kind of species blurb proc. if(istype(target,/mob/living/carbon/alien/diona)) to_chat(target, "You are \a [target], one of a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders.") diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm index 7c6996f0a43..2936abe4b3f 100644 --- a/code/modules/hydroponics/grown.dm +++ b/code/modules/hydroponics/grown.dm @@ -28,7 +28,7 @@ if(!plantname) return - seed = plant_controller.seeds[plantname] + seed = SSplants.seeds[plantname] if(!seed) return @@ -65,15 +65,9 @@ . = ..() if(!seed) return - if(!plant_controller) - addtimer(CALLBACK(src, /atom/proc/update_desc), 250) // ugly hack, should mean roundstart plants are fine. - if(!plant_controller) - to_chat(world, "Plant controller does not exist and [src] requires it. Aborting.") - qdel(src) - return - if(plant_controller.product_descs["[seed.uid]"]) - desc = plant_controller.product_descs["[seed.uid]"] + if(SSplants.product_descs["[seed.uid]"]) + desc = SSplants.product_descs["[seed.uid]"] else var/list/descriptors = list() if(reagents.has_reagent("sugar") || reagents.has_reagent("cherryjelly") || reagents.has_reagent("honey") || reagents.has_reagent("berryjuice")) @@ -125,17 +119,17 @@ desc += " mushroom" else desc += " fruit" - plant_controller.product_descs["[seed.uid]"] = desc + SSplants.product_descs["[seed.uid]"] = desc desc += ". Delicious! Probably." /obj/item/reagent_containers/food/snacks/grown/update_icon() - if(!seed || !plant_controller || !plant_controller.plant_icon_cache) + if(!seed || !SSplants || !SSplants.plant_icon_cache) return overlays.Cut() var/image/plant_icon var/icon_key = "fruit-[seed.get_trait(TRAIT_PRODUCT_ICON)]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]-[seed.get_trait(TRAIT_PLANT_COLOUR)]" - if(plant_controller.plant_icon_cache[icon_key]) - plant_icon = plant_controller.plant_icon_cache[icon_key] + if(SSplants.plant_icon_cache[icon_key]) + plant_icon = SSplants.plant_icon_cache[icon_key] else plant_icon = image('icons/obj/hydroponics_products.dmi',"blank") var/image/fruit_base = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-product") @@ -145,7 +139,7 @@ var/image/fruit_leaves = image('icons/obj/hydroponics_products.dmi',"[seed.get_trait(TRAIT_PRODUCT_ICON)]-leaf") fruit_leaves.color = "[seed.get_trait(TRAIT_PLANT_COLOUR)]" plant_icon.overlays |= fruit_leaves - plant_controller.plant_icon_cache[icon_key] = plant_icon + SSplants.plant_icon_cache[icon_key] = plant_icon overlays |= plant_icon /obj/item/reagent_containers/food/snacks/grown/Crossed(var/mob/living/M) diff --git a/code/modules/hydroponics/grown_inedible.dm b/code/modules/hydroponics/grown_inedible.dm index 84cf424c778..a3402bdc014 100644 --- a/code/modules/hydroponics/grown_inedible.dm +++ b/code/modules/hydroponics/grown_inedible.dm @@ -17,7 +17,7 @@ //Handle some post-spawn var stuff. if(planttype) plantname = planttype - var/datum/seed/S = plant_controller.seeds[plantname] + var/datum/seed/S = SSplants.seeds[plantname] if(!S || !S.chems) return diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 91ecfcde768..fa437d430a4 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -389,8 +389,8 @@ seed_noun = pick("spores","nodes","cuttings","seeds") set_trait(TRAIT_POTENCY,rand(5,30),200,0) - set_trait(TRAIT_PRODUCT_ICON,pick(plant_controller.plant_product_sprites)) - set_trait(TRAIT_PLANT_ICON,pick(plant_controller.plant_sprites)) + set_trait(TRAIT_PRODUCT_ICON,pick(SSplants.plant_product_sprites)) + set_trait(TRAIT_PLANT_ICON,pick(SSplants.plant_sprites)) set_trait(TRAIT_PLANT_COLOUR,"#[get_random_colour(0,75,190)]") set_trait(TRAIT_PRODUCT_COLOUR,"#[get_random_colour(0,75,190)]") update_growth_stages() @@ -687,10 +687,10 @@ if(istype(user)) to_chat(user, "You [harvest_sample ? "take a sample" : "harvest"] from the [display_name].") //This may be a new line. Update the global if it is. - if(name == "new line" || !(name in plant_controller.seeds)) - uid = plant_controller.seeds.len + 1 + if(name == "new line" || !(name in SSplants.seeds)) + uid = SSplants.seeds.len + 1 name = "[uid]" - plant_controller.seeds[name] = src + SSplants.seeds[name] = src if(harvest_sample) var/obj/item/seeds/seeds = new(get_turf(user)) @@ -776,6 +776,6 @@ /datum/seed/proc/update_growth_stages() if(get_trait(TRAIT_PLANT_ICON)) - growth_stages = plant_controller.plant_sprites[get_trait(TRAIT_PLANT_ICON)] + growth_stages = SSplants.plant_sprites[get_trait(TRAIT_PLANT_ICON)] else growth_stages = 0 diff --git a/code/modules/hydroponics/seed_controller.dm b/code/modules/hydroponics/seed_controller.dm deleted file mode 100644 index 942f24f28bf..00000000000 --- a/code/modules/hydroponics/seed_controller.dm +++ /dev/null @@ -1,162 +0,0 @@ -// Attempts to offload processing for the spreading plants from the MC. -// Processes vines/spreading plants. - -#define PLANTS_PER_TICK 500 // Cap on number of plant segments processed. -#define PLANT_TICK_TIME 75 // Number of ticks between the plant processor cycling. - -// Debug for testing seed genes. -/client/proc/show_plant_genes() - set category = "Debug" - set name = "Show Plant Genes" - set desc = "Prints the round's plant gene masks." - - if(!holder) return - - if(!plant_controller || !plant_controller.gene_tag_masks) - to_chat(usr, "Gene masks not set.") - return - - for(var/mask in plant_controller.gene_tag_masks) - to_chat(usr, "[mask]: [plant_controller.gene_tag_masks[mask]]") - -var/global/datum/controller/plants/plant_controller // Set in New(). - -/datum/controller/plants - - var/plants_per_tick = PLANTS_PER_TICK - var/plant_tick_time = PLANT_TICK_TIME - var/list/product_descs = list() // Stores generated fruit descs. - var/list/plant_queue = list() // All queued plants. - var/list/seeds = list() // All seed data stored here. - var/list/gene_tag_masks = list() // Gene obfuscation for delicious trial and error goodness. - var/list/plant_icon_cache = list() // Stores images of growth, fruits and seeds. - var/list/plant_sprites = list() // List of all harvested product sprites. - var/list/plant_product_sprites = list() // List of all growth sprites plus number of growth stages. - var/processing = 0 // Off/on. - var/list/gene_masked_list = list() // Stored gene masked list, rather than recreating it when needed. - var/list/plant_gene_datums = list() // Stored datum versions of the gene masked list. - -/datum/controller/plants/New() - if(plant_controller && plant_controller != src) - log_debug("Rebuilding plant controller.") - qdel(plant_controller) - plant_controller = src - setup() - process() - -// Predefined/roundstart varieties use a string key to make it -// easier to grab the new variety when mutating. Post-roundstart -// and mutant varieties use their uid converted to a string instead. -// Looks like shit but it's sort of necessary. -/datum/controller/plants/proc/setup() - - // Build the icon lists. - for(var/icostate in icon_states('icons/obj/hydroponics_growing.dmi')) - var/split = findtext(icostate,"-") - if(!split) - // invalid icon_state - continue - - var/ikey = copytext(icostate,(split+1)) - if(ikey == "dead") - // don't count dead icons - continue - ikey = text2num(ikey) - var/base = copytext(icostate,1,split) - - if(!(plant_sprites[base]) || (plant_sprites[base]= 100) + failed_task = 1 + genetics = null + degradation = 0 + return TRUE - loaded_disk.genesource = "[genetics.display_name]" - if(!genetics.roundstart) - loaded_disk.genesource += " (variety #[genetics.uid])" - - loaded_disk.name += " ([plant_controller.gene_tag_masks[href_list["get_gene"]]], #[genetics.uid])" - loaded_disk.desc += " The label reads \'gene [plant_controller.gene_tag_masks[href_list["get_gene"]]], sampled from [genetics.display_name]\'." - eject_disk = 1 - - degradation += rand(20,60) - if(degradation >= 100) - failed_task = 1 + if("clear_buffer") + if(!genetics) + return genetics = null degradation = 0 - - if(href_list["clear_buffer"]) - if(!genetics) return - genetics = null - degradation = 0 - - src.updateUsrDialog() - return + return TRUE // Fires an extracted trait into another packet of seeds with a chance // of destroying it based on the size/complexity of the plasmid. @@ -264,12 +263,14 @@ icon_state = "traitgun" disk_needs_genes = 1 -/obj/machinery/botany/editor/nano_ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/botany/editor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "BotanyEditor", name) + ui.open() - if(!user) - return - - var/list/data = list() +/obj/machinery/botany/editor/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() data["activity"] = active @@ -285,7 +286,7 @@ for(var/datum/plantgene/P in loaded_disk.genes) if(data["locus"] != "") data["locus"] += ", " - data["locus"] += "[plant_controller.gene_tag_masks[P.genetype]]" + data["locus"] += "[SSplants.gene_tag_masks[P.genetype]]" else data["disk"] = 0 @@ -297,36 +298,30 @@ else data["loaded"] = 0 - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) - if (!ui) - ui = new(user, src, ui_key, "botany_editor.tmpl", "Bioballistic Delivery UI", 470, 450) - ui.set_initial_data(data) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/botany/editor/Topic(href, href_list) + return data +/obj/machinery/botany/editor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return 1 + return TRUE - if(href_list["apply_gene"]) - if(!loaded_disk || !seed) return + switch(action) + if("apply_gene") + if(!loaded_disk || !seed) + return - last_action = world.time - active = 1 + last_action = world.time + active = 1 - if(!isnull(plant_controller.seeds[seed.seed.name])) - seed.seed = seed.seed.diverge(1) - seed.seed_type = seed.seed.name - seed.update_seed() + if(!isnull(SSplants.seeds[seed.seed.name])) + seed.seed = seed.seed.diverge(1) + seed.seed_type = seed.seed.name + seed.update_seed() - if(prob(seed.modified)) - failed_task = 1 - seed.modified = 101 + if(prob(seed.modified)) + failed_task = 1 + seed.modified = 101 - for(var/datum/plantgene/gene in loaded_disk.genes) - seed.seed.apply_gene(gene) - seed.modified += rand(5,10) - - usr.set_machine(src) - src.add_fingerprint(usr) + for(var/datum/plantgene/gene in loaded_disk.genes) + seed.seed.apply_gene(gene) + seed.modified += rand(5,10) + return TRUE diff --git a/code/modules/hydroponics/seed_packets.dm b/code/modules/hydroponics/seed_packets.dm index e9f676e27e3..f5966e638e6 100644 --- a/code/modules/hydroponics/seed_packets.dm +++ b/code/modules/hydroponics/seed_packets.dm @@ -19,8 +19,8 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds) //Grabs the appropriate seed datum from the global list. /obj/item/seeds/proc/update_seed() - if(!seed && seed_type && !isnull(plant_controller.seeds) && plant_controller.seeds[seed_type]) - seed = plant_controller.seeds[seed_type] + if(!seed && seed_type && !isnull(SSplants.seeds) && SSplants.seeds[seed_type]) + seed = SSplants.seeds[seed_type] update_appearance() //Updates strings and icon appropriately based on seed datum. @@ -78,7 +78,7 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds) seed_type = null /obj/item/seeds/random/Initialize(mapload) - seed = plant_controller.create_random_seed() + seed = SSplants.create_random_seed() seed_type = seed.name . = ..() diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm index d19dc22ba77..8f86ea34f41 100644 --- a/code/modules/hydroponics/seed_storage.dm +++ b/code/modules/hydroponics/seed_storage.dm @@ -212,18 +212,10 @@ if(lockdown) return user.set_machine(src) - interact(user) + ui_interact(user) -/obj/machinery/seed_storage/interact(mob/user as mob) - if (..()) - return - - if(smart) - scanner = list("stats", "produce", "soil", "temperature", "light", "pressure") - else - scanner = initial(scanner) - - if (!seeds_initialized) +/obj/machinery/seed_storage/ui_interact(mob/user, datum/tgui/ui) + if(!seeds_initialized) for(var/typepath in starting_seeds) var/amount = starting_seeds[typepath] if(isnull(amount)) amount = 1 @@ -240,212 +232,134 @@ add(O, 1) seeds_initialized = 1 - var/dat = "

Seed storage contents

" - if (piles.len == 0) - dat += "No seeds" + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "SeedStorage", name) + ui.open() + +/obj/machinery/seed_storage/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + + if(smart) + scanner = list("stats", "produce", "soil", "temperature", "light", "pressure") else - dat += "" - dat += "" - if ("stats" in scanner) - dat += "" + scanner = initial(scanner) + + data["scanner"] = scanner + + var/list/piles_to_check = piles + if(hacked || emagged) + piles_to_check = piles + piles_contra + + var/list/seeds = list() + for(var/datum/seed_pile/S in piles_to_check) + var/datum/seed/seed = S.seed_type + if(!seed) + continue + var/list/seedinfo = list( + "name" = seed.seed_name, + "uid" = seed.uid, + "amount" = S.amount, + "id" = S.ID, + ) + + seedinfo["traits"] = list() + if("stats" in scanner) + seedinfo["traits"]["Endurance"] = seed.get_trait(TRAIT_ENDURANCE) + seedinfo["traits"]["Yield"] = seed.get_trait(TRAIT_YIELD) + seedinfo["traits"]["Production"] = seed.get_trait(TRAIT_PRODUCTION) + seedinfo["traits"]["Potency"] = seed.get_trait(TRAIT_POTENCY) + seedinfo["traits"]["Repeat Harvest"] = seed.get_trait(TRAIT_HARVEST_REPEAT) + if("temperature" in scanner) + seedinfo["traits"]["Ideal Heat"] = seed.get_trait(TRAIT_IDEAL_HEAT) + if("light" in scanner) + seedinfo["traits"]["Ideal Light"] = seed.get_trait(TRAIT_IDEAL_LIGHT) + if("soil" in scanner) + if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS)) + if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) < 0.05) + seedinfo["traits"]["Nutrient Consumption"] = "Low" + else if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0.2) + seedinfo["traits"]["Nutrient Consumption"] = "High" + else + seedinfo["traits"]["Nutrient Consumption"] = "Norm" + else + seedinfo["traits"]["Nutrient Consumption"] = "No" + if(seed.get_trait(TRAIT_REQUIRES_WATER)) + if(seed.get_trait(TRAIT_WATER_CONSUMPTION) < 1) + seedinfo["traits"]["Water Consumption"] = "Low" + else if(seed.get_trait(TRAIT_WATER_CONSUMPTION) > 5) + seedinfo["traits"]["Water Consumption"] = "High" + else + seedinfo["traits"]["Water Consumption"] = "Norm" + else + seedinfo["traits"]["Water Consumption"] = "No" + + seedinfo["traits"]["notes"] = "" + switch(seed.get_trait(TRAIT_CARNIVOROUS)) + if(1) + seedinfo["traits"]["notes"] += "CARN " + if(2) + seedinfo["traits"]["notes"] += "FASTCARN" + switch(seed.get_trait(TRAIT_SPREAD)) + if(1) + seedinfo["traits"]["notes"] += "VINE " + if(2) + seedinfo["traits"]["notes"] += "FASTVINE" + if ("pressure" in scanner) + if(seed.get_trait(TRAIT_LOWKPA_TOLERANCE) < 20) + seedinfo["traits"]["notes"] += "LP " + if(seed.get_trait(TRAIT_HIGHKPA_TOLERANCE) > 220) + seedinfo["traits"]["notes"] += "HP " if ("temperature" in scanner) - dat += "" + if(seed.get_trait(TRAIT_HEAT_TOLERANCE) > 30) + seedinfo["traits"]["notes"] += "TEMRES " + else if(seed.get_trait(TRAIT_HEAT_TOLERANCE) < 10) + seedinfo["traits"]["notes"] += "TEMSEN " if ("light" in scanner) - dat += "" - if ("soil" in scanner) - dat += "" - dat += "" - for (var/datum/seed_pile/S in piles) - var/datum/seed/seed = S.seed_type - if(!seed) - continue - dat += "" - dat += "" - dat += "" - if ("stats" in scanner) - dat += "" - if(seed.get_trait(TRAIT_HARVEST_REPEAT)) - dat += "" - else - dat += "" - if ("temperature" in scanner) - dat += "" - if ("light" in scanner) - dat += "" - if ("soil" in scanner) - if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS)) - if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) < 0.05) - dat += "" - else if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0.2) - dat += "" - else - dat += "" - else - dat += "" - if(seed.get_trait(TRAIT_REQUIRES_WATER)) - if(seed.get_trait(TRAIT_WATER_CONSUMPTION) < 1) - dat += "" - else if(seed.get_trait(TRAIT_WATER_CONSUMPTION) > 5) - dat += "" - else - dat += "" - else - dat += "" + if(seed.get_trait(TRAIT_LIGHT_TOLERANCE) > 10) + seedinfo["traits"]["notes"] += "LIGRES " + else if(seed.get_trait(TRAIT_LIGHT_TOLERANCE) < 3) + seedinfo["traits"]["notes"] += "LIGSEN " + if(seed.get_trait(TRAIT_TOXINS_TOLERANCE) < 3) + seedinfo["traits"]["notes"] += "TOXSEN " + else if(seed.get_trait(TRAIT_TOXINS_TOLERANCE) > 6) + seedinfo["traits"]["notes"] += "TOXRES " + if(seed.get_trait(TRAIT_PEST_TOLERANCE) < 3) + seedinfo["traits"]["notes"] += "PESTSEN " + else if(seed.get_trait(TRAIT_PEST_TOLERANCE) > 6) + seedinfo["traits"]["notes"] += "PESTRES " + if(seed.get_trait(TRAIT_WEED_TOLERANCE) < 3) + seedinfo["traits"]["notes"] += "WEEDSEN " + else if(seed.get_trait(TRAIT_WEED_TOLERANCE) > 6) + seedinfo["traits"]["notes"] += "WEEDRES " + if(seed.get_trait(TRAIT_PARASITE)) + seedinfo["traits"]["notes"] += "PAR " + if ("temperature" in scanner) + if(seed.get_trait(TRAIT_ALTER_TEMP) > 0) + seedinfo["traits"]["notes"] += "TEMP+ " + if(seed.get_trait(TRAIT_ALTER_TEMP) < 0) + seedinfo["traits"]["notes"] += "TEMP- " + if(seed.get_trait(TRAIT_BIOLUM)) + seedinfo["traits"]["notes"] += "LUM " - dat += "" - dat += "" - dat += "" - dat += "" - if(hacked || emagged) - for (var/datum/seed_pile/S in piles_contra) - var/datum/seed/seed = S.seed_type - if(!seed) - continue - dat += "" - dat += "" - dat += "" - if ("stats" in scanner) - dat += "" - if(seed.get_trait(TRAIT_HARVEST_REPEAT)) - dat += "" - else - dat += "" - if ("temperature" in scanner) - dat += "" - if ("light" in scanner) - dat += "" - if ("soil" in scanner) - if(seed.get_trait(TRAIT_REQUIRES_NUTRIENTS)) - if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) < 0.05) - dat += "" - else if(seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0.2) - dat += "" - else - dat += "" - else - dat += "" - if(seed.get_trait(TRAIT_REQUIRES_WATER)) - if(seed.get_trait(TRAIT_WATER_CONSUMPTION) < 1) - dat += "" - else if(seed.get_trait(TRAIT_WATER_CONSUMPTION) > 5) - dat += "" - else - dat += "" - else - dat += "" + seeds.Add(list(seedinfo)) - dat += "" - dat += "" - dat += "" - dat += "" - dat += "
NameVarietyEYMPrPtHarvestTempLightNutriWaterNotesAmount
[seed.seed_name]#[seed.uid][seed.get_trait(TRAIT_ENDURANCE)][seed.get_trait(TRAIT_YIELD)][seed.get_trait(TRAIT_MATURATION)][seed.get_trait(TRAIT_PRODUCTION)][seed.get_trait(TRAIT_POTENCY)]MultipleSingle[seed.get_trait(TRAIT_IDEAL_HEAT)] K[seed.get_trait(TRAIT_IDEAL_LIGHT)] LLowHighNormNoLowHighNormNo" - switch(seed.get_trait(TRAIT_CARNIVOROUS)) - if(1) - dat += "CARN " - if(2) - dat += "CARN " - switch(seed.get_trait(TRAIT_SPREAD)) - if(1) - dat += "VINE " - if(2) - dat += "VINE " - if ("pressure" in scanner) - if(seed.get_trait(TRAIT_LOWKPA_TOLERANCE) < 20) - dat += "LP " - if(seed.get_trait(TRAIT_HIGHKPA_TOLERANCE) > 220) - dat += "HP " - if ("temperature" in scanner) - if(seed.get_trait(TRAIT_HEAT_TOLERANCE) > 30) - dat += "TEMRES " - else if(seed.get_trait(TRAIT_HEAT_TOLERANCE) < 10) - dat += "TEMSEN " - if ("light" in scanner) - if(seed.get_trait(TRAIT_LIGHT_TOLERANCE) > 10) - dat += "LIGRES " - else if(seed.get_trait(TRAIT_LIGHT_TOLERANCE) < 3) - dat += "LIGSEN " - if(seed.get_trait(TRAIT_TOXINS_TOLERANCE) < 3) - dat += "TOXSEN " - else if(seed.get_trait(TRAIT_TOXINS_TOLERANCE) > 6) - dat += "TOXRES " - if(seed.get_trait(TRAIT_PEST_TOLERANCE) < 3) - dat += "PESTSEN " - else if(seed.get_trait(TRAIT_PEST_TOLERANCE) > 6) - dat += "PESTRES " - if(seed.get_trait(TRAIT_WEED_TOLERANCE) < 3) - dat += "WEEDSEN " - else if(seed.get_trait(TRAIT_WEED_TOLERANCE) > 6) - dat += "WEEDRES " - if(seed.get_trait(TRAIT_PARASITE)) - dat += "PAR " - if ("temperature" in scanner) - if(seed.get_trait(TRAIT_ALTER_TEMP) > 0) - dat += "TEMP+ " - if(seed.get_trait(TRAIT_ALTER_TEMP) < 0) - dat += "TEMP- " - if(seed.get_trait(TRAIT_BIOLUM)) - dat += "LUM " - dat += "[S.amount]Vend Purge
[seed.seed_name]#[seed.uid][seed.get_trait(TRAIT_ENDURANCE)][seed.get_trait(TRAIT_YIELD)][seed.get_trait(TRAIT_MATURATION)][seed.get_trait(TRAIT_PRODUCTION)][seed.get_trait(TRAIT_POTENCY)]MultipleSingle[seed.get_trait(TRAIT_IDEAL_HEAT)] K[seed.get_trait(TRAIT_IDEAL_LIGHT)] LLowHighNormNoLowHighNormNo" - switch(seed.get_trait(TRAIT_CARNIVOROUS)) - if(1) - dat += "CARN " - if(2) - dat += "CARN " - switch(seed.get_trait(TRAIT_SPREAD)) - if(1) - dat += "VINE " - if(2) - dat += "VINE " - if ("pressure" in scanner) - if(seed.get_trait(TRAIT_LOWKPA_TOLERANCE) < 20) - dat += "LP " - if(seed.get_trait(TRAIT_HIGHKPA_TOLERANCE) > 220) - dat += "HP " - if ("temperature" in scanner) - if(seed.get_trait(TRAIT_HEAT_TOLERANCE) > 30) - dat += "TEMRES " - else if(seed.get_trait(TRAIT_HEAT_TOLERANCE) < 10) - dat += "TEMSEN " - if ("light" in scanner) - if(seed.get_trait(TRAIT_LIGHT_TOLERANCE) > 10) - dat += "LIGRES " - else if(seed.get_trait(TRAIT_LIGHT_TOLERANCE) < 3) - dat += "LIGSEN " - if(seed.get_trait(TRAIT_TOXINS_TOLERANCE) < 3) - dat += "TOXSEN " - else if(seed.get_trait(TRAIT_TOXINS_TOLERANCE) > 6) - dat += "TOXRES " - if(seed.get_trait(TRAIT_PEST_TOLERANCE) < 3) - dat += "PESTSEN " - else if(seed.get_trait(TRAIT_PEST_TOLERANCE) > 6) - dat += "PESTRES " - if(seed.get_trait(TRAIT_WEED_TOLERANCE) < 3) - dat += "WEEDSEN " - else if(seed.get_trait(TRAIT_WEED_TOLERANCE) > 6) - dat += "WEEDRES " - if(seed.get_trait(TRAIT_PARASITE)) - dat += "PAR " - if ("temperature" in scanner) - if(seed.get_trait(TRAIT_ALTER_TEMP) > 0) - dat += "TEMP+ " - if(seed.get_trait(TRAIT_ALTER_TEMP) < 0) - dat += "TEMP- " - if(seed.get_trait(TRAIT_BIOLUM)) - dat += "LUM " - dat += "[S.amount]Vend Purge
" + data["seeds"] = seeds - user << browse(dat, "window=seedstorage") - onclose(user, "seedstorage") + return data -/obj/machinery/seed_storage/Topic(var/href, var/list/href_list) - if (..()) - return - var/task = href_list["task"] - var/ID = text2num(href_list["id"]) +/obj/machinery/seed_storage/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE + var/ID = text2num(params["id"]) - for (var/datum/seed_pile/N in piles) - if (N.ID == ID) - if (task == "vend") + var/list/piles_to_check = piles + if(hacked || emagged) + piles_to_check = piles + piles_contra + + for(var/datum/seed_pile/N in piles_to_check) + if(N.ID == ID) + if(action == "vend") var/obj/O = pick(N.seeds) if (O) --N.amount @@ -457,34 +371,14 @@ else piles -= N qdel(N) - else if (task == "purge") - for (var/obj/O in N.seeds) + return TRUE + else if(action == "purge") + for(var/obj/O in N.seeds) qdel(O) piles -= N qdel(N) + return TRUE break - if(hacked || emagged) - for (var/datum/seed_pile/N in piles_contra) - if (N.ID == ID) - if (task == "vend") - var/obj/O = pick(N.seeds) - if (O) - --N.amount - N.seeds -= O - if (N.amount <= 0 || N.seeds.len <= 0) - piles_contra -= N - qdel(N) - O.loc = src.loc - else - piles_contra -= N - qdel(N) - else if (task == "purge") - for (var/obj/O in N.seeds) - qdel(O) - piles_contra -= N - qdel(N) - break - updateUsrDialog() /obj/machinery/seed_storage/attackby(var/obj/item/O as obj, var/mob/user as mob) if (istype(O, /obj/item/seeds) && !lockdown) diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm index 9c20d74186d..f2d84413851 100644 --- a/code/modules/hydroponics/spreading/spreading.dm +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -11,7 +11,7 @@ if(turfs.len) //Pick a turf to spawn at if we can var/turf/simulated/floor/T = pick(turfs) - var/datum/seed/seed = plant_controller.create_random_seed(1) + var/datum/seed/seed = SSplants.create_random_seed(1) seed.set_trait(TRAIT_SPREAD,2) // So it will function properly as vines. seed.set_trait(TRAIT_POTENCY,rand(potency_min, potency_max)) seed.set_trait(TRAIT_MATURATION,rand(maturation_min, maturation_max)) @@ -72,10 +72,10 @@ var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/plant /obj/effect/plant/Destroy() - if(plant_controller) - plant_controller.remove_plant(src) + if(SSplants) + SSplants.remove_plant(src) for(var/obj/effect/plant/neighbor in range(1,src)) - plant_controller.add_plant(neighbor) + SSplants.add_plant(neighbor) return ..() /obj/effect/plant/single @@ -88,15 +88,15 @@ else parent = newparent - if(!plant_controller) + if(!SSplants) sleep(250) // ugly hack, should mean roundstart plants are fine. TODO initialize perhaps? - if(!plant_controller) + if(!SSplants) to_chat(world, "Plant controller does not exist and [src] requires it. Aborting.") qdel(src) return if(!istype(newseed)) - newseed = plant_controller.seeds[DEFAULT_SEED] + newseed = SSplants.seeds[DEFAULT_SEED] seed = newseed if(!seed) qdel(src) @@ -124,7 +124,7 @@ /obj/effect/plant/proc/finish_spreading() setDir(calc_dir()) update_icon() - plant_controller.add_plant(src) + SSplants.add_plant(src) //Some plants eat through plating. if(islist(seed.chems) && !isnull(seed.chems["pacid"])) var/turf/T = get_turf(src) @@ -228,7 +228,7 @@ /obj/effect/plant/attackby(var/obj/item/W, var/mob/user) user.setClickCooldown(user.get_attack_speed(W)) - plant_controller.add_plant(src) + SSplants.add_plant(src) if(W.is_wirecutter() || istype(W, /obj/item/surgical/scalpel)) if(sampled) diff --git a/code/modules/hydroponics/spreading/spreading_growth.dm b/code/modules/hydroponics/spreading/spreading_growth.dm index 67549d7a9f0..20d6b4ab3a7 100644 --- a/code/modules/hydroponics/spreading/spreading_growth.dm +++ b/code/modules/hydroponics/spreading/spreading_growth.dm @@ -33,7 +33,7 @@ neighbors |= floor if(neighbors.len) - plant_controller.add_plant(src) //if we have neighbours again, start processing + SSplants.add_plant(src) //if we have neighbours again, start processing // Update all of our friends. var/turf/T = get_turf(src) @@ -118,7 +118,7 @@ // We shouldn't have spawned if the controller doesn't exist. check_health() if(has_buckled_mobs() || neighbors.len) - plant_controller.add_plant(src) + SSplants.add_plant(src) //spreading vines aren't created on their final turf. //Instead, they are created at their parent and then move to their destination. @@ -168,7 +168,7 @@ continue for(var/obj/effect/plant/neighbor in check_turf.contents) neighbor.neighbors |= check_turf - plant_controller.add_plant(neighbor) + SSplants.add_plant(neighbor) spawn(1) if(src) qdel(src) #undef NEIGHBOR_REFRESH_TIME diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 2b75a97a322..0702f1fe8f1 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -344,7 +344,7 @@ //Remove the seed if something is already planted. if(seed) seed = null - seed = plant_controller.seeds[pick(list("reishi","nettle","amanita","mushrooms","plumphelmet","towercap","harebells","weeds"))] + seed = SSplants.seeds[pick(list("reishi","nettle","amanita","mushrooms","plumphelmet","towercap","harebells","weeds"))] if(!seed) return //Weed does not exist, someone fucked up. dead = 0 @@ -374,7 +374,7 @@ // We need to make sure we're not modifying one of the global seed datums. // If it's not in the global list, then no products of the line have been // harvested yet and it's safe to assume it's restricted to this tray. - if(!isnull(plant_controller.seeds[seed.name])) + if(!isnull(SSplants.seeds[seed.name])) seed = seed.diverge() seed.mutate(severity,get_turf(src)) @@ -430,8 +430,8 @@ var/previous_plant = seed.display_name var/newseed = seed.get_mutant_variant() - if(newseed in plant_controller.seeds) - seed = plant_controller.seeds[newseed] + if(newseed in SSplants.seeds) + seed = SSplants.seeds[newseed] else return diff --git a/code/modules/hydroponics/trays/tray_tools.dm b/code/modules/hydroponics/trays/tray_tools.dm index 0a901843ab0..33b769cc3dc 100644 --- a/code/modules/hydroponics/trays/tray_tools.dm +++ b/code/modules/hydroponics/trays/tray_tools.dm @@ -5,53 +5,61 @@ desc = "A tool used to take samples from plants." /obj/item/tool/wirecutters/clippers/trimmers - name = "hedgetrimmers" - desc = "An old pair of trimmers with a pretty dull blade. You would probably have a hard time cutting anything but plants with it." - icon_state = "hedget" - item_state = "hedget" - force = 7 //One point extra than standard wire cutters. + name = "hedgetrimmers" + desc = "An old pair of trimmers with a pretty dull blade. You would probably have a hard time cutting anything but plants with it." + icon_state = "hedget" + item_state = "hedget" + force = 7 //One point extra than standard wire cutters. /obj/item/analyzer/plant_analyzer name = "plant analyzer" icon = 'icons/obj/device.dmi' icon_state = "hydro" item_state = "analyzer" - var/form_title - var/last_data + var/datum/seed/last_seed + var/list/last_reagents -/obj/item/analyzer/plant_analyzer/proc/print_report_verb() - set name = "Print Plant Report" - set category = "Object" - set src = usr +/obj/item/analyzer/plant_analyzer/attack_self(mob/user) + ui_interact(user) - if(usr.stat || usr.restrained() || usr.lying) - return - print_report(usr) +/obj/item/analyzer/plant_analyzer/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PlantAnalyzer", name) + ui.open() -/obj/item/analyzer/plant_analyzer/Topic(href, href_list) +/obj/item/analyzer/plant_analyzer/ui_state(mob/user) + return GLOB.inventory_state + +/obj/item/analyzer/plant_analyzer/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + + var/datum/seed/grown_seed = locate(last_seed) + if(!istype(grown_seed)) + return list("no_seed" = TRUE) + + data["no_seed"] = FALSE + data["seed"] = grown_seed.get_tgui_analyzer_data(user) + data["reagents"] = last_reagents + + return data + +/obj/item/analyzer/plant_analyzer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return - if(href_list["print"]) - print_report(usr) + return TRUE -/obj/item/analyzer/plant_analyzer/proc/print_report(var/mob/living/user) - if(!last_data) - to_chat(user, "There is no scan data to print.") - return - var/obj/item/paper/P = new /obj/item/paper(get_turf(src)) - P.name = "paper - [form_title]" - P.info = "[last_data]" - if(istype(user,/mob/living/carbon/human)) - user.put_in_hands(P) - user.visible_message("\The [src] spits out a piece of paper.") - return - -/obj/item/analyzer/plant_analyzer/attack_self(mob/user as mob) - print_report(user) - return 0 + switch(action) + if("print") + print_report(usr) + return TRUE + if("close") + last_seed = null + last_reagents = null + return TRUE /obj/item/analyzer/plant_analyzer/afterattack(obj/target, mob/user, flag) - if(!flag) return + if(!flag) + return var/datum/seed/grown_seed var/datum/reagents/grown_reagents @@ -60,13 +68,13 @@ else if(istype(target,/obj/item/reagent_containers/food/snacks/grown)) var/obj/item/reagent_containers/food/snacks/grown/G = target - grown_seed = plant_controller.seeds[G.plantname] + grown_seed = SSplants.seeds[G.plantname] grown_reagents = G.reagents else if(istype(target,/obj/item/grown)) var/obj/item/grown/G = target - grown_seed = plant_controller.seeds[G.plantname] + grown_seed = SSplants.seeds[G.plantname] grown_reagents = G.reagents else if(istype(target,/obj/item/seeds)) @@ -87,12 +95,38 @@ to_chat(user, "[src] can tell you nothing about \the [target].") return - form_title = "[grown_seed.seed_name] (#[grown_seed.uid])" - var/dat = "

Plant data for [form_title]

" + last_seed = REF(grown_seed) + user.visible_message("[user] runs the scanner over \the [target].") - dat += "

General Data

" + last_reagents = list() + if(grown_reagents && grown_reagents.reagent_list && grown_reagents.reagent_list.len) + for(var/datum/reagent/R in grown_reagents.reagent_list) + last_reagents.Add(list(list( + "name" = R.name, + "volume" = grown_reagents.get_reagent_amount(R.id), + ))) + ui_interact(user) + +/obj/item/analyzer/plant_analyzer/proc/print_report_verb() + set name = "Print Plant Report" + set category = "Object" + set src = usr + + if(usr.stat || usr.restrained() || usr.lying) + return + print_report(usr) + +/obj/item/analyzer/plant_analyzer/proc/print_report(var/mob/living/user) + var/datum/seed/grown_seed = locate(last_seed) + if(!istype(grown_seed)) + to_chat(user, SPAN_WARNING("There is no scan data to print.")) + return + + var/form_title = "[grown_seed.seed_name] (#[grown_seed.uid])" + var/dat = "

Plant data for [form_title]

" + dat += "

General Data

" dat += "" dat += "" dat += "" @@ -101,138 +135,156 @@ dat += "" dat += "
Endurance[grown_seed.get_trait(TRAIT_ENDURANCE)]
Yield[grown_seed.get_trait(TRAIT_YIELD)]
Potency[grown_seed.get_trait(TRAIT_POTENCY)]
" - if(grown_reagents && grown_reagents.reagent_list && grown_reagents.reagent_list.len) + if(LAZYLEN(last_reagents)) dat += "

Reagent Data

" - dat += "
This sample contains: " - for(var/datum/reagent/R in grown_reagents.reagent_list) - dat += "
- [R.name], [grown_reagents.get_reagent_amount(R.id)] unit(s)" + for(var/i in 1 to LAZYLEN(last_reagents)) + dat += "
- [last_reagents[i]["name"]], [last_reagents[i]["volume"]] unit(s)" dat += "

Other Data

" - if(grown_seed.get_trait(TRAIT_HARVEST_REPEAT)) - dat += "This plant can be harvested repeatedly.
" + var/list/tgui_data = grown_seed.get_tgui_analyzer_data() - if(grown_seed.get_trait(TRAIT_IMMUTABLE) == -1) - dat += "This plant is highly mutable.
" - else if(grown_seed.get_trait(TRAIT_IMMUTABLE) > 0) - dat += "This plant does not possess genetics that are alterable.
" + dat += jointext(tgui_data["trait_info"], "
\n") - if(grown_seed.get_trait(TRAIT_REQUIRES_NUTRIENTS)) - if(grown_seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) < 0.05) - dat += "It consumes a small amount of nutrient fluid.
" - else if(grown_seed.get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0.2) - dat += "It requires a heavy supply of nutrient fluid.
" + var/obj/item/paper/P = new /obj/item/paper(get_turf(src)) + P.name = "paper - [form_title]" + P.info = "[dat]" + if(istype(user,/mob/living/carbon/human)) + user.put_in_hands(P) + user.visible_message("\The [src] spits out a piece of paper.") + return + +/datum/seed/proc/get_tgui_analyzer_data(mob/user) + var/list/data = list() + + data["name"] = seed_name + data["uid"] = uid + data["endurance"] = get_trait(TRAIT_ENDURANCE) + data["yield"] = get_trait(TRAIT_YIELD) + data["maturation_time"] = get_trait(TRAIT_MATURATION) + data["production_time"] = get_trait(TRAIT_PRODUCTION) + data["potency"] = get_trait(TRAIT_POTENCY) + + data["trait_info"] = list() + if(get_trait(TRAIT_HARVEST_REPEAT)) + data["trait_info"] += "This plant can be harvested repeatedly." + + if(get_trait(TRAIT_IMMUTABLE) == -1) + data["trait_info"] += "This plant is highly mutable." + else if(get_trait(TRAIT_IMMUTABLE) > 0) + data["trait_info"] += "This plant does not possess genetics that are alterable." + + if(get_trait(TRAIT_REQUIRES_NUTRIENTS)) + if(get_trait(TRAIT_NUTRIENT_CONSUMPTION) < 0.05) + data["trait_info"] += "It consumes a small amount of nutrient fluid." + else if(get_trait(TRAIT_NUTRIENT_CONSUMPTION) > 0.2) + data["trait_info"] += "It requires a heavy supply of nutrient fluid." else - dat += "It requires a supply of nutrient fluid.
" + data["trait_info"] += "It requires a supply of nutrient fluid." - if(grown_seed.get_trait(TRAIT_REQUIRES_WATER)) - if(grown_seed.get_trait(TRAIT_WATER_CONSUMPTION) < 1) - dat += "It requires very little water.
" - else if(grown_seed.get_trait(TRAIT_WATER_CONSUMPTION) > 5) - dat += "It requires a large amount of water.
" + if(get_trait(TRAIT_REQUIRES_WATER)) + if(get_trait(TRAIT_WATER_CONSUMPTION) < 1) + data["trait_info"] += "It requires very little water." + else if(get_trait(TRAIT_WATER_CONSUMPTION) > 5) + data["trait_info"] += "It requires a large amount of water." else - dat += "It requires a stable supply of water.
" + data["trait_info"] += "It requires a stable supply of water." - if(grown_seed.mutants && grown_seed.mutants.len) - dat += "It exhibits a high degree of potential subspecies shift.
" + if(mutants && mutants.len) + data["trait_info"] += "It exhibits a high degree of potential subspecies shift." - dat += "It thrives in a temperature of [grown_seed.get_trait(TRAIT_IDEAL_HEAT)] Kelvin." + data["trait_info"] += "It thrives in a temperature of [get_trait(TRAIT_IDEAL_HEAT)] Kelvin." - if(grown_seed.get_trait(TRAIT_LOWKPA_TOLERANCE) < 20) - dat += "
It is well adapted to low pressure levels." - if(grown_seed.get_trait(TRAIT_HIGHKPA_TOLERANCE) > 220) - dat += "
It is well adapted to high pressure levels." + if(get_trait(TRAIT_LOWKPA_TOLERANCE) < 20) + data["trait_info"] += "It is well adapted to low pressure levels." + if(get_trait(TRAIT_HIGHKPA_TOLERANCE) > 220) + data["trait_info"] += "It is well adapted to high pressure levels." - if(grown_seed.get_trait(TRAIT_HEAT_TOLERANCE) > 30) - dat += "
It is well adapted to a range of temperatures." - else if(grown_seed.get_trait(TRAIT_HEAT_TOLERANCE) < 10) - dat += "
It is very sensitive to temperature shifts." + if(get_trait(TRAIT_HEAT_TOLERANCE) > 30) + data["trait_info"] += "It is well adapted to a range of temperatures." + else if(get_trait(TRAIT_HEAT_TOLERANCE) < 10) + data["trait_info"] += "It is very sensitive to temperature shifts." - dat += "
It thrives in a light level of [grown_seed.get_trait(TRAIT_IDEAL_LIGHT)] lumen[grown_seed.get_trait(TRAIT_IDEAL_LIGHT) == 1 ? "" : "s"]." + data["trait_info"] += "It thrives in a light level of [get_trait(TRAIT_IDEAL_LIGHT)] lumen[get_trait(TRAIT_IDEAL_LIGHT) == 1 ? "" : "s"]." - if(grown_seed.get_trait(TRAIT_LIGHT_TOLERANCE) > 10) - dat += "
It is well adapted to a range of light levels." - else if(grown_seed.get_trait(TRAIT_LIGHT_TOLERANCE) < 3) - dat += "
It is very sensitive to light level shifts." + if(get_trait(TRAIT_LIGHT_TOLERANCE) > 10) + data["trait_info"] += "It is well adapted to a range of light levels." + else if(get_trait(TRAIT_LIGHT_TOLERANCE) < 3) + data["trait_info"] += "It is very sensitive to light level shifts." - if(grown_seed.get_trait(TRAIT_TOXINS_TOLERANCE) < 3) - dat += "
It is highly sensitive to toxins." - else if(grown_seed.get_trait(TRAIT_TOXINS_TOLERANCE) > 6) - dat += "
It is remarkably resistant to toxins." + if(get_trait(TRAIT_TOXINS_TOLERANCE) < 3) + data["trait_info"] += "It is highly sensitive to toxins." + else if(get_trait(TRAIT_TOXINS_TOLERANCE) > 6) + data["trait_info"] += "It is remarkably resistant to toxins." - if(grown_seed.get_trait(TRAIT_PEST_TOLERANCE) < 3) - dat += "
It is highly sensitive to pests." - else if(grown_seed.get_trait(TRAIT_PEST_TOLERANCE) > 6) - dat += "
It is remarkably resistant to pests." + if(get_trait(TRAIT_PEST_TOLERANCE) < 3) + data["trait_info"] += "It is highly sensitive to pests." + else if(get_trait(TRAIT_PEST_TOLERANCE) > 6) + data["trait_info"] += "It is remarkably resistant to pests." - if(grown_seed.get_trait(TRAIT_WEED_TOLERANCE) < 3) - dat += "
It is highly sensitive to weeds." - else if(grown_seed.get_trait(TRAIT_WEED_TOLERANCE) > 6) - dat += "
It is remarkably resistant to weeds." + if(get_trait(TRAIT_WEED_TOLERANCE) < 3) + data["trait_info"] += "It is highly sensitive to weeds." + else if(get_trait(TRAIT_WEED_TOLERANCE) > 6) + data["trait_info"] += "It is remarkably resistant to weeds." - switch(grown_seed.get_trait(TRAIT_SPREAD)) + switch(get_trait(TRAIT_SPREAD)) if(1) - dat += "
It is able to be planted outside of a tray." + data["trait_info"] += "It is able to be planted outside of a tray." if(2) - dat += "
It is a robust and vigorous vine that will spread rapidly." + data["trait_info"] += "It is a robust and vigorous vine that will spread rapidly." - switch(grown_seed.get_trait(TRAIT_CARNIVOROUS)) + switch(get_trait(TRAIT_CARNIVOROUS)) if(1) - dat += "
It is carnivorous and will eat tray pests for sustenance." + data["trait_info"] += "It is carnivorous and will eat tray pests for sustenance." if(2) - dat += "
It is carnivorous and poses a significant threat to living things around it." + data["trait_info"] += "It is carnivorous and poses a significant threat to living things around it." - if(grown_seed.get_trait(TRAIT_PARASITE)) - dat += "
It is capable of parisitizing and gaining sustenance from tray weeds." + if(get_trait(TRAIT_PARASITE)) + data["trait_info"] += "It is capable of parisitizing and gaining sustenance from tray weeds." /* There's currently no code that actually changes the temperature of the local environment, so let's not show it until there is. - if(grown_seed.get_trait(TRAIT_ALTER_TEMP)) - dat += "
It will periodically alter the local temperature by [grown_seed.get_trait(TRAIT_ALTER_TEMP)] degrees Kelvin." + if(get_trait(TRAIT_ALTER_TEMP)) + data["trait_info"] += "It will periodically alter the local temperature by [get_trait(TRAIT_ALTER_TEMP)] degrees Kelvin." */ - if(grown_seed.get_trait(TRAIT_BIOLUM)) - dat += "
It is [grown_seed.get_trait(TRAIT_BIOLUM_COLOUR) ? "bio-luminescent" : "bio-luminescent"]." + if(get_trait(TRAIT_BIOLUM)) + data["trait_info"] += "It is [get_trait(TRAIT_BIOLUM_COLOUR) ? "bio-luminescent" : "bio-luminescent"]." - if(grown_seed.get_trait(TRAIT_PRODUCES_POWER)) - dat += "
The fruit will function as a battery if prepared appropriately." + if(get_trait(TRAIT_PRODUCES_POWER)) + data["trait_info"] += "The fruit will function as a battery if prepared appropriately." - if(grown_seed.get_trait(TRAIT_STINGS)) - dat += "
The fruit is covered in stinging spines." + if(get_trait(TRAIT_STINGS)) + data["trait_info"] += "The fruit is covered in stinging spines." - if(grown_seed.get_trait(TRAIT_JUICY) == 1) - dat += "
The fruit is soft-skinned and juicy." - else if(grown_seed.get_trait(TRAIT_JUICY) == 2) - dat += "
The fruit is excessively juicy." + if(get_trait(TRAIT_JUICY) == 1) + data["trait_info"] += "The fruit is soft-skinned and juicy." + else if(get_trait(TRAIT_JUICY) == 2) + data["trait_info"] += "The fruit is excessively juicy." - if(grown_seed.get_trait(TRAIT_EXPLOSIVE)) - dat += "
The fruit is internally unstable." + if(get_trait(TRAIT_EXPLOSIVE)) + data["trait_info"] += "The fruit is internally unstable." - if(grown_seed.get_trait(TRAIT_TELEPORTING)) - dat += "
The fruit is temporal/spatially unstable." + if(get_trait(TRAIT_TELEPORTING)) + data["trait_info"] += "The fruit is temporal/spatially unstable." - if(grown_seed.exude_gasses && grown_seed.exude_gasses.len) - for(var/gas in grown_seed.exude_gasses) + if(exude_gasses && exude_gasses.len) + for(var/gas in exude_gasses) var/amount = "" - if (grown_seed.exude_gasses[gas] > 7) + if(exude_gasses[gas] > 7) amount = "large amounts of " - else if (grown_seed.exude_gasses[gas] < 5) + else if(exude_gasses[gas] < 5) amount = "small amounts of " - dat += "
It will release [amount][GLOB.meta_gas_names[gas]] into the environment." + data["trait_info"] += "It will release [amount][GLOB.meta_gas_names[gas]] into the environment." - if(grown_seed.consume_gasses && grown_seed.consume_gasses.len) - for(var/gas in grown_seed.consume_gasses) + if(consume_gasses && consume_gasses.len) + for(var/gas in consume_gasses) var/amount = "" - if (grown_seed.consume_gasses[gas] > 7) + if(consume_gasses[gas] > 7) amount = "large amounts of " - else if (grown_seed.consume_gasses[gas] < 5) + else if(consume_gasses[gas] < 5) amount = "small amounts of " - dat += "
It will consume [amount][GLOB.meta_gas_names[gas]] from the environment." + data["trait_info"] += "It will consume [amount][GLOB.meta_gas_names[gas]] from the environment." - if(dat) - last_data = dat - dat += "

\[print report\]" - user << browse(dat,"window=plant_analyzer") - - return + return data diff --git a/code/modules/hydroponics/trays/tray_update_icons.dm b/code/modules/hydroponics/trays/tray_update_icons.dm index 82e9d93232a..538c7e2cdeb 100644 --- a/code/modules/hydroponics/trays/tray_update_icons.dm +++ b/code/modules/hydroponics/trays/tray_update_icons.dm @@ -21,7 +21,7 @@ if(dead) var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-dead" - var/image/dead_overlay = plant_controller.plant_icon_cache["[ikey]"] + var/image/dead_overlay = SSplants.plant_icon_cache["[ikey]"] if(!dead_overlay) dead_overlay = image('icons/obj/hydroponics_growing.dmi', "[ikey]") dead_overlay.color = DEAD_PLANT_COLOUR @@ -41,23 +41,23 @@ maturation = 1 overlay_stage = maturation ? max(1,round(age/maturation)) : 1 var/ikey = "[seed.get_trait(TRAIT_PLANT_ICON)]-[overlay_stage]" - var/image/plant_overlay = plant_controller.plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] + var/image/plant_overlay = SSplants.plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] if(frozen == 1) plant_overlay = image('icons/obj/hydroponics_growing.dmi', "[ikey]") plant_overlay.color = FROZEN_PLANT_COLOUR if(!plant_overlay) plant_overlay = image('icons/obj/hydroponics_growing.dmi', "[ikey]") plant_overlay.color = seed.get_trait(TRAIT_PLANT_COLOUR) - plant_controller.plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] = plant_overlay + SSplants.plant_icon_cache["[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] = plant_overlay overlays |= plant_overlay if(harvest && overlay_stage == seed.growth_stages) ikey = "[seed.get_trait(TRAIT_PRODUCT_ICON)]" - var/image/harvest_overlay = plant_controller.plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] + var/image/harvest_overlay = SSplants.plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PLANT_COLOUR)]"] if(!harvest_overlay) harvest_overlay = image('icons/obj/hydroponics_products.dmi', "[ikey]") harvest_overlay.color = seed.get_trait(TRAIT_PRODUCT_COLOUR) - plant_controller.plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]"] = harvest_overlay + SSplants.plant_icon_cache["product-[ikey]-[seed.get_trait(TRAIT_PRODUCT_COLOUR)]"] = harvest_overlay overlays |= harvest_overlay diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm index 21ea93a2592..89a5a5e89dc 100644 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -3,7 +3,6 @@ // Here is where the base definition lives. // Specific subtypes are in their own folder. - /obj/item/electronic_assembly name = "electronic assembly" desc = "It's a case, for building small electronics with." @@ -46,88 +45,125 @@ if(!draw_power(IC.power_draw_idle)) IC.power_fail() - - - -/obj/item/electronic_assembly/proc/resolve_nano_host() - return src - /obj/item/electronic_assembly/proc/check_interactivity(mob/user) - if(!CanInteract(user, physical_state)) - return 0 - return 1 + return ui_status(user, GLOB.physical_state) == UI_INTERACTIVE /obj/item/electronic_assembly/get_cell() return battery -/obj/item/electronic_assembly/interact(mob/user) - if(!check_interactivity(user)) - return +// TGUI +/obj/item/electronic_assembly/ui_state(mob/user) + return GLOB.physical_state + +/obj/item/electronic_assembly/ui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ICAssembly", name, parent_ui) + ui.open() + +/obj/item/electronic_assembly/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() var/total_parts = 0 var/total_complexity = 0 for(var/obj/item/integrated_circuit/part in contents) total_parts += part.size total_complexity = total_complexity + part.complexity - var/HTML = list() - HTML += "[src.name]" - HTML += "
\[Refresh\] | " - HTML += "\[Rename\]
" - HTML += "[total_parts]/[max_components] ([round((total_parts / max_components) * 100, 0.1)]%) space taken up in the assembly.
" - HTML += "[total_complexity]/[max_complexity] ([round((total_complexity / max_complexity) * 100, 0.1)]%) maximum complexity.
" - if(battery) - HTML += "[round(battery.charge, 0.1)]/[battery.maxcharge] ([round(battery.percent(), 0.1)]%) cell charge. \[Remove\]
" - HTML += "Net energy: [format_SI(net_power / CELLRATE, "W")]." - else - HTML += "No powercell detected!" - HTML += "

" - HTML += "Components:
" - HTML += "Built in:
" + data["total_parts"] = total_parts + data["max_components"] = max_components + data["total_complexity"] = total_complexity + data["max_complexity"] = max_complexity + data["battery_charge"] = round(battery?.charge, 0.1) + data["battery_max"] = round(battery?.maxcharge, 0.1) + data["net_power"] = net_power / CELLRATE -//Put removable circuits in separate categories from non-removable + // This works because lists are always passed by reference in BYOND, so modifying unremovable_circuits + // after setting data["unremovable_circuits"] = unremovable_circuits also modifies data["unremovable_circuits"] + // Same for the removable one + var/list/unremovable_circuits = list() + data["unremovable_circuits"] = unremovable_circuits + var/list/removable_circuits = list() + data["removable_circuits"] = removable_circuits for(var/obj/item/integrated_circuit/circuit in contents) - if(!circuit.removable) - HTML += "[circuit.displayed_name] | " - HTML += "\[Rename\] | " - HTML += "\[Scan with Debugger\] | " - HTML += "\[Move to Bottom\]" - HTML += "
" + var/list/target = circuit.removable ? removable_circuits : unremovable_circuits + target.Add(list(list( + "name" = circuit.displayed_name, + "ref" = REF(circuit), + ))) - HTML += "
" - HTML += "Removable:
" + return data - for(var/obj/item/integrated_circuit/circuit in contents) - if(circuit.removable) - HTML += "[circuit.displayed_name] | " - HTML += "\[Rename\] | " - HTML += "\[Scan with Debugger\] | " - HTML += "\[Remove\] | " - HTML += "\[Move to Bottom\]" - HTML += "
" - - HTML += "" - user << browse(jointext(HTML,null), "window=assembly-\ref[src];size=600x350;border=1;can_resize=1;can_close=1;can_minimize=1") - -/obj/item/electronic_assembly/Topic(href, href_list[]) +/obj/item/electronic_assembly/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return 1 + return TRUE - if(href_list["rename"]) - rename(usr) + var/obj/held_item = usr.get_active_hand() - if(href_list["remove_cell"]) - if(!battery) - to_chat(usr, "There's no power cell to remove from \the [src].") - else + switch(action) + //Actual assembly actions + if("rename") + rename(usr) + return TRUE + + if("remove_cell") + if(!battery) + to_chat(usr, SPAN_WARNING("There's no power cell to remove from \the [src].")) + return FALSE var/turf/T = get_turf(src) battery.forceMove(T) - playsound(T, 'sound/items/Crowbar.ogg', 50, 1) - to_chat(usr, "You pull \the [battery] out of \the [src]'s power supplier.") + playsound(T, 'sound/items/Crowbar.ogg', 50, TRUE) + to_chat(usr, SPAN_NOTICE("You pull \the [battery] out of \the [src]'s power supplier.")) battery = null + return TRUE - interact(usr) // To refresh the UI. + // Circuit actions + if("open_circuit") + var/obj/item/integrated_circuit/C = locate(params["ref"]) in contents + if(!istype(C)) + return + C.ui_interact(usr, null, ui) + return TRUE + + if("rename_circuit") + var/obj/item/integrated_circuit/C = locate(params["ref"]) in contents + if(!istype(C)) + return + C.rename_component(usr) + return TRUE + + if("scan_circuit") + var/obj/item/integrated_circuit/C = locate(params["ref"]) in contents + if(!istype(C)) + return + if(istype(held_item, /obj/item/integrated_electronics/debugger)) + var/obj/item/integrated_electronics/debugger/D = held_item + if(D.accepting_refs) + D.afterattack(C, usr, TRUE) + else + to_chat(usr, SPAN_WARNING("The Debugger's 'ref scanner' needs to be on.")) + else + to_chat(usr, SPAN_WARNING("You need a multitool/debugger set to 'ref' mode to do that.")) + return TRUE + + if("remove_circuit") + var/obj/item/integrated_circuit/C = locate(params["ref"]) in contents + if(!istype(C)) + return + C.remove(usr) + return TRUE + + if("bottom_circuit") + var/obj/item/integrated_circuit/C = locate(params["ref"]) in contents + if(!istype(C)) + return + // Puts it at the bottom of our contents + // Note, this intentionally does *not* use forceMove, because forceMove will stop if it detects the same loc + C.loc = null + C.loc = src + return FALSE +// End TGUI /obj/item/electronic_assembly/verb/rename() set name = "Rename Circuit" @@ -140,7 +176,7 @@ var/input = sanitizeSafe(input("What do you want to name this?", "Rename", src.name) as null|text, MAX_NAME_LEN) if(src && input) - to_chat(M, "The machine now has a label reading '[input]'.") + to_chat(M, SPAN_NOTICE("The machine now has a label reading '[input]'.")) name = input /obj/item/electronic_assembly/proc/can_move() @@ -173,10 +209,11 @@ /obj/item/electronic_assembly/examine(mob/user) . = ..() - for(var/obj/item/integrated_circuit/IC in contents) - IC.external_examine(user) - if(opened) - interact(user) + if(Adjacent(user)) + for(var/obj/item/integrated_circuit/IC in contents) + . += IC.external_examine(user) + if(opened) + ui_interact(user) /obj/item/electronic_assembly/proc/get_part_complexity() . = 0 @@ -191,21 +228,21 @@ // Returns true if the circuit made it inside. /obj/item/electronic_assembly/proc/add_circuit(var/obj/item/integrated_circuit/IC, var/mob/user) if(!opened) - to_chat(user, "\The [src] isn't opened, so you can't put anything inside. Try using a crowbar.") + to_chat(user, SPAN_WARNING("\The [src] isn't opened, so you can't put anything inside. Try using a crowbar.")) return FALSE if(IC.w_class > src.w_class) - to_chat(user, "\The [IC] is way too big to fit into \the [src].") + to_chat(user, SPAN_WARNING("\The [IC] is way too big to fit into \the [src].")) return FALSE var/total_part_size = get_part_size() var/total_complexity = get_part_complexity() if((total_part_size + IC.size) > max_components) - to_chat(user, "You can't seem to add the '[IC.name]', as there's insufficient space.") + to_chat(user, SPAN_WARNING("You can't seem to add the '[IC.name]', as there's insufficient space.")) return FALSE if((total_complexity + IC.complexity) > max_complexity) - to_chat(user, "You can't seem to add the '[IC.name]', since this setup's too complicated for the case.") + to_chat(user, SPAN_WARNING("You can't seem to add the '[IC.name]', since this setup's too complicated for the case.")) return FALSE if(!IC.forceMove(src)) @@ -229,12 +266,12 @@ if(S.scan(target)) scanned = TRUE if(scanned) - visible_message("\The [user] waves \the [src] around [target].") + visible_message(SPAN_NOTICE("\The [user] waves \the [src] around [target].")) /obj/item/electronic_assembly/attackby(var/obj/item/I, var/mob/user) if(can_anchor && I.is_wrench()) anchored = !anchored - to_chat(user, span("notice", "You've [anchored ? "" : "un"]secured \the [src] to \the [get_turf(src)].")) + to_chat(user, SPAN_NOTICE("You've [anchored ? "" : "un"]secured \the [src] to \the [get_turf(src)].")) if(anchored) on_anchored() else @@ -246,24 +283,23 @@ if(!user.unEquip(I) && !istype(user, /mob/living/silicon/robot)) //Robots cannot de-equip items in grippers. return FALSE if(add_circuit(I, user)) - to_chat(user, "You slide \the [I] inside \the [src].") + to_chat(user, SPAN_NOTICE("You slide \the [I] inside \the [src].")) playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1) - interact(user) + ui_interact(user) return TRUE else if(I.is_crowbar()) playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1) opened = !opened - to_chat(user, "You [opened ? "opened" : "closed"] \the [src].") + to_chat(user, SPAN_NOTICE("You [opened ? "opened" : "closed"] \the [src].")) update_icon() return TRUE else if(istype(I, /obj/item/integrated_electronics/wirer) || istype(I, /obj/item/integrated_electronics/debugger) || I.is_screwdriver()) if(opened) - interact(user) + ui_interact(user) else - to_chat(user, "\The [src] isn't opened, so you can't fiddle with the internal components. \ - Try using a crowbar.") + to_chat(user, SPAN_WARNING("\The [src] isn't opened, so you can't fiddle with the internal components. Try using a crowbar.")) else if(istype(I, /obj/item/integrated_electronics/detailer)) var/obj/item/integrated_electronics/detailer/D = I @@ -272,20 +308,19 @@ else if(istype(I, /obj/item/cell/device)) if(!opened) - to_chat(user, "\The [src] isn't opened, so you can't put anything inside. Try using a crowbar.") + to_chat(user, SPAN_WARNING("\The [src] isn't opened, so you can't put anything inside. Try using a crowbar.")) return FALSE if(battery) - to_chat(user, "\The [src] already has \a [battery] inside. Remove it first if you want to replace it.") + to_chat(user, SPAN_WARNING("\The [src] already has \a [battery] inside. Remove it first if you want to replace it.")) return FALSE var/obj/item/cell/device/cell = I user.drop_item(cell) cell.forceMove(src) battery = cell playsound(get_turf(src), 'sound/items/Deconstruct.ogg', 50, 1) - to_chat(user, "You slot \the [cell] inside \the [src]'s power supplier.") - interact(user) + to_chat(user, SPAN_NOTICE("You slot \the [cell] inside \the [src]'s power supplier.")) + ui_interact(user) return TRUE - else return ..() @@ -293,7 +328,7 @@ if(!check_interactivity(user)) return if(opened) - interact(user) + ui_interact(user) var/list/input_selection = list() var/list/available_inputs = list() diff --git a/code/modules/integrated_electronics/core/assemblies/clothing.dm b/code/modules/integrated_electronics/core/assemblies/clothing.dm index 54f1a976229..e9379fda662 100644 --- a/code/modules/integrated_electronics/core/assemblies/clothing.dm +++ b/code/modules/integrated_electronics/core/assemblies/clothing.dm @@ -12,11 +12,8 @@ max_complexity = IC_COMPLEXITY_BASE var/obj/item/clothing/clothing = null -/obj/item/electronic_assembly/clothing/nano_host() - return clothing - -/obj/item/electronic_assembly/clothing/resolve_nano_host() - return clothing +/obj/item/electronic_assembly/clothing/ui_host() + return clothing.ui_host() /obj/item/electronic_assembly/clothing/update_icon() ..() diff --git a/code/modules/integrated_electronics/core/assemblies/implant.dm b/code/modules/integrated_electronics/core/assemblies/implant.dm index 15c0797714c..54c6110c730 100644 --- a/code/modules/integrated_electronics/core/assemblies/implant.dm +++ b/code/modules/integrated_electronics/core/assemblies/implant.dm @@ -10,11 +10,8 @@ max_complexity = IC_COMPLEXITY_BASE / 2 var/obj/item/implant/integrated_circuit/implant = null -/obj/item/electronic_assembly/implant/nano_host() - return implant - -/obj/item/electronic_assembly/implant/resolve_nano_host() - return implant +/obj/item/electronic_assembly/implant/ui_host() + return implant.ui_host() /obj/item/electronic_assembly/implant/update_icon() ..() diff --git a/code/modules/integrated_electronics/core/detailer.dm b/code/modules/integrated_electronics/core/detailer.dm index a3b96ad851e..ec2fb37a02e 100644 --- a/code/modules/integrated_electronics/core/detailer.dm +++ b/code/modules/integrated_electronics/core/detailer.dm @@ -7,7 +7,7 @@ w_class = ITEMSIZE_SMALL var/detail_color = COLOR_ASSEMBLY_WHITE var/list/color_list = list( - "black" = COLOR_ASSEMBLY_BLACK, + "dark gray" = COLOR_ASSEMBLY_BLACK, "machine gray" = COLOR_ASSEMBLY_BGRAY, "white" = COLOR_ASSEMBLY_WHITE, "red" = COLOR_ASSEMBLY_RED, @@ -35,11 +35,41 @@ detail_overlay.color = detail_color add_overlay(detail_overlay) +/obj/item/integrated_electronics/detailer/ui_state(mob/user) + return GLOB.inventory_state + +/obj/item/integrated_electronics/detailer/ui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ICDetailer", name) + ui.open() + +/obj/item/integrated_electronics/detailer/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + data["detail_color"] = detail_color + data["color_list"] = color_list + return data + +/obj/item/integrated_electronics/detailer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE + + switch(action) + if("change_color") + if(!(params["color"] in color_list)) + return // to prevent href exploits causing runtimes + detail_color = color_list[params["color"]] + update_icon() + return TRUE + /obj/item/integrated_electronics/detailer/attack_self(mob/user) - var/color_choice = input(user, "Select color.", "Assembly Detailer", detail_color) as null|anything in color_list - if(!color_list[color_choice]) - return - if(!in_range(src, user)) - return - detail_color = color_list[color_choice] - update_icon() + ui_interact(user) + // Leaving this commented out in case someone decides that this would be better as an "any color" selection system + // Just uncomment this and get rid of all of the TGUI bullshit lol + // if(!in_range(user, src)) + // return + // var/new_color = input(user, "Pick a color", "Color Selection", detail_color) as color|null + // if(!new_color) + // return + // detail_color = new_color + // update_icon() diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm index 0c57fcaa431..fbc42c4a338 100644 --- a/code/modules/integrated_electronics/core/integrated_circuit.dm +++ b/code/modules/integrated_electronics/core/integrated_circuit.dm @@ -4,9 +4,9 @@ a creative player the means to solve many problems. Circuits are held inside an */ /obj/item/integrated_circuit/examine(mob/user) - interact(user) - external_examine(user) . = ..() + external_examine(user) + ui_interact(user) // This should be used when someone is examining while the case is opened. /obj/item/integrated_circuit/proc/internal_examine(mob/user) @@ -21,7 +21,7 @@ a creative player the means to solve many problems. Circuits are held inside an if(A.linked.len) to_chat(user, "The '[A]' is connected to [A.get_linked_to_desc()].") any_examine(user) - interact(user) + ui_interact(user) // This should be used when someone is examining from an 'outside' perspective, e.g. reading a screen or LED. /obj/item/integrated_circuit/proc/external_examine(mob/user) @@ -53,22 +53,12 @@ a creative player the means to solve many problems. Circuits are held inside an qdel(A) . = ..() -/obj/item/integrated_circuit/nano_host() - if(istype(src.loc, /obj/item/electronic_assembly)) - var/obj/item/electronic_assembly/assembly = loc - return assembly.resolve_nano_host() - return ..() - /obj/item/integrated_circuit/emp_act(severity) for(var/datum/integrated_io/io in inputs + outputs + activators) io.scramble() /obj/item/integrated_circuit/proc/check_interactivity(mob/user) - if(assembly) - return assembly.check_interactivity(user) - else if(!CanInteract(user, physical_state)) - return 0 - return 1 + return ui_status(user, GLOB.physical_state) == UI_INTERACTIVE /obj/item/integrated_circuit/verb/rename_component() set name = "Rename Circuit" @@ -81,276 +71,177 @@ a creative player the means to solve many problems. Circuits are held inside an var/input = sanitizeSafe(input("What do you want to name the circuit?", "Rename", src.name) as null|text, MAX_NAME_LEN) if(src && input && assembly.check_interactivity(M)) - to_chat(M, "The circuit '[src.name]' is now labeled '[input]'.") + to_chat(M, SPAN_NOTICE("The circuit '[src.name]' is now labeled '[input]'.")) displayed_name = input -/obj/item/integrated_circuit/interact(mob/user) - if(!check_interactivity(user)) - return -// if(!assembly) -// return +/obj/item/integrated_circuit/ui_state(mob/user) + return GLOB.physical_state - var/window_height = 350 - var/window_width = 600 +/obj/item/integrated_circuit/ui_host(mob/user) + if(istype(loc, /obj/item/electronic_assembly)) + return loc.ui_host() + return ..() - //var/table_edge_width = "[(window_width - window_width * 0.1) / 4]px" - //var/table_middle_width = "[(window_width - window_width * 0.1) - (table_edge_width * 2)]px" - var/table_edge_width = "30%" - var/table_middle_width = "40%" +/obj/item/integrated_circuit/ui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ICCircuit", name, parent_ui) + ui.open() - var/HTML = list() - HTML += "[src.displayed_name]" - HTML += "
" - HTML += "" +/obj/item/integrated_circuit/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() - HTML += "
\[Return to Assembly\]" + data["name"] = name + data["desc"] = desc + data["displayed_name"] = displayed_name + data["removable"] = removable - HTML += "
\[Refresh\] | " - HTML += "\[Rename\] | " - HTML += "\[Scan with Device\] | " - if(src.removable) - HTML += "\[Remove\]
" + data["complexity"] = complexity + data["power_draw_idle"] = power_draw_idle + data["power_draw_per_use"] = power_draw_per_use + data["extended_desc"] = extended_desc - HTML += "" - HTML += "" - HTML += "" - HTML += "" - HTML += "" + var/list/inputs_list = list() + var/list/outputs_list = list() + var/list/activators_list = list() + for(var/datum/integrated_io/io in inputs) + inputs_list.Add(list(tgui_pin_data(io))) - var/column_width = 3 - var/row_height = max(inputs.len, outputs.len, 1) + for(var/datum/integrated_io/io in outputs) + outputs_list.Add(list(tgui_pin_data(io))) - for(var/i = 1 to row_height) - HTML += "" - for(var/j = 1 to column_width) - var/datum/integrated_io/io = null - var/words = list() - var/height = 1 - switch(j) - if(1) - io = get_pin_ref(IC_INPUT, i) - if(io) - words += "[io.display_pin_type()] [io.name] [io.display_data(io.data)]
" - if(io.linked.len) - for(var/datum/integrated_io/linked in io.linked) -// words += "\[[linked.name]\] - words += "[linked.name] \ - @ [linked.holder.displayed_name]
" + for(var/datum/integrated_io/io in activators) + var/list/list/activator = list( + "ref" = REF(io), + "name" = io.name, + "pulse_out" = io.data, + "linked" = list() + ) + for(var/datum/integrated_io/linked in io.linked) + activator["linked"].Add(list(list( + "ref" = REF(linked), + "name" = linked.name, + "holder_ref" = REF(linked.holder), + "holder_name" = linked.holder.displayed_name, + ))) - if(outputs.len > inputs.len) - height = 1 - if(2) - if(i == 1) - words += "[src.displayed_name]
[src.name != src.displayed_name ? "([src.name])":""]
[src.desc]" - height = row_height - else - continue - if(3) - io = get_pin_ref(IC_OUTPUT, i) - if(io) - words += "[io.display_pin_type()] [io.name] [io.display_data(io.data)]
" - if(io.linked.len) - for(var/datum/integrated_io/linked in io.linked) -// words += "\[[linked.name]\] - words += "[linked.name] \ - @ [linked.holder.displayed_name]
" + activators_list.Add(list(activator)) - if(inputs.len > outputs.len) - height = 1 - HTML += "" - HTML += "" + data["inputs"] = inputs_list + data["outputs"] = outputs_list + data["activators"] = activators_list - for(var/activator in activators) - var/datum/integrated_io/io = activator - var/words = list() + return data - words += "[io.name] [io.data?"\":"\"]
" - if(io.linked.len) - for(var/datum/integrated_io/linked in io.linked) -// words += "\[[linked.name]\] - words += "[linked.name] \ - @ [linked.holder.displayed_name]
" +/obj/item/integrated_circuit/proc/tgui_pin_data(datum/integrated_io/io) + if(!istype(io)) + return list() + var/list/pindata = list() + pindata["type"] = io.display_pin_type() + pindata["name"] = io.name + pindata["data"] = io.display_data(io.data) + pindata["ref"] = REF(io) + var/list/linked_list = list() + for(var/datum/integrated_io/linked in io.linked) + linked_list.Add(list(list( + "ref" = REF(linked), + "name" = linked.name, + "holder_ref" = REF(linked.holder), + "holder_name" = linked.holder.displayed_name, + ))) + pindata["linked"] = linked_list - HTML += "" - HTML += "" - HTML += "" + return pindata - HTML += "
[jointext(words, null)]
[jointext(words, null)]
" - HTML += "
" - -// HTML += "
Meta Variables;" // If more meta vars get introduced, uncomment this. -// HTML += "
" - - HTML += "
Complexity: [complexity]" - if(power_draw_idle) - HTML += "
Power Draw: [power_draw_idle] W (Idle)" - if(power_draw_per_use) - HTML += "
Power Draw: [power_draw_per_use] W (Active)" // Borgcode says that powercells' checked_use() takes joules as input. - HTML += "
[extended_desc]" - - HTML += "" - if(src.assembly) - user << browse(jointext(HTML, null), "window=assembly-\ref[src.assembly];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") - else - user << browse(jointext(HTML, null), "window=circuit-\ref[src];size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") - - onclose(user, "assembly-\ref[src.assembly]") - -/obj/item/integrated_circuit/Topic(href, href_list, state = interactive_state) - if(!check_interactivity(usr)) - return +/obj/item/integrated_circuit/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return 1 + return TRUE - var/update = 1 - var/obj/item/electronic_assembly/A = src.assembly - var/update_to_assembly = 0 - var/datum/integrated_io/pin = locate(href_list["pin"]) in inputs + outputs + activators + var/datum/integrated_io/pin = locate(params["pin"]) in inputs + outputs + activators var/datum/integrated_io/linked = null - if(href_list["link"]) - linked = locate(href_list["link"]) in pin.linked + + if(params["link"]) + linked = locate(params["link"]) in pin.linked var/obj/held_item = usr.get_active_hand() - if(href_list["rename"]) - rename_component(usr) - if(href_list["from_assembly"]) - update = 0 - var/obj/item/electronic_assembly/ea = loc - if(istype(ea)) - ea.interact(usr) - - if(href_list["pin_name"]) - if (!istype(held_item, /obj/item/multitool) || !allow_multitool) - href_list["wire"] = 1 - else - var/obj/item/multitool/M = held_item - M.wire(pin,usr) - - - - if(href_list["pin_data"]) - if (!istype(held_item, /obj/item/multitool) || !allow_multitool) - href_list["wire"] = 1 - - else - var/datum/integrated_io/io = pin - io.ask_for_pin_data(usr, held_item) // The pins themselves will determine how to ask for data, and will validate the data. - /* - if(io.io_type == DATA_CHANNEL) - - var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number", "null") - if(!check_interactivity(usr)) - return - - var/new_data = null - switch(type_to_use) - if("string") - new_data = input("Now type in a string.","[src] string writing") as null|text - to_chat(usr, "You input [new_data] into the pin.") - //to_chat(user, "You write '[new_data]' to the '[io]' pin of \the [io.holder].") - if("number") - new_data = input("Now type in a number.","[src] number writing") as null|num - if(isnum(new_data) && check_interactivity(usr) ) - to_chat(usr, "You input [new_data] into the pin.") - if("null") - if(check_interactivity(usr)) - to_chat(usr, "You clear the pin's memory.") - - io.write_data_to_pin(new_data) - - else if(io.io_type == PULSE_CHANNEL) - io.holder.check_then_do_work(ignore_power = TRUE) - to_chat(usr, "You pulse \the [io.holder]'s [io] pin.") - */ - - - if(href_list["pin_unwire"]) - if (!istype(held_item, /obj/item/multitool) || !allow_multitool) - href_list["wire"] = 1 - else - var/obj/item/multitool/M = held_item - M.unwire(pin, linked, usr) - - if(href_list["wire"]) - if(istype(held_item, /obj/item/integrated_electronics/wirer)) - var/obj/item/integrated_electronics/wirer/wirer = held_item - if(linked) - wirer.wire(linked, usr) - else if(pin) - wirer.wire(pin, usr) - - else if(istype(held_item, /obj/item/integrated_electronics/debugger)) - var/obj/item/integrated_electronics/debugger/debugger = held_item - if(pin) - debugger.write_data(pin, usr) - else - to_chat(usr, "You can't do a whole lot without the proper tools.") - - if(href_list["examine"]) - var/obj/item/integrated_circuit/examined - if(href_list["examined"]) - examined = href_list["examined"] - else - examined = src - examined.interact(usr) - update = 0 - - if(href_list["bottom"]) - var/obj/item/integrated_circuit/circuit = locate(href_list["bottom"]) in src.assembly.contents - var/assy = circuit.assembly - if(!circuit) + . = TRUE + switch(action) + if("rename") + rename_component(usr) return - circuit.loc = null - circuit.loc = assy - . = 1 - update_to_assembly = 1 - if(href_list["scan"]) - if(istype(held_item, /obj/item/integrated_electronics/debugger)) - var/obj/item/integrated_electronics/debugger/D = held_item - if(D.accepting_refs) - D.afterattack(src, usr, TRUE) + if("wire", "pin_name", "pin_data", "pin_unwire") + if(istype(held_item, /obj/item/multitool) && allow_multitool) + var/obj/item/multitool/M = held_item + switch(action) + if("pin_name") + M.wire(pin, usr) + if("pin_data") + var/datum/integrated_io/io = pin + io.ask_for_pin_data(usr, held_item) // The pins themselves will determine how to ask for data, and will validate the data. + if("pin_unwire") + M.unwire(pin, linked, usr) + + else if(istype(held_item, /obj/item/integrated_electronics/wirer)) + var/obj/item/integrated_electronics/wirer/wirer = held_item + if(linked) + wirer.wire(linked, usr) + else if(pin) + wirer.wire(pin, usr) + + else if(istype(held_item, /obj/item/integrated_electronics/debugger)) + var/obj/item/integrated_electronics/debugger/debugger = held_item + if(pin) + debugger.write_data(pin, usr) else - to_chat(usr, "The Debugger's 'ref scanner' needs to be on.") - else - to_chat(usr, "You need a multitool/debugger set to 'ref' mode to do that.") - - if(href_list["return"]) - if(A) - update_to_assembly = 1 - usr << browse(null, "window=circuit-\ref[src];border=1;can_resize=1;can_close=1;can_minimize=1") - else - to_chat(usr, "This circuit is not in an assembly!") - - - if(href_list["remove"]) - if(!A) - to_chat(usr, "This circuit is not in an assembly!") + to_chat(usr, SPAN_WARNING("You can't do a whole lot without the proper tools.")) return - if(!removable) - to_chat(usr, "\The [src] seems to be permanently attached to the case.") - return - var/obj/item/electronic_assembly/ea = loc - power_fail() - disconnect_all() - var/turf/T = get_turf(src) - forceMove(T) - assembly = null - playsound(T, 'sound/items/Crowbar.ogg', 50, 1) - to_chat(usr, "You pop \the [src] out of the case, and slide it out.") - if(istype(ea)) - ea.interact(usr) - update = 0 + if("scan") + if(istype(held_item, /obj/item/integrated_electronics/debugger)) + var/obj/item/integrated_electronics/debugger/D = held_item + if(D.accepting_refs) + D.afterattack(src, usr, TRUE) + else + to_chat(usr, SPAN_WARNING("The Debugger's 'ref scanner' needs to be on.")) + else + to_chat(usr, SPAN_WARNING("You need a multitool/debugger set to 'ref' mode to do that.")) + return + + if("examine") + var/obj/item/integrated_circuit/examined = locate(params["ref"]) + if(istype(examined) && (examined.loc == loc)) + if(ui.parent_ui) + examined.ui_interact(usr, null, ui.parent_ui) + else + examined.ui_interact(usr) + + if("remove") + remove(usr) + return + return FALSE + +/obj/item/integrated_circuit/proc/remove(mob/user) + var/obj/item/electronic_assembly/A = assembly + if(!A) + to_chat(user, SPAN_WARNING("This circuit is not in an assembly!")) return + if(!removable) + to_chat(user, SPAN_WARNING("\The [src] seems to be permanently attached to the case.")) + return + var/obj/item/electronic_assembly/ea = loc - if(update) - if(A && istype(A) && update_to_assembly) - A.interact(usr) - else - interact(usr) // To refresh the UI. + power_fail() + disconnect_all() + var/turf/T = get_turf(src) + forceMove(T) + assembly = null + playsound(T, 'sound/items/Crowbar.ogg', 50, TRUE) + to_chat(user, SPAN_NOTICE("You pop \the [src] out of the case, and slide it out.")) + if(istype(ea)) + ea.ui_interact(user) /obj/item/integrated_circuit/proc/push_data() diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm index e10626a7a7f..5ae0cea2da9 100644 --- a/code/modules/integrated_electronics/core/printer.dm +++ b/code/modules/integrated_electronics/core/printer.dm @@ -13,8 +13,8 @@ var/upgraded = FALSE // When hit with an upgrade disk, will turn true, allowing it to print the higher tier circuits. var/can_clone = FALSE // Same for above, but will allow the printer to duplicate a specific assembly. (Not implemented) // var/static/list/recipe_list = list() - var/current_category = null - var/obj/item/electronic_assembly/assembly_to_clone = null + var/obj/item/electronic_assembly/assembly_to_clone = null // Not implemented x3 + var/dirty_items = FALSE /obj/item/integrated_circuit_printer/upgraded upgraded = TRUE @@ -38,132 +38,164 @@ var/obj/item/stack/material/stack = O if(stack.material.name == DEFAULT_WALL_MATERIAL) if(debug) - to_chat(user, span("warning", "\The [src] does not need any material.")) + to_chat(user, SPAN_WARNING("\The [src] does not need any material.")) return var/num = min((max_metal - metal) / metal_per_sheet, stack.amount) if(num < 1) - to_chat(user, span("warning", "\The [src] is too full to add more metal.")) + to_chat(user, SPAN_WARNING("\The [src] is too full to add more metal.")) return if(stack.use(max(1, round(num)))) // We don't want to create stacks that aren't whole numbers - to_chat(user, span("notice", "You add [num] sheet\s to \the [src].")) + to_chat(user, SPAN_NOTICE("You add [num] sheet\s to \the [src].")) metal += num * metal_per_sheet - interact(user) + attack_self(user) return TRUE if(istype(O,/obj/item/integrated_circuit)) - to_chat(user, span("notice", "You insert the circuit into \the [src].")) + to_chat(user, SPAN_NOTICE("You insert the circuit into \the [src].")) user.unEquip(O) metal = min(metal + O.w_class, max_metal) qdel(O) - interact(user) + attack_self(user) return TRUE if(istype(O,/obj/item/disk/integrated_circuit/upgrade/advanced)) if(upgraded) - to_chat(user, span("warning", "\The [src] already has this upgrade.")) + to_chat(user, SPAN_WARNING("\The [src] already has this upgrade.")) return TRUE - to_chat(user, span("notice", "You install \the [O] into \the [src].")) + to_chat(user, SPAN_NOTICE("You install \the [O] into \the [src].")) upgraded = TRUE - interact(user) + dirty_items = TRUE + attack_self(user) return TRUE if(istype(O,/obj/item/disk/integrated_circuit/upgrade/clone)) if(can_clone) - to_chat(user, span("warning", "\The [src] already has this upgrade.")) + to_chat(user, SPAN_WARNING("\The [src] already has this upgrade.")) return TRUE - to_chat(user, span("notice", "You install \the [O] into \the [src].")) + to_chat(user, SPAN_NOTICE("You install \the [O] into \the [src].")) can_clone = TRUE - interact(user) + attack_self(user) return TRUE return ..() +/obj/item/integrated_circuit_printer/vv_edit_var(var_name, var_value) + // Gotta update the static data in case an admin VV's the upgraded var for some reason..! //I would :) -Zan + if(var_name == "upgraded") + dirty_items = TRUE + return ..() + /obj/item/integrated_circuit_printer/attack_self(var/mob/user) interact(user) + ui_interact(user) -/obj/item/integrated_circuit_printer/interact(mob/user) - var/window_height = 600 - var/window_width = 500 +/obj/item/integrated_circuit_printer/ui_state(mob/user) + return GLOB.inventory_state - if(isnull(current_category)) - current_category = SScircuit.circuit_fabricator_recipe_list[1] +/obj/item/integrated_circuit_printer/ui_interact(mob/user, datum/tgui/ui) + if(dirty_items) + update_static_data(user, ui) + dirty_items = FALSE - var/HTML = "

Integrated Circuit Printer


" - if(!debug) - HTML += "Metal: [metal/metal_per_sheet]/[max_metal/metal_per_sheet] sheets.
" - else - HTML += "Metal: INFINITY.
" - HTML += "Circuits available: [upgraded ? "Advanced":"Regular"].
" - HTML += "Assembly Cloning: [can_clone ? "Available": "Unavailable"].
" - if(assembly_to_clone) - HTML += "Assembly '[assembly_to_clone.name]' loaded.
" - HTML += "Crossed out circuits mean that the printer is not sufficentally upgraded to create that circuit.
" - HTML += "
" - HTML += "Categories:" + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ICPrinter", name) // 500, 600 + ui.open() + +/obj/item/integrated_circuit_printer/ui_static_data(mob/user) + var/list/data = ..() + + var/list/categories = list() for(var/category in SScircuit.circuit_fabricator_recipe_list) - if(category != current_category) - HTML += " \[[category]\] " - else // Bold the button if it's already selected. - HTML += " \[[category]\] " - HTML += "
" - HTML += "

[current_category]

" + var/list/cat_obj = list( + "name" = category, + "items" = null + ) + var/list/circuit_list = SScircuit.circuit_fabricator_recipe_list[category] + var/list/items = list() + for(var/path in circuit_list) + var/obj/O = path + var/can_build = TRUE - var/list/current_list = SScircuit.circuit_fabricator_recipe_list[current_category] - for(var/path in current_list) - var/obj/O = path - var/can_build = TRUE - if(ispath(path, /obj/item/integrated_circuit)) - var/obj/item/integrated_circuit/IC = path - if((initial(IC.spawn_flags) & IC_SPAWN_RESEARCH) && (!(initial(IC.spawn_flags) & IC_SPAWN_DEFAULT)) && !upgraded) - can_build = FALSE - if(can_build) - HTML += "\[[initial(O.name)]\]: [initial(O.desc)]
" - else - HTML += "\[[initial(O.name)]\]: [initial(O.desc)]
" + if(ispath(path, /obj/item/integrated_circuit)) + var/obj/item/integrated_circuit/IC = path + if((initial(IC.spawn_flags) & IC_SPAWN_RESEARCH) && (!(initial(IC.spawn_flags) & IC_SPAWN_DEFAULT)) && !upgraded) + can_build = FALSE - user << browse(jointext(HTML, null), "window=integrated_printer;size=[window_width]x[window_height];border=1;can_resize=1;can_close=1;can_minimize=1") + var/cost = 1 + if(ispath(path, /obj/item/electronic_assembly)) + var/obj/item/electronic_assembly/E = path + cost = round((initial(E.max_complexity) + initial(E.max_components)) / 4) + else + var/obj/item/I = path + cost = initial(I.w_class) + items.Add(list(list( + "name" = initial(O.name), + "desc" = initial(O.desc), + "can_build" = can_build, + "cost" = cost, + "path" = path, + ))) -/obj/item/integrated_circuit_printer/Topic(href, href_list) + cat_obj["items"] = items + categories.Add(list(cat_obj)) + data["categories"] = categories + + return data + +/obj/item/integrated_circuit_printer/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + + data["metal"] = metal + data["max_metal"] = max_metal + data["metal_per_sheet"] = metal_per_sheet + data["debug"] = debug + data["upgraded"] = upgraded + data["can_clone"] = can_clone + data["assembly_to_clone"] = assembly_to_clone + + return data + +/obj/item/integrated_circuit_printer/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return 1 + return TRUE - add_fingerprint(usr) + switch(action) + if("build") + var/build_type = text2path(params["build"]) + if(!build_type || !ispath(build_type)) + return TRUE - if(href_list["category"]) - current_category = href_list["category"] + var/cost = 1 - if(href_list["build"]) - var/build_type = text2path(href_list["build"]) - if(!build_type || !ispath(build_type)) - return 1 + if(ispath(build_type, /obj/item/electronic_assembly)) + var/obj/item/electronic_assembly/E = build_type + cost = round( (initial(E.max_complexity) + initial(E.max_components) ) / 4) + else + var/obj/item/I = build_type + cost = initial(I.w_class) - var/cost = 1 + var/in_some_category = FALSE + for(var/category in SScircuit.circuit_fabricator_recipe_list) + if(build_type in SScircuit.circuit_fabricator_recipe_list[category]) + in_some_category = TRUE + break + if(!in_some_category) + return - if(isnull(current_category)) - current_category = SScircuit.circuit_fabricator_recipe_list[1] - if(ispath(build_type, /obj/item/electronic_assembly)) - var/obj/item/electronic_assembly/E = build_type - cost = round( (initial(E.max_complexity) + initial(E.max_components) ) / 4) - else - var/obj/item/I = build_type - cost = initial(I.w_class) - if(!(build_type in SScircuit.circuit_fabricator_recipe_list[current_category])) - return - - if(!debug) - if(!Adjacent(usr)) - to_chat(usr, "You are too far away from \the [src].") - if(metal - cost < 0) - to_chat(usr, "You need [cost] metal to build that!.") - return 1 - metal -= cost - var/obj/item/built = new build_type(get_turf(loc)) - usr.put_in_hands(built) - to_chat(usr, "[capitalize(built.name)] printed.") - playsound(src, 'sound/items/jaws_pry.ogg', 50, TRUE) - - interact(usr) + if(!debug) + if(!Adjacent(usr)) + to_chat(usr, SPAN_NOTICE("You are too far away from \the [src].")) + if(metal - cost < 0) + to_chat(usr, SPAN_WARNING("You need [cost] metal to build that!.")) + return TRUE + metal -= cost + var/obj/item/built = new build_type(get_turf(loc)) + usr.put_in_hands(built) + to_chat(usr, SPAN_NOTICE("[capitalize(built.name)] printed.")) + playsound(src, 'sound/items/jaws_pry.ogg', 50, TRUE) + return TRUE // FUKKEN UPGRADE DISKS diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm index 730a0177c13..8dac9e649c2 100644 --- a/code/modules/library/lib_machines.dm +++ b/code/modules/library/lib_machines.dm @@ -521,16 +521,32 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f */ /obj/machinery/bookbinder name = "Book Binder" - icon = 'icons/obj/library.dmi' + icon = 'icons/obj/machines/fabricators/book.dmi' icon_state = "binder" - anchored = 1 - density = 1 + base_icon_state = "binder" + anchored = TRUE + density = TRUE + +/obj/machinery/bookbinder/update_icon_state() + . = ..() + if(stat & NOPOWER) + icon_state = "[base_icon_state]-off" + else + icon_state = base_icon_state + +/obj/machinery/bookbinder/update_overlays() + . = ..() + cut_overlays() + if(panel_open) + add_overlay("[base_icon_state]-panel") /obj/machinery/bookbinder/attackby(var/obj/O as obj, var/mob/user as mob) if(istype(O, /obj/item/paper)) user.drop_item() O.loc = src user.visible_message("[user] loads some paper into [src].", "You load some paper into [src].") + flick_overlay_view("[base_icon_state]-load-paper", src, 10) + flick_overlay_view("[base_icon_state]-active", src, 12) src.visible_message("[src] begins to hum as it warms up its printing drums.") sleep(rand(200,400)) src.visible_message("[src] whirs as it prints and binds a new book.") diff --git a/code/modules/mining/ore_redemption_machine/survey_vendor.dm b/code/modules/mining/ore_redemption_machine/survey_vendor.dm index 689ce83659a..686299d1b92 100644 --- a/code/modules/mining/ore_redemption_machine/survey_vendor.dm +++ b/code/modules/mining/ore_redemption_machine/survey_vendor.dm @@ -11,42 +11,43 @@ child = TRUE //VOREStation Edit Start - Heavily modified list prize_list = list( - new /datum/data/mining_equipment("1 Marker Beacon", /obj/item/stack/marker_beacon, 1), - new /datum/data/mining_equipment("10 Marker Beacons", /obj/item/stack/marker_beacon/ten, 10), - new /datum/data/mining_equipment("30 Marker Beacons", /obj/item/stack/marker_beacon/thirty, 30), + new /datum/data/mining_equipment("1 Marker Beacon", /obj/item/stack/marker_beacon, 1), + new /datum/data/mining_equipment("10 Marker Beacons", /obj/item/stack/marker_beacon/ten, 10), + new /datum/data/mining_equipment("30 Marker Beacons", /obj/item/stack/marker_beacon/thirty, 30), new /datum/data/mining_equipment("GPS Device", /obj/item/gps/explorer, 10), - new /datum/data/mining_equipment("Whiskey", /obj/item/reagent_containers/food/drinks/bottle/whiskey, 10), + new /datum/data/mining_equipment("Whiskey", /obj/item/reagent_containers/food/drinks/bottle/whiskey, 10), new /datum/data/mining_equipment("Absinthe", /obj/item/reagent_containers/food/drinks/bottle/absinthe, 10), - new /datum/data/mining_equipment("Cigar", /obj/item/clothing/mask/smokable/cigarette/cigar/havana, 15), + new /datum/data/mining_equipment("Cigar", /obj/item/clothing/mask/smokable/cigarette/cigar/havana, 15), new /datum/data/mining_equipment("Soap", /obj/item/soap/nanotrasen, 20), - new /datum/data/mining_equipment("Laser Pointer", /obj/item/laser_pointer, 90), + new /datum/data/mining_equipment("Laser Pointer", /obj/item/laser_pointer, 90), new /datum/data/mining_equipment("Geiger Counter", /obj/item/geiger, 75), - new /datum/data/mining_equipment("Plush Toy", /obj/random/plushie, 30), - new /datum/data/mining_equipment("Extraction Equipment - Fulton Beacon", /obj/item/fulton_core, 300), - new /datum/data/mining_equipment("Extraction Equipment - Fulton Pack", /obj/item/extraction_pack, 125), - new /datum/data/mining_equipment("Umbrella", /obj/item/melee/umbrella/random, 20), - new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 50), - new /datum/data/mining_equipment("Point Transfer Card", /obj/item/card/mining_point_card/survey, 50), + new /datum/data/mining_equipment("Plush Toy", /obj/random/plushie, 30), + new /datum/data/mining_equipment("Extraction Equipment - Fulton Beacon", /obj/item/fulton_core, 300), + new /datum/data/mining_equipment("Extraction Equipment - Fulton Pack", /obj/item/extraction_pack, 125), + new /datum/data/mining_equipment("Umbrella", /obj/item/melee/umbrella/random, 20), + new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 50), + new /datum/data/mining_equipment("Point Transfer Card", /obj/item/card/mining_point_card/survey, 50), new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/autoinjector/miner, 50), - new /datum/data/mining_equipment("Injector (L) - Glucose",/obj/item/reagent_containers/hypospray/autoinjector/biginjector/glucose, 50), - new /datum/data/mining_equipment("Injector (L) - Panacea",/obj/item/reagent_containers/hypospray/autoinjector/biginjector/purity, 50), - new /datum/data/mining_equipment("Injector (L) - Trauma",/obj/item/reagent_containers/hypospray/autoinjector/biginjector/brute, 50), - new /datum/data/mining_equipment("Digital Tablet - Standard", /obj/item/modular_computer/tablet/preset/custom_loadout/standard, 50), - new /datum/data/mining_equipment("Digital Tablet - Advanced", /obj/item/modular_computer/tablet/preset/custom_loadout/advanced, 100), - new /datum/data/mining_equipment("Nanopaste Tube", /obj/item/stack/nanopaste, 100), + new /datum/data/mining_equipment("Injector (L) - Glucose", /obj/item/reagent_containers/hypospray/autoinjector/biginjector/glucose, 50), + new /datum/data/mining_equipment("Injector (L) - Panacea", /obj/item/reagent_containers/hypospray/autoinjector/biginjector/purity, 50), + new /datum/data/mining_equipment("Injector (L) - Trauma", /obj/item/reagent_containers/hypospray/autoinjector/biginjector/brute, 50), + new /datum/data/mining_equipment("Digital Tablet - Standard", /obj/item/modular_computer/tablet/preset/custom_loadout/standard, 50), + new /datum/data/mining_equipment("Digital Tablet - Advanced", /obj/item/modular_computer/tablet/preset/custom_loadout/advanced, 100), + new /datum/data/mining_equipment("Nanopaste Tube", /obj/item/stack/nanopaste, 100), new /datum/data/mining_equipment("Mini-Translocator", /obj/item/perfect_tele/one_beacon, 120), - new /datum/data/mining_equipment("AR-V Glasses", /obj/item/clothing/glasses/omnihud/exp, 350), + //new /datum/data/mining_equipment("UAV - Recon Skimmer", /obj/item/uav, 400), + new /datum/data/mining_equipment("AR-V Glasses", /obj/item/clothing/glasses/omnihud/exp, 350), new /datum/data/mining_equipment("Space Cash", /obj/item/spacecash/c100, 100), - new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 250), + new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 250), new /datum/data/mining_equipment("Luxury Shelter Capsule", /obj/item/survivalcapsule/luxury, 310), new /datum/data/mining_equipment("Industrial Equipment - Phoron Bore", /obj/item/gun/magnetic/matfed, 300), - new /datum/data/mining_equipment("Colonial Recce Pack", /obj/item/storage/lockbox/colonial, 350), - new /datum/data/mining_equipment("Gateway Guardian Pack", /obj/item/storage/lockbox/gateway, 800), - new /datum/data/mining_equipment("Cyan Posse Pack", /obj/item/storage/lockbox/cowboy, 800), - new /datum/data/mining_equipment("Conscript Pack", /obj/item/storage/lockbox/russian, 250), - new /datum/data/mining_equipment("Holy Crusade Pack", /obj/item/storage/lockbox/crusade, 200), - new /datum/data/mining_equipment("Maniple Pack", /obj/item/storage/lockbox/maniple, 200), - new /datum/data/mining_equipment("Away Team Pack", /obj/item/storage/lockbox/away, 550), + new /datum/data/mining_equipment("Colonial Recce Pack", /obj/item/storage/lockbox/colonial, 350), + new /datum/data/mining_equipment("Gateway Guardian Pack", /obj/item/storage/lockbox/gateway, 800), + new /datum/data/mining_equipment("Cyan Posse Pack", /obj/item/storage/lockbox/cowboy, 800), + new /datum/data/mining_equipment("Conscript Pack", /obj/item/storage/lockbox/russian, 250), + new /datum/data/mining_equipment("Holy Crusade Pack", /obj/item/storage/lockbox/crusade, 200), + new /datum/data/mining_equipment("Maniple Pack", /obj/item/storage/lockbox/maniple, 200), + new /datum/data/mining_equipment("Away Team Pack", /obj/item/storage/lockbox/away, 550), new /datum/data/mining_equipment("Survey Tools - Shovel", /obj/item/shovel, 40), new /datum/data/mining_equipment("Survey Tools - Mechanical Trap", /obj/item/beartrap, 50), new /datum/data/mining_equipment("Defense Equipment - Smoke Bomb",/obj/item/grenade/smokebomb, 10), @@ -54,11 +55,11 @@ new /datum/data/mining_equipment("Defense Equipment - Sentry Drone Deployer",/obj/item/grenade/spawnergrenade/ward, 150), new /datum/data/mining_equipment("Defense Equipment - Steel Machete", /obj/item/material/knife/machete, 75), new /datum/data/mining_equipment("Defense Equipment - Kinetic Dagger", /obj/item/kinetic_crusher/dagger, 75), - new /datum/data/mining_equipment("Defense Equipment - Marksman Box", /obj/item/gunbox/marksman, 1500), + new /datum/data/mining_equipment("Defense Equipment - Marksman Box", /obj/item/gunbox/marksman, 1500), new /datum/data/mining_equipment("Fishing Net", /obj/item/material/fishing_net, 50), new /datum/data/mining_equipment("Titanium Fishing Rod", /obj/item/material/fishing_rod/modern, 100), new /datum/data/mining_equipment("Durasteel Fishing Rod", /obj/item/material/fishing_rod/modern/strong, 750), - new /datum/data/mining_equipment("Bar Shelter Capsule", /obj/item/survivalcapsule/luxurybar, 1000) + new /datum/data/mining_equipment("Bar Shelter Capsule", /obj/item/survivalcapsule/luxurybar, 1000) ) //VOREStation Edit End diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index a6de7c63427..d214d79564d 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -133,6 +133,10 @@ var/list/slot_equipment_priority = list( \ /mob/proc/is_holding_item_of_type(typepath) return FALSE +// Override for your specific mob's hands or lack thereof. +/mob/proc/get_all_held_items() + return list() + //Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success. /mob/proc/put_in_l_hand(var/obj/item/W) if(lying || !istype(W)) diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm index af6c42644a5..9c754f3b6fd 100644 --- a/code/modules/mob/living/bot/cleanbot.dm +++ b/code/modules/mob/living/bot/cleanbot.dm @@ -14,14 +14,14 @@ botcard_access = list(access_janitor) catalogue_data = list(/datum/category_item/catalogue/technology/bot/cleanbot) - locked = 0 // Start unlocked so roboticist can set them to patrol. - wait_if_pulled = 1 + locked = FALSE //Starts unlocked so roboticist can set them to patrol. + wait_if_pulled = TRUE min_target_dist = 0 - var/cleaning = 0 - var/screwloose = 0 - var/oddbutton = 0 - var/blood = 1 + var/cleaning = FALSE + var/wet_floors = FALSE + var/spray_blood = FALSE + var/blood = TRUE var/list/target_types = list() /mob/living/bot/cleanbot/Initialize(mapload) @@ -29,16 +29,16 @@ get_targets() /mob/living/bot/cleanbot/handleIdle() - if(!screwloose && !oddbutton && prob(2)) + if(!wet_floors && !spray_blood && prob(2)) custom_emote(2, "makes an excited booping sound!") - playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0) + playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, FALSE) - if(screwloose && prob(5)) // Make a mess + if(wet_floors && prob(5)) // Make a mess if(istype(loc, /turf/simulated)) var/turf/simulated/T = loc T.wet_floor() - if(oddbutton && prob(5)) // Make a big mess + if(spray_blood && prob(5)) // Make a big mess visible_message("Something flies out of [src]. It seems to be acting oddly.") var/obj/effect/decal/cleanable/blood/gibs/gib = new /obj/effect/decal/cleanable/blood/gibs(loc) // TODO - I have a feeling weakrefs will not work in ignore_list, verify this ~Leshana @@ -81,11 +81,11 @@ /mob/living/bot/cleanbot/confirmTarget(var/obj/effect/decal/cleanable/D) if(!..()) - return 0 + return FALSE for(var/T in target_types) if(istype(D, T)) - return 1 - return 0 + return TRUE + return FALSE /mob/living/bot/cleanbot/handleAdjacentTarget() if(get_turf(target) == src.loc) @@ -101,7 +101,7 @@ if(D.loc != loc) return - busy = 1 + busy = TRUE if(prob(20)) custom_emote(2, "begins to clean up \the [D]") update_icons() @@ -109,18 +109,18 @@ if(do_after(src, cleantime)) if(istype(loc, /turf/simulated)) var/turf/simulated/f = loc - f.dirt = 0 + f.dirt = FALSE if(!D) return qdel(D) if(D == target) target = null - busy = 0 + busy = FALSE update_icons() /mob/living/bot/cleanbot/explode() - on = 0 - visible_message("[src] blows apart!") + on = FALSE + visible_message(SPAN_DANGER("[src] blows apart!")) var/turf/Tsec = get_turf(src) new /obj/item/reagent_containers/glass/bucket(Tsec) @@ -141,57 +141,71 @@ icon_state = "cleanbot[on]" /mob/living/bot/cleanbot/attack_hand(var/mob/user) - var/dat - dat += "Automatic Station Cleaner v1.0

" - dat += "Status: [on ? "On" : "Off"]
" - dat += "Behaviour controls are [locked ? "locked" : "unlocked"]
" - dat += "Maintenance panel is [open ? "opened" : "closed"]" - if(!locked || issilicon(user)) - dat += "
Cleans Blood: [blood ? "Yes" : "No"]
" - if(GLOB.using_map.bot_patrolling) - dat += "
Patrol station: [will_patrol ? "Yes" : "No"]
" - if(open && !locked) - dat += "Odd looking screw twiddled: [screwloose ? "Yes" : "No"]
" - dat += "Weird button pressed: [oddbutton ? "Yes" : "No"]" + ui_interact(user) - user << browse("Cleaner v1.0 controls[dat]", "window=autocleaner") - onclose(user, "autocleaner") - return +/mob/living/bot/cleanbot/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Cleanbot", name) + ui.open() -/mob/living/bot/cleanbot/Topic(href, href_list) +/mob/living/bot/cleanbot/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + data["on"] = on + data["open"] = open + data["locked"] = locked + + data["blood"] = blood + data["patrol"] = will_patrol + + data["wet_floors"] = wet_floors + data["spray_blood"] = spray_blood + data["version"] = "v2.0" + return data + +/mob/living/bot/cleanbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return + return TRUE + usr.set_machine(src) - add_fingerprint(usr) - switch(href_list["operation"]) + + switch(action) if("start") if(on) turn_off() else turn_on() + . = TRUE + if("blood") blood = !blood get_targets() + . = TRUE + if("patrol") will_patrol = !will_patrol patrol_path = null - if("screw") - screwloose = !screwloose - to_chat(usr, "You twiddle the screw.") - if("oddbutton") - oddbutton = !oddbutton - to_chat(usr, "You press the weird button.") - attack_hand(usr) + . = TRUE + + if("wet_floors") + wet_floors = !wet_floors + to_chat(usr, SPAN_NOTICE("You twiddle the screw.")) + . = TRUE + + if("spray_blood") + spray_blood = !spray_blood + to_chat(usr, SPAN_NOTICE("You press the weird button.")) + . = TRUE /mob/living/bot/cleanbot/emag_act(var/remaining_uses, var/mob/user) . = ..() - if(!screwloose || !oddbutton) + if(!wet_floors || !spray_blood) if(user) - to_chat(user, "The [src] buzzes and beeps.") - playsound(src.loc, 'sound/machines/buzzbeep.ogg', 50, 0) - oddbutton = 1 - screwloose = 1 - return 1 + to_chat(user, SPAN_NOTICE("The [src] buzzes and beeps.")) + playsound(src.loc, 'sound/machines/buzzbeep.ogg', 50, FALSE) + spray_blood = TRUE + wet_floors = TRUE + return TRUE /mob/living/bot/cleanbot/proc/get_targets() target_types = list() diff --git a/code/modules/mob/living/bot/edCLNbot.dm b/code/modules/mob/living/bot/edCLNbot.dm index 86a9bd50778..5dd258f7389 100644 --- a/code/modules/mob/living/bot/edCLNbot.dm +++ b/code/modules/mob/living/bot/edCLNbot.dm @@ -15,15 +15,15 @@ botcard_access = list(access_janitor, access_maint_tunnels) catalogue_data = list(/datum/category_item/catalogue/technology/bot/cleanbot/edCLN) - locked = 0 // Start unlocked so roboticist can set them to patrol. - wait_if_pulled = 0 // One big boi. + locked = FALSE //Starts unlocked so roboticist can set them to patrol. + wait_if_pulled = FALSE //One big boi. min_target_dist = 0 patrol_speed = 3 target_speed = 6 - cleaning = 0 - blood = 0 + cleaning = FALSE + blood = FALSE var/red_switch = 0 var/blue_switch = 0 var/green_switch = 0 @@ -81,53 +81,34 @@ qdel(src) return -/mob/living/bot/cleanbot/edCLN/attack_hand(var/mob/user) - var/dat - usr.set_machine(src) - add_fingerprint(usr) +/mob/living/bot/cleanbot/edCLN/ui_data(mob/user) + var/list/data = ..() + data["version"] = "v3.0" + data["rgbpanel"] = TRUE + data["red_switch"] = red_switch + data["green_switch"] = green_switch + data["blue_switch"] = blue_switch + return data - dat += "Automatic Station Cleaner v2.0

" - dat += "Status: [on ? "On" : "Off"]
" - dat += "Behaviour controls are [locked ? "locked" : "unlocked"]
" - dat += "Maintenance panel is [open ? "opened" : "closed"]" - if(!locked || issilicon(user)) - dat += "
Cleans Blood: [blood ? "Yes" : "No"]
" - if(GLOB.using_map.bot_patrolling) - dat += "
Patrol station: [will_patrol ? "Yes" : "No"]
" - if(open && !locked) - dat += "
Red Switch: [red_switch ? "On" : "Off"]
" - dat += "
Green Switch: [green_switch ? "On" : "Off"]
" - dat += "
Blue Switch: [blue_switch ? "On" : "Off"]" +/mob/living/bot/cleanbot/edCLN/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE - user << browse("Cleaner v2.0 controls[dat]", "window=autocleaner") - onclose(user, "autocleaner") - return - -/mob/living/bot/cleanbot/edCLN/Topic(href, href_list) - usr.set_machine(src) - add_fingerprint(usr) - switch(href_list["operation"]) - if("start") - if(on) - turn_off() - else - turn_on() - if("blood") - blood = !blood - get_targets() - if("patrol") - will_patrol = !will_patrol - patrol_path = null + switch(action) if("red_switch") red_switch = !red_switch - to_chat(usr, "You flip the red switch [red_switch ? "on" : "off"].") + to_chat(usr, SPAN_NOTICE("You flip the red switch [red_switch ? "on" : "off"].")) + . = TRUE + if("green_switch") - green_switch = !blue_switch - to_chat(usr, "You flip the green switch [green_switch ? "on" : "off"].") + green_switch = !green_switch + to_chat(usr, SPAN_NOTICE("You flip the green switch [green_switch ? "on" : "off"].")) + . = TRUE + if("blue_switch") blue_switch = !blue_switch - to_chat(usr, "You flip the blue switch [blue_switch ? "on" : "off"].") - attack_hand(usr) + to_chat(usr, SPAN_NOTICE("You flip the blue switch [blue_switch ? "on" : "off"].")) + . = TRUE /mob/living/bot/cleanbot/edCLN/emag_act(var/remaining_uses, var/mob/user) . = ..() diff --git a/code/modules/mob/living/bot/farmbot.dm b/code/modules/mob/living/bot/farmbot.dm index bf138677841..8237ed86375 100644 --- a/code/modules/mob/living/bot/farmbot.dm +++ b/code/modules/mob/living/bot/farmbot.dm @@ -17,16 +17,16 @@ icon_state = "farmbot0" health = 50 maxHealth = 50 - req_one_access = list(access_robotics, access_hydroponics, access_xenobiology) //TFF 11/7/19 - adds Xenobio access on behalf of Nalarac + req_one_access = list(access_robotics, access_hydroponics, access_xenobiology) catalogue_data = list(/datum/category_item/catalogue/technology/bot/farmbot) var/action = "" // Used to update icon - var/waters_trays = 1 - var/refills_water = 1 - var/uproots_weeds = 1 - var/replaces_nutriment = 0 - var/collects_produce = 0 - var/removes_dead = 0 + var/waters_trays = TRUE + var/refills_water = TRUE + var/uproots_weeds = TRUE + var/replaces_nutriment = FALSE + var/collects_produce = FALSE + var/removes_dead = FALSE var/obj/structure/reagent_dispensers/watertank/tank /mob/living/bot/farmbot/Initialize(mapload, newTank) @@ -36,77 +36,93 @@ tank = newTank tank.forceMove(src) -/mob/living/bot/farmbot/attack_hand(var/mob/user as mob) +/mob/living/bot/farmbot/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Farmbot", name) + ui.open() + +/mob/living/bot/farmbot/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + + data["on"] = on + data["tank"] = !!tank + if(tank) + data["tankVolume"] = tank.reagents.total_volume + data["tankMaxVolume"] = tank.reagents.maximum_volume + data["locked"] = locked + + data["waters_trays"] = null + data["refills_water"] = null + data["uproots_weeds"] = null + data["replaces_nutriment"] = null + data["collects_produce"] = null + data["removes_dead"] = null + + if(!locked) + data["waters_trays"] = waters_trays + data["refills_water"] = refills_water + data["uproots_weeds"] = uproots_weeds + data["replaces_nutriment"] = replaces_nutriment + data["collects_produce"] = collects_produce + data["removes_dead"] = removes_dead + + return data + +/mob/living/bot/farmbot/attack_hand(mob/user) . = ..() if(.) return - var/dat = "" - dat += "Automatic Hyrdoponic Assisting Unit v1.0

" - dat += "Status: [on ? "On" : "Off"]
" - dat += "Water Tank: " - if (tank) - dat += "[tank.reagents.total_volume]/[tank.reagents.maximum_volume]" - else - dat += "Error: Watertank not found" - dat += "
Behaviour controls are [locked ? "locked" : "unlocked"]
" - if(!locked) - dat += "Watering controls:
" - dat += "Water plants : [waters_trays ? "Yes" : "No"]
" - dat += "Refill watertank : [refills_water ? "Yes" : "No"]
" - dat += "
Weeding controls:
" - dat += "Weed plants: [uproots_weeds ? "Yes" : "No"]
" - dat += "
Nutriment controls:
" - dat += "Replace fertilizer: [replaces_nutriment ? "Yes" : "No"]
" - /*VOREStation Removal - No whole-job lag-bot automation. - dat += "
Plant controls:
" - dat += "Collect produce: [collects_produce ? "Yes" : "No"]
" - dat += "Remove dead plants: [removes_dead ? "Yes" : "No"]
" - */ - dat += "
" - - user << browse("Farmbot v1.0 controls[dat]", "window=autofarm") - onclose(user, "autofarm") - return + ui_interact(user) /mob/living/bot/farmbot/emag_act(var/remaining_charges, var/mob/user) . = ..() if(!emagged) if(user) - to_chat(user, "You short out [src]'s plant identifier circuits.") + to_chat(user, SPAN_NOTICE("You short out [src]'s plant identifier circuits.")) spawn(rand(30, 50)) - visible_message("[src] buzzes oddly.") - emagged = 1 - return 1 + visible_message(SPAN_WARNING("[src] buzzes oddly.")) + emagged = TRUE + return TRUE -/mob/living/bot/farmbot/Topic(href, href_list) +/mob/living/bot/farmbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return - usr.machine = src - add_fingerprint(usr) - if((href_list["power"]) && (access_scanner.allowed(usr))) - if(on) - turn_off() - else - turn_on() + return TRUE + + switch(action) + if("power") + if(!access_scanner.allowed(usr)) + return FALSE + if(on) + turn_off() + else + turn_on() + . = TRUE if(locked) - return + return TRUE - if(href_list["water"]) - waters_trays = !waters_trays - else if(href_list["refill"]) - refills_water = !refills_water - else if(href_list["weed"]) - uproots_weeds = !uproots_weeds - else if(href_list["replacenutri"]) - replaces_nutriment = !replaces_nutriment - else if(href_list["collect"]) - collects_produce = !collects_produce - else if(href_list["removedead"]) - removes_dead = !removes_dead - - attack_hand(usr) - return + switch(action) + if("water") + waters_trays = !waters_trays + . = TRUE + if("refill") + refills_water = !refills_water + . = TRUE + if("weed") + uproots_weeds = !uproots_weeds + . = TRUE + if("replacenutri") + replaces_nutriment = !replaces_nutriment + . = TRUE + // VOREStation Edit: No automatic hydroponics + // if("collect") + // collects_produce = !collects_produce + // . = TRUE + // if("removedead") + // removes_dead = !removes_dead + // . = TRUE + // VOREStation Edit End /mob/living/bot/farmbot/update_icons() if(on && action) @@ -114,13 +130,10 @@ else icon_state = "farmbot[on]" - /mob/living/bot/farmbot/handleRegular() if(emagged && prob(1)) flick("farmbot_broke", src) - - /mob/living/bot/farmbot/handleAdjacentTarget() UnarmedAttack(target) @@ -138,6 +151,7 @@ for(var/obj/structure/sink/source in view(7, src)) target = source return + /mob/living/bot/farmbot/calcTargetPath() // We need to land NEXT to the tray, because the tray itself is impassable for(var/trayDir in list(NORTH, SOUTH, EAST, WEST)) target_path = AStar(get_turf(loc), get_step(get_turf(target), trayDir), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, max_target_dist, id = botcard) diff --git a/code/modules/mob/living/bot/floorbot.dm b/code/modules/mob/living/bot/floorbot.dm index c27254062f8..a2c02fc2e9a 100644 --- a/code/modules/mob/living/bot/floorbot.dm +++ b/code/modules/mob/living/bot/floorbot.dm @@ -19,16 +19,17 @@ icon_state = "floorbot" base_icon_state = "toolbox" req_one_access = list(access_robotics, access_construction) - wait_if_pulled = 1 + + wait_if_pulled = TRUE min_target_dist = 0 catalogue_data = list(/datum/category_item/catalogue/technology/bot/floorbot) var/amount = 10 // 1 for tile, 2 for lattice var/maxAmount = 60 var/tilemake = 0 // When it reaches 100, bot makes a tile - var/improvefloors = 0 - var/eattiles = 0 - var/maketiles = 0 + var/improvefloors = FALSE + var/eattiles = FALSE + var/maketiles = FALSE var/targetdirection = null var/floor_build_type = /decl/flooring/tiling // Basic steel floor. var/toolbox = /obj/item/storage/toolbox/mechanical @@ -58,70 +59,81 @@ add_overlay("[base_icon_state]-[on]") -/mob/living/bot/floorbot/attack_hand(var/mob/user) - user.set_machine(src) - var/list/dat = list() - dat += "Automatic Station Floor Repairer v1.0

" - dat += "Status: [src.on ? "On" : "Off"]
" - dat += "Maintenance panel is [open ? "opened" : "closed"]
" - dat += "Tiles left: [amount]
" - dat += "Behvaiour controls are [locked ? "locked" : "unlocked"]
" +/mob/living/bot/floorbot/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Floorbot", name) + ui.open() + +/mob/living/bot/floorbot/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + + data["on"] = on + data["open"] = open + data["locked"] = locked + + data["amount"] = amount + + data["possible_bmode"] = list("NORTH", "EAST", "SOUTH", "WEST") + + data["improvefloors"] = null + data["eattiles"] = null + data["maketiles"] = null + data["bmode"] = null + if(!locked || issilicon(user)) - dat += "Improves floors: [improvefloors ? "Yes" : "No"]
" - dat += "Finds tiles: [eattiles ? "Yes" : "No"]
" - dat += "Make singles pieces of metal into tiles when empty: [maketiles ? "Yes" : "No"]
" - var/bmode - if(targetdirection) - bmode = dir2text(targetdirection) - else - bmode = "Disabled" - dat += "

Bridge Mode : [bmode]
" - var/datum/browser/popup = new(user, "autorepair", "Repairbot v1.1 controls") - popup.set_content(jointext(dat,null)) - popup.open() - return + data["improvefloors"] = improvefloors + data["eattiles"] = eattiles + data["maketiles"] = maketiles + data["bmode"] = dir2text(targetdirection) + + return data + +/mob/living/bot/floorbot/attack_hand(var/mob/user) + ui_interact(user) /mob/living/bot/floorbot/emag_act(var/remaining_charges, var/mob/user) . = ..() if(!emagged) - emagged = 1 + emagged = TRUE if(user) - to_chat(user, "The [src] buzzes and beeps.") - playsound(src.loc, 'sound/machines/buzzbeep.ogg', 50, 0) - return 1 + to_chat(user, SPAN_NOTICE("The [src] buzzes and beeps.")) + playsound(src.loc, 'sound/machines/buzzbeep.ogg', 50, FALSE) + return TRUE -/mob/living/bot/floorbot/Topic(href, href_list) +/mob/living/bot/floorbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return - usr.set_machine(src) + return TRUE + add_fingerprint(usr) - switch(href_list["operation"]) + + switch(action) if("start") - if (on) + if(on) turn_off() else turn_on() + . = TRUE + + if(locked && !issilicon(usr)) + return + + switch(action) if("improve") improvefloors = !improvefloors + . = TRUE + if("tiles") eattiles = !eattiles + . = TRUE + if("make") maketiles = !maketiles + . = TRUE + if("bridgemode") - switch(targetdirection) - if(null) - targetdirection = 1 - if(1) - targetdirection = 2 - if(2) - targetdirection = 4 - if(4) - targetdirection = 8 - if(8) - targetdirection = null - else - targetdirection = null - attack_hand(usr) + targetdirection = text2dir(params["dir"]) + . = TRUE /mob/living/bot/floorbot/handleRegular() ++tilemake @@ -131,7 +143,7 @@ if(prob(1)) custom_emote(2, "makes an excited beeping sound!") - playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) + playsound(src.loc, 'sound/machines/twobeep.ogg', 50, FALSE) /mob/living/bot/floorbot/handleAdjacentTarget() if(get_turf(target) == src.loc) @@ -407,7 +419,7 @@ created_name = "Floorbot" var/toolbox = /obj/item/storage/toolbox -/obj/item/bot_assembly/floorbot/Initialize() +/obj/item/bot_assembly/floorbot/Initialize(mapload) . = ..() spawn(1) icon_state = "[base_icon_state]-[skin]" diff --git a/code/modules/mob/living/bot/medibot.dm b/code/modules/mob/living/bot/medibot.dm index 204872de339..11898ff5217 100644 --- a/code/modules/mob/living/bot/medibot.dm +++ b/code/modules/mob/living/bot/medibot.dm @@ -1,3 +1,18 @@ +// Medibot Info + +#define MEDIBOT_PANIC_NONE 0 +#define MEDIBOT_PANIC_LOW 15 +#define MEDIBOT_PANIC_MED 35 +#define MEDIBOT_PANIC_HIGH 55 +#define MEDIBOT_PANIC_FUCK 70 +#define MEDIBOT_PANIC_ENDING 90 +#define MEDIBOT_PANIC_END 100 + +#define MEDIBOT_MIN_INJECTION 5 +#define MEDIBOT_MAX_INJECTION 15 +#define MEDIBOT_MIN_HEAL 0.1 +#define MEDIBOT_MAX_HEAL 75 + /datum/category_item/catalogue/technology/bot/medibot name = "Bot - Medibot" desc = "Medibots have become vital additions to hazardous workplaces \ @@ -37,6 +52,16 @@ var/treatment_emag = "toxin" var/declare_treatment = 0 //When attempting to treat a patient, should it notify everyone wearing medhuds? + // Are we tipped over? + var/is_tipped = FALSE + //How panicked we are about being tipped over (why would you do this?) + var/tipped_status = MEDIBOT_PANIC_NONE + //The name we got when we were tipped + var/tipper_name + //The last time we were tipped/righted and said a voice line, to avoid spam + var/last_tipping_action_voice = 0 + + /mob/living/bot/medibot/Initialize(mapload, new_skin) . = ..() skin = new_skin @@ -104,16 +129,17 @@ icon_state = "beebot0" base_icon_state = "beebot" -/mob/living/bot/medibot/apidean/update_icons() - cut_overlays() - if(skin) - add_overlay("[base_icon_state]-[skin]") +/mob/living/bot/medibot/apidean/update_icon_state() + . = ..() if(busy) - icon_state = "beebots" + icon_state = "[base_icon_state]a" else - icon_state = "beebot[on]" + icon_state = "[base_icon_state][on]" /mob/living/bot/medibot/apidean/handleIdle() + if(is_tipped) //Don't handle idle things if we're incapacitated! + return + if(vocal && prob(1)) var/message_options = list( "Bzzz bzzz!" = 'sound/voice/moth/scream_moth.ogg', @@ -125,6 +151,9 @@ playsound(loc, message_options[message], 50, 0) /mob/living/bot/medibot/handleIdle() + if(is_tipped) //Don't handle idle things if we're incapacitated! + return + if(vocal && prob(1)) var/message_options = list( "Radar, put a mask on!" = 'sound/voice/medibot/mradar.ogg', @@ -138,9 +167,11 @@ playsound(loc, message_options[message], 50, 0) /mob/living/bot/medibot/handleAdjacentTarget() + if(is_tipped) //Don't handle targets if we're incapacitated! + return UnarmedAttack(target) -/mob/living/bot/medibot/handlePanic() // Speed modification based on alert level. +/mob/living/bot/medibot/handlePanic() //Speed modification based on alert level. . = 0 switch(get_security_level()) if(SEC_LEVEL_GREEN) @@ -167,6 +198,9 @@ return . /mob/living/bot/medibot/lookForTargets() + if(is_tipped) // Don't look for targets if we're incapacitated! + return + for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient! if(confirmTarget(H)) target = H @@ -206,7 +240,7 @@ var/area/location = get_area(src) GLOB.global_announcer.autosay("[src] is treating [H] in [location]", "[src]", "Medical") busy = TRUE - update_icons() + update_appearance() if(do_mob(src, H, 30)) if(t == 1) reagent_glass.reagents.trans_to_mob(H, injection_amount, CHEM_BLOOD) @@ -242,44 +276,60 @@ playsound(loc, possible_messages[message], 50, FALSE) busy = FALSE - update_icons() + update_appearance() -/mob/living/bot/medibot/attack_hand(var/mob/user) - var/dat - dat += "Automatic Medical Unit v1.0

" - dat += "Status: [on ? "On" : "Off"]
" - dat += "Maintenance panel is [open ? "opened" : "closed"]
" - dat += "Beaker: " - if (reagent_glass) - dat += "Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]" +/mob/living/bot/medibot/attack_hand(mob/living/carbon/human/H) + if(H.a_intent == INTENT_DISARM && !is_tipped) + H.visible_message(SPAN_DANGER("[H] begins tipping over [src]."), SPAN_WARNING("You begin tipping over [src]...")) + + if(world.time > last_tipping_action_voice + 15 SECONDS) + last_tipping_action_voice = world.time // message for tipping happens when we start interacting, message for righting comes after finishing + var/list/messagevoice = list("Hey, wait..." = 'sound/voice/medibot/hey_wait.ogg',"Please don't..." = 'sound/voice/medibot/please_dont.ogg',"I trusted you..." = 'sound/voice/medibot/i_trusted_you.ogg', "Nooo..." = 'sound/voice/medibot/nooo.ogg', "Oh fuck-" = 'sound/voice/medibot/oh_fuck.ogg') + var/message = pick(messagevoice) + say(message) + playsound(src, messagevoice[message], 70, FALSE) + + if(do_after(H, 3 SECONDS, target=src)) + tip_over(H) + + else if(H.a_intent == INTENT_HELP && is_tipped) + H.visible_message(SPAN_NOTICE("[H] begins righting [src]."), SPAN_NOTICE("You begin righting [src]...")) + if(do_after(H, 3 SECONDS, target=src)) + set_right(H) else - dat += "None Loaded" - dat += "
Behaviour controls are [locked ? "locked" : "unlocked"]
" + ui_interact(H) + +/mob/living/bot/medibot/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Medibot", name) + ui.open() + +/mob/living/bot/medibot/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + data["on"] = on + data["open"] = open + data["beaker"] = FALSE + if(reagent_glass) + data["beaker"] = TRUE + data["beaker_total"] = reagent_glass.reagents.total_volume + data["beaker_max"] = reagent_glass.reagents.maximum_volume + data["locked"] = locked + data["heal_threshold"] = null + data["heal_threshold_max"] = MEDIBOT_MAX_HEAL + data["injection_amount_min"] = MEDIBOT_MIN_INJECTION + data["injection_amount"] = null + data["injection_amount_max"] = MEDIBOT_MAX_INJECTION + data["use_beaker"] = null + data["declare_treatment"] = null + data["vocal"] = null if(!locked || issilicon(user)) - dat += "Healing Threshold: " - dat += "-- " - dat += "- " - dat += "[heal_threshold] " - dat += "+ " - dat += "++" - dat += "
" - - dat += "Injection Level: " - dat += "- " - dat += "[injection_amount] " - dat += "+ " - dat += "
" - - dat += "Reagent Source: " - dat += "[use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]
" - - dat += "Treatment report is [declare_treatment ? "on" : "off"]. Toggle
" - - dat += "The speaker switch is [vocal ? "on" : "off"]. Toggle
" - - user << browse("Medibot v1.0 controls[dat]", "window=automed") - onclose(user, "automed") - return + data["heal_threshold"] = heal_threshold + data["injection_amount"] = injection_amount + data["use_beaker"] = use_beaker + data["declare_treatment"] = declare_treatment + data["vocal"] = vocal + return data /mob/living/bot/medibot/attackby(var/obj/item/O, var/mob/user) if(istype(O, /obj/item/reagent_containers/glass)) @@ -298,51 +348,51 @@ else ..() -/mob/living/bot/medibot/Topic(href, href_list) +/mob/living/bot/medibot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return + return TRUE + usr.set_machine(src) - add_fingerprint(usr) - if ((href_list["power"]) && access_scanner.allowed(usr)) - if (on) - turn_off() - else - turn_on() - else if((href_list["adj_threshold"]) && (!locked || issilicon(usr))) - var/adjust_num = text2num(href_list["adj_threshold"]) - heal_threshold += adjust_num - if(heal_threshold <= 0) - heal_threshold = 0.1 - if(heal_threshold > 75) - heal_threshold = 75 + . = TRUE + switch(action) + if("power") + if(!access_scanner.allowed(usr)) + return FALSE + if(on) + turn_off() + else + turn_on() - else if((href_list["adj_inject"]) && (!locked || issilicon(usr))) - var/adjust_num = text2num(href_list["adj_inject"]) - injection_amount += adjust_num - if(injection_amount < 5) - injection_amount = 5 - if(injection_amount > 15) - injection_amount = 15 + if(locked && !issilicon(usr)) + return TRUE - else if((href_list["use_beaker"]) && (!locked || issilicon(usr))) - use_beaker = !use_beaker + switch(action) + if("adj_threshold") + heal_threshold = clamp(text2num(params["val"]), MEDIBOT_MIN_HEAL, MEDIBOT_MAX_HEAL) + . = TRUE - else if (href_list["eject"] && (!isnull(reagent_glass))) - if(!locked) - reagent_glass.loc = get_turf(src) - reagent_glass = null - else - to_chat(usr, SPAN_NOTICE("You cannot eject the beaker because the panel is locked.")) + if("adj_inject") + injection_amount = clamp(text2num(params["val"]), MEDIBOT_MIN_INJECTION, MEDIBOT_MAX_INJECTION) + . = TRUE - else if ((href_list["togglevoice"]) && (!locked || issilicon(usr))) - vocal = !vocal + if("use_beaker") + use_beaker = !use_beaker + . = TRUE - else if ((href_list["declaretreatment"]) && (!locked || issilicon(usr))) - declare_treatment = !declare_treatment + if("eject") + if(reagent_glass) + reagent_glass.forceMove(get_turf(src)) + reagent_glass = null + . = TRUE - attack_hand(usr) - return + if("togglevoice") + vocal = !vocal + . = TRUE + + if("declaretreatment") + declare_treatment = !declare_treatment + . = TRUE /mob/living/bot/medibot/emag_act(var/remaining_uses, var/mob/user) . = ..() @@ -355,7 +405,7 @@ busy = FALSE emagged = TRUE on = TRUE - update_icons() + update_appearance() . = TRUE ignore_list |= user @@ -382,6 +432,90 @@ s.start() qdel(src) +/mob/living/bot/medibot/handleRegular() + . = ..() + + if(is_tipped) + handle_panic() + return + +/mob/living/bot/medibot/proc/tip_over(mob/user) + playsound(src, 'sound/machines/warning-buzzer.ogg', 50) + user.visible_message(SPAN_DANGER("[user] tips over [src]!"), SPAN_DANGER("You tip [src] over!")) + is_tipped = TRUE + tipper_name = user.name + var/matrix/mat = transform + transform = mat.Turn(180) + +/mob/living/bot/medibot/proc/set_right(mob/user) + var/list/messagevoice + if(user) + user.visible_message(SPAN_NOTICE("[user] sets [src] right-side up!"), SPAN_GREEN("You set [src] right-side up!")) + if(user.name == tipper_name) + messagevoice = list("I forgive you." = 'sound/voice/medibot/forgive.ogg') + else + messagevoice = list("Thank you!" = 'sound/voice/medibot/thank_you.ogg', "You are a good person." = 'sound/voice/medibot/youre_good.ogg') + else + visible_message(SPAN_NOTICE("[src] manages to [pick("writhe", "wriggle", "wiggle")] enough to right itself.")) + messagevoice = list("Fuck you." = 'sound/voice/medibot/fuck_you.ogg', "Your behavior has been reported, have a nice day." = 'sound/voice/medibot/reported.ogg') + + tipper_name = null + if(world.time > last_tipping_action_voice + 15 SECONDS) + last_tipping_action_voice = world.time + var/message = pick(messagevoice) + say(message) + playsound(src, messagevoice[message], 70) + tipped_status = MEDIBOT_PANIC_NONE + is_tipped = FALSE + transform = matrix() + +// if someone tipped us over, check whether we should ask for help or just right ourselves eventually +/mob/living/bot/medibot/proc/handle_panic() + tipped_status++ + var/list/messagevoice + switch(tipped_status) + if(MEDIBOT_PANIC_LOW) + messagevoice = list("I require assistance." = 'sound/voice/medibot/i_require_asst.ogg') + if(MEDIBOT_PANIC_MED) + messagevoice = list("Please put me back." = 'sound/voice/medibot/please_put_me_back.ogg') + if(MEDIBOT_PANIC_HIGH) + messagevoice = list("Please, I am scared!" = 'sound/voice/medibot/please_im_scared.ogg') + if(MEDIBOT_PANIC_FUCK) + messagevoice = list("I don't like this, I need help!" = 'sound/voice/medibot/dont_like.ogg', "This hurts, my pain is real!" = 'sound/voice/medibot/pain_is_real.ogg') + if(MEDIBOT_PANIC_ENDING) + messagevoice = list("Is this the end?" = 'sound/voice/medibot/is_this_the_end.ogg', "Nooo!" = 'sound/voice/medibot/nooo.ogg') + if(MEDIBOT_PANIC_END) + GLOB.global_announcer.autosay("PSYCH ALERT: Crewmember [tipper_name] recorded displaying antisocial tendencies torturing bots in [get_area(src)]. Please schedule psych evaluation.", "[src]", "Medical") + set_right() // strong independent medibot + + // if(prob(tipped_status)) // Commented out pending introduction of jitter stuff from /tg/ + // do_jitter_animation(tipped_status * 0.1) + + if(messagevoice) + var/message = pick(messagevoice) + say(message) + playsound(src, messagevoice[message], 70) + else if(prob(tipped_status * 0.2)) + playsound(src, 'sound/machines/warning-buzzer.ogg', 30, extrarange=-2) + +/mob/living/bot/medibot/examine(mob/user) + . = ..() + if(tipped_status == MEDIBOT_PANIC_NONE) + return + + switch(tipped_status) + if(MEDIBOT_PANIC_NONE to MEDIBOT_PANIC_LOW) + . += "It appears to be tipped over, and is quietly waiting for someone to set it right." + if(MEDIBOT_PANIC_LOW to MEDIBOT_PANIC_MED) + . += "It is tipped over and requesting help." + //Now we humanize the Medibot as a they, not an it. FEEL THE GUILT! + if(MEDIBOT_PANIC_MED to MEDIBOT_PANIC_HIGH) + . += "They are tipped over and appear visibly distressed." + if(MEDIBOT_PANIC_HIGH to MEDIBOT_PANIC_FUCK) + . += SPAN_WARNING("They are tipped over and visibly panicking!") + if(MEDIBOT_PANIC_FUCK to INFINITY) + . += SPAN_BOLDWARNING("They are freaking out from being tipped over!") + /mob/living/bot/medibot/confirmTarget(var/mob/living/carbon/human/H) if(!..()) return FALSE @@ -471,7 +605,7 @@ var/healthanalyzer = /obj/item/healthanalyzer var/firstaid = /obj/item/storage/firstaid -/obj/item/bot_assembly/medibot/Initialize() +/obj/item/bot_assembly/medibot/Initialize(mapload) . = ..() spawn(1) if(skin) @@ -505,3 +639,12 @@ S.healthanalyzer = healthanalyzer user.drop_from_inventory(src) qdel(src) + +// Undefine these. +#undef MEDIBOT_PANIC_NONE +#undef MEDIBOT_PANIC_LOW +#undef MEDIBOT_PANIC_MED +#undef MEDIBOT_PANIC_HIGH +#undef MEDIBOT_PANIC_FUCK +#undef MEDIBOT_PANIC_ENDING +#undef MEDIBOT_PANIC_END diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm index 6f3ac1b7496..467254e7730 100644 --- a/code/modules/mob/living/bot/secbot.dm +++ b/code/modules/mob/living/bot/secbot.dm @@ -129,65 +129,93 @@ else set_light(0) -/mob/living/bot/secbot/attack_hand(var/mob/user) - user.set_machine(src) - var/list/dat = list() - dat += "Automatic Security Unit

" - dat += "Status: [on ? "On" : "Off"]
" - dat += "Behaviour controls are [locked ? "locked" : "unlocked"]
" - dat += "Maintenance panel is [open ? "opened" : "closed"]" +/mob/living/bot/secbot/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Secbot", name) + ui.open() + +/mob/living/bot/secbot/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + + data["on"] = on + data["open"] = open + data["locked"] = locked + + data["idcheck"] = null + data["check_records"] = null + data["check_arrest"] = null + data["arrest_type"] = null + data["declare_arrests"] = null + data["will_patrol"] = null + if(!locked || issilicon(user)) - dat += "
Check for Weapon Authorization: [idcheck ? "Yes" : "No"]
" - dat += "Check Security Records: [check_records ? "Yes" : "No"]
" - dat += "Check Arrest Status: [check_arrest ? "Yes" : "No"]
" - dat += "Operating Mode: [arrest_type ? "Detain" : "Arrest"]
" - dat += "Report Arrests: [declare_arrests ? "Yes" : "No"]
" + data["idcheck"] = idcheck + data["check_records"] = check_records + data["check_arrest"] = check_arrest + data["arrest_type"] = arrest_type + data["declare_arrests"] = declare_arrests if(GLOB.using_map.bot_patrolling) - dat += "Auto Patrol: [will_patrol ? "On" : "Off"]" - var/datum/browser/popup = new(user, "autosec", "Securitron controls") - popup.set_content(jointext(dat,null)) - popup.open() + data["will_patrol"] = will_patrol -/mob/living/bot/secbot/Topic(href, href_list) + return data + +/mob/living/bot/secbot/attack_hand(var/mob/user) + ui_interact(user) + +/mob/living/bot/secbot/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) if(..()) - return + return TRUE - usr.set_machine(src) - add_fingerprint(usr) + switch(action) + if("power") + if(!access_scanner.allowed(usr)) + return FALSE + if(on) + turn_off() + else + turn_on() + . = TRUE - if((href_list["power"]) && (access_scanner.allowed(usr))) - if(on) - turn_off() - else - turn_on() - return + if(locked && !issilicon(usr)) + return TRUE - switch(href_list["operation"]) + switch(action) if("idcheck") idcheck = !idcheck + . = TRUE + if("ignorerec") check_records = !check_records + . = TRUE + if("ignorearr") check_arrest = !check_arrest + . = TRUE + if("switchmode") arrest_type = !arrest_type + . = TRUE + if("patrol") will_patrol = !will_patrol + . = TRUE + if("declarearrests") declare_arrests = !declare_arrests - attack_hand(usr) + . = TRUE /mob/living/bot/secbot/emag_act(var/remaining_uses, var/mob/user) . = ..() if(!emagged) if(user) - to_chat(user, "\The [src] buzzes and beeps.") + to_chat(user, SPAN_NOTICE("\The [src] buzzes and beeps.")) emagged = TRUE patrol_speed = 3 target_speed = 4 return TRUE else - to_chat(user, "\The [src] is already corrupt.") + to_chat(user, SPAN_NOTICE("\The [src] is already corrupt.")) /mob/living/bot/secbot/attackby(var/obj/item/O, var/mob/user) var/curhealth = health diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index d435d9e7b1d..e27f5a56de9 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -417,7 +417,7 @@ BITSET(hud_updateflag, WANTED_HUD) if(istype(usr,/mob/living/carbon/human)) var/mob/living/carbon/human/U = usr - U.handle_regular_hud_updates() + U.handle_hud_list() if(istype(usr,/mob/living/silicon/robot)) var/mob/living/silicon/robot/U = usr U.handle_regular_hud_updates() diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index c5f25543c4c..7ecbbf322fd 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -89,7 +89,7 @@ if(!client) species.handle_npc(src) - if(!handle_some_updates()) + if(skip_some_updates()) return //We go ahead and process them 5 times for HUD images and other stuff though. //Update our name based on whether our face is obscured/disfigured @@ -97,10 +97,10 @@ pulse = handle_pulse() -/mob/living/carbon/human/proc/handle_some_updates() +/mob/living/carbon/human/proc/skip_some_updates() if(life_tick > 5 && timeofdeath && (timeofdeath < 5 || world.time - timeofdeath > 6000)) //We are long dead, or we're junk mobs spawned like the clowns on the clown shuttle - return 0 - return 1 + return TRUE + return FALSE /mob/living/carbon/human/breathe() if(!inStasisNow()) @@ -999,8 +999,8 @@ //DO NOT CALL handle_statuses() from this proc, it's called from living/Life() as long as this returns a true value. /mob/living/carbon/human/handle_regular_UI_updates() - if(!handle_some_updates()) - return 0 + if(skip_some_updates()) + return FALSE if(status_flags & GODMODE) return 0 @@ -1464,11 +1464,12 @@ if(machine) var/viewflags = machine.check_eye(src) - machine.apply_visual(src) if(viewflags < 0) reset_view(null, 0) - else if(viewflags) + else if(viewflags && !looking_elsewhere) sight |= viewflags + else + machine.apply_visual(src) else if(eyeobj) if(eyeobj.owner != src) diff --git a/code/modules/mob/living/carbon/human/species/station/alraune.dm b/code/modules/mob/living/carbon/human/species/station/alraune.dm index 811f14599e8..5d867414dd8 100644 --- a/code/modules/mob/living/carbon/human/species/station/alraune.dm +++ b/code/modules/mob/living/carbon/human/species/station/alraune.dm @@ -437,7 +437,7 @@ to_chat(src, "[pick(fruit_gland.empty_message)]") return - var/datum/seed/S = plant_controller.seeds["[fruit_gland.fruit_type]"] + var/datum/seed/S = SSplants.seeds["[fruit_gland.fruit_type]"] S.harvest(usr,0,0,1) var/index = rand(0,2) diff --git a/code/modules/mob/living/carbon/human/species/station/xenomorph_hybrids/hybrid_abilities.dm b/code/modules/mob/living/carbon/human/species/station/xenomorph_hybrids/hybrid_abilities.dm index 8b86c91eb6a..958653124b7 100644 --- a/code/modules/mob/living/carbon/human/species/station/xenomorph_hybrids/hybrid_abilities.dm +++ b/code/modules/mob/living/carbon/human/species/station/xenomorph_hybrids/hybrid_abilities.dm @@ -15,7 +15,7 @@ set category = "Abilities" if(check_alien_ability(10,1,O_RESIN)) - visible_message("[src] has planted some alien weeds!") + visible_message("[src] has planted some alien weeds!") var/obj/O = new /obj/effect/alien/weeds/hybrid(loc) if(O) O.color = "#422649" diff --git a/code/modules/mob/living/carbon/human/species/station/xenomorph_hybrids/hybrid_resin.dm b/code/modules/mob/living/carbon/human/species/station/xenomorph_hybrids/hybrid_resin.dm index 7c4eedbd5b7..fd8df6d67a8 100644 --- a/code/modules/mob/living/carbon/human/species/station/xenomorph_hybrids/hybrid_resin.dm +++ b/code/modules/mob/living/carbon/human/species/station/xenomorph_hybrids/hybrid_resin.dm @@ -45,7 +45,7 @@ if(!check_alien_ability(75,1,O_RESIN)) return - visible_message("[src] spits out a thick purple substance and begins to shape it!", "You shape a [choice].") + visible_message("[src] spits out a thick purple substance and begins to shape it!", "You shape a [choice].") var/obj/O @@ -81,7 +81,7 @@ /obj/structure/bed/hybrid_nest/update_icon() return - + /obj/structure/bed/hybrid_nest/user_unbuckle_mob(mob/living/buckled_mob, mob/user) if(buckled_mob) if(buckled_mob.buckled == src) @@ -300,4 +300,3 @@ plane = TURF_PLANE layer = ABOVE_TURF_LAYER color = "#422649" - diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm index 240b0d74b4e..7761a69fa9a 100644 --- a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm @@ -59,12 +59,12 @@ set category = "Abilities" if (get_dist(src,M) <= 1) - to_chat(src, "You need to be closer.") + to_chat(src, "You need to be closer.") return var/obj/item/organ/internal/xenos/plasmavessel/I = M.internal_organs_by_name[O_PLASMA] if(!istype(I)) - to_chat(src, "Their plasma vessel is missing.") + to_chat(src, "Their plasma vessel is missing.") return var/amount = input("Amount:", "Transfer Plasma to [M]") as num @@ -72,8 +72,8 @@ amount = abs(round(amount)) if(check_alien_ability(amount,0,O_PLASMA)) M.gain_plasma(amount) - to_chat(M, "[src] has transfered [amount] plasma to you.") - to_chat(src, "You have transferred [amount] plasma to [M].") + to_chat(M, "[src] has transfered [amount] plasma to you.") + to_chat(src, "You have transferred [amount] plasma to [M].") return // Queen verbs. @@ -93,7 +93,7 @@ return if(check_alien_ability(75,1,O_EGG)) - visible_message("[src] has laid an egg!") + visible_message("[src] has laid an egg!") new /obj/effect/alien/egg(loc) return @@ -109,7 +109,7 @@ return if(check_alien_ability(500)) - visible_message("[src] begins to twist and contort!", "You begin to evolve!") + visible_message("[src] begins to twist and contort!", "You begin to evolve!") src.set_species("Xenomorph Queen") return @@ -120,7 +120,7 @@ set category = "Abilities" if(check_alien_ability(50,1,O_RESIN)) - visible_message("[src] has planted some alien weeds!") + visible_message("[src] has planted some alien weeds!") var/obj/O = new /obj/effect/alien/weeds/node(loc) if(O) O.color = "#321D37" @@ -141,7 +141,7 @@ if(!check_alien_ability(20,0,O_ACID)) spitting = 0 return - visible_message("[src] spits [spit_name] at \the [A]!", "You spit [spit_name] at \the [A].") + visible_message("[src] spits [spit_name] at \the [A]!", "You spit [spit_name] at \the [A].") var/obj/item/projectile/P = new spit_projectile(get_turf(src)) P.firer = src P.old_style_target(A) @@ -154,7 +154,7 @@ set category = "Abilities" if(!(O in oview(1))) - to_chat(src, "[O] is too far away.") + to_chat(src, "[O] is too far away.") return // OBJ CHECK @@ -175,12 +175,12 @@ cannot_melt = 1 if(cannot_melt) - to_chat(src, "You cannot dissolve this object.") + to_chat(src, "You cannot dissolve this object.") return if(check_alien_ability(200,0,O_ACID)) new /obj/effect/alien/acid(get_turf(O), O) - visible_message("[src] vomits globs of vile stuff all over [O]. It begins to sizzle and melt under the bubbling mess of acid!") + visible_message("[src] vomits globs of vile stuff all over [O]. It begins to sizzle and melt under the bubbling mess of acid!") return @@ -190,7 +190,7 @@ set category = "Abilities" if(spitting) - to_chat(src, "You stop preparing to spit.") + to_chat(src, "You stop preparing to spit.") spitting = 0 return @@ -203,7 +203,7 @@ spitting = 1 spit_projectile = /obj/item/projectile/energy/neurotoxin spit_name = "neurotoxin" - to_chat(src, "You prepare to spit neurotoxin.") + to_chat(src, "You prepare to spit neurotoxin.") /mob/living/carbon/human/proc/acidspit() set name = "Toggle Acid Spit (50)" @@ -211,7 +211,7 @@ set category = "Abilities" if(spitting) - to_chat(src, "You stop preparing to spit.") + to_chat(src, "You stop preparing to spit.") spitting = 0 return @@ -224,7 +224,7 @@ spitting = 1 spit_projectile = /obj/item/projectile/energy/acid spit_name = "acid" - to_chat(src, "You prepare to spit acid.") + to_chat(src, "You prepare to spit acid.") /mob/living/carbon/human/proc/resin() // -- TLE set name = "Secrete Resin (75)" @@ -238,7 +238,7 @@ if(!check_alien_ability(75,1,O_RESIN)) return - visible_message("[src] vomits up a thick purple substance and begins to shape it!", "You shape a [choice].") + visible_message("[src] vomits up a thick purple substance and begins to shape it!", "You shape a [choice].") var/obj/O diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 7b255c3414c..213bb26da83 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -170,17 +170,15 @@ if(ear_damage < 100) adjustEarDamage(-0.05,-1) -//this handles hud updates. Calls update_vision() and handle_hud_icons() /mob/living/handle_regular_hud_updates() if(!client) - return 0 + return FALSE ..() - handle_vision() handle_darksight() handle_hud_icons() - return 1 + return TRUE /mob/living/proc/update_sight() if(!seedarkness) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm index 5dd6d9c280d..b973f4a2f3d 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -7,23 +7,24 @@ /obj/machinery/drone_fabricator name = "drone fabricator" desc = "A large automated factory for producing maintenance drones." + icon = 'icons/obj/machines/fabricators/industrial_fab.dmi' + icon_state = "industrial" + base_icon_state = "industrial" + appearance_flags = 0 - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE use_power = USE_POWER_IDLE idle_power_usage = 20 active_power_usage = 5000 - + var/printing = FALSE var/fabricator_tag = "Upper Level" var/drone_progress = 0 var/produce_drones = 2 var/time_last_drone = 500 var/drone_type = /mob/living/silicon/robot/drone - icon = 'icons/obj/machines/drone_fab.dmi' - icon_state = "drone_fab_idle" - /obj/machinery/drone_fabricator/derelict name = "construction drone fabricator" fabricator_tag = "Upper Level Construction" @@ -34,31 +35,40 @@ fabricator_tag = "Upper Level Mining" drone_type = /mob/living/silicon/robot/drone/mining -/obj/machinery/drone_fabricator/power_change() - ..() - if (stat & NOPOWER) - icon_state = "drone_fab_nopower" +/obj/machinery/drone_fabricator/update_icon_state() + . = ..() + if(stat & NOPOWER || !produce_drones) + icon_state = "[base_icon_state]-off" + else if(printing) + icon_state = "[base_icon_state]-active" + else + icon_state = base_icon_state + +/obj/machinery/drone_fabricator/update_overlays() + . = ..() + cut_overlays() + if(panel_open) + add_overlay("[base_icon_state]-panel") /obj/machinery/drone_fabricator/process(delta_time) if(SSticker.current_state < GAME_STATE_PLAYING) return - if(stat & NOPOWER || !produce_drones) - if(icon_state != "drone_fab_nopower") icon_state = "drone_fab_nopower" - return - if(drone_progress >= 100) - icon_state = "drone_fab_idle" + printing = FALSE + update_appearance() return - icon_state = "drone_fab_active" + printing = TRUE var/elapsed = world.time - time_last_drone drone_progress = round((elapsed/config_legacy.drone_build_time)*100) if(drone_progress >= 100) visible_message("\The [src] voices a strident beep, indicating a drone chassis is prepared.") + update_appearance() + /obj/machinery/drone_fabricator/examine(mob/user) . = ..() if(produce_drones && drone_progress >= 100 && istype(user,/mob/observer/dead) && config_legacy.allow_drone_spawn && count_drones() < config_legacy.max_maint_drones) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 730b1698ac2..349e568c9a1 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -100,32 +100,38 @@ var/obj/item/pda/ai/rbPDA = null - var/opened = 0 + var/opened = FALSE var/emagged = 0 - var/emag_items = 0 - var/wiresexposed = 0 - var/locked = 1 - var/has_power = 1 + var/emag_items = FALSE + var/wiresexposed = FALSE + var/locked = TRUE + var/has_power = TRUE var/list/req_access = list(access_robotics) var/ident = 0 //var/list/laws = list() - var/viewalerts = 0 + var/viewalerts = FALSE var/modtype = "Default" var/lower_mod = 0 var/jetpack = 0 var/datum/effect_system/ion_trail_follow/ion_trail = null var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N - var/jeton = 0 - var/killswitch = 0 + var/jeton = FALSE + var/killswitch = FALSE var/killswitch_time = 60 - var/weapon_lock = 0 + var/weapon_lock = FALSE var/weaponlock_time = 120 - var/lawupdate = 1 //Cyborgs will sync their laws with their AI by default - var/lockcharge //Used when looking to see if a borg is locked down. - var/lockdown = 0 //Controls whether or not the borg is actually locked down. - var/speed = 0 //Cause sec borgs gotta go fast //No they dont! - var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them. - var/tracking_entities = 0 //The number of known entities currently accessing the internal camera + ///Cyborgs will sync their laws with their AI by default + var/lawupdate = TRUE + ///Used when looking to see if a borg is locked down. + var/lockcharge + ///Controls whether or not the borg is actually locked down. + var/lockdown = FALSE + ///Cause sec borgs gotta go fast //No they dont! + var/speed = 0 + ///Used to determine if a borg shows up on the robotics console. Setting to one hides them. + var/scrambledcodes = FALSE + ///The number of known entities currently accessing the internal camera + var/tracking_entities = 0 var/braintype = "Cyborg" var/list/robot_verbs_default = list( diff --git a/code/modules/mob/living/silicon/subystems.dm b/code/modules/mob/living/silicon/subystems.dm index 36951ff9c52..e684ed053b1 100644 --- a/code/modules/mob/living/silicon/subystems.dm +++ b/code/modules/mob/living/silicon/subystems.dm @@ -1,11 +1,11 @@ /mob/living/silicon var/register_alarms = 1 - var/datum/nano_module/alarm_monitor/all/alarm_monitor - var/datum/nano_module/atmos_control/atmos_control + var/datum/tgui_module/alarm_monitor/all/robot/alarm_monitor + var/datum/tgui_module/atmos_control/robot/atmos_control var/datum/tgui_module/crew_monitor/robot/crew_monitor var/datum/nano_module/law_manager/law_manager - var/datum/nano_module/power_monitor/power_monitor - var/datum/nano_module/rcon/rcon + var/datum/tgui_module/power_monitor/robot/power_monitor + var/datum/tgui_module/rcon/robot/rcon /mob/living/silicon var/list/silicon_subsystems = list( @@ -49,7 +49,7 @@ set name = "Alarm Monitor" set category = "Subystems" - alarm_monitor.nano_ui_interact(usr, state = self_state) + alarm_monitor.ui_interact(usr) /******************** * Atmos Control * @@ -58,7 +58,7 @@ set category = "Subystems" set name = "Atmospherics Control" - atmos_control.nano_ui_interact(usr, state = self_state) + atmos_control.ui_interact(usr) /******************** * Crew Monitor * @@ -85,7 +85,7 @@ set category = "Subystems" set name = "Power Monitor" - power_monitor.nano_ui_interact(usr, state = self_state) + power_monitor.ui_interact(usr) /************ * RCON * @@ -94,4 +94,4 @@ set category = "Subystems" set name = "RCON" - rcon.nano_ui_interact(usr, state = self_state) + rcon.ui_interact(usr) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index f9f3e1cd540..df620899b92 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -95,8 +95,9 @@ */ /client/Move(n, direct) - if(!mob?.loc) - return FALSE + //if(!mob) // Clients cannot have a null mob, as enforced by byond + // return // Moved here to avoid nullrefs below + if(!mob.check_move_cooldown()) //do not move anything ahead of this check please return FALSE else @@ -164,6 +165,12 @@ return FALSE */ + //Relaymove could handle it + if(mob.machine) + var/result = mob.machine.relaymove(mob, direct) + if(result) + return result + if(isobj(mob.loc) || ismob(mob.loc)) //Inside an object, tell it we moved var/atom/O = mob.loc return O.relaymove(mob, direct) diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm index fba00a13e6c..df383abfe59 100644 --- a/code/modules/modular_computers/computers/modular_computer/core.dm +++ b/code/modules/modular_computers/computers/modular_computer/core.dm @@ -255,6 +255,18 @@ else return ..() +/obj/item/modular_computer/apply_visual(var/mob/user) + if(active_program) + return active_program.apply_visual(user) + +/obj/item/modular_computer/remove_visual(var/mob/user) + if(active_program) + return active_program.remove_visual(user) + +/obj/item/modular_computer/relaymove(var/mob/user, direction) + if(active_program) + return active_program.relaymove(user, direction) + /obj/item/modular_computer/proc/set_autorun(program) if(!hard_drive) return diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index d9e3e3d78b6..41a71285557 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -218,8 +218,12 @@ /datum/computer_file/program/apply_visual(mob/M) if(NM) - NM.apply_visual(M) + return NM.apply_visual(M) /datum/computer_file/program/remove_visual(mob/M) if(NM) - NM.remove_visual(M) + return NM.remove_visual(M) + +/datum/computer_file/program/proc/relaymove(var/mob/M, direction) + if(NM) + return NM.relaymove(M, direction) diff --git a/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm index d88805eff07..1115e767131 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/alarm_monitor.dm @@ -46,11 +46,11 @@ /datum/nano_module/alarm_monitor/engineering/New() ..() - alarm_handlers = list(SSalarms.atmosphere_alarm, SSalarms.fire_alarm, SSalarms.power_alarm) + alarm_handlers = list(atmosphere_alarm, fire_alarm, power_alarm) /datum/nano_module/alarm_monitor/security/New() ..() - alarm_handlers = list(SSalarms.camera_alarm, SSalarms.motion_alarm) + alarm_handlers = list(camera_alarm, motion_alarm) /datum/nano_module/alarm_monitor/proc/register_alarm(var/object, var/procName) for(var/datum/alarm_handler/AH in alarm_handlers) @@ -112,7 +112,7 @@ if(isAI(user)) for(var/obj/machinery/camera/C in A.cameras()) - cameras[++cameras.len] = C.nano_structure() + cameras[++cameras.len] = C.ui_structure() for(var/datum/alarm_source/AS in A.sources) if(!AS.source) lost_sources[++lost_sources.len] = AS.source_name diff --git a/code/modules/modular_computers/file_system/programs/generic/uav.dm b/code/modules/modular_computers/file_system/programs/generic/uav.dm new file mode 100644 index 00000000000..a2aed1f70f2 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/generic/uav.dm @@ -0,0 +1,266 @@ +/obj/item/modular_computer + var/list/paired_uavs //Weakrefs, don't worry about it! + +/datum/computer_file/program/uav + filename = "rigger" + filedesc = "UAV Control" + nanomodule_path = /datum/nano_module/uav + program_icon_state = "comm_monitor" + program_key_state = "generic_key" + program_menu_icon = "link" + extended_desc = "This program allows remote control of certain drones, but only when paired with this device." + size = 12 + available_on_ntnet = 1 + //requires_ntnet = 1 + +/datum/nano_module/uav + name = "UAV Control program" + var/obj/item/uav/current_uav = null //The UAV we're watching + var/signal_strength = 0 //Our last signal strength report (cached for a few seconds) + var/signal_test_counter = 0 //How long until next signal strength check + var/list/viewers //Who's viewing a UAV through us + var/adhoc_range = 30 //How far we can operate on a UAV without NTnet + +/datum/nano_module/uav/Destroy() + if(LAZYLEN(viewers)) + for(var/datum/weakref/W in viewers) + var/M = W.resolve() + if(M) + unlook(M) + . = ..() + +/datum/nano_module/uav/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state) + var/list/data = host.initial_data() + + if(current_uav) + if(QDELETED(current_uav)) + set_current(null) + else if(signal_test_counter-- <= 0) + signal_strength = get_signal_to(current_uav) + if(!signal_strength) + set_current(null) + else // Don't reset counter until we find a UAV that's actually in range we can stay connected to + signal_test_counter = 20 + + data["current_uav"] = null + if(current_uav) + data["current_uav"] = list("status" = current_uav.get_status_string(), "power" = current_uav.state == 1 ? 1 : null) + data["signal_strength"] = signal_strength ? signal_strength >= 2 ? "High" : "Low" : "None" + data["in_use"] = LAZYLEN(viewers) + + var/list/paired_map = list() + var/obj/item/modular_computer/mc_host = nano_host() + if(istype(mc_host)) + for(var/puav in mc_host.paired_uavs) + var/datum/weakref/wr = puav + var/obj/item/uav/U = wr.resolve() + paired_map[++paired_map.len] = list("name" = "[U ? U.nickname : "!!Missing!!"]", "uavref" = "\ref[U]") + + data["paired_uavs"] = paired_map + + ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "mod_uav.tmpl", "UAV Control", 600, 500, state = state) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/datum/nano_module/uav/Topic(var/href, var/href_list = list(), var/datum/topic_state/state) + if((. = ..())) + return + state = state || DefaultTopicState() || global.default_state + if(CanUseTopic(usr, state, href_list) == UI_INTERACTIVE) + CouldUseTopic(usr) + return OnTopic(usr, href_list, state) + CouldNotUseTopic(usr) + return TRUE + +/datum/nano_module/uav/proc/OnTopic(var/mob/user, var/list/href_list) + if(href_list["switch_uav"]) + var/obj/item/uav/U = locate(href_list["switch_uav"]) //This is a \ref to the UAV itself + if(!istype(U)) + to_chat(usr,"Something is blocking the connection to that UAV. In-person investigation is required.") + return TOPIC_NOACTION + + if(!get_signal_to(U)) + to_chat(usr,"The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.") + return TOPIC_NOACTION + + set_current(U) + return TOPIC_REFRESH + + if(href_list["del_uav"]) + var/refstring = href_list["del_uav"] //This is a \ref to the UAV itself + var/obj/item/modular_computer/mc_host = nano_host() + //This is so we can really scrape up any weakrefs that can't resolve + for(var/datum/weakref/wr in mc_host.paired_uavs) + if(wr.reference == refstring) + if(WEAKREF(current_uav) == wr) + set_current(null) + LAZYREMOVE(mc_host.paired_uavs, wr) + + else if(href_list["view_uav"]) + if(!current_uav) + return TOPIC_NOACTION + + if(current_uav.check_eye(user) < 0) + to_chat(usr,SPAN_WARNING("The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.")) + else + viewing_uav(user) ? unlook(user) : look(user) + return TOPIC_NOACTION + + else if(href_list["power_uav"]) + if(!current_uav) + return TOPIC_NOACTION + else if(current_uav.toggle_power()) + //Clean up viewers faster + if(LAZYLEN(viewers)) + for(var/datum/weakref/W in viewers) + var/M = W.resolve() + if(M) + unlook(M) + return TOPIC_REFRESH + +/datum/nano_module/uav/proc/DefaultTopicState() + return global.default_state + +/datum/nano_module/uav/proc/CouldNotUseTopic(mob/user) + . = ..() + unlook(user) + +/datum/nano_module/uav/proc/CouldUseTopic(mob/user) + . = ..() + if(viewing_uav(user)) + look(user) + +/datum/nano_module/uav/proc/set_current(var/obj/item/uav/U) + if(current_uav == U) + return + + signal_strength = 0 + current_uav = U + + if(LAZYLEN(viewers)) + for(var/datum/weakref/W in viewers) + var/M = W.resolve() + if(M) + if(current_uav) + to_chat(M, "You're disconnected from the UAV's camera!") + unlook(M) + else + look(M) + +//// +//// Finding signal strength between us and the UAV +//// +/datum/nano_module/uav/proc/get_signal_to(var/atom/movable/AM) + // Following roughly the ntnet signal levels + // 0 is none + // 1 is weak + // 2 is strong + var/obj/item/modular_computer/host = nano_host() //Better not add this to anything other than modular computers. + if(!istype(host)) + return + var/our_signal = host.get_ntnet_status() //1 low, 2 good, 3 wired, 0 none + var/their_z = get_z(AM) + + //If we have no NTnet connection don't bother getting theirs + if(!our_signal) + if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range)) + return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs + else + return 0 + + var/list/zlevels_in_range = GLOB.using_map.get_map_levels(their_z, FALSE) + var/list/zlevels_in_long_range = GLOB.using_map.get_map_levels(their_z, TRUE) - zlevels_in_range + var/their_signal = 0 + for(var/relay in ntnet_global.relays) + var/obj/machinery/ntnet_relay/R = relay + if(!R.operable()) + continue + if(R.z == their_z) + their_signal = 2 + break + if(R.z in zlevels_in_range) + their_signal = 2 + break + if(R.z in zlevels_in_long_range) + their_signal = 1 + break + + if(!their_signal) //They have no NTnet at all + if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range)) + return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs + else + return 0 + else + return max(our_signal, their_signal) + +//// +//// UAV viewer handling +//// +/datum/nano_module/uav/proc/viewing_uav(mob/user) + return (WEAKREF(user) in viewers) + +/datum/nano_module/uav/proc/look(var/mob/user) + if(issilicon(user)) //Too complicated for me to want to mess with at the moment + to_chat(user, "Regulations prevent you from controlling several corporeal forms at the same time!") + return + + if(!current_uav) + return + + user.set_machine(nano_host()) + user.reset_view(current_uav) + current_uav.add_master(user) + LAZYDISTINCTADD(viewers, WEAKREF(user)) + +/datum/nano_module/uav/proc/unlook(var/mob/user) + user.unset_machine() + user.reset_view() + if(current_uav) + current_uav.remove_master(user) + LAZYREMOVE(viewers, WEAKREF(user)) + +/datum/nano_module/uav/check_eye(var/mob/user) + if(get_dist(user, nano_host()) > 1 || user.blinded || !current_uav) + unlook(user) + return -1 + + var/viewflag = current_uav.check_eye(user) + if (viewflag < 0) //camera doesn't work + unlook(user) + return -1 + + return viewflag + +//// +//// Relaying movements to the UAV +//// +/datum/nano_module/uav/relaymove(var/mob/user, direction) + if(current_uav) + return current_uav.relaymove(user, direction, signal_strength) + +//// +//// The effects when looking through a UAV +//// +/datum/nano_module/uav/apply_visual(var/mob/M) + if(!M.client) + return + if(WEAKREF(M) in viewers) + M.overlay_fullscreen("fishbed",/atom/movable/screen/fullscreen/fishbed) + M.overlay_fullscreen("scanlines",/atom/movable/screen/fullscreen/scanline) + + if(signal_strength <= 1) + M.overlay_fullscreen("whitenoise",/atom/movable/screen/fullscreen/noise) + else + M.clear_fullscreen("whitenoise", 0) + else + remove_visual(M) + +/datum/nano_module/uav/remove_visual(mob/M) + if(!M.client) + return + M.clear_fullscreen("fishbed",0) + M.clear_fullscreen("scanlines",0) + M.clear_fullscreen("whitenoise",0) diff --git a/code/modules/modular_computers/hardware/network_card.dm b/code/modules/modular_computers/hardware/network_card.dm index 809d0ba8294..30f057652a6 100644 --- a/code/modules/modular_computers/hardware/network_card.dm +++ b/code/modules/modular_computers/hardware/network_card.dm @@ -39,6 +39,24 @@ var/global/ntnet_card_uid = 1 icon_state = "netcard_advanced" hardware_size = 1 +/obj/item/computer_hardware/network_card/quantum + name = "quantum NTNet network card" + desc = "A network card that can connect to NTnet from anywhere, using quantum entanglement." + long_range = 1 + origin_tech = list(TECH_DATA = 6, TECH_ENGINEERING = 7) + power_usage = 200 // Infinite range but higher power usage. + icon_state = "netcard_advanced" + hardware_size = 1 + +/obj/item/computer_hardware/network_card/quantum/get_signal(var/specific_action = 0) + if(!holder2) + return 0 + if(!enabled) + return 0 + if(!check_functionality() || !ntnet_global || is_banned()) + return 0 + return 2 + /obj/item/computer_hardware/network_card/wired name = "wired NTNet network card" desc = "An advanced network card for usage with standard NTNet frequencies. This one also supports wired connection." diff --git a/code/modules/multiz/turf_obj_hooks.dm b/code/modules/multiz/turf_obj_hooks.dm index b5becc60db5..b1cfcd1a02a 100644 --- a/code/modules/multiz/turf_obj_hooks.dm +++ b/code/modules/multiz/turf_obj_hooks.dm @@ -16,6 +16,7 @@ // log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].Exited([AM])") SSopenspace.add_turf(T, 1) +///Updates the icon of the obj /obj/update_icon() . = ..() if(SSopenspace.subsystem_initialized && !invisibility && isturf(loc)) @@ -24,7 +25,7 @@ // log_debug("[T] ([T.x],[T.y],[T.z]) queued for update for [src].update_icon()") SSopenspace.add_turf(T, 1) -// Just as New() we probably should hook Destroy() If we can think of something more efficient, lets hear it. +///Just as New() we probably should hook Destroy() If we can think of something more efficient, lets hear it. /obj/Destroy() if(SSopenspace.subsystem_initialized && !invisibility && isturf(loc)) var/turf/T = GetAbove(src) diff --git a/code/modules/nano/modules/nano_module.dm b/code/modules/nano/modules/nano_module.dm index 2edb1bfc6e0..7b9b9a57972 100644 --- a/code/modules/nano/modules/nano_module.dm +++ b/code/modules/nano/modules/nano_module.dm @@ -62,3 +62,6 @@ /datum/proc/update_layout() return FALSE + +/datum/nano_module/proc/relaymove(var/mob/user, direction) + return FALSE diff --git a/code/modules/nifsoft/nif.dm b/code/modules/nifsoft/nif.dm index 7654e503380..04e4bae859f 100644 --- a/code/modules/nifsoft/nif.dm +++ b/code/modules/nifsoft/nif.dm @@ -141,6 +141,11 @@ GLOBAL_LIST_INIT(nif_id_lookup, init_nif_id_lookup()) human.nif = src stat = NIF_INSTALLING H.verbs |= /mob/living/carbon/human/proc/set_nif_examine + menu = H.AddComponent(/datum/component/nif_menu) +// if(starting_software) +// for(var/path in starting_software) +// new path(src) +// starting_software = null return TRUE return FALSE @@ -161,6 +166,8 @@ GLOBAL_LIST_INIT(nif_id_lookup, init_nif_id_lookup()) forceMove(parent) parent.implants += src spawn(0) //Let the character finish spawning yo. + if(!H) //Or letting them get deleted + return if(H.mind) owner = H.mind.name implant(H) @@ -177,6 +184,7 @@ GLOBAL_LIST_INIT(nif_id_lookup, init_nif_id_lookup()) stat = NIF_PREINSTALL vis_update() H.verbs -= /mob/living/carbon/human/proc/set_nif_examine + QDEL_NULL(menu) H.nif = null human = null install_done = null @@ -205,19 +213,29 @@ GLOBAL_LIST_INIT(nif_id_lookup, init_nif_id_lookup()) wear *= (rand(85,115) / 100) //Apparently rand() only takes integers. durability -= wear + if(human) + persist_nif_data(human) + if(durability <= 0) stat = NIF_TEMPFAIL update_icon() if(human) notify("Danger! General system insta#^!($",TRUE) - to_chat(human,"Your NIF vision overlays disappear and your head suddenly seems very quiet...") + to_chat(human, SPAN_BOLDDANGER("Your NIF vision overlays disappear and your head suddenly seems very quiet...")) + +//Repair update/check proc +/obj/item/nif/proc/repair(var/repair = 0) + durability = min(durability + repair, initial(durability)) + + if(human) + persist_nif_data(human) //Attackby proc, for maintenance /obj/item/nif/attackby(obj/item/W, mob/user as mob) if(open == 0 && W.is_screwdriver()) if(do_after(user, 4 SECONDS, src) && open == 0) - user.visible_message("[user] unscrews and pries open \the [src].","You unscrew and pry open \the [src].") + user.visible_message("[user] unscrews and pries open \the [src].", SPAN_NOTICE("You unscrew and pry open \the [src].")) playsound(user, 'sound/items/Screwdriver.ogg', 50, 1) open = 1 update_icon() @@ -348,8 +366,7 @@ GLOBAL_LIST_INIT(nif_id_lookup, init_nif_id_lookup()) //nif_hud.process_hud(human,1) //TODO VIS //Process all the ones that want that - for(var/S in nifsofts_life) - var/datum/nifsoft/nifsoft = S + for(var/datum/nifsoft/nifsoft as anything in nifsofts_life) nifsoft.life(human) if(NIF_POWFAIL) @@ -372,8 +389,10 @@ GLOBAL_LIST_INIT(nif_id_lookup, init_nif_id_lookup()) /obj/item/nif/proc/notify(var/message,var/alert = 0) if(!human || stat == NIF_TEMPFAIL) return + last_notification = message //TGUI Hook + to_chat(human,"\[[icon2html(thing = src.big_icon, target = human)]NIF\] displays, \"[message]\"") - if(prob(1)) human.visible_message("\The [human.real_name] [pick(look_messages)].") + if(prob(1)) human.visible_message(SPAN_NOTICE("\The [human.real_name] [pick(look_messages)].")) if(alert) SEND_SOUND(human, bad_sound) else @@ -395,6 +414,29 @@ GLOBAL_LIST_INIT(nif_id_lookup, init_nif_id_lookup()) human.nutrition -= use_charge return TRUE +// This operates on a nifsoft *path*, not an instantiation. +// It tells the nifsoft shop if it's installation will succeed, to prevent it +// from charging the user for incompatible software. +/obj/item/nif/proc/can_install(var/datum/nifsoft/path) + if(stat == NIF_TEMPFAIL) + return FALSE + + if(nifsofts[initial(path.list_pos)]) + notify("The software \"[initial(path.name)]\" is already installed.", TRUE) + return FALSE + + if(human) + var/applies_to = initial(path.applies_to) + var/synth = human.isSynthetic() + if(synth && !(applies_to & NIF_SYNTHETIC)) + notify("The software \"[initial(path.name)]\" is not supported on your chassis type.",TRUE) + return FALSE + if(!synth && !(applies_to & NIF_ORGANIC)) + notify("The software \"[initial(path.name)]\" is not supported in organic life.",TRUE) + return FALSE + + return TRUE + //Install a piece of software /obj/item/nif/proc/install(var/datum/nifsoft/new_soft) if(stat == NIF_TEMPFAIL) return FALSE diff --git a/code/modules/nifsoft/nif_statpanel.dm b/code/modules/nifsoft/nif_statpanel.dm deleted file mode 100644 index 45c6dc1d42e..00000000000 --- a/code/modules/nifsoft/nif_statpanel.dm +++ /dev/null @@ -1,80 +0,0 @@ -/mob/living/carbon/human/Stat() - . = ..() - if(nif && statpanel("NIF")) - SetupNifStat() - -/mob/living/carbon/human/proc/SetupNifStat() - var/nif_status = "" - var/nif_percent = round((nif.durability/initial(nif.durability))*100) - switch(nif.stat) - if(NIF_WORKING) - if(nif_percent < 20) - nif_status = "Service Needed Soon" - else - nif_status = "Operating Normally" - if(NIF_POWFAIL) - nif_status = "Insufficient Energy!" - if(NIF_TEMPFAIL) - nif_status = "System Failure!" - if(NIF_INSTALLING) - nif_status = "Adapting To User" - else - nif_status = "Unknown - Error" - nif_status += " (Condition: [nif_percent]%)" - stat("NIF Status", nif_status) - - if(nif.stat == NIF_WORKING) - stat("- Modules -", "LMB: Toggle, Shift+LMB: Info/Uninstall") - for(var/nifsoft in nif.nifsofts) - if(!nifsoft) - continue - var/datum/nifsoft/NS = nifsoft - var/obj/effect/nif_stat/stat_line = NS.stat_line - stat("[stat_line.nifsoft_name]",stat_line.atom_button_text()) - -/////////////////// -// Stat Line Object -/obj/effect/nif_stat - name = "" - var/nifsoft_name //Prevents deeper lookups, and the name won't change - var/datum/nifsoft/nifsoft //Reference to our nifsoft - var/toggleable = FALSE //Won't change, prevents looking it up deeper - -INITIALIZE_IMMEDIATE(/obj/effect/nif_stat) -/obj/effect/nif_stat/Initialize(mapload, datum/nifsoft/new_soft) - . = ..() - nifsoft = new_soft - nifsoft_name = new_soft.name - name = new_soft.name - -/obj/effect/nif_stat/Destroy() - nifsoft = null - return ..() - -/obj/effect/nif_stat/proc/atom_button_text() - name = nifsoft.stat_text() - return src - -/obj/effect/nif_stat/Click(var/location, var/control, var/params) - if(usr != nifsoft.nif.human) return - - var/list/clickprops = params2list(params) - var/opts = clickprops["shift"] - - if(opts) - var/choice = alert("Select an option","[nifsoft_name]","Display Info","Cancel","Uninstall") - switch(choice) - if("Display Info") - nifsoft.nif.notify("[nifsoft_name]: [nifsoft.desc] - It consumes [nifsoft.p_drain] energy units \ - while installed, and [nifsoft.a_drain] additionally while active. It is [nifsoft.illegal ? "NOT " : ""]\ - a legal software package. The MSRP of the package is [nifsoft.cost] Thalers. The difficulty to construct \ - the associated implant is Rating [nifsoft.wear].") - if("Uninstall") - var/confirm = alert("Really uninstall [nifsoft_name]?","Are you sure?","Cancel","Uninstall","Cancel") - if(confirm == "Uninstall") - nifsoft.uninstall() - else if(nifsoft.activates) - if(nifsoft.active) - nifsoft.deactivate() - else - nifsoft.activate() diff --git a/code/modules/nifsoft/nif_tgui.dm b/code/modules/nifsoft/nif_tgui.dm new file mode 100644 index 00000000000..65e9ab309c1 --- /dev/null +++ b/code/modules/nifsoft/nif_tgui.dm @@ -0,0 +1,177 @@ +/************************************************************************\ + * This module controls everything to do with the NIF's tgui interface. * +\************************************************************************/ +/** + * Etc variables on the NIF to keep this self contained + */ +/obj/item/nif + var/static/list/valid_ui_themes = list( + "abductor", + "cardtable", + "hackerman", + "malfunction", + "ntos", + "paper", + "retro", + "syndicate" + ) + var/tmp/last_notification + var/tmp/datum/component/nif_menu/menu + +/** + * Small helper component to manage the HUD icon + */ +/datum/component/nif_menu + var/obj/screen/nif/screen_icon + +/datum/component/nif_menu/Initialize(mapload) + if(!ismob(parent)) + return COMPONENT_INCOMPATIBLE + . = ..() + +/datum/component/nif_menu/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_MOB_CLIENT_LOGIN, .proc/create_mob_button) + var/mob/owner = parent + if(owner.client) + create_mob_button(parent) + +/datum/component/nif_menu/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, COMSIG_MOB_CLIENT_LOGIN) + if(ismob(parent)) + var/mob/owner = parent + if(screen_icon) + owner?.client?.screen -= screen_icon + UnregisterSignal(screen_icon, COMSIG_CLICK) + QDEL_NULL(screen_icon) + if(ishuman(parent)) + owner.verbs -= /mob/living/carbon/human/proc/nif_menu + + +/datum/component/nif_menu/proc/create_mob_button(mob/user) + var/datum/hud/HUD = user.hud_used + if(!screen_icon) + screen_icon = new() + RegisterSignal(screen_icon, COMSIG_CLICK, .proc/nif_menu_click) + screen_icon.icon = HUD.ui_style + screen_icon.color = HUD.ui_color + screen_icon.alpha = HUD.ui_alpha + LAZYADD(HUD.other_important, screen_icon) + user.client?.screen += screen_icon + + user.verbs |= /mob/living/carbon/human/proc/nif_menu + +/datum/component/nif_menu/proc/nif_menu_click(obj/screen/nif/image, location, control, params, user) + var/mob/living/carbon/human/H = user + if(istype(H) && H.nif) + INVOKE_ASYNC(H.nif, .proc/ui_interact, user) + +/** + * Screen object for NIF menu access + */ +/obj/screen/nif + name = "nif menu" + icon = 'icons/mob/screen/midnight.dmi' + icon_state = "nif" + screen_loc = ui_smallquad + +/** + * Verb to open the interface + */ +/mob/living/carbon/human/proc/nif_menu() + set name = "NIF Menu" + set category = "IC" + set desc = "Open the NIF user interface." + + var/obj/item/nif/N = nif + if(istype(N)) + N.ui_interact(usr) + +/** + * The NIF State ensures that only our authorized implanted user can touch us. + */ +/obj/item/nif/ui_state(mob/user) + return GLOB.ui_nif_main_state + +/** + * Standard TGUI stub to open the NIF.js template. + */ +/obj/item/nif/ui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "NIF", name) + ui.open() + +/** + * tgui_data gives the UI any relevant data it needs. + * In our case, that's basically everything from our statpanel. + */ +/obj/item/nif/ui_data(mob/user, datum/tgui/ui, datum/ui_state/state) + var/list/data = ..() + + data["theme"] = save_data["ui_theme"] + data["last_notification"] = last_notification + + // Random biometric information + data["nutrition"] = human.nutrition + data["isSynthetic"] = human.isSynthetic() + + data["nif_percent"] = round((durability/initial(durability))*100) + data["nif_stat"] = stat + + + var/list/modules = list() + if(stat == NIF_WORKING) + for(var/nifsoft in nifsofts) + if(!nifsoft) + continue + var/datum/nifsoft/NS = nifsoft + modules.Add(list(list( + "name" = NS.name, + "desc" = NS.desc, + "p_drain" = NS.p_drain, + "a_drain" = NS.a_drain, + "illegal" = NS.illegal, + "wear" = NS.wear, + "cost" = NS.cost, + "activates" = NS.activates, + "active" = NS.active, + "stat_text" = NS.stat_text(), + "ref" = REF(NS), + ))) + data["modules"] = modules + + return data + +/** + * tgui_act handles all user input in the UI. + */ +/obj/item/nif/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + if(..()) + return TRUE + + switch(action) + if("setTheme") + if((params["theme"] in valid_ui_themes) || params["theme"] == null) + save_data["ui_theme"] = params["theme"] + return TRUE + if("toggle_module") + var/datum/nifsoft/NS = locate(params["module"]) in nifsofts + if(!istype(NS)) + return + if(NS.activates) + if(NS.active) + NS.deactivate() + else + NS.activate() + return TRUE + if("uninstall") + var/datum/nifsoft/NS = locate(params["module"]) in nifsofts + if(!istype(NS)) + return + NS.uninstall() + return TRUE + if("dismissNotification") + last_notification = null + return TRUE diff --git a/code/modules/nifsoft/nifsoft.dm b/code/modules/nifsoft/nifsoft.dm index 097b4b9fa60..8237933ac3f 100644 --- a/code/modules/nifsoft/nifsoft.dm +++ b/code/modules/nifsoft/nifsoft.dm @@ -39,15 +39,11 @@ var/list/incompatible_with = null // List of NIFSofts that are disabled when this one is enabled - var/obj/effect/nif_stat/stat_line // The stat line in the statpanel for this NIFSoft - - //Constructor accepts the NIF it's being loaded into /datum/nifsoft/New(var/obj/item/nif/nif_load) ASSERT(nif_load) nif = nif_load - stat_line = new(null, src) if(!install(nif)) qdel(src) @@ -56,7 +52,6 @@ if(nif) uninstall() nif = null - QDEL_NULL(stat_line) return ..() //Called when the software is installed in the NIF @@ -105,7 +100,7 @@ return nif_result //Called when attempting to deactivate an implant -/datum/nifsoft/proc/deactivate(force = FALSE) +/datum/nifsoft/proc/deactivate(var/force = FALSE) if(!active && !force) return var/nif_result = nif.deactivate(src) @@ -136,7 +131,7 @@ /datum/nifsoft/proc/disk_install(var/mob/living/carbon/human/target,var/mob/living/carbon/human/user) return TRUE -//Stat-line clickable text +//Status text for menu /datum/nifsoft/proc/stat_text() if(activates) return "[active ? "Active" : "Disabled"]" diff --git a/code/modules/nifsoft/software/01_vision.dm b/code/modules/nifsoft/software/01_vision.dm index f41338b1187..b63e2bd8634 100644 --- a/code/modules/nifsoft/software/01_vision.dm +++ b/code/modules/nifsoft/software/01_vision.dm @@ -106,12 +106,12 @@ vision_flags = (NIF_V_MESONS) incompatible_with = list(NIF_MATERIAL,NIF_THERMALS,NIF_NIGHTVIS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.sight |= SEE_TURFS - if(H.client) - H.client.screen |= GLOB.global_hud.meson +/datum/nifsoft/mesons/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.sight |= SEE_TURFS + if(H.client) + H.client.screen |= GLOB.global_hud.meson /datum/nifsoft/material name = "Material Scanner" @@ -125,12 +125,12 @@ vision_flags = (NIF_V_MATERIAL) incompatible_with = list(NIF_MESONS,NIF_THERMALS,NIF_NIGHTVIS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.sight |= SEE_OBJS - if(H.client) - H.client.screen |= GLOB.global_hud.material +/datum/nifsoft/material/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.sight |= SEE_OBJS + if(H.client) + H.client.screen |= GLOB.global_hud.material /datum/nifsoft/thermals name = "Thermal Scanner" @@ -145,12 +145,12 @@ vision_flags = (NIF_V_THERMALS) incompatible_with = list(NIF_MESONS,NIF_MATERIAL,NIF_NIGHTVIS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.sight |= SEE_MOBS - if(H.client) - H.client.screen |= GLOB.global_hud.thermal +/datum/nifsoft/thermals/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.sight |= SEE_MOBS + if(H.client) + H.client.screen |= GLOB.global_hud.thermal /datum/nifsoft/nightvis name = "Low-Light Amp" @@ -164,9 +164,9 @@ vision_flags = (NIF_V_NIGHTVIS) incompatible_with = list(NIF_MESONS,NIF_MATERIAL,NIF_THERMALS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.see_in_dark += 7 - if(H.client) - H.client.screen |= GLOB.global_hud.nvg +/datum/nifsoft/nightvis/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.see_in_dark += 7 + if(H.client) + H.client.screen |= GLOB.global_hud.nvg diff --git a/code/modules/nifsoft/software/05_health.dm b/code/modules/nifsoft/software/05_health.dm index 69962e3209f..7dc2ad22ab4 100644 --- a/code/modules/nifsoft/software/05_health.dm +++ b/code/modules/nifsoft/software/05_health.dm @@ -13,63 +13,63 @@ health_flags = (NIF_H_ORGREPAIR) //These self-activate on their own, these aren't user-settable to on/off. - activate() - if((. = ..())) - mode = 1 +/datum/nifsoft/medichines_org/activate() + if((. = ..())) + mode = 1 - deactivate(force = FALSE) - if((. = ..())) - a_drain = initial(a_drain) - mode = initial(mode) - nif.human.Stasis(0) +/datum/nifsoft/medichines_org/deactivate(var/force = FALSE) + if((. = ..())) + a_drain = initial(a_drain) + mode = initial(mode) + nif.human.Stasis(0) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - var/HP_percent = H.health/H.getMaxHealth() +/datum/nifsoft/medichines_org/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + var/HP_percent = H.health/H.getMaxHealth() - //Mode changing state machine - if(HP_percent >= 0.9) - if(mode) - nif.notify("User Status: NORMAL. Medichines deactivating.") - deactivate() - return TRUE - else if(!mode && HP_percent < 0.8) - nif.notify("User Status: INJURED. Commencing medichine routines.",TRUE) - activate() - else if(mode == 1 && HP_percent < 0.2) - nif.notify("User Status: DANGER. Seek medical attention!",TRUE) - mode = 2 - else if(mode == 2 && HP_percent < -0.4) - nif.notify("User Status: CRITICAL. Notifying medical, and starting emergency stasis!",TRUE) - mode = 3 - if(!ishuman(H.loc)) //Not notified in case of vore, for gameplay purposes. - var/turf/T = get_turf(H) - var/obj/item/radio/headset/a = new /obj/item/radio/headset/heads/captain(null) - a.autosay("[H.real_name] has been put in emergency stasis, located at ([T.x],[T.y],[T.z])!", "[H.real_name]'s NIF", "Medical") - qdel(a) - - //Handle the actions in each mode - - //Injured but not critical + //Mode changing state machine + if(HP_percent >= 0.9) if(mode) - H.adjustToxLoss(-0.1 * mode) - H.adjustBruteLoss(-0.1 * mode) - H.adjustFireLoss(-0.1 * mode) - - if(mode >= 2) - nif.use_charge(a_drain) //A second drain if we're in level 2+ - - //Patient critical - emergency stasis - if(mode >= 3) - if(HP_percent <= 0) - H.Stasis(3) - if(HP_percent > 0.2) - H.Stasis(0) - nif.notify("Ending emergency stasis.",TRUE) - mode = 2 - + nif.notify("User Status: NORMAL. Medichines deactivating.") + deactivate() return TRUE + else if(!mode && HP_percent < 0.8) + nif.notify("User Status: INJURED. Commencing medichine routines.",TRUE) + activate() + else if(mode == 1 && HP_percent < 0.2) + nif.notify("User Status: DANGER. Seek medical attention!",TRUE) + mode = 2 + else if(mode == 2 && HP_percent < -0.4) + nif.notify("User Status: CRITICAL. Notifying medical, and starting emergency stasis!",TRUE) + mode = 3 + if(!isbelly(H.loc)) //Not notified in case of vore, for gameplay purposes. + var/turf/T = get_turf(H) + var/obj/item/radio/headset/a = new /obj/item/radio/headset/heads/captain(null) + a.autosay("[H.real_name] has been put in emergency stasis, located at ([T.x],[T.y],[T.z])!", "[H.real_name]'s NIF", "Medical") + qdel(a) + + //Handle the actions in each mode + + //Injured but not critical + if(mode) + H.adjustToxLoss(-0.1 * mode) + H.adjustBruteLoss(-0.1 * mode) + H.adjustFireLoss(-0.1 * mode) + + if(mode >= 2) + nif.use_charge(a_drain) //A second drain if we're in level 2+ + + //Patient critical - emergency stasis + if(mode >= 3) + if(HP_percent <= 0) + H.Stasis(3) + if(HP_percent > 0.2) + H.Stasis(0) + nif.notify("Ending emergency stasis.",TRUE) + mode = 2 + + return TRUE /datum/nifsoft/medichines_syn name = "Medichines" @@ -86,44 +86,44 @@ health_flags = (NIF_H_SYNTHREPAIR) //These self-activate on their own, these aren't user-settable to on/off. - activate() - if((. = ..())) - mode = 1 +/datum/nifsoft/medichines_syn/activate() + if((. = ..())) + mode = 1 - deactivate(force = FALSE) - if((. = ..())) - mode = 0 - - life() - if((. = ..())) - //We're good! - if(!nif.human.bad_external_organs.len) - if(mode || active) - nif.notify("User Status: NORMAL. Medichines deactivating.") - deactivate() - return TRUE - - if(!mode && !active) - nif.notify("User Status: DAMAGED. Medichines performing minor repairs.",TRUE) - activate() - - for(var/eo in nif.human.bad_external_organs) - var/obj/item/organ/external/EO = eo - for(var/w in EO.wounds) - var/datum/wound/W = w - if(W.damage <= 5) - W.heal_damage(0.1) - EO.update_damages() - if(EO.update_icon()) - nif.human.UpdateDamageIcon(1) - nif.use_charge(0.1) - return TRUE //Return entirely, we only heal one at a time. - else if(mode == 1) - mode = 2 - nif.notify("Medichines unable to repair all damage. Perform manual repairs.",TRUE) +/datum/nifsoft/medichines_syn/deactivate(var/force = FALSE) + if((. = ..())) + mode = 0 +/datum/nifsoft/medichines_syn/life() + if((. = ..())) + //We're good! + if(!nif.human.bad_external_organs.len) + if(mode || active) + nif.notify("User Status: NORMAL. Medichines deactivating.") + deactivate() return TRUE + if(!mode && !active) + nif.notify("User Status: DAMAGED. Medichines performing minor repairs.",TRUE) + activate() + + for(var/eo in nif.human.bad_external_organs) + var/obj/item/organ/external/EO = eo + for(var/w in EO.wounds) + var/datum/wound/W = w + if(W.damage <= 5) + W.heal_damage(0.1) + EO.update_damages() + if(EO.update_icon()) + nif.human.UpdateDamageIcon(1) + nif.use_charge(0.1) + return TRUE //Return entirely, we only heal one at a time. + else if(mode == 1) + mode = 2 + nif.notify("Medichines unable to repair all damage. Perform manual repairs.",TRUE) + + return TRUE + /datum/nifsoft/spare_breath name = "Respirocytes" desc = "Nanites simulating red blood cells will filter and recycle oxygen for a short time, preventing suffocation in hostile environments. NOTE: Only capable of supplying OXYGEN." @@ -137,47 +137,47 @@ var/filled = 100 //Tracks the internal tank 'refilling', which still uses power health_flags = (NIF_H_SPAREBREATH) - activate() - if(!(filled > 50)) - nif.notify("Respirocytes not saturated!",TRUE) - return FALSE - if((. = ..())) - nif.notify("Now taking air from reserves.") +/datum/nifsoft/spare_breath/activate() + if(!(filled > 50)) + nif.notify("Respirocytes not saturated!",TRUE) + return FALSE + if((. = ..())) + nif.notify("Now taking air from reserves.") - deactivate(force = FALSE) - if((. = ..())) - nif.notify("Now taking air from environment and refilling reserves.") +/datum/nifsoft/spare_breath/deactivate(var/force = FALSE) + if((. = ..())) + nif.notify("Now taking air from environment and refilling reserves.") - life() - if((. = ..())) - if(active) //Supplying air, not recharging it - switch(filled) //Text warnings - if(75) - nif.notify("Respirocytes at 75% saturation.",TRUE) - if(50) - nif.notify("Respirocytes at 50% saturation!",TRUE) - if(25) - nif.notify("Respirocytes at 25% saturation, seek a habitable environment!",TRUE) - if(5) - nif.notify("Respirocytes at 5% saturation! Failure imminent!",TRUE) +/datum/nifsoft/spare_breath/life() + if((. = ..())) + if(active) //Supplying air, not recharging it + switch(filled) //Text warnings + if(75) + nif.notify("Respirocytes at 75% saturation.",TRUE) + if(50) + nif.notify("Respirocytes at 50% saturation!",TRUE) + if(25) + nif.notify("Respirocytes at 25% saturation, seek a habitable environment!",TRUE) + if(5) + nif.notify("Respirocytes at 5% saturation! Failure imminent!",TRUE) - if(filled == 0) //Ran out - deactivate() - else //Drain a little - filled-- + if(filled == 0) //Ran out + deactivate() + else //Drain a little + filled-- - else //Recharging air, not supplying it - if(filled == 100) - return TRUE - else if(nif.use_charge(0.1) && ++filled == 100) - nif.notify("Respirocytes now fully saturated.") + else //Recharging air, not supplying it + if(filled == 100) + return TRUE + else if(nif.use_charge(0.1) && ++filled == 100) + nif.notify("Respirocytes now fully saturated.") - proc/resp_breath() - if(!active) return null - var/datum/gas_mixture/breath = new(BREATH_VOLUME) - breath.adjust_gas(/datum/gas/oxygen, BREATH_MOLES) - breath.temperature = T20C - return breath +/datum/nifsoft/spare_breath/proc/resp_breath() + if(!active) return null + var/datum/gas_mixture/breath = new(BREATH_VOLUME) + breath.adjust_gas("oxygen", BREATH_MOLES) + breath.temperature = T20C + return breath /* /datum/nifsoft/mindbackup name = "Mind Backup" @@ -185,16 +185,18 @@ list_pos = NIF_BACKUP cost = 125 - activate() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - SStranscore.m_backup(H.mind,H.nif,one_time = TRUE) - persist_nif_data(H) - nif.notify("Mind backed up!") - nif.use_charge(0.1) - deactivate() - return TRUE - - stat_text() - return "Store Backup" +/datum/nifsoft/mindbackup/activate() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + SStranscore.m_backup(H.mind,H.nif,one_time = TRUE) + persist_nif_data(H) + nif.notify("Mind backed up!") + nif.use_charge(0.1) + deactivate() + return TRUE +/datum/nifsoft/mindbackup/deactivate() + if((. = ..())) + return TRUE +/datum/nifsoft/mindbackup/stat_text() + return "Store Backup" */ diff --git a/code/modules/nifsoft/software/06_screens.dm b/code/modules/nifsoft/software/06_screens.dm index 487745f9efd..d0749bcca30 100644 --- a/code/modules/nifsoft/software/06_screens.dm +++ b/code/modules/nifsoft/software/06_screens.dm @@ -20,6 +20,10 @@ arscreen.ui_interact(nif.human) return TRUE +/datum/nifsoft/crewmonitor/deactivate(var/force = FALSE) + if((. = ..())) + return TRUE + /datum/nifsoft/crewmonitor/stat_text() return "Show Monitor" @@ -42,7 +46,11 @@ /datum/nifsoft/alarmmonitor/activate() if((. = ..())) - arscreen.nano_ui_interact(nif.human,"main",null,1,nif_state) + arscreen.ui_interact(nif.human) + return TRUE + +/datum/nifsoft/alarmmonitor/deactivate(var/force = FALSE) + if((. = ..())) return TRUE /datum/nifsoft/alarmmonitor/stat_text() diff --git a/code/modules/nifsoft/software/10_combat.dm b/code/modules/nifsoft/software/10_combat.dm index 7c3d6aaf4c1..fb4b3cfd125 100644 --- a/code/modules/nifsoft/software/10_combat.dm +++ b/code/modules/nifsoft/software/10_combat.dm @@ -34,10 +34,10 @@ tick_flags = NIF_ACTIVETICK combat_flags = (NIF_C_PAINKILLERS) - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - H.bloodstr.add_reagent("numbenzyme",0.5) +/datum/nifsoft/painkillers/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + H.bloodstr.add_reagent("numbenzyme",0.5) /datum/nifsoft/hardclaws name = "Bloodletters" @@ -74,25 +74,25 @@ var/global/datum/unarmed_attack/hardclaws/unarmed_hardclaws = new() var/used = FALSE combat_flags = (NIF_C_HIDELASER) - activate() - if((. = ..())) - if(used) - nif.notify("You do not have a hidden weapon to deploy anymore!",TRUE) - deactivate() - return FALSE - if(!nif.use_charge(50)) - nif.notify("Insufficient energy to deploy weapon!",TRUE) - deactivate() - return FALSE +/datum/nifsoft/hidelaser/activate() + if((. = ..())) + if(used) + nif.notify("You do not have a hidden weapon to deploy anymore!",TRUE) + deactivate() + return FALSE + if(!nif.use_charge(50)) + nif.notify("Insufficient energy to deploy weapon!",TRUE) + deactivate() + return FALSE - var/mob/living/carbon/human/H = nif.human - H.adjustHalLoss(30) - var/obj/item/gun/energy/gun/martin/dazzle/dgun = new(get_turf(H)) - H.put_in_hands(dgun) - nif.notify("Weapon deployed!",TRUE) - used = TRUE - spawn(0) - uninstall() + var/mob/living/carbon/human/H = nif.human + H.adjustHalLoss(30) + var/obj/item/gun/energy/gun/martin/dazzle/dgun = new(get_turf(H)) + H.put_in_hands(dgun) + nif.notify("Weapon deployed!",TRUE) + used = TRUE + spawn(0) + uninstall() //The gun to go with this implant /obj/item/gun/energy/gun/martin/dazzle diff --git a/code/modules/nifsoft/software/13_soulcatcher.dm b/code/modules/nifsoft/software/13_soulcatcher.dm index 2edbc13728e..ac85ce60387 100644 --- a/code/modules/nifsoft/software/13_soulcatcher.dm +++ b/code/modules/nifsoft/software/13_soulcatcher.dm @@ -34,28 +34,34 @@ /datum/nifsoft/soulcatcher/activate() if((. = ..())) show_settings(nif.human) - deactivate() + spawn(0) + deactivate() /datum/nifsoft/soulcatcher/stat_text() return "Change Settings ([brainmobs.len] minds)" /datum/nifsoft/soulcatcher/install() if((. = ..())) - nif.set_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) //Required on install, because other_flags aren't sufficient for our complicated settings. - nif.human.verbs |= /mob/living/carbon/human/proc/nsay - nif.human.verbs |= /mob/living/carbon/human/proc/nme + //nif.set_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) //Only required on install if the flag is in the default setting_flags list defined few lines above. + if(nif?.human) + nif.human.verbs |= /mob/proc/nsay + nif.human.verbs |= /mob/proc/nme /datum/nifsoft/soulcatcher/uninstall() QDEL_LIST_NULL(brainmobs) - if((. = ..()) && nif && nif.human) //Sometimes NIFs are deleted outside of a human - nif.human.verbs -= /mob/living/carbon/human/proc/nsay - nif.human.verbs -= /mob/living/carbon/human/proc/nme + if((. = ..()) && nif?.human) //Sometimes NIFs are deleted outside of a human + nif.human.verbs -= /mob/proc/nsay + nif.human.verbs -= /mob/proc/nme /datum/nifsoft/soulcatcher/proc/save_settings() + if(!nif) + return nif.save_data["[list_pos]"] = inside_flavor return TRUE /datum/nifsoft/soulcatcher/proc/load_settings() + if(!nif) + return var/load = nif.save_data["[list_pos]"] if(load) inside_flavor = load @@ -64,12 +70,12 @@ /datum/nifsoft/soulcatcher/proc/notify_into(var/message) var/sound = nif.good_sound - to_chat(nif.human,"\[[icon2html(thing = nif.big_icon, target = nif.human)]NIF\] Soulcatcher displays, \"[message]\"") + to_chat(nif.human,"\[[icon2html(thing = nif.big_icon, target = nif.human)]NIF\] Soulcatcher displays, \"[message]\"") SEND_SOUND(nif.human, sound) for(var/brainmob in brainmobs) var/mob/living/carbon/brain/caught_soul/CS = brainmob - to_chat(CS,"\[[icon2html(thing = nif.big_icon, target = CS)]NIF\] Soulcatcher displays, \"[message]\"") + to_chat(CS,"\[[icon2html(thing = nif.big_icon, target = CS)]NIF\] Soulcatcher displays, \"[message]\"") SEND_SOUND(brainmob, sound) /datum/nifsoft/soulcatcher/proc/say_into(var/message, var/mob/living/sender, var/mob/eyeobj) @@ -85,10 +91,9 @@ //Not AR Projecting else - to_chat(nif.human,"\[[icon2html(thing = nif.big_icon, target = nif.human)]NIF\] [sender_name] speaks, \"[message]\"") - for(var/brainmob in brainmobs) - var/mob/living/carbon/brain/caught_soul/CS = brainmob - to_chat(CS,"\[[icon2html(thing = nif.big_icon, target = CS)]NIF\] [sender_name] speaks, \"[message]\"") + to_chat(nif.human,"\[[icon2html(thing = nif.big_icon, target = nif.human)]NIF\] [sender_name] speaks, \"[message]\"") + for(var/mob/living/carbon/brain/caught_soul/CS as anything in brainmobs) + to_chat(CS,"\[[icon2html(thing = nif.big_icon, target = CS)]NIF\] [sender_name] speaks, \"[message]\"") log_nsay(message,nif.human.real_name,sender) @@ -101,14 +106,13 @@ //AR Projecting if(eyeobj) - sender.eyeobj.visible_message("[sender_name] [message]") + sender.eyeobj.visible_message("[sender_name] [message]") //Not AR Projecting else - to_chat(nif.human,"\[[icon2html(thing = nif.big_icon, target = nif.human)]NIF\] [sender_name] [message]") - for(var/brainmob in brainmobs) - var/mob/living/carbon/brain/caught_soul/CS = brainmob - to_chat(CS,"\[[icon2html(thing = nif.big_icon, target = CS)]NIF\] [sender_name] [message]") + to_chat(nif.human,"\[[icon2html(thing = nif.big_icon, target = nif.human)]NIF\] [sender_name] [message]") + for(var/mob/living/carbon/brain/caught_soul/CS as anything in brainmobs) + to_chat(CS,"\[[icon2html(thing = nif.big_icon, target = CS)]NIF\] [sender_name] [message]") log_nme(message,nif.human.real_name,sender) @@ -123,7 +127,7 @@ "AR Projecting \[[setting_flags & NIF_SC_PROJECTING ? "Enabled" : "Disabled"]\]" = NIF_SC_PROJECTING, "Design Inside", "Erase Contents") - var/choice = input(nif.human,"Select a setting to modify:","Soulcatcher NIFSoft") as null|anything in settings_list + var/choice = tgui_input_list(nif.human,"Select a setting to modify:","Soulcatcher NIFSoft", settings_list) if(choice in settings_list) switch(choice) @@ -132,19 +136,18 @@ printed after an intro ending with: \"Around you, you see...\" to the prey. If you already \ have prey, this will be printed to them after \"Your surroundings change to...\". Limit 2048 char.", \ "VR Environment", html_decode(inside_flavor)) as message - new_flavor = sanitize(new_flavor, 32768, extra = FALSE) + new_flavor = sanitize(new_flavor, MAX_MESSAGE_LEN*2) inside_flavor = new_flavor nif.notify("Updating VR environment...") - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/CS = brain + for(var/mob/living/carbon/brain/caught_soul/CS as anything in brainmobs) to_chat(CS,"Your surroundings change to...\n[inside_flavor]") save_settings() return TRUE if("Erase Contents") - var/mob/living/carbon/brain/caught_soul/brainpick = input(nif.human,"Select a mind to delete:","Erase Mind") as null|anything in brainmobs + var/mob/living/carbon/brain/caught_soul/brainpick = tgui_input_list(nif.human,"Select a mind to delete:","Erase Mind", brainmobs) - var/warning = alert(nif.human,"Are you SURE you want to erase \"[brainpick]\"?","Erase Mind","CANCEL","DELETE","CANCEL") + var/warning = tgui_alert(nif.human,"Are you SURE you want to erase \"[brainpick]\"?","Erase Mind",list("CANCEL","DELETE")) if(warning == "DELETE") brainmobs -= brainpick qdel(brainpick) @@ -179,24 +182,20 @@ nif.clear_flag(NIF_O_SCOTHERS,NIF_FLAGS_OTHER) if(NIF_SC_ALLOW_EARS) if(setting_flags & NIF_SC_ALLOW_EARS) - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/brainmob = brain + for(var/mob/living/carbon/brain/caught_soul/brainmob as anything in brainmobs) brainmob.ext_deaf = FALSE notify_message = "External audio input enabled." else - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/brainmob = brain + for(var/mob/living/carbon/brain/caught_soul/brainmob as anything in brainmobs) brainmob.ext_deaf = TRUE notify_message = "External audio input disabled." if(NIF_SC_ALLOW_EYES) if(setting_flags & NIF_SC_ALLOW_EYES) - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/brainmob = brain + for(var/mob/living/carbon/brain/caught_soul/brainmob as anything in brainmobs) brainmob.ext_blind = FALSE notify_message = "External video input enabled." else - for(var/brain in brainmobs) - var/mob/living/carbon/brain/caught_soul/brainmob = brain + for(var/mob/living/carbon/brain/caught_soul/brainmob as anything in brainmobs) brainmob.ext_blind = TRUE notify_message = "External video input disabled." @@ -309,14 +308,18 @@ . = ..() - if(!client) - return - if(!parent_mob && !transient &&(life_tick % 150 == 0) && soulcatcher.setting_flags & NIF_SC_BACKUPS) SStranscore.m_backup(mind,0) //Passed 0 means "Don't touch the nif fields on the mind record" life_tick++ + if(!client) + if(++client_missing == 300) + qdel(src) + return + else + client_missing = 0 + if(parent_mob) return @@ -412,7 +415,7 @@ return if (src.client) if (client.prefs.muted & MUTE_IC) - to_chat(src, "You cannot send IC messages (muted).") + to_chat(src, SPAN_WARNING("You cannot send IC messages (muted).")) return if (stat) return @@ -431,7 +434,7 @@ set name = "Resist" set category = "IC" - to_chat(src,"There's no way out! You're stuck in VR.") + to_chat(src,SPAN_WARNING("There's no way out! You're stuck in VR.")) /mob/living/carbon/brain/caught_soul/set_typing_indicator(state) return eyeobj?.set_typing_indicator(state) @@ -535,45 +538,63 @@ /////////////////// //Verbs for humans -/mob/living/carbon/human/proc/nsay(message as text) +/mob/proc/nsay(message as text) set name = "NSay" set desc = "Speak into your NIF's Soulcatcher." set category = "IC" + src.nsay_act(message) + +/mob/proc/nsay_act(message as text|null) + to_chat(src, SPAN_WARNING("You must be a humanoid with a NIF implanted to use that.")) + +/mob/living/carbon/human/nsay_act(message as text|null) + if(stat != CONSCIOUS) + to_chat(src, SPAN_WARNING("You can't use NSay while unconscious.")) + return if(!nif) - to_chat(src,"You can't use NSay without a NIF.") + to_chat(src, SPAN_WARNING("You can't use NSay without a NIF.")) return var/datum/nifsoft/soulcatcher/SC = nif.imp_check(NIF_SOULCATCHER) if(!SC) - to_chat(src,"You need the Soulcatcher software to use NSay.") + to_chat(src, SPAN_WARNING("You need the Soulcatcher software to use NSay.")) return if(!SC.brainmobs.len) - to_chat(src,"You need a loaded mind to use NSay.") + to_chat(src, SPAN_WARNING("You need a loaded mind to use NSay.")) return if(!message) - return + message = input(usr, "Type a message to say.","Speak into Soulcatcher") as text|null if(message) var/sane_message = sanitize(message) SC.say_into(sane_message,src) -/mob/living/carbon/human/proc/nme(message as message) +/mob/proc/nme(message as text|null) set name = "NMe" set desc = "Emote into your NIF's Soulcatcher." set category = "IC" + src.nme_act(message) + +/mob/proc/nme_act(message as text|null) + to_chat(src, SPAN_WARNING("You must be a humanoid with a NIF implanted to use that.")) + +/mob/living/carbon/human/nme_act(message as text|null) + if(stat != CONSCIOUS) + to_chat(src, SPAN_WARNING("You can't use NMe while unconscious.")) + return if(!nif) - to_chat(src,"You can't use NMe without a NIF.") + to_chat(src, SPAN_WARNING("You can't use NMe without a NIF.")) return var/datum/nifsoft/soulcatcher/SC = nif.imp_check(NIF_SOULCATCHER) if(!SC) - to_chat(src,"You need the Soulcatcher software to use NMe.") + to_chat(src, SPAN_WARNING("You need the Soulcatcher software to use NMe.")) return if(!SC.brainmobs.len) - to_chat(src,"You need a loaded mind to use NMe.") + to_chat(src, SPAN_WARNING("You need a loaded mind to use NMe.")) return if(!message) - return + message = input(usr, "Type an action to perform.","Emote into Soulcatcher") as text|null if(message) var/sane_message = sanitize(message) SC.emote_into(sane_message,src) @@ -628,25 +649,3 @@ QDEL_NULL(eyeobj) soulcatcher.notify_into("[src] ended AR projection.") - -/mob/living/carbon/brain/caught_soul/verb/nsay(message as text|null) - set name = "NSay" - set desc = "Speak into the NIF's Soulcatcher (circumventing AR speaking)." - set category = "Soulcatcher" - - if(!message) - message = input("Type a message to say.","Speak into Soulcatcher") as text|null - if(message) - var/sane_message = sanitize(message) - soulcatcher.say_into(sane_message,src,null) - -/mob/living/carbon/brain/caught_soul/verb/nme(message as text|null) - set name = "NMe" - set desc = "Emote into the NIF's Soulcatcher (circumventing AR speaking)." - set category = "Soulcatcher" - - if(!message) - message = input("Type an action to perform.","Emote into Soulcatcher") as text|null - if(message) - var/sane_message = sanitize(message) - soulcatcher.emote_into(sane_message,src,null) diff --git a/code/modules/nifsoft/software/14_commlink.dm b/code/modules/nifsoft/software/14_commlink.dm index 98577e109a0..34b9d3044b5 100644 --- a/code/modules/nifsoft/software/14_commlink.dm +++ b/code/modules/nifsoft/software/14_commlink.dm @@ -21,7 +21,7 @@ /datum/nifsoft/commlink/activate() if((. = ..())) nif.comm.initialize_exonet(nif.human) - nif.comm.ui_interact(nif.human, custom_state = GLOB.tgui_commlink_state) + nif.comm.ui_interact(nif.human, custom_state = GLOB.ui_commlink_state) spawn(0) deactivate() diff --git a/code/modules/nifsoft/software/15_misc.dm b/code/modules/nifsoft/software/15_misc.dm index a2f9e83de01..33121b5662b 100644 --- a/code/modules/nifsoft/software/15_misc.dm +++ b/code/modules/nifsoft/software/15_misc.dm @@ -9,37 +9,38 @@ var/obj/machinery/power/apc/apc other_flags = (NIF_O_APCCHARGE) - activate() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - apc = locate(/obj/machinery/power/apc) in get_step(H,H.dir) - if(!apc) - apc = locate(/obj/machinery/power/apc) in get_step(H,0) - if(!apc) - nif.notify("You must be facing an APC to connect to.",TRUE) - spawn(0) - deactivate() - return FALSE - - H.visible_message("Thin snakelike tendrils grow from [H] and connect to \the [apc].","Thin snakelike tendrils grow from you and connect to \the [apc].") - - deactivate(force = FALSE) - . = ..() - if(.) - apc = null - - life() - if((. = ..())) - var/mob/living/carbon/human/H = nif.human - if(apc && (get_dist(H,apc) <= 1) && H.nutrition < (H.species.max_nutrition - 10)) // 440 vs 450, life() happens before we get here so it'll never be EXACTLY 450 - H.nutrition = min(H.nutrition+10, H.species.max_nutrition) - apc.cell.use(SYNTHETIC_NUTRITION_CHARGE_RATE * 10) //This is from the large rechargers. No idea what the math is. - return TRUE - else - nif.notify("APC charging has ended.") - H.visible_message("[H]'s snakelike tendrils whip back into their body from \the [apc].","The APC connector tendrils return to your body.") +/datum/nifsoft/apc_recharge/activate() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + apc = locate(/obj/machinery/power/apc) in get_step(H,H.dir) + if(!apc) + apc = locate(/obj/machinery/power/apc) in get_step(H,0) + if(!apc) + nif.notify("You must be facing an APC to connect to.",TRUE) + spawn(0) deactivate() - return FALSE + return FALSE + + H.visible_message(SPAN_WARNING("Thin snakelike tendrils grow from [H] and connect to \the [apc]."), \ + SPAN_NOTICE("Thin snakelike tendrils grow from you and connect to \the [apc].")) + +/datum/nifsoft/apc_recharge/deactivate(var/force = FALSE) + if((. = ..())) + apc = null + +/datum/nifsoft/apc_recharge/life() + if((. = ..())) + var/mob/living/carbon/human/H = nif.human + if(apc && (get_dist(H,apc) <= 1) && H.nutrition < 440) // 440 vs 450, life() happens before we get here so it'll never be EXACTLY 450 + H.nutrition = min(H.nutrition+10, 450) + apc.drain_power(7000/450*10) //This is from the large rechargers. No idea what the math is. + return TRUE + else + nif.notify("APC charging has ended.") + H.visible_message(SPAN_WARNING("[H]'s snakelike tendrils whip back into their body from \the [apc]."), \ + SPAN_NOTICE("The APC connector tendrils return to your body.")) + deactivate() + return FALSE /datum/nifsoft/pressure name = "Pressure Seals" @@ -63,31 +64,31 @@ applies_to = NIF_SYNTHETIC other_flags = (NIF_O_HEATSINKS) - activate() - if((. = ..())) - if(used >= 1500) - nif.notify("Heat sinks not safe to operate again yet! Max 75% on activation.",TRUE) - spawn(0) - deactivate() - return FALSE - - stat_text() - return "[active ? "Active" : "Disabled"] (Stored Heat: [FLOOR((used/20), 1)]%)" - - life() - if((. = ..())) - //Not being used, all clean. - if(!active && !used) - return TRUE - - //Being used, and running out. - else if(active && ++used == 2000) - nif.notify("Heat sinks overloaded! Shutting down!",TRUE) +/datum/nifsoft/heatsinks/activate() + if((. = ..())) + if(used >= 1500) + nif.notify("Heat sinks not safe to operate again yet! Max 75% on activation.",TRUE) + spawn(0) deactivate() + return FALSE - //Being cleaned, and finishing empty. - else if(!active && --used == 0) - nif.notify("Heat sinks re-chilled.") +/datum/nifsoft/heatsinks/stat_text() + return "[active ? "Active" : "Disabled"] (Stored Heat: [FLOOR((used/20), 1)]%)" + +/datum/nifsoft/heatsinks/life() + if((. = ..())) + //Not being used, all clean. + if(!active && !used) + return TRUE + + //Being used, and running out. + else if(active && ++used == 2000) + nif.notify("Heat sinks overloaded! Shutting down!",TRUE) + deactivate() + + //Being cleaned, and finishing empty. + else if(!active && --used == 0) + nif.notify("Heat sinks re-chilled.") /datum/nifsoft/compliance name = "Compliance Module" @@ -100,29 +101,30 @@ access = 999 //Prevents anyone from buying it without an emag. var/laws = "Be nice to people!" - New(var/newloc,var/newlaws) - laws = newlaws //Sanitize before this (the disk does) - ..(newloc) +/datum/nifsoft/compliance/New(var/newloc,var/newlaws) + laws = newlaws //Sanitize before this (the disk does) + ..(newloc) - activate() - if((. = ..())) - to_chat(nif.human,"You feel a strong compulsion towards these directives:
[laws]\ -
While the disk has a considerable hold on your mind, you feel like you would be able to resist the control if you were pushed to do something you would consider utterly unacceptable.\ -
\[OOC NOTE: Compliance laws are only a scene tool, and not something that is effective in actual gameplay, hence the above. For example, if you are compelled to do something that would affect the round or other players (kill a crewmember, steal an item, give the disker elevated access), you should not do so.\]
") +/datum/nifsoft/compliance/activate() + if((. = ..())) + to_chat(nif.human,"You feel a strong compulsion towards these directives:
[laws]\ +
While the disk has a considerable hold on your mind, you feel like you would be able to resist the control if you were pushed to do something you would consider utterly unacceptable.\ +
\[OOC NOTE: Compliance laws are only a scene tool, and not something that is effective in actual gameplay, hence the above. For example, if you are compelled to do something that would affect the round or other players (kill a crewmember, steal an item, give the disker elevated access), you should not do so.\]
") - install() - if((. = ..())) - log_game("[nif.human? nif.human : "ERROR: NO HUMAN ON NIF"] was compliance disked with [laws]") - to_chat(nif.human,"You feel a strong compulsion towards these directives:
[laws]\ -
While the disk has a considerable hold on your mind, you feel like you would be able to resist the control if you were pushed to do something you would consider utterly unacceptable.\ -
\[OOC NOTE: Compliance laws are only a scene tool, and not something that is effective in actual gameplay, hence the above. For example, if you are compelled to do something that would affect the round or other players (kill a crewmember, steal an item, give the disker elevated access), you should not do so.\]
") - uninstall() - nif.notify("ERROR! Unable to comply!",TRUE) - return FALSE //NOPE. +/datum/nifsoft/compliance/install() + if((. = ..())) + log_game("[nif.human? nif.human : "ERROR: NO HUMAN ON NIF"] was compliance disked with [laws]") + to_chat(nif.human,"You feel a strong compulsion towards these directives:
[laws]\ +
While the disk has a considerable hold on your mind, you feel like you would be able to resist the control if you were pushed to do something you would consider utterly unacceptable.\ +
\[OOC NOTE: Compliance laws are only a scene tool, and not something that is effective in actual gameplay, hence the above. For example, if you are compelled to do something that would affect the round or other players (kill a crewmember, steal an item, give the disker elevated access), you should not do so.\]
") - stat_text() - return "Show Laws" +/datum/nifsoft/compliance/uninstall() + nif.notify("ERROR! Unable to comply!",TRUE) + return FALSE //NOPE. + +/datum/nifsoft/compliance/stat_text() + return "Show Laws" /datum/nifsoft/sizechange name = "Mass Alteration" @@ -131,32 +133,32 @@ cost = 375 wear = 6 - activate() - if((. = ..())) - var/new_size = input("Put the desired size (25-200%)", "Set Size", 200) as num +/datum/nifsoft/sizechange/activate() + if((. = ..())) + var/new_size = input("Put the desired size (25-200%)", "Set Size", 200) as num - if (!ISINRANGE(new_size,25,200)) - to_chat(nif.human,"The safety features of the NIF Program prevent you from choosing this size.") - return - else - nif.human.resize(new_size/100, TRUE) - to_chat(nif.human,"You set the size to [new_size]%") + if (!ISINRANGE(new_size,25,200)) + to_chat(nif.human, SPAN_NOTICE("The safety features of the NIF Program prevent you from choosing this size.")) + return + else + nif.human.resize(new_size/100) + to_chat(nif.human, SPAN_NOTICE("You set the size to [new_size]%")) - nif.human.visible_message("Swirling grey mist envelops [nif.human] as they change size!","Swirling streams of nanites wrap around you as you change size!") - nif.human.update_icons() //Apply matrix transform asap - log_game("[key_name(nif.human)] was resized to [new_size / 100] scale via nifsoft.") - - if (new_size < 75) - to_chat(nif.human,"You get dizzy as the floor rushes up to you!") - else if(new_size > 125) - to_chat(nif.human,"You feel disoriented as the floor falls away from you!") - else - to_chat(nif.human,"You feel sick as your mass is rearranged!") + nif.human.visible_message(SPAN_WARNING("Swirling grey mist envelops [nif.human] as they change size!"), SPAN_NOTICE("Swirling streams of nanites wrap around you as you change size!")) + nif.human.update_icons() //Apply matrix transform asap + log_game("[key_name(nif.human)] was resized to [new_size / 100] scale via nifsoft.") + if (new_size < 75) + to_chat(nif.human, SPAN_WARNING("You get dizzy as the floor rushes up to you!")) + else if(new_size > 125) + to_chat(nif.human, SPAN_WARNING("You feel disoriented as the floor falls away from you!")) + else + to_chat(nif.human, SPAN_WARNING("You feel sick as your mass is rearranged!")) + spawn(0) deactivate() - stat_text() - return "Change Size" +/datum/nifsoft/sizechange/stat_text() + return "Change Size" /datum/nifsoft/worldbend name = "World Bender" @@ -165,22 +167,22 @@ cost = 100 a_drain = 0.01 - activate() - if((. = ..())) - var/list/justme = list(nif.human) - for(var/human in human_mob_list) - if(human == nif.human) - continue - var/mob/living/carbon/human/H = human - H.display_alt_appearance("animals", justme) - alt_farmanimals += nif.human +/datum/nifsoft/worldbend/activate() + if((. = ..())) + var/list/justme = list(nif.human) + for(var/human in human_mob_list) + if(human == nif.human) + continue + var/mob/living/carbon/human/H = human + H.display_alt_appearance("animals", justme) + alt_farmanimals += nif.human - deactivate(force = FALSE) - if((. = ..())) - var/list/justme = list(nif.human) - for(var/human in human_mob_list) - if(human == nif.human) - continue - var/mob/living/carbon/human/H = human - H.hide_alt_appearance("animals", justme) - alt_farmanimals -= nif.human +/datum/nifsoft/worldbend/deactivate(var/force = FALSE) + if((. = ..())) + var/list/justme = list(nif.human) + for(var/human in human_mob_list) + if(human == nif.human) + continue + var/mob/living/carbon/human/H = human + H.hide_alt_appearance("animals", justme) + alt_farmanimals -= nif.human diff --git a/code/modules/organs/internal/adherent.dm b/code/modules/organs/internal/adherent.dm index 2fa118c5999..fc491dc61cb 100644 --- a/code/modules/organs/internal/adherent.dm +++ b/code/modules/organs/internal/adherent.dm @@ -178,7 +178,7 @@ cooling = !cooling to_chat(C, "You toggle your cooling fans [cooling ? "on" : "off"] ") -/obj/item/organ/internal/powered/cooling_fins/process() +/obj/item/organ/internal/powered/cooling_fins/process(delta_time) var/mob/living/carbon/human/C = src.owner if(cooling) var/temp_diff = min(C.bodytemperature - target_temp, max_cooling) diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm index 94905076418..21f3c25c4ac 100644 --- a/code/modules/organs/internal/brain.dm +++ b/code/modules/organs/internal/brain.dm @@ -155,7 +155,7 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain) can_assist = FALSE /obj/item/organ/internal/brain/slime - icon = 'icons/obj/surgery_vr.dmi' // Vorestation edit + icon = 'icons/obj/surgery.dmi' name = "slime core" desc = "A complex, organic knot of jelly and crystalline particles." icon_state = "core" diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index 6525f8fb32a..58dc0b752db 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -58,30 +58,49 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ R.species_alternates[species] = all_robolimbs[species_company] /datum/robolimb - var/company = "Unbranded" // Shown when selecting the limb. - var/desc = "A generic unbranded robotic prosthesis." // Seen when examining a limb. - var/icon = 'icons/mob/human_races/robotic.dmi' // Icon base to draw from. - var/monitor_icon = "icons/mob/monitor_icons.dmi" // Where it draws the monitor icon from. - var/unavailable_at_chargen // If set, not available at chargen. - var/unavailable_to_build // If set, can't be constructed. - var/lifelike // If set, appears organic. - var/skin_tone // If set, applies skin tone rather than part color Overrides color. - var/skin_color // If set, applies skin color rather than part color. + ///Shown when selecting the limb. + var/company = "Unbranded" + ///Seen when examining a limb. + var/desc = "A generic unbranded robotic prosthesis." + ///Icon base to draw from. + var/icon = 'icons/mob/human_races/robotic.dmi' + ///Where it draws the monitor icon from. + var/monitor_icon = "icons/mob/monitor_icons.dmi" + ///If set, not available at character creator. + var/unavailable_at_chargen + ///If set, can't be constructed. + var/unavailable_to_build + ///If set, appears organic. + var/lifelike + ///If set, applies skin tone rather than part color Overrides color. + var/skin_tone + ///If set, applies skin color rather than part color. + var/skin_color + ///If set, applies blood color rather than species' blood color. var/blood_color = "#030303" - var/list/species_cannot_use = list(SPECIES_TESHARI, SPECIES_PROMETHEAN, SPECIES_DIONA, SPECIES_XENOCHIMERA) //VOREStation Edit - var/list/species_alternates = list(SPECIES_TAJ = "Unbranded - Tajaran", SPECIES_UNATHI = "Unbranded - Unathi") //"Species Name" = "Robolimb Company" , List, when initialized, will become "Species Name" = RobolimbDatum, used for alternate species sprites. - var/list/monitor_styles //If empty, the model of limbs offers a head compatible with monitors. - var/parts = BP_ALL //Defines what parts said brand can replace on a body. - var/health_hud_intensity = 1 // Intensity modifier for the health GUI indicator. - var/suggested_species = "Human" //If it should make the torso a species - var/speech_bubble_appearance = "synthetic" // What icon_state to use for speech bubbles when talking. Check talk.dmi for all the icons. - - var/robo_brute_mod = 1 // Multiplier for incoming brute damage. - var/robo_burn_mod = 1 // As above for burn. - - var/includes_tail //Cyberlimbs dmi includes a tail sprite to wear. - var/includes_wing //Cyberlimbs dmi includes a wing sprite to wear. - var/list/whitelisted_to //List of ckeys that are allowed to pick this in charsetup. + var/list/species_cannot_use = list(SPECIES_TESHARI, SPECIES_PROMETHEAN, SPECIES_DIONA, SPECIES_XENOCHIMERA) + ///"Species Name" = "Robolimb Company" , List, when initialized, will become "Species Name" = RobolimbDatum, used for alternate species sprites. + var/list/species_alternates = list(SPECIES_TAJ = "Unbranded - Tajaran", SPECIES_UNATHI = "Unbranded - Unathi") + ///If empty, the model of limbs offers a head compatible with monitors. + var/list/monitor_styles + ///Defines what parts said brand can replace on a body. + var/parts = BP_ALL + ///Intensity modifier for the health GUI indicator. + var/health_hud_intensity = 1 + ///If it should make the torso a species + var/suggested_species = "Human" + ///What icon_state to use for speech bubbles when talking. Check talk.dmi for all the icons. + var/speech_bubble_appearance = "synthetic" + ///Multiplier for incoming brute damage. + var/robo_brute_mod = 1 + ///Multiplier for incoming burn damage. + var/robo_burn_mod = 1 + ///Cyberlimbs dmi includes a tail sprite to wear. + var/includes_tail + ///Cyberlimbs dmi includes a wing sprite to wear. + var/includes_wing + ///List of ckeys that are allowed to pick this in charsetup. + var/list/whitelisted_to /datum/robolimb/unbranded_monitor company = "Unbranded Monitor" @@ -89,19 +108,19 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_monitor.dmi' parts = list(BP_HEAD) monitor_styles = standard_monitor_styles - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/unbranded_alt1 company = "Unbranded - Protez" desc = "A simple robotic limb with retro design. Seems rather stiff." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_alt1.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/unbranded_alt2 company = "Unbranded - Mantis Prosis" desc = "This limb has a casing of sleek black metal and repulsive insectile design." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_alt2.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/unbranded_tajaran company = "Unbranded - Tajaran" @@ -109,7 +128,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ suggested_species = SPECIES_TAJ desc = "A simple robotic limb with feline design. Seems rather stiff." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_tajaran.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/unbranded_unathi company = "Unbranded - Unathi" @@ -117,7 +136,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ suggested_species = SPECIES_UNATHI desc = "A simple robotic limb with reptilian design. Seems rather stiff." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_unathi.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/unbranded_teshari company = "Unbranded - Teshari" @@ -125,7 +144,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ suggested_species = SPECIES_TESHARI desc = "A simple robotic limb with a small, raptor-like design. Seems rather stiff." icon = 'icons/mob/human_races/cyberlimbs/unbranded/unbranded_teshari.dmi' - unavailable_to_build = 0 + unavailable_to_build = TRUE /datum/robolimb/nanotrasen company = "NanoTrasen" @@ -140,7 +159,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ suggested_species = SPECIES_TAJ desc = "A simple but efficient robotic limb, created by NanoTrasen." icon = 'icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_tajaran.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/nanotrasen_unathi company = "NanoTrasen - Unathi" @@ -149,43 +168,43 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ suggested_species = SPECIES_UNATHI desc = "A simple but efficient robotic limb, created by NanoTrasen." icon = 'icons/mob/human_races/cyberlimbs/nanotrasen/nanotrasen_unathi.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/bishop company = "Bishop" desc = "This limb has a white polymer casing with blue holo-displays." icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/bishop_alt1 company = "Bishop - Glyph" desc = "This limb has a white polymer casing with blue holo-displays." icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_alt1.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) /datum/robolimb/bishop_alt2 company = "Bishop - Rook" desc = "This limb has a solid plastic casing with blue lights along it." icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_alt2.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/bishop_monitor company = "Bishop Monitor" desc = "Bishop Cybernetics' unique spin on a popular prosthetic head model. The themes conflict in an intriguing way." icon = 'icons/mob/human_races/cyberlimbs/bishop/bishop_monitor.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) monitor_styles = standard_monitor_styles /datum/robolimb/cenilimicybernetics_teshari company = "Cenilimi Cybernetics" - species_cannot_use = list(SPECIES_UNATHI, SPECIES_PROMETHEAN, SPECIES_DIONA, SPECIES_HUMAN, SPECIES_VOX, SPECIES_HUMAN_VATBORN, SPECIES_TAJ, SPECIES_SKRELL, SPECIES_ZADDAT) - species_alternates = list(SPECIES_HUMAN = "NanoTrasen") - suggested_species = SPECIES_TESHARI desc = "Made by a Teshari-owned company, for Teshari." icon = 'icons/mob/human_races/cyberlimbs/cenilimicybernetics/cenilimicybernetics_teshari.dmi' - unavailable_to_build = 1 + suggested_species = SPECIES_TESHARI + species_cannot_use = list(SPECIES_UNATHI, SPECIES_PROMETHEAN, SPECIES_DIONA, SPECIES_HUMAN, SPECIES_VOX, SPECIES_HUMAN_VATBORN, SPECIES_TAJ, SPECIES_SKRELL, SPECIES_ZADDAT) + species_alternates = list(SPECIES_HUMAN = "NanoTrasen") + unavailable_to_build = TRUE /datum/robolimb/gestaltframe company = "Skrellian Exoskeleton" @@ -193,7 +212,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/veymed/dionaea/skrellian.dmi' blood_color = "#63b521" speech_bubble_appearance = "machine" - unavailable_to_build = 1 + unavailable_to_build = TRUE species_cannot_use = list(SPECIES_TESHARI, SPECIES_PROMETHEAN, SPECIES_TAJ, SPECIES_HUMAN, SPECIES_VOX, SPECIES_HUMAN_VATBORN, SPECIES_UNATHI, SPECIES_SKRELL, SPECIES_ZADDAT) suggested_species = SPECIES_DIONA // Dionaea are naturally very tanky, so the robotic limbs are actually far weaker than their normal bodies. @@ -204,32 +223,32 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Cyber Solutions" desc = "This limb is grey and rough, with little in the way of aesthetic." icon = 'icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/cybersolutions_alt2 company = "Cyber Solutions - Array" desc = "This limb is simple and functional; array of sensors on a featureless case." icon = 'icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_alt2.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) /datum/robolimb/cybersolutions_alt1 company = "Cyber Solutions - Wight" desc = "This limb has cheap plastic panels mounted on grey metal." icon = 'icons/mob/human_races/cyberlimbs/cybersolutions/cybersolutions_alt1.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/einstein company = "Einstein Engines" desc = "This limb is lightweight with a sleek design." icon = 'icons/mob/human_races/cyberlimbs/einstein/einstein_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/grayson company = "Grayson" desc = "This limb has a sturdy and heavy build to it." icon = 'icons/mob/human_races/cyberlimbs/grayson/grayson_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE monitor_styles = "blank=grayson_off;\ red=grayson_red;\ green=grayson_green;\ @@ -240,7 +259,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Grayson - Reinforced" desc = "This limb has a sturdy and heavy build to it." icon = 'icons/mob/human_races/cyberlimbs/grayson/grayson_alt1.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) monitor_styles = "blank=grayson_alt_off;\ green=grayson_alt_green;\ @@ -252,7 +271,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Grayson Monitor" desc = "This limb has a sturdy and heavy build to it, and uses plastics in the place of glass for the monitor." icon = 'icons/mob/human_races/cyberlimbs/grayson/grayson_monitor.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) monitor_styles = standard_monitor_styles @@ -260,13 +279,13 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Hephaestus" desc = "This limb has a militaristic black and green casing with gold stripes." icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/hephaestus_alt1 company = "Hephaestus - Frontier" desc = "A rugged prosthetic head featuring the standard Hephaestus theme, a visor and an external display." icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_alt1.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) monitor_styles = "blank=hephaestus_alt_off;\ pink=hephaestus_alt_pink;\ @@ -280,7 +299,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Hephaestus - Athena" desc = "This rather thick limb has a militaristic green plating." icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_alt2.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE monitor_styles = "red=athena_red;\ blank=athena_off" @@ -288,7 +307,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Hephaestus Monitor" desc = "Hephaestus' unique spin on a popular prosthetic head model. It looks rugged and sturdy." icon = 'icons/mob/human_races/cyberlimbs/hephaestus/hephaestus_monitor.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) monitor_styles = standard_monitor_styles @@ -296,35 +315,35 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Morpheus" desc = "This limb is simple and functional; no effort has been made to make it look human." icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE monitor_styles = standard_monitor_styles /datum/robolimb/morpheus_alt1 company = "Morpheus - Zenith" desc = "This limb is simple and functional; no effort has been made to make it look human." icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt1.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) /datum/robolimb/morpheus_alt2 company = "Morpheus - Skeleton Crew" desc = "This limb is simple and functional; it's basically just a case for a brain." icon = 'icons/mob/human_races/cyberlimbs/morpheus/morpheus_alt2.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) /datum/robolimb/veymed company = "Vey-Med" desc = "This high quality limb is nearly indistinguishable from an organic one." - icon = 'icons/mob/human_races/cyberlimbs/veymed/veymed_main_vr.dmi' //Vorestation edit, fixing the color application - unavailable_to_build = 1 + icon = 'icons/mob/human_races/cyberlimbs/veymed/veymed_main_vr.dmi' + unavailable_to_build = TRUE lifelike = 1 skin_tone = 1 species_alternates = list(SPECIES_SKRELL = "Vey-Med - Skrell") blood_color = "#CCCCCC" speech_bubble_appearance = "normal" - //robo_brute_mod = 1.1 //VOREStation Edit - //robo_burn_mod = 1.1 //VOREStation Edit + robo_brute_mod = 1.1 + robo_burn_mod = 1.1 /datum/robolimb/veymed/skrell company = "Vey-Med - Skrell" @@ -355,26 +374,26 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Ward-Takahashi" desc = "This limb features sleek black and white polymers." icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/wardtakahashi_alt1 company = "Ward-Takahashi - Shroud" desc = "This limb features sleek black and white polymers. This one looks more like a helmet of some sort." icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_alt1.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) /datum/robolimb/wardtakahashi_alt2 company = "Ward-Takahashi - Spirit" desc = "This limb has white and purple features, with a heavier casing." icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_alt2.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/wardtakahashi_monitor company = "Ward-Takahashi Monitor" desc = "Ward-Takahashi's unique spin on a popular prosthetic head model. It looks sleek and modern." icon = 'icons/mob/human_races/cyberlimbs/wardtakahashi/wardtakahashi_monitor.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) monitor_styles = standard_monitor_styles @@ -382,20 +401,20 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Xion" desc = "This limb has a minimalist black and red casing." icon = 'icons/mob/human_races/cyberlimbs/xion/xion_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/xion_alt1 company = "Xion - Breach" desc = "This limb has a minimalist black and red casing. Looks a bit menacing." icon = 'icons/mob/human_races/cyberlimbs/xion/xion_alt1.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) /datum/robolimb/xion_alt2 company = "Xion - Hull" desc = "This limb has a thick orange casing with steel plating." icon = 'icons/mob/human_races/cyberlimbs/xion/xion_alt2.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE monitor_styles = "blank=xion_off;\ red=xion_red;\ green=xion_green;\ @@ -406,13 +425,13 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Xion - Whiteout" desc = "This limb has a minimalist black and white casing." icon = 'icons/mob/human_races/cyberlimbs/xion/xion_alt3.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE /datum/robolimb/xion_alt4 company = "Xion - Breach - Whiteout" desc = "This limb has a minimalist black and white casing. Looks a bit menacing." icon = 'icons/mob/human_races/cyberlimbs/xion/xion_alt4.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) @@ -420,7 +439,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Xion Monitor" desc = "Xion Mfg.'s unique spin on a popular prosthetic head model. It looks and minimalist and utilitarian." icon = 'icons/mob/human_races/cyberlimbs/xion/xion_monitor.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) monitor_styles = standard_monitor_styles @@ -430,7 +449,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Zeng-Hu" desc = "This limb has a rubbery fleshtone covering with visible seams." icon = 'icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE skin_tone = 1 @@ -439,7 +458,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Cyber Tech" desc = "Adjusted for deep space the material is durable, and heavy." icon = 'icons/mob/human_races/cyberlimbs/c-tech/c_beast.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) monitor_styles = cyberbeast_monitor_styles @@ -538,7 +557,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/_fluff_vr/rahboop.dmi' blood_color = "#5e280d" includes_tail = 1 - unavailable_to_build = 1 + unavailable_to_build = TRUE /obj/item/disk/limb/eggnerdltd company = "Eggnerd Prototyping Ltd." @@ -551,7 +570,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ desc = "This limb is crafted out of hammered brass. Unlike other prosthetics, the internals of this device run off of a complex system of clockwork gears and arms, with a wired superstructure layered on top. This level of craftsmanship is incredibly atypical." icon = 'icons/mob/human_races/cyberlimbs/_fluff_vr/brassworks.dmi' blood_color = "#1F2631" - unavailable_to_build = 1 + unavailable_to_build = TRUE /obj/item/disk/limb/vulkanwrks company = "Vulcan Brassworks Inc." @@ -572,7 +591,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Zeng-Hu - Tajaran" desc = "This limb has a rubbery fleshtone covering with visible seams." icon = 'icons/mob/human_races/cyberlimbs/zenghu/zenghu_taj.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) /datum/robolimb/eggnerdltdred @@ -581,7 +600,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/rahboopred/rahboopred.dmi' blood_color = "#5e280d" includes_tail = 1 - unavailable_to_build = 1 + unavailable_to_build = TRUE /obj/item/disk/limb/eggnerdltdred company = "Eggnerd Prototyping Ltd. (Red)" @@ -597,10 +616,10 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/DSITajaran/dsi_tajaran.dmi' blood_color = "#ffe2ff" lifelike = 1 - unavailable_to_build = 1 + unavailable_to_build = TRUE includes_tail = 1 skin_tone = 1 - suggested_species = "Tajara" + suggested_species = SPECIES_TAJ speech_bubble_appearance = "normal" /obj/item/disk/limb/dsi_tajaran @@ -612,10 +631,10 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/DSILizard/dsi_lizard.dmi' blood_color = "#ffe2ff" lifelike = 1 - unavailable_to_build = 1 + unavailable_to_build = TRUE includes_tail = 1 skin_tone = 1 - suggested_species = "Unathi" + suggested_species = SPECIES_UNATHI speech_bubble_appearance = "normal" /obj/item/disk/limb/dsi_lizard @@ -627,10 +646,10 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/DSISergal/dsi_sergal.dmi' blood_color = "#ffe2ff" lifelike = 1 - unavailable_to_build = 1 + unavailable_to_build = TRUE includes_tail = 1 skin_tone = 1 - suggested_species = "Sergal" + suggested_species = SPECIES_SERGAL speech_bubble_appearance = "normal" /obj/item/disk/limb/dsi_sergal @@ -642,10 +661,10 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/DSINevrean/dsi_nevrean.dmi' blood_color = "#ffe2ff" lifelike = 1 - unavailable_to_build = 1 + unavailable_to_build = TRUE includes_tail = 1 skin_tone = 1 - suggested_species = "Nevrean" + suggested_species = SPECIES_NEVREAN speech_bubble_appearance = "normal" /obj/item/disk/limb/dsi_nevrean @@ -657,10 +676,10 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/DSIVulpkanin/dsi_vulpkanin.dmi' blood_color = "#ffe2ff" lifelike = 1 - unavailable_to_build = 1 + unavailable_to_build = TRUE includes_tail = 1 skin_tone = 1 - suggested_species = "Vulpkanin" + suggested_species = SPECIES_VULPKANIN speech_bubble_appearance = "normal" /obj/item/disk/limb/dsi_vulpkanin @@ -672,10 +691,10 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/DSIAkula/dsi_akula.dmi' blood_color = "#ffe2ff" lifelike = 1 - unavailable_to_build = 1 + unavailable_to_build = TRUE includes_tail = 1 skin_tone = 1 - suggested_species = "Akula" + suggested_species = SPECIES_AKULA speech_bubble_appearance = "normal" /obj/item/disk/limb/dsi_akula @@ -687,10 +706,10 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ icon = 'icons/mob/human_races/cyberlimbs/DSISpider/dsi_spider.dmi' blood_color = "#ffe2ff" lifelike = 1 - unavailable_to_build = 1 + unavailable_to_build = TRUE includes_tail = 1 skin_tone = 1 - suggested_species = "Vasilissan" + suggested_species = SPECIES_VASILISSAN speech_bubble_appearance = "normal" /obj/item/disk/limb/dsi_spider @@ -701,8 +720,9 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ desc = "This limb has a thin synthflesh casing with a few connection ports." icon = 'icons/mob/human_races/cyberlimbs/DSITeshari/dsi_teshari.dmi' lifelike = 1 + unavailable_to_build = TRUE skin_tone = 1 - suggested_species = "Teshari" + suggested_species = SPECIES_TESHARI speech_bubble_appearance = "normal" /datum/robolimb/dsi_teshari/New() @@ -718,7 +738,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "cortexCases - MMI" desc = "A solid, transparent case to hold your important bits in with style." icon = 'icons/mob/human_races/cyberlimbs/cortex/braincase.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) /obj/item/disk/limb/braincase @@ -728,7 +748,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "cortexCases - Posi" desc = "A solid, transparent case to hold your important bits in with style." icon = 'icons/mob/human_races/cyberlimbs/cortex/posicase.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE parts = list(BP_HEAD) /obj/item/disk/limb/posicase @@ -738,7 +758,7 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ company = "Antares Robotics" desc = "Mustard-yellow industrial limb. Heavyset and thick." icon = 'icons/mob/human_races/cyberlimbs/antares/antares_main.dmi' - unavailable_to_build = 1 + unavailable_to_build = TRUE monitor_styles = standard_monitor_styles /obj/item/disk/limb/antares @@ -746,10 +766,13 @@ var/const/cyberbeast_monitor_styles = "blank=cyber_blank;\ /datum/robolimb/adherent - company = "NULL DATA." // Shown when selecting the limb. - desc = "NULL DATA." // Seen when examining a limb. - icon = 'icons/mob/human_races/r_adherent.dmi' // Icon base to draw from. - species_cannot_use = list(SPECIES_UNATHI, SPECIES_PROMETHEAN, SPECIES_DIONA, SPECIES_HUMAN, SPECIES_VOX, SPECIES_HUMAN_VATBORN, SPECIES_TAJ, SPECIES_SKRELL, SPECIES_ZADDAT, SPECIES_TESHARI) - unavailable_at_chargen = TRUE // If set, not available at chargen. - unavailable_to_build = TRUE // If set, can't be constructed. - suggested_species = SPECIES_ADHERENT //If it should make the torso a species + company = "NULL DATA." + desc = "NULL DATA." + icon = 'icons/mob/human_races/r_adherent.dmi' + unavailable_to_build = TRUE + suggested_species = SPECIES_ADHERENT + +/datum/robolimb/adherent/New() + species_cannot_use = GLOB.all_species.Copy() + species_cannot_use -= SPECIES_ADHERENT + ..() diff --git a/code/modules/organs/subtypes/diona.dm b/code/modules/organs/subtypes/diona.dm index 78c9e2a1e0c..ae4f701d1ea 100644 --- a/code/modules/organs/subtypes/diona.dm +++ b/code/modules/organs/subtypes/diona.dm @@ -3,7 +3,7 @@ return 0 //This is a terrible hack and I should be ashamed. - var/datum/seed/diona = plant_controller.seeds["diona"] + var/datum/seed/diona = SSplants.seeds["diona"] if(!diona) return 0 diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 7f50c1453ed..483acf2986c 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -14,8 +14,8 @@ desc = "A large cabinet with drawers." icon = 'icons/obj/bureaucracy.dmi' icon_state = "filingcabinet" - density = 1 - anchored = 1 + density = TRUE + anchored = TRUE /obj/structure/filingcabinet/chestdrawer name = "chest drawer" @@ -33,50 +33,41 @@ /obj/structure/filingcabinet/attackby(obj/item/P as obj, mob/user as mob) if(istype(P, /obj/item/paper) || istype(P, /obj/item/folder) || istype(P, /obj/item/photo) || istype(P, /obj/item/paper_bundle)) - to_chat(user, "You put [P] in [src].") + to_chat(user, SPAN_NOTICE("You put [P] in [src].")) user.drop_item() P.loc = src - icon_state = "[initial(icon_state)]-open" - sleep(5) - icon_state = initial(icon_state) - updateUsrDialog() + open_animation() + SStgui.update_uis(src) + else if(P.is_wrench()) playsound(loc, P.usesound, 50, 1) anchored = !anchored - to_chat(user, "You [anchored ? "wrench" : "unwrench"] \the [src].") + to_chat(user, SPAN_NOTICE("You [anchored ? "wrench" : "unwrench"] \the [src].")) + else if(P.is_screwdriver()) - to_chat(user, "You begin taking the [name] apart.") + to_chat(user, SPAN_NOTICE("You begin taking the [name] apart.")) playsound(src, P.usesound, 50, 1) if(do_after(user, 10 * P.toolspeed)) playsound(loc, P.usesound, 50, 1) - to_chat(user, "You take the [name] apart.") + to_chat(user, SPAN_NOTICE("You take the [name] apart.")) new /obj/item/stack/material/steel( src.loc, 4 ) for(var/obj/item/I in contents) I.forceMove(loc) qdel(src) return else - to_chat(user, "You can't put [P] in [src]!") + to_chat(user, SPAN_NOTICE("You can't put [P] in [src]!")) /obj/structure/filingcabinet/attack_hand(mob/user as mob) if(contents.len <= 0) - to_chat(user, "\The [src] is empty.") + to_chat(user, SPAN_NOTICE("\The [src] is empty.")) return - - user.set_machine(src) - var/dat = "
" - for(var/obj/item/P in src) - dat += "" - dat += "
[P.name]
" - user << browse("[name][dat]", "window=filingcabinet;size=350x300") - - return + ui_interact(user) /obj/structure/filingcabinet/attack_tk(mob/user) if(anchored) - attack_self_tk(user) - else - ..() + return attack_self_tk(user) + return ..() /obj/structure/filingcabinet/attack_self_tk(mob/user) if(contents.len) @@ -85,23 +76,48 @@ I.loc = loc if(prob(25)) step_rand(I) - to_chat(user, "You pull \a [I] out of [src] at random.") + to_chat(user, SPAN_NOTICE("You pull \a [I] out of [src] at random.")) return - to_chat(user, "You find nothing in [src].") + to_chat(user, SPAN_NOTICE("You find nothing in [src].")) -/obj/structure/filingcabinet/Topic(href, href_list) - if(href_list["retrieve"]) - usr << browse("", "window=filingcabinet") // Close the menu +/obj/structure/filingcabinet/ui_state(mob/user) + return GLOB.physical_state - //var/retrieveindex = text2num(href_list["retrieve"]) - var/obj/item/P = locate(href_list["retrieve"])//contents[retrieveindex] - if(istype(P) && (P.loc == src) && src.Adjacent(usr)) - usr.put_in_hands(P) - updateUsrDialog() - icon_state = "[initial(icon_state)]-open" - spawn(0) - sleep(5) - icon_state = initial(icon_state) +/obj/structure/filingcabinet/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "FileCabinet", name) + ui.set_autoupdate(FALSE) + ui.open() + +/obj/structure/filingcabinet/ui_data(mob/user) + var/list/files = list() + for(var/obj/item/P in src) + files.Add(list(list( + "name" = P.name, + "ref" = "\ref[P]", + ))) + + return list("contents" = files) + +/obj/structure/filingcabinet/ui_act(action, params) + if(..()) + return TRUE + + switch(action) + if("retrieve") + var/obj/item/P = locate(params["ref"]) + if(istype(P) && (P.loc == src) && usr.Adjacent(src)) + usr.put_in_hands(P) + open_animation() + SStgui.update_uis(src) + +/obj/structure/filingcabinet/proc/open_animation() + flick("[initial(icon_state)]-open",src) + playsound(src, 'sound/bureaucracy/filingcabinet.ogg', 50, 1) + spawn(0) + sleep(20) + icon_state = initial(icon_state) /* * Security Record Cabinets diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 2883cd03118..1dacfa608d5 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -1149,7 +1149,7 @@ GLOBAL_LIST_EMPTY(apcs) equipment = autoset(equipment, 0) lighting = autoset(lighting, 0) environ = autoset(environ, 0) - SSalarms.power_alarm.triggerAlarm(loc, src, hidden=alarms_hidden) + power_alarm.triggerAlarm(loc, src, hidden=alarms_hidden) autoflag = 0 // update icon & area power if anything changed @@ -1173,27 +1173,27 @@ GLOBAL_LIST_EMPTY(apcs) lighting = autoset(lighting, 1) environ = autoset(environ, 1) autoflag = 3 - SSalarms.power_alarm.clearAlarm(loc, src) + power_alarm.clearAlarm(loc, src) else if((cell.percent() <= 30) && (cell.percent() > 15) && longtermpower < 0) // <30%, turn off equipment if(autoflag != 2) equipment = autoset(equipment, 2) lighting = autoset(lighting, 1) environ = autoset(environ, 1) - SSalarms.power_alarm.triggerAlarm(loc, src, hidden=alarms_hidden) + power_alarm.triggerAlarm(loc, src, hidden=alarms_hidden) autoflag = 2 else if(cell.percent() <= 15) // <15%, turn off lighting & equipment if((autoflag > 1 && longtermpower < 0) || (autoflag > 1 && longtermpower >= 0)) equipment = autoset(equipment, 2) lighting = autoset(lighting, 2) environ = autoset(environ, 1) - SSalarms.power_alarm.triggerAlarm(loc, src, hidden=alarms_hidden) + power_alarm.triggerAlarm(loc, src, hidden=alarms_hidden) autoflag = 1 else // zero charge, turn all off if(autoflag != 0) equipment = autoset(equipment, 0) lighting = autoset(lighting, 0) environ = autoset(environ, 0) - SSalarms.power_alarm.triggerAlarm(loc, src, hidden=alarms_hidden) + power_alarm.triggerAlarm(loc, src, hidden=alarms_hidden) autoflag = 0 // val 0=off, 1=off(auto) 2=on 3=on(auto) @@ -1321,7 +1321,7 @@ obj/machinery/power/apc/proc/autoset(var/cur_state, var/on) //start with main breaker off, chargemode in the default state and all channels on auto upon reboot operating = 0 chargemode = initial(chargemode) - SSalarms.power_alarm.clearAlarm(loc, src) + power_alarm.clearAlarm(loc, src) lighting = POWERCHAN_ON_AUTO equipment = POWERCHAN_ON_AUTO diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index d2ea4f80b0f..9dcb13dd738 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -549,3 +549,25 @@ GLOBAL_LIST_EMPTY(smeses) input_level = 100000 output_level = 200000 +#define SMES_UI_INPUT 1 +#define SMES_UI_OUTPUT 2 + +/obj/machinery/power/smes/proc/ui_set_io(io, target, adjust) + if(target == "min") + target = 0 + . = TRUE + else if(target == "max") + target = output_level_max + . = TRUE + else if(adjust) + target = output_level + adjust + . = TRUE + else if(text2num(target) != null) + target = text2num(target) + . = TRUE + if(.) + switch(io) + if(SMES_UI_INPUT) + set_input(target) + if(SMES_UI_OUTPUT) + set_output(target) diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm index 4516ff5f4f8..83180c82791 100644 --- a/code/modules/power/smes_construction.dm +++ b/code/modules/power/smes_construction.dm @@ -376,27 +376,27 @@ // Proc: toggle_input() // Parameters: None // Description: Switches the input on/off depending on previous setting -/obj/machinery/power/smes/buildable/proc/toggle_input() +/obj/machinery/power/smes/proc/toggle_input() inputting(!input_attempt) update_icon() // Proc: toggle_output() // Parameters: None // Description: Switches the output on/off depending on previous setting -/obj/machinery/power/smes/buildable/proc/toggle_output() +/obj/machinery/power/smes/proc/toggle_output() outputting(!output_attempt) update_icon() // Proc: set_input() // Parameters: 1 (new_input - New input value in Watts) // Description: Sets input setting on this SMES. Trims it if limits are exceeded. -/obj/machinery/power/smes/buildable/proc/set_input(var/new_input = 0) +/obj/machinery/power/smes/proc/set_input(var/new_input = 0) input_level = between(0, new_input, input_level_max) update_icon() // Proc: set_output() // Parameters: 1 (new_output - New output value in Watts) // Description: Sets output setting on this SMES. Trims it if limits are exceeded. -/obj/machinery/power/smes/buildable/proc/set_output(var/new_output = 0) +/obj/machinery/power/smes/proc/set_output(var/new_output = 0) output_level = between(0, new_output, output_level_max) update_icon() diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index f73c68e7500..9dfc0d9eaca 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -67,12 +67,12 @@ set category = "Object" set src in view(1) - var/genemask = input("Choose a gene to modify.") as null|anything in plant_controller.plant_gene_datums + var/genemask = input("Choose a gene to modify.") as null|anything in SSplants.plant_gene_datums if(!genemask) return - gene = plant_controller.plant_gene_datums[genemask] + gene = SSplants.plant_gene_datums[genemask] to_chat(usr, "You set the [src]'s targeted genetic area to [genemask].") diff --git a/code/modules/random_map/automata/diona.dm b/code/modules/random_map/automata/diona.dm index f266f3995cc..ce1c26ddbeb 100644 --- a/code/modules/random_map/automata/diona.dm +++ b/code/modules/random_map/automata/diona.dm @@ -6,7 +6,7 @@ if(can_open == WALL_OPENING) return can_open = WALL_CAN_OPEN - user.visible_message("\The [user] strokes its feelers against \the [src] and the biomass [density ? "moves aside" : "closes up"].") + user.visible_message("\The [user] strokes its feelers against \the [src] and the biomass [density ? "moves aside" : "closes up"].") toggle_open(user) sleep(15) if(can_open == WALL_CAN_OPEN) can_open = 0 diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index 222c5cafaba..f6116cc37d3 100644 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -331,30 +331,37 @@ item_state = "electronic" slot_flags = SLOT_BELT -/obj/item/destTagger/proc/openwindow(mob/user as mob) - var/dat = "

TagMaster 2.3

" - dat += "" - for(var/i = 1, i <= GLOB.tagger_locations.len, i++) - dat += "" +/obj/item/destTagger/ui_state(mob/user) + return GLOB.inventory_state - if (i%4==0) - dat += "" +/obj/item/destTagger/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "DestinationTagger", name) + ui.open() - dat += "
[GLOB.tagger_locations[i]]

Current Selection: [currTag ? currTag : "None"]
" +/obj/item/destTagger/ui_data(mob/user, datum/tgui/ui) + var/list/data = ..() - user << browse(dat, "window=destTagScreen;size=450x350") - onclose(user, "destTagScreen") + data["currTag"] = currTag + data["taggerLocs"] = GLOB.tagger_locations + + return data /obj/item/destTagger/attack_self(mob/user as mob) - openwindow(user) - return + ui_interact(user) -/obj/item/destTagger/Topic(href, href_list) +/obj/item/destTagger/ui_act(action, params) if(..()) return TRUE - if(href_list["nextTag"] && (href_list["nextTag"] in GLOB.tagger_locations)) - src.currTag = href_list["nextTag"] - openwindow(usr) + add_fingerprint(usr) + switch(action) + if("set_tag") + var/new_tag = params["tag"] + if(!(new_tag in GLOB.tagger_locations)) + return FALSE + currTag = new_tag + . = TRUE /obj/machinery/disposal/deliveryChute name = "Delivery chute" diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm index 7bef03a5cad..1c39797d698 100644 --- a/code/modules/research/circuitprinter.dm +++ b/code/modules/research/circuitprinter.dm @@ -6,7 +6,9 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid). /obj/machinery/r_n_d/circuit_imprinter name = "Circuit Imprinter" - icon_state = "circuit_imprinter" + icon = 'icons/obj/machines/fabricators/imprinter.dmi' + icon_state = "imprinter" + base_icon_state = "imprinter" flags = OPENCONTAINER circuit = /obj/item/circuitboard/circuit_imprinter var/list/datum/design/queue = list() @@ -16,9 +18,34 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid). var/mat_efficiency = 1 var/speed = 1 - materials = list(DEFAULT_WALL_MATERIAL = 0, "glass" = 0, MAT_PLASTEEL = 0, "plastic" = 0, "gold" = 0, "silver" = 0, MAT_COPPER = 0, "osmium" = 0, MAT_LEAD = 0, "phoron" = 0, "uranium" = 0, "diamond" = 0, MAT_DURASTEEL = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0, MAT_METALHYDROGEN = 0, MAT_SUPERMATTER = 0) + materials = list( + DEFAULT_WALL_MATERIAL = 0, + MAT_GLASS = 0, + MAT_PLASTEEL = 0, + MAT_PLASTIC = 0, + MAT_GOLD = 0, + MAT_SILVER = 0, + MAT_COPPER = 0, + MAT_OSMIUM = 0, + MAT_LEAD = 0, + MAT_PHORON = 0, + MAT_URANIUM = 0, + MAT_DIAMOND = 0, + MAT_DURASTEEL = 0, + MAT_VERDANTIUM = 0, + MAT_MORPHIUM = 0, + MAT_METALHYDROGEN = 0, + MAT_SUPERMATTER = 0 + ) - hidden_materials = list(MAT_PLASTEEL, MAT_DURASTEEL, MAT_VERDANTIUM, MAT_MORPHIUM, MAT_METALHYDROGEN, MAT_SUPERMATTER) + hidden_materials = list( + MAT_PLASTEEL, + MAT_DURASTEEL, + MAT_VERDANTIUM, + MAT_MORPHIUM, + MAT_METALHYDROGEN, + MAT_SUPERMATTER + ) use_power = USE_POWER_IDLE idle_power_usage = 30 @@ -26,21 +53,17 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid). /obj/machinery/r_n_d/circuit_imprinter/Initialize(mapload) . = ..() - component_parts = list() - component_parts += new /obj/item/stock_parts/matter_bin(src) - component_parts += new /obj/item/stock_parts/manipulator(src) - component_parts += new /obj/item/reagent_containers/glass/beaker(src) - component_parts += new /obj/item/reagent_containers/glass/beaker(src) + default_apply_parts() RefreshParts() /obj/machinery/r_n_d/circuit_imprinter/process(delta_time) ..() if(stat) - update_icon() + update_appearance() return if(queue.len == 0) busy = 0 - update_icon() + update_appearance() return var/datum/design/D = queue[1] if(canBuild(D)) @@ -52,12 +75,12 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid). removeFromQueue(1) if(linked_console) linked_console.updateUsrDialog() - update_icon() + update_appearance() else if(busy) - visible_message("\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].") + visible_message(SPAN_NOTICE("\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].")) busy = 0 - update_icon() + update_appearance() /obj/machinery/r_n_d/circuit_imprinter/RefreshParts() var/T = 0 @@ -73,13 +96,20 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid). mat_efficiency = max(1 - (T - 1) / 4, 0.2) speed = T -/obj/machinery/r_n_d/circuit_imprinter/update_icon() - if(panel_open) - icon_state = "circuit_imprinter_t" +/obj/machinery/r_n_d/circuit_imprinter/update_icon_state() + . = ..() + if(stat & NOPOWER) + icon_state = "[base_icon_state]-off" else if(busy) - icon_state = "circuit_imprinter_ani" + icon_state = "[base_icon_state]-active" else - icon_state = "circuit_imprinter" + icon_state = base_icon_state + +/obj/machinery/r_n_d/circuit_imprinter/update_overlays() + . = ..() + cut_overlays() + if(panel_open) + add_overlay("[base_icon_state]-panel") /obj/machinery/r_n_d/circuit_imprinter/proc/TotalMaterials() var/t = 0 @@ -101,7 +131,7 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid). /obj/machinery/r_n_d/circuit_imprinter/attackby(var/obj/item/O as obj, var/mob/user as mob) if(busy) - to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") + to_chat(user, SPAN_NOTICE("\The [src] is busy. Please wait for completion of previous operation.")) return 1 if(default_deconstruction_screwdriver(user, O)) if(linked_console) @@ -115,7 +145,7 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid). if(istype(O, /obj/item/gripper/no_use/loader)) return 0 //Sheet loaders weren't finishing attack(), this prevents the message "You can't stuff that gripper into this" without preventing the rest of the attack sequence from finishing if(panel_open) - to_chat(user, "You can't load \the [src] while it's opened.") + to_chat(user, SPAN_NOTICE("You can't load \the [src] while it's opened.")) return 1 if(!linked_console) to_chat(user, "\The [src] must be linked to an R&D console first.") @@ -123,18 +153,18 @@ using metal and glass, it uses glass and reagents (usually sulphuric acid). if(O.is_open_container()) return 0 if(!istype(O, /obj/item/stack/material)) //Previously checked for specific material sheets, for some reason? Made the check on 133 redundant. - to_chat(user, "You cannot insert this item into \the [src].") + to_chat(user, SPAN_NOTICE("You cannot insert this item into \the [src].")) return 1 if(stat) return 1 if(TotalMaterials() + SHEET_MATERIAL_AMOUNT > max_material_storage) - to_chat(user, "\The [src]'s material bin is full. Please remove material before adding more.") + to_chat(user, SPAN_NOTICE("\The [src]'s material bin is full. Please remove material before adding more.")) return 1 var/obj/item/stack/material/S = O if(!(S.material.name in materials)) - to_chat(user, "The [src] doesn't accept [S.material]!") + to_chat(user, SPAN_WARNING("The [src] doesn't accept [S.material]!")) return busy = 1 diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index ae0ea23b3a8..7685df5a2fe 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -18,24 +18,40 @@ other types of metals and chemistry for reagents). */ //Note: More then one of these can be added to a design. -/datum/design //Datum for object designs, used in construction - var/name = null //Name of the created object. If null it will be 'guessed' from build_path if possible. - var/desc = null //Description of the created object. If null it will use group_desc and name where applicable. - var/item_name = null //An item name before it is modified by various name-modifying procs - var/id = "id" //ID of the created object for easy refernece. Alphanumeric, lower-case, no symbols. - var/list/req_tech = list() //IDs of that techs the object originated from and the minimum level requirements. - var/build_type = null //Flag as to what kind machine the design is built in. See defines. - var/list/materials = list() //List of materials. Format: "id" = amount. - var/list/chemicals = list() //List of chemicals. - var/build_path = null //The path of the object that gets created. - var/time = 6 //How many ticks it requires to build - var/category = null //Primarily used for Mech Fabricators, but can be used for anything. - var/sort_string = "ZZZZZ" //Sorting order - /// Optional string that interfaces can use as part of search filters. See- item/borg/upgrade/ai and the Exosuit Fabs. +///Datum for object designs, used in construction +/datum/design + ///Name of the created object. If null it will be 'guessed' from build_path if possible. + var/name = null + ///Description of the created object. If null it will use group_desc and name where applicable. + var/desc = null + ///An item name before it is modified by various name-modifying procs + var/item_name = null + ///ID of the created object for easy refernece. Alphanumeric, lower-case, no symbols. + var/id = "id" + ///IDs of that techs the object originated from and the minimum level requirements. + var/list/req_tech = list() + ///Flag as to what kind machine the design is built in. See defines. + var/build_type = null + ///List of materials. Format: "id" = amount. + var/list/materials = list() + ///List of chemicals. + var/list/chemicals = list() + ///The path of the object that gets created. + var/build_path = null + ///How many ticks it requires to build + var/time = 6 + ///Primarily used for Mech Fabricators, but can be used for anything. + var/list/category = list() + ///Sorting order + var/sort_string = "ZZZZZ" + ///Optional string that interfaces can use as part of search filters. See- item/borg/upgrade/ai and the Exosuit Fabs. var/search_metadata /datum/design/New() ..() + if(!islist(category)) + log_runtime(EXCEPTION("Warning: Design [type] defined a non-list category. Please fix this.")) + category = list(category) item_name = name AssembleDesignInfo() diff --git a/code/modules/research/designs/ai_holders.dm b/code/modules/research/designs/ai_holders.dm index 823e8571545..a24fab4e0be 100644 --- a/code/modules/research/designs/ai_holders.dm +++ b/code/modules/research/designs/ai_holders.dm @@ -10,7 +10,7 @@ build_type = PROTOLATHE | PROSFAB materials = list(DEFAULT_WALL_MATERIAL = 1000, "glass" = 500) build_path = /obj/item/mmi - category = "Misc" + category = list("Misc") sort_string = "SAAAA" /datum/design/item/ai_holder/posibrain @@ -20,7 +20,7 @@ build_type = PROTOLATHE | PROSFAB materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 1000, "silver" = 1000, "gold" = 500, "phoron" = 500, "diamond" = 100) build_path = /obj/item/mmi/digital/posibrain - category = "Misc" + category = list("Misc") sort_string = "SAAAB" /datum/design/item/ai_holder/dronebrain @@ -30,7 +30,7 @@ build_type = PROTOLATHE | PROSFAB materials = list(DEFAULT_WALL_MATERIAL = 2000, "glass" = 1000, "silver" = 1000, "gold" = 500) build_path = /obj/item/mmi/digital/robot - category = "Misc" + category = list("Misc") sort_string = "SAAAC" /datum/design/item/ai_holder/paicard diff --git a/code/modules/research/designs/circuits/circuits.dm b/code/modules/research/designs/circuits/circuits.dm index d78b4ca324e..8a8acb0be88 100644 --- a/code/modules/research/designs/circuits/circuits.dm +++ b/code/modules/research/designs/circuits/circuits.dm @@ -657,7 +657,7 @@ CIRCUITS BELOW sort_string = "OAABA" /datum/design/circuit/pointdefense_control - name = "point defense control" + name = "point defense control" //Once upon a time, this was called a deluxe microwave. id = "pointdefense_control" req_tech = list(TECH_DATA = 4, TECH_ENGINEERING = 3, TECH_COMBAT = 2) build_path = /obj/item/circuitboard/pointdefense_control diff --git a/code/modules/research/designs/power_cells.dm b/code/modules/research/designs/power_cells.dm index 2b652c4b1d8..4ba91e48574 100644 --- a/code/modules/research/designs/power_cells.dm +++ b/code/modules/research/designs/power_cells.dm @@ -22,7 +22,7 @@ req_tech = list(TECH_POWER = 1) materials = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 50) build_path = /obj/item/cell - category = "Misc" + category = list("Misc") sort_string = "BAAAA" /datum/design/item/powercell/high @@ -32,7 +32,7 @@ req_tech = list(TECH_POWER = 2) materials = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 60) build_path = /obj/item/cell/high - category = "Misc" + category = list("Misc") sort_string = "BAAAB" /datum/design/item/powercell/super @@ -41,7 +41,7 @@ req_tech = list(TECH_POWER = 3, TECH_MATERIAL = 2) materials = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 70) build_path = /obj/item/cell/super - category = "Misc" + category = list("Misc") sort_string = "BAAAC" /datum/design/item/powercell/hyper @@ -50,7 +50,7 @@ req_tech = list(TECH_POWER = 5, TECH_MATERIAL = 4) materials = list(DEFAULT_WALL_MATERIAL = 400, "gold" = 150, "silver" = 150, "glass" = 70) build_path = /obj/item/cell/hyper - category = "Misc" + category = list("Misc") sort_string = "BAAAD" /datum/design/item/powercell/device @@ -59,7 +59,7 @@ id = "device" materials = list(DEFAULT_WALL_MATERIAL = 350, "glass" = 25) build_path = /obj/item/cell/device - category = "Misc" + category = list("Misc") sort_string = "BAABA" /datum/design/item/powercell/weapon @@ -68,5 +68,5 @@ id = "weapon" materials = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 50) build_path = /obj/item/cell/device/weapon - category = "Misc" + category = list("Misc") sort_string = "BAABB" diff --git a/code/modules/research/mechfab_designs.dm b/code/modules/research/mechfab_designs.dm index 186a8c9404d..8842072eafd 100644 --- a/code/modules/research/mechfab_designs.dm +++ b/code/modules/research/mechfab_designs.dm @@ -1,10 +1,10 @@ /datum/design/item/mechfab build_type = MECHFAB - category = "Other" + category = list("Other") req_tech = list(TECH_MATERIAL = 1) /datum/design/item/mechfab/ripley - category = "Ripley" + category = list("Ripley") /datum/design/item/mechfab/ripley/chassis name = "Ripley Chassis" @@ -66,7 +66,7 @@ materials = list(DEFAULT_WALL_MATERIAL = 22500) /datum/design/item/mechfab/odysseus - category = "Odysseus" + category = list("Odysseus") /datum/design/item/mechfab/odysseus/chassis name = "Odysseus Chassis" @@ -118,7 +118,7 @@ materials = list(DEFAULT_WALL_MATERIAL = 11250) /datum/design/item/mechfab/gygax - category = "Gygax" + category = list("Gygax") /datum/design/item/mechfab/gygax/chassis/serenity name = "Serenity Chassis" @@ -183,7 +183,7 @@ materials = list(DEFAULT_WALL_MATERIAL = 37500, "diamond" = 7500) /datum/design/item/mechfab/durand - category = "Durand" + category = list("Durand") /datum/design/item/mechfab/durand/chassis name = "Durand Chassis" @@ -242,7 +242,7 @@ materials = list(DEFAULT_WALL_MATERIAL = 37500, "uranium" = 7500) /datum/design/item/mechfab/janus - category = "Janus" + category = list("Janus") req_tech = list(TECH_MATERIAL = 7, TECH_BLUESPACE = 5, TECH_MAGNET = 6, TECH_PHORON = 3, TECH_ARCANE = 1, TECH_PRECURSOR = 2) /datum/design/item/mechfab/janus/chassis @@ -303,7 +303,7 @@ materials = list(MAT_SUPERMATTER = 2000, MAT_PLASTEEL = 60000, MAT_URANIUM = 3250, MAT_DURASTEEL = 2000, MAT_MORPHIUM = 3000, MAT_GOLD = 5000, MAT_VERDANTIUM = 5000, MAT_DIAMOND = 10000, MAT_LEAD = 15000) /datum/design/item/mechfab/honker - category = "H.O.N.K." + category = list("H.O.N.K.") /datum/design/item/mechfab/honker/chassis name = "H.O.N.K. Chassis" @@ -362,7 +362,7 @@ materials = list(DEFAULT_WALL_MATERIAL = 37500, "diamond" = 7500, "plastic" = 5000, "bananium" = 20000) /datum/design/item/mechfab/reticent - category = "Reticent" + category = list("Reticent") /datum/design/item/mechfab/reticent/chassis name = "Reticent Chassis" @@ -422,7 +422,7 @@ /datum/design/item/mecha build_type = MECHFAB - category = "Exosuit Equipment" + category = list("Exosuit Equipment") time = 10 materials = list(DEFAULT_WALL_MATERIAL = 7500) @@ -876,7 +876,7 @@ build_type = MECHFAB materials = list(DEFAULT_WALL_MATERIAL = 562, "glass" = 562) build_path = /obj/item/flash/synthetic - category = "Misc" + category = list("Misc") /* * Printable Internal Components @@ -889,7 +889,7 @@ build_type = MECHFAB materials = list(DEFAULT_WALL_MATERIAL = 5000, "glass" = 2500) build_path = /obj/item/mecha_parts/component/actuator - category = "Components" + category = list("Components") /datum/design/item/mecha_component/actuator_high name = "Mecha Actuator - High Speed" @@ -981,7 +981,7 @@ /datum/design/item/mechfab/vehicle build_type = MECHFAB - category = "Vehicle" + category = list("Vehicle") req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 6) /datum/design/item/mechfab/vehicle/spacebike_chassis @@ -999,3 +999,13 @@ req_tech = list(TECH_MATERIAL = 5, TECH_ENGINEERING = 6, TECH_MAGNET = 3, TECH_POWER = 2) materials = list(DEFAULT_WALL_MATERIAL = 15000, "silver" = 3000, "plastic" = 3000, "osmium" = 1000) build_path = /obj/item/vehicle_assembly/quadbike + +/* +/datum/design/item/mechfab/uav/basic + name = "UAV - Recon Skimmer" + id = "recon_skimmer" + build_path = /obj/item/uav + time = 20 + req_tech = list(TECH_MATERIAL = 6, TECH_ENGINEERING = 5, TECH_PHORON = 3, TECH_MAGNET = 4, TECH_POWER = 6) + materials = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 6000, "silver" = 4000) +*/ diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index 6591065848d..3c705f5575d 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -1,6 +1,8 @@ /obj/machinery/r_n_d/protolathe name = "Protolathe" + icon = 'icons/obj/machines/fabricators/protolathe.dmi' icon_state = "protolathe" + base_icon_state = "protolathe" flags = OPENCONTAINER circuit = /obj/item/circuitboard/protolathe use_power = USE_POWER_IDLE @@ -21,23 +23,17 @@ /obj/machinery/r_n_d/protolathe/Initialize(mapload) . = ..() - component_parts = list() - component_parts += new /obj/item/stock_parts/matter_bin(src) - component_parts += new /obj/item/stock_parts/matter_bin(src) - component_parts += new /obj/item/stock_parts/manipulator(src) - component_parts += new /obj/item/stock_parts/manipulator(src) - component_parts += new /obj/item/reagent_containers/glass/beaker(src) - component_parts += new /obj/item/reagent_containers/glass/beaker(src) + default_apply_parts() RefreshParts() /obj/machinery/r_n_d/protolathe/process(delta_time) ..() if(stat) - update_icon() + update_appearance() return if(queue.len == 0) busy = 0 - update_icon() + update_appearance() return var/datum/design/D = queue[1] if(canBuild(D)) @@ -49,12 +45,12 @@ removeFromQueue(1) if(linked_console) linked_console.updateUsrDialog() - update_icon() + update_appearance() else if(busy) - visible_message("\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].") + visible_message(SPAN_NOTICE("\icon [src] flashes: insufficient materials: [getLackingMaterials(D)].")) busy = 0 - update_icon() + update_appearance() /obj/machinery/r_n_d/protolathe/proc/TotalMaterials() //returns the total of all the stored materials. Makes code neater. var/t = 0 @@ -81,19 +77,24 @@ eject_materials(f, -1) ..() -/obj/machinery/r_n_d/protolathe/update_icon() +/obj/machinery/r_n_d/protolathe/update_overlays() + . = ..() + cut_overlays() if(panel_open) - icon_state = "protolathe_t" + add_overlay("[base_icon_state]-panel") + +/obj/machinery/r_n_d/protolathe/update_icon_state() + . = ..() + if(stat & NOPOWER) + icon_state = "[base_icon_state]-off" else if(busy) - icon_state = "protolathe_n" + icon_state = "[base_icon_state]-active" else - if(icon_state == "protolathe_n") - flick("protolathe_u", src) // If lid WAS closed, show opening animation - icon_state = "protolathe" + icon_state = base_icon_state /obj/machinery/r_n_d/protolathe/attackby(var/obj/item/O as obj, var/mob/user as mob) if(busy) - to_chat(user, "\The [src] is busy. Please wait for completion of previous operation.") + to_chat(user, SPAN_NOTICE("\The [src] is busy. Please wait for completion of previous operation.")) return 1 if(default_deconstruction_screwdriver(user, O)) if(linked_console) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 0da94948626..4154208d764 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -42,7 +42,6 @@ won't update every console in existence) but it's more of a hassle to do. Also, var/obj/machinery/r_n_d/protolathe/linked_lathe = null //Linked Protolathe var/obj/machinery/r_n_d/circuit_imprinter/linked_imprinter = null //Linked Circuit Imprinter - var/screen = 1.0 //Which screen is currently showing. var/id = 0 //ID of the computer (for server restrictions). var/sync = 1 //If sync = 0, it doesn't show up on Server Control Console @@ -71,17 +70,10 @@ won't update every console in existence) but it's more of a hassle to do. Also, return return_name /obj/machinery/computer/rdconsole/proc/CallReagentName(var/ID) - var/return_name = ID - var/datum/reagent/temp_reagent - for(var/R in (typesof(/datum/reagent) - /datum/reagent)) - temp_reagent = null - temp_reagent = new R() - if(temp_reagent.id == ID) - return_name = temp_reagent.name - qdel(temp_reagent) - temp_reagent = null - break - return return_name + var/datum/reagent/R = SSchemistry.chemical_reagents["[ID]"] + if(!R) + return ID + return R.name /obj/machinery/computer/rdconsole/proc/SyncRDevices() //Makes sure it is properly sync'ed up with the devices attached to it (if any). for(var/obj/machinery/r_n_d/D in range(5, src)) //Originally 3, buffed to 5 - Werewolf @@ -142,7 +134,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, //The construction/deconstruction of the console code. ..() - src.updateUsrDialog() + SStgui.update_uis(src) return /obj/machinery/computer/rdconsole/emp_act(var/remaining_charges, var/mob/user) @@ -152,296 +144,6 @@ won't update every console in existence) but it's more of a hassle to do. Also, to_chat(user, "You you disable the security protocols.") return 1 -/obj/machinery/computer/rdconsole/Topic(href, href_list) - if(..()) - return 1 - - add_fingerprint(usr) - - usr.set_machine(src) - if((screen < 1 || (screen == 1.6 && href_list["menu"] != "1.0")) && (!allowed(usr) && !emagged)) //Stops people from HREF exploiting out of the lock screen, but allow it if they have the access. - to_chat(usr, "Unauthorized Access") - return - - if(href_list["menu"]) //Switches menu screens. Converts a sent text string into a number. Saves a LOT of code. - var/temp_screen = text2num(href_list["menu"]) - screen = temp_screen - - else if(href_list["updt_tech"]) //Update the research holder with information from the technology disk. - screen = 0.0 - spawn(5 SECONDS) - screen = 1.2 - files.AddTech2Known(t_disk.stored) - updateUsrDialog() - griefProtection() //Update CentCom too - - else if(href_list["clear_tech"]) //Erase data on the technology disk. - t_disk.stored = null - - else if(href_list["eject_tech"]) //Eject the technology disk. - t_disk.loc = loc - t_disk = null - screen = 1.0 - - else if(href_list["copy_tech"]) //Copys some technology data from the research holder to the disk. - for(var/datum/tech/T in files.known_tech) - if(href_list["copy_tech_ID"] == T.id) - t_disk.stored = T - break - screen = 1.2 - - else if(href_list["updt_design"]) //Updates the research holder with design data from the design disk. - screen = 0.0 - spawn(5 SECONDS) - screen = 1.4 - files.AddDesign2Known(d_disk.blueprint) - updateUsrDialog() - griefProtection() //Update CentCom too - - else if(href_list["clear_design"]) //Erases data on the design disk. - d_disk.blueprint = null - - else if(href_list["eject_design"]) //Eject the design disk. - d_disk.loc = loc - d_disk = null - screen = 1.0 - - else if(href_list["copy_design"]) //Copy design data from the research holder to the design disk. - for(var/datum/design/D in files.known_designs) - if(href_list["copy_design_ID"] == D.id) - d_disk.blueprint = D - break - screen = 1.4 - - else if(href_list["eject_item"]) //Eject the item inside the destructive analyzer. - if(linked_destroy) - if(linked_destroy.busy) - to_chat(usr, "The destructive analyzer is busy at the moment.") - - else if(linked_destroy.loaded_item) - linked_destroy.loaded_item.loc = linked_destroy.loc - linked_destroy.loaded_item = null - linked_destroy.icon_state = "d_analyzer" - screen = 2.1 - - else if(href_list["deconstruct"]) //Deconstruct the item in the destructive analyzer and update the research holder. - if(linked_destroy) - if(linked_destroy.busy) - to_chat(usr, "The destructive analyzer is busy at the moment.") - else - if(alert("Proceeding will destroy loaded item. Continue?", "Destructive analyzer confirmation", "Yes", "No") == "No" || !linked_destroy) - return - linked_destroy.busy = 1 - screen = 0.1 - updateUsrDialog() - flick("d_analyzer_process", linked_destroy) - spawn(2.4 SECONDS) - if(linked_destroy) - linked_destroy.busy = 0 - if(!linked_destroy.loaded_item) - to_chat(usr, "The destructive analyzer appears to be empty.") - screen = 1.0 - return - - for(var/T in linked_destroy.loaded_item.origin_tech) - files.UpdateTech(T, linked_destroy.loaded_item.origin_tech[T]) - if(linked_lathe && linked_destroy.loaded_item.matter) // Also sends salvaged materials to a linked protolathe, if any. - for(var/t in linked_destroy.loaded_item.matter) - if(t in linked_lathe.materials) - linked_lathe.materials[t] += min(linked_lathe.max_material_storage - linked_lathe.TotalMaterials(), linked_destroy.loaded_item.matter[t] * linked_destroy.decon_mod) - - linked_destroy.loaded_item = null - for(var/obj/I in linked_destroy.contents) - for(var/mob/M in I.contents) - M.death() - if(istype(I,/obj/item/stack/material))//Only deconsturcts one sheet at a time instead of the entire stack - var/obj/item/stack/material/S = I - if(S.get_amount() > 1) - S.use(1) - linked_destroy.loaded_item = S - else - qdel(S) - linked_destroy.icon_state = "d_analyzer" - else - if(I != linked_destroy.circuit && !(I in linked_destroy.component_parts)) - qdel(I) - linked_destroy.icon_state = "d_analyzer" - - use_power(linked_destroy.active_power_usage) - screen = 1.0 - updateUsrDialog() - - else if(href_list["lock"]) //Lock the console from use by anyone without tox access. - if(allowed(usr)) - screen = text2num(href_list["lock"]) - else - to_chat(usr, "Unauthorized Access.") - - else if(href_list["sync"]) //Sync the research holder with all the R&D consoles in the game that aren't sync protected. - screen = 0.0 - if(!allowed(usr) && !emagged) - to_chat(usr, "Unauthorized Access.") - return - if(!sync) - to_chat(usr, "You must connect to the network first.") - else - griefProtection() //Putting this here because I dont trust the sync process - spawn(3 SECONDS) - if(src) - for(var/obj/machinery/r_n_d/server/S in machines) - var/server_processed = 0 - if((id in S.id_with_upload) || istype(S, /obj/machinery/r_n_d/server/centcom)) - for(var/datum/tech/T in files.known_tech) - S.files.AddTech2Known(T) - for(var/datum/design/D in files.known_designs) - S.files.AddDesign2Known(D) - S.files.RefreshResearch() - server_processed = 1 - if((id in S.id_with_download) && !istype(S, /obj/machinery/r_n_d/server/centcom)) - for(var/datum/tech/T in S.files.known_tech) - files.AddTech2Known(T) - for(var/datum/design/D in S.files.known_designs) - files.AddDesign2Known(D) - files.RefreshResearch() - server_processed = 1 - if(!istype(S, /obj/machinery/r_n_d/server/centcom) && server_processed) - S.produce_heat() - screen = 1.6 - updateUsrDialog() - - else if(href_list["togglesync"]) //Prevents the console from being synced by other consoles. Can still send data. - sync = !sync - - else if(href_list["build"]) //Causes the Protolathe to build something. - if(linked_lathe) - var/datum/design/being_built = null - for(var/datum/design/D in files.known_designs) - if(D.id == href_list["build"]) - being_built = D - break - if(being_built) - linked_lathe.addToQueue(being_built) - - else if(href_list["buildfive"]) //Causes the Protolathe to build 5 of something. - if(linked_lathe) - var/datum/design/being_built = null - for(var/datum/design/D in files.known_designs) - if(D.id == href_list["buildfive"]) - being_built = D - break - if(being_built) - for(var/i = 1 to 5) - linked_lathe.addToQueue(being_built) - - screen = 3.1 - - else if(href_list["protofilter"]) - var/filterstring = input(usr, "Input a filter string, or blank to not filter:", "Design Filter", protofilter) as null|text - if(!Adjacent(usr)) - return - if(isnull(filterstring)) //Clicked Cancel - return - if(filterstring == "") //Cleared value - protofilter = null - protofilter = sanitize(filterstring, 25) - - else if(href_list["circuitfilter"]) - var/filterstring = input(usr, "Input a filter string, or blank to not filter:", "Design Filter", circuitfilter) as null|text - if(!Adjacent(usr)) - return - if(isnull(filterstring)) //Clicked Cancel - return - if(filterstring == "") //Cleared value - circuitfilter = null - circuitfilter = sanitize(filterstring, 25) - - else if(href_list["imprint"]) //Causes the Circuit Imprinter to build something. - if(linked_imprinter) - var/datum/design/being_built = null - for(var/datum/design/D in files.known_designs) - if(D.id == href_list["imprint"]) - being_built = D - break - if(being_built) - linked_imprinter.addToQueue(being_built) - screen = 4.1 - - else if(href_list["disposeI"] && linked_imprinter) //Causes the circuit imprinter to dispose of a single reagent (all of it) - linked_imprinter.reagents.del_reagent(href_list["dispose"]) - - else if(href_list["disposeallI"] && linked_imprinter) //Causes the circuit imprinter to dispose of all it's reagents. - linked_imprinter.reagents.clear_reagents() - - else if(href_list["removeI"] && linked_lathe) - linked_imprinter.removeFromQueue(text2num(href_list["removeI"])) - - else if(href_list["disposeP"] && linked_lathe) //Causes the protolathe to dispose of a single reagent (all of it) - linked_lathe.reagents.del_reagent(href_list["dispose"]) - - else if(href_list["disposeallP"] && linked_lathe) //Causes the protolathe to dispose of all it's reagents. - linked_lathe.reagents.clear_reagents() - - else if(href_list["removeP"] && linked_lathe) - linked_lathe.removeFromQueue(text2num(href_list["removeP"])) - - else if(href_list["lathe_ejectsheet"] && linked_lathe) //Causes the protolathe to eject a sheet of material - linked_lathe.eject(href_list["lathe_ejectsheet"], text2num(href_list["amount"])) - - else if(href_list["imprinter_ejectsheet"] && linked_imprinter) //Causes the protolathe to eject a sheet of material - linked_imprinter.eject(href_list["imprinter_ejectsheet"], text2num(href_list["amount"])) - - else if(href_list["find_device"]) //The R&D console looks for devices nearby to link up with. - screen = 0.0 - spawn(10) - SyncRDevices() - screen = 1.7 - updateUsrDialog() - - else if(href_list["disconnect"]) //The R&D console disconnects with a specific device. - switch(href_list["disconnect"]) - if("destroy") - linked_destroy.linked_console = null - linked_destroy = null - if("lathe") - linked_lathe.linked_console = null - linked_lathe = null - if("imprinter") - linked_imprinter.linked_console = null - linked_imprinter = null - - else if(href_list["reset"]) //Reset the R&D console's database. - griefProtection() - var/choice = alert("R&D Console Database Reset", "Are you sure you want to reset the R&D console's database? Data lost cannot be recovered.", "Continue", "Cancel") - if(choice == "Continue") - screen = 0.0 - qdel(files) - files = new /datum/research(src) - spawn(20) - screen = 1.6 - updateUsrDialog() - - else if (href_list["print"]) //Print research information - screen = 0.5 - spawn(20) - var/obj/item/paper/PR = new/obj/item/paper - PR.name = "list of researched technologies" - PR.info = "
[station_name()] Science Laboratories" - PR.info += "

[ (text2num(href_list["print"]) == 2) ? "Detailed" : null] Research Progress Report

" - PR.info += "report prepared at [stationtime2text()] station time

" - if(text2num(href_list["print"]) == 2) - PR.info += GetResearchListInfo() - else - PR.info += GetResearchLevelsInfo() - PR.info_links = PR.info - PR.icon_state = "paper_words" - PR.loc = src.loc - spawn(10) - screen = ((text2num(href_list["print"]) == 2) ? 5.0 : 1.1) - updateUsrDialog() - - updateUsrDialog() - return - /obj/machinery/computer/rdconsole/proc/GetResearchLevelsInfo() var/list/dat = list() dat += "" - - if(1.2) //Technology Disk Menu - - dat += "Main Menu
" - dat += "Disk Contents: (Technology Data Disk)

" - if(t_disk.stored == null) - dat += "The disk has no data stored on it.
" - dat += "Operations: " - dat += "Load Tech to Disk || " - else - dat += "Name: [t_disk.stored.name]
" - dat += "Level: [t_disk.stored.level]
" - dat += "Description: [t_disk.stored.desc]
" - dat += "Operations: " - dat += "Upload to Database || " - dat += "Clear Disk || " - dat += "Eject Disk" - - if(1.3) //Technology Disk submenu - dat += "
Main Menu || " - dat += "Return to Disk Operations
" - dat += "Load Technology to Disk:

" - dat += "" - - if(1.4) //Design Disk menu. - dat += "Main Menu
" - if(d_disk.blueprint == null) - dat += "The disk has no data stored on it.
" - dat += "Operations: " - dat += "Load Design to Disk || " - else - dat += "Name: [d_disk.blueprint.name]
" - switch(d_disk.blueprint.build_type) - if(IMPRINTER) dat += "Lathe Type: Circuit Imprinter
" - if(PROTOLATHE) dat += "Lathe Type: Proto-lathe
" - dat += "Required Materials:
" - for(var/M in d_disk.blueprint.materials) - if(copytext(M, 1, 2) == "$") dat += "* [copytext(M, 2)] x [d_disk.blueprint.materials[M]]
" - else dat += "* [M] x [d_disk.blueprint.materials[M]]
" - dat += "
Operations: " - dat += "Upload to Database || " - dat += "Clear Disk || " - dat += "Eject Disk" - - if(1.5) //Technology disk submenu - dat += "Main Menu || " - dat += "Return to Disk Operations
" - dat += "Load Design to Disk:

" - dat += "" - - if(1.6) //R&D console settings - dat += "Main Menu
" - dat += "R&D Console Setting:
" - dat += "