diff --git a/.github/workflows/merge_upstream_master.yml b/.github/workflows/merge_upstream_master.yml index 152bbf2ca06a..372f144899d0 100644 --- a/.github/workflows/merge_upstream_master.yml +++ b/.github/workflows/merge_upstream_master.yml @@ -113,7 +113,7 @@ jobs: - name: Rebuild TGUI run: | - if git diff-tree --name-only -r $(git rev-parse HEAD~2) | grep "tgui/public/" + if git diff-tree --name-only -r $(git rev-parse HEAD~2) | grep "tgui/public/" ; then bash tgui/bin/tgui git commit -m "Rebuild TGUI" git push origin diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 57b3491a44d2..397debf6b8af 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -406,8 +406,11 @@ CREATE TABLE `notes` ( `server` varchar(50) NOT NULL, `crew_playtime` mediumint(8) UNSIGNED DEFAULT '0', `automated` TINYINT(3) UNSIGNED NULL DEFAULT '0', + `deleted` TINYINT(4) NOT NULL DEFAULT '0', + `deletedby` VARCHAR(32) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci', PRIMARY KEY (`id`), - KEY `ckey` (`ckey`) + KEY `ckey` (`ckey`), + KEY `deleted` (`deleted`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/SQL/updates/55-56.sql b/SQL/updates/55-56.sql new file mode 100644 index 000000000000..c6799413b388 --- /dev/null +++ b/SQL/updates/55-56.sql @@ -0,0 +1,7 @@ +# Updating DB from 55-56 ~AffectedArc07 +# Adds a new column to the notes table for tracking deleted notes +ALTER TABLE `notes` + ADD COLUMN `deleted` TINYINT NOT NULL DEFAULT 0 AFTER `automated`, + ADD COLUMN `deletedby` VARCHAR(32) NULL DEFAULT NULL AFTER `deleted`, + ADD INDEX `deleted` (`deleted`); + diff --git a/_maps/map_files/generic/centcomm.dmm b/_maps/map_files/generic/centcomm.dmm index 21d26a44f026..6949d75e90f5 100644 --- a/_maps/map_files/generic/centcomm.dmm +++ b/_maps/map_files/generic/centcomm.dmm @@ -490,6 +490,11 @@ icon_state = "green" }, /area/holodeck/source_emptycourt) +"cb" = ( +/obj/structure/closet/abductor, +/obj/item/storage/belt/janitor/abductor/full, +/turf/simulated/floor/plating/abductor, +/area/abductor_ship) "cc" = ( /obj/structure/window/reinforced{ dir = 1 @@ -46742,7 +46747,7 @@ aN aN lz lz -nr +cb bK nr lz @@ -46756,7 +46761,7 @@ aN aN lz lz -nr +cb bK nr lz @@ -50340,7 +50345,7 @@ aN aN lz lz -nr +cb bK nr lz @@ -50354,7 +50359,7 @@ aN aN lz lz -nr +cb bK nr lz diff --git a/_maps/map_files/stations/boxstation.dmm b/_maps/map_files/stations/boxstation.dmm index 473def6e1647..01ace0aec760 100644 --- a/_maps/map_files/stations/boxstation.dmm +++ b/_maps/map_files/stations/boxstation.dmm @@ -52327,12 +52327,6 @@ icon_state = "vault" }, /area/station/engineering/gravitygenerator) -"dCJ" = ( -/obj/structure/transit_tube/cap{ - dir = 8 - }, -/turf/simulated/floor/plating, -/area/station/turret_protected/aisat/interior) "dCM" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -57689,10 +57683,12 @@ layer = 4; pixel_y = 32 }, -/obj/structure/transit_tube/station, /obj/structure/transit_tube_pod{ dir = 4 }, +/obj/structure/transit_tube/station/reverse/flipped{ + dir = 1 + }, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -64056,9 +64052,6 @@ name = "north bump"; pixel_y = 24 }, -/obj/structure/transit_tube/cap{ - dir = 4 - }, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -72430,11 +72423,11 @@ /turf/simulated/floor/plasteel, /area/station/supply/storage) "nrh" = ( -/obj/structure/transit_tube/station, /obj/structure/transit_tube_pod{ dir = 8 }, /obj/machinery/atmospherics/pipe/simple/visible/yellow, +/obj/structure/transit_tube/station/reverse, /turf/simulated/floor/plating, /area/station/turret_protected/aisat/interior) "nrD" = ( @@ -131948,7 +131941,7 @@ aab aaa cQp wza -dCJ +dnW dnv dnW diz diff --git a/_maps/map_files/stations/deltastation.dmm b/_maps/map_files/stations/deltastation.dmm index 2c1a42832b33..0d416241c107 100644 --- a/_maps/map_files/stations/deltastation.dmm +++ b/_maps/map_files/stations/deltastation.dmm @@ -87549,9 +87549,6 @@ /area/station/maintenance/starboard) "rjL" = ( /obj/effect/decal/cleanable/dirt, -/obj/structure/transit_tube/cap{ - dir = 8 - }, /obj/item/radio/intercom{ name = "south bump"; pixel_y = -28 @@ -97341,9 +97338,7 @@ /obj/machinery/ai_status_display{ pixel_y = -32 }, -/obj/structure/transit_tube/station{ - dir = 1 - }, +/obj/structure/transit_tube/station/reverse/flipped, /turf/simulated/floor/plasteel{ dir = 8; icon_state = "vault" diff --git a/_maps/map_files/stations/metastation.dmm b/_maps/map_files/stations/metastation.dmm index 44f5f507aeab..7380ac464208 100644 --- a/_maps/map_files/stations/metastation.dmm +++ b/_maps/map_files/stations/metastation.dmm @@ -19446,10 +19446,12 @@ /turf/simulated/floor/wood, /area/station/command/office/captain/bedroom) "bsI" = ( -/obj/structure/transit_tube/station, /obj/structure/sign/securearea{ pixel_y = 32 }, +/obj/structure/transit_tube/station/reverse/flipped{ + dir = 1 + }, /turf/simulated/floor/plasteel{ dir = 4; icon_state = "darkbluecorners" @@ -53883,9 +53885,6 @@ }, /area/station/medical/virology) "hkm" = ( -/obj/structure/transit_tube/cap{ - dir = 4 - }, /obj/machinery/status_display{ layer = 4; pixel_y = 32 diff --git a/_maps/map_files220/stations/boxstation.dmm b/_maps/map_files220/stations/boxstation.dmm index b8bb1362d025..312184f91b35 100644 --- a/_maps/map_files220/stations/boxstation.dmm +++ b/_maps/map_files220/stations/boxstation.dmm @@ -41614,9 +41614,6 @@ /area/station/maintenance/turbine) "dgT" = ( /obj/machinery/firealarm/directional/north, -/obj/structure/transit_tube/cap{ - dir = 4 - }, /turf/simulated/floor/plasteel{ dir = 5; icon_state = "darkblue" @@ -58643,7 +58640,9 @@ /area/station/maintenance/aft) "iuO" = ( /obj/machinery/status_display/directional/north, -/obj/structure/transit_tube/station, +/obj/structure/transit_tube/station/reverse/flipped{ + dir = 1 + }, /turf/simulated/floor/plasteel{ icon_state = "darkbluefull" }, @@ -82397,9 +82396,6 @@ /area/station/maintenance/asmaint) "raN" = ( /obj/effect/turf_decal/stripes/end, -/obj/structure/transit_tube/cap{ - dir = 1 - }, /turf/simulated/floor/plating, /area/station/turret_protected/aisat/interior) "raP" = ( @@ -91643,8 +91639,8 @@ /turf/simulated/floor/plating, /area/station/maintenance/asmaint) "uwh" = ( -/obj/structure/transit_tube/station{ - dir = 4 +/obj/structure/transit_tube/station/reverse/flipped{ + dir = 8 }, /obj/structure/transit_tube_pod{ dir = 1 diff --git a/_maps/map_files220/stations/deltastation.dmm b/_maps/map_files220/stations/deltastation.dmm index f63068d5d2d6..207fb8820cdc 100644 --- a/_maps/map_files220/stations/deltastation.dmm +++ b/_maps/map_files220/stations/deltastation.dmm @@ -50395,9 +50395,6 @@ "eJn" = ( /obj/item/radio/intercom/directional/south, /obj/effect/decal/cleanable/dirt, -/obj/structure/transit_tube/cap{ - dir = 8 - }, /turf/simulated/floor/plasteel{ dir = 8; icon_state = "vault" @@ -58052,9 +58049,7 @@ /area/station/supply/miningdock) "hgg" = ( /obj/machinery/ai_status_display/south, -/obj/structure/transit_tube/station{ - dir = 1 - }, +/obj/structure/transit_tube/station/reverse/flipped, /turf/simulated/floor/plasteel{ dir = 8; icon_state = "vault" diff --git a/_maps/map_files220/stations/metastation.dmm b/_maps/map_files220/stations/metastation.dmm index 09df0237ed74..a8e53a5043d2 100644 --- a/_maps/map_files220/stations/metastation.dmm +++ b/_maps/map_files220/stations/metastation.dmm @@ -19028,7 +19028,9 @@ /turf/simulated/floor/wood, /area/station/command/office/captain/bedroom) "bsI" = ( -/obj/structure/transit_tube/station, +/obj/structure/transit_tube/station/reverse/flipped{ + dir = 1 + }, /obj/structure/sign/securearea{ pixel_y = 32 }, @@ -52918,9 +52920,6 @@ }, /area/station/medical/virology) "hkm" = ( -/obj/structure/transit_tube/cap{ - dir = 4 - }, /obj/machinery/status_display/directional/north, /obj/effect/turf_decal/stripes/corner{ dir = 1 diff --git a/code/__DEFINES/atmospherics_defines.dm b/code/__DEFINES/atmospherics_defines.dm index fa2355a729f4..a9e2c82b71ee 100644 --- a/code/__DEFINES/atmospherics_defines.dm +++ b/code/__DEFINES/atmospherics_defines.dm @@ -141,6 +141,9 @@ //LAVALAND #define LAVALAND_EQUIPMENT_EFFECT_PRESSURE 50 //what pressure you have to be under to increase the effect of equipment meant for lavaland +#define LAVALAND_TEMPERATURE 500 +#define LAVALAND_OXYGEN 8 +#define LAVALAND_NITROGEN 14 // Reactions #define N2O_DECOMPOSITION_MIN_ENERGY 1400 diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index ea134741bec4..3dd763ba3dab 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -342,6 +342,8 @@ #define COMSIG_MIND_TRANSER_TO "mind_transfer_to" ///called on the mob instead of the mind #define COMSIG_BODY_TRANSFER_TO "body_transfer_to" +///called when the mind is initialized (called every time the mob logins) +#define COMSIG_MIND_INITIALIZE "mind_initialize" // /mob signals diff --git a/code/__DEFINES/emotes_defines.dm b/code/__DEFINES/emotes_defines.dm index 9940edab859d..f654bb678bbe 100644 --- a/code/__DEFINES/emotes_defines.dm +++ b/code/__DEFINES/emotes_defines.dm @@ -57,6 +57,8 @@ #define EMOTE_TARGET_BHVR_RAW 4 /// The emote target should be just a number. Anything else will be rejected. #define EMOTE_TARGET_BHVR_NUM 5 +/// The emote target is used elsewhere, and processing should be skipped. +#define EMOTE_TARGET_BHVR_IGNORE 6 // This set determines the type of target that we want to check for. @@ -75,3 +77,12 @@ /// List of emotes useable by ghosties #define USABLE_DEAD_EMOTES list("*flip", "*spin") + +// Strings used for the rock paper scissors emote and status effect +#define RPS_EMOTE_ROCK "rock" +#define RPS_EMOTE_PAPER "paper" +#define RPS_EMOTE_SCISSORS "scissors" + +#define RPS_EMOTE_THEY_WIN "aww" +#define RPS_EMOTE_WE_WIN "yay" +#define RPS_EMOTE_TIE "tie" diff --git a/code/__DEFINES/food_defines.dm b/code/__DEFINES/food_defines.dm index 83d378400e11..35131425ad72 100644 --- a/code/__DEFINES/food_defines.dm +++ b/code/__DEFINES/food_defines.dm @@ -1,5 +1,13 @@ -// Used for secondary goals. +/// Used for secondary goals. +/// TOO easy, not accepted for variety goals. #define FOOD_GOAL_SKIP 0 +/// Easy food, ask for a lot for single goals. #define FOOD_GOAL_EASY 1 +/// Normal food, ask for a middling amount for single goals. #define FOOD_GOAL_NORMAL 2 +/// Hard reagent, ask for a little for single goals. #define FOOD_GOAL_HARD 3 +/// TOO hard, accepted for variety goals, but never used for single goals. +#define FOOD_GOAL_EXCESSIVE 4 +/// Same as FOOD_GOAL_EXCESSIVE, just different name to indicate that there's another version of this food that's used in variety goals. +#define FOOD_GOAL_DUPLICATE FOOD_GOAL_EXCESSIVE diff --git a/code/__DEFINES/mecha_hides.dm b/code/__DEFINES/mecha_hides.dm new file mode 100644 index 000000000000..3c1c1496a54a --- /dev/null +++ b/code/__DEFINES/mecha_hides.dm @@ -0,0 +1,6 @@ +#define HIDES_COVERED_FULL 3 +#define PLATES_COVERED_FULL 3 + +#define DRAKE_HIDES_COVERED_SLIGHT 1 +#define DRAKE_HIDES_COVERED_MODERATE 2 +#define DRAKE_HIDES_COVERED_FULL 3 diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm index d946b9763acf..7b8821a388b3 100644 --- a/code/__DEFINES/misc_defines.dm +++ b/code/__DEFINES/misc_defines.dm @@ -250,6 +250,10 @@ 0.4,0.6,0.0,\ 0.2,0.2,0.6) +#define MATRIX_STANDARD list(1.0,0.0,0.0,\ + 0.0,1.0,0.0,\ + 0.0,0.0,1.0) + /* Used for wire name appearances. Replaces the color name on the left with the one on the right. The color on the left is the one used as the actual color of the wire, but it doesn't look good when written. @@ -398,7 +402,7 @@ #define INVESTIGATE_BOMB "bombs" // The SQL version required by this version of the code -#define SQL_VERSION 552206 // SS220 EDIT +#define SQL_VERSION 562206 // SS220 EDIT // Vending machine stuff #define CAT_NORMAL (1<<0) diff --git a/code/__DEFINES/particle_defines.dm b/code/__DEFINES/particle_defines.dm index b261cd4f98d5..e4c0b381bbcb 100644 --- a/code/__DEFINES/particle_defines.dm +++ b/code/__DEFINES/particle_defines.dm @@ -5,3 +5,16 @@ #define DEBRIS_GLASS "glass" #define DEBRIS_LEAF "leaf" #define DEBRIS_SNOW "snow" + +/* + * Generator defines + */ + +#define GEN_NUM "num" +#define GEN_VECTOR "vector" +#define GEN_BOX "box" +#define GEN_COLOR "color" +#define GEN_CIRCLE "circle" +#define GEN_SPHERE "sphere" +#define GEN_SQUARE "square" +#define GEN_CUBE "cube" diff --git a/code/__DEFINES/reagents_defines.dm b/code/__DEFINES/reagents_defines.dm index 45bc2fafd1d2..25f1b1661a27 100644 --- a/code/__DEFINES/reagents_defines.dm +++ b/code/__DEFINES/reagents_defines.dm @@ -34,7 +34,13 @@ #define BLOOD_TYPE_FAKE_BLOOD "Vh Null" /// Used for secondary goals. +/// TOO easy, not accepted for variety goals. #define REAGENT_GOAL_SKIP 0 +/// Easy reagent, ask for a lot for single goals. #define REAGENT_GOAL_EASY 1 +/// Normal reagent, ask for a middling amount for single goals. #define REAGENT_GOAL_NORMAL 2 +/// Hard reagent, ask for a little for single goals. #define REAGENT_GOAL_HARD 3 +/// TOO hard, accepted for variety goals, but never used for single goals. +#define REAGENT_GOAL_EXCESSIVE 4 diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index d34fb4868293..9f3b5bb88935 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -178,6 +178,7 @@ #define STATUS_EFFECT_HIGHFIVE /datum/status_effect/high_five #define STATUS_EFFECT_DAP /datum/status_effect/high_five/dap #define STATUS_EFFECT_HANDSHAKE /datum/status_effect/high_five/handshake +#define STATUS_EFFECT_RPS /datum/status_effect/high_five/rps #define STATUS_EFFECT_CHARGING /datum/status_effect/charging diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index 36082679a21c..9a22a2b28914 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -239,6 +239,8 @@ GLOBAL_LIST_EMPTY(radial_menus) return else next_check = world.time + check_delay + // if you're wondering why your radial menus aren't clickable while debugging: + // it's probably the stoplag call here, try it again without any breakpoints stoplag(1) /datum/radial_menu/Destroy() diff --git a/code/controllers/subsystem/SSeconomy.dm b/code/controllers/subsystem/SSeconomy.dm index c261d7f963a7..8e6e428e69b5 100644 --- a/code/controllers/subsystem/SSeconomy.dm +++ b/code/controllers/subsystem/SSeconomy.dm @@ -68,6 +68,7 @@ SUBSYSTEM_DEF(economy) var/credits_per_easy_food_goal = 300 var/credits_per_normal_food_goal = 450 var/credits_per_hard_food_goal = 600 + var/credits_per_variety_food_goal = 450 var/credits_per_ripley_goal = 600 var/credits_per_kudzu_goal = 600 /// credits lost for sending unsecured cargo diff --git a/code/datums/components/debris.dm b/code/datums/components/debris.dm index fd1f058fa798..57bd8c8e32fc 100644 --- a/code/datums/components/debris.dm +++ b/code/datums/components/debris.dm @@ -3,35 +3,6 @@ * Originally from https://github.com/tgstation/TerraGov-Marine-Corps/pull/12752 */ -/particles/debris - icon = 'icons/effects/particles/generic_particles.dmi' - width = 500 - height = 500 - count = 10 - spawning = 10 - lifespan = 0.5 SECONDS - fade = 0.3 SECONDS - drift = generator("circle", 0, 7) - scale = 0.3 - velocity = list(50, 0) - friction = generator("num", 0.1, 0.15) - spin = generator("num", -20, 20) - -/particles/impact_smoke - icon = 'icons/effects/effects.dmi' - icon_state = "smoke" - width = 500 - height = 500 - count = 20 - spawning = 20 - lifespan = 0.8 SECONDS - fade = 10 SECONDS - grow = 0.1 - scale = 0.2 - spin = generator("num", -20, 20) - velocity = list(50, 0) - friction = generator("num", 0.1, 0.5) - /datum/component/debris /// Icon state of debris when impacted by a projectile var/debris @@ -76,7 +47,7 @@ if(debris && P.damage_type == BRUTE) debris_visuals = new(parent, /particles/debris) - debris_visuals.particles.position = generator("circle", position_offset, position_offset) + debris_visuals.particles.position = generator(GEN_CIRCLE, position_offset, position_offset) debris_visuals.particles.velocity = list(x_component, y_component) debris_visuals.layer = ABOVE_OBJ_LAYER + 0.02 debris_visuals.particles.icon_state = debris diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 01e94bffe157..5b159ce5e2cd 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -951,6 +951,14 @@ log_admin("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") message_admins("[key_name(usr)] has added [amount] units of [chosen_id] to \the [A]") + else if(href_list["editreagents"]) + if(!check_rights(R_DEBUG|R_ADMIN)) + return + + var/atom/A = locateUID(href_list["editreagents"]) + + try_open_reagent_editor(A) + else if(href_list["explode"]) if(!check_rights(R_DEBUG|R_EVENT)) return diff --git a/code/datums/elements/shatters_when_thrown.dm b/code/datums/elements/shatters_when_thrown.dm index 441d365e58c5..d8e3aec4273b 100644 --- a/code/datums/elements/shatters_when_thrown.dm +++ b/code/datums/elements/shatters_when_thrown.dm @@ -35,7 +35,7 @@ /// Handles the actual shattering part, throwing shards of whatever is defined on the component everywhere /datum/element/shatters_when_thrown/proc/shatter(atom/movable/source, atom/hit_atom) - var/generator/scatter_gen = generator("circle", 0, 48, NORMAL_RAND) + var/generator/scatter_gen = generator(GEN_CIRCLE, 0, 48, NORMAL_RAND) var/scatter_turf = get_turf(hit_atom) for(var/obj/item/scattered_item as anything in source.contents) diff --git a/code/datums/emote.dm b/code/datums/emote.dm index ee4dc262ba9c..b5b6d7178ed9 100644 --- a/code/datums/emote.dm +++ b/code/datums/emote.dm @@ -147,16 +147,16 @@ * * Arguments: * * user - Person that is trying to send the emote. - * * params - Parameters added after the emote. + * * emote_arg - String parameter added after the emote. * * type_override - Override to the current emote_type. * * intentional - Bool that says whether the emote was forced (FALSE) or not (TRUE). * * Returns TRUE if it was able to run the emote, FALSE otherwise. */ -/datum/emote/proc/run_emote(mob/user, params, type_override, intentional = FALSE) +/datum/emote/proc/run_emote(mob/user, emote_arg, type_override, intentional = FALSE) . = TRUE var/msg = select_message_type(user, message, intentional) - if(params && message_param) + if(emote_arg && message_param) // In this case, we did make some changes to the message that will be used, and we want to add the postfix on with the new parameters. // This is applicable to things like mimes, who this lets have a target on their canned emote responses. // Note that we only do this if we would otherwise have a message param, meaning there should be some target by default. @@ -164,17 +164,17 @@ if(message_param == EMOTE_PARAM_USE_POSTFIX || (msg != message && message_postfix)) if(!message_postfix) CRASH("Emote was specified to use postfix but message_postfix is empty.") - msg = select_param(user, params, "[remove_ending_punctuation(msg)] [message_postfix]", msg) + msg = select_param(user, emote_arg, "[remove_ending_punctuation(msg)] [message_postfix]", msg) else if(msg == message) // In this case, we're not making any substitutions in select_message_type, but we do have some params we want to sub in. - msg = select_param(user, params, message_param, message) + msg = select_param(user, emote_arg, message_param, message) // If this got propogated up, jump out. if(msg == EMOTE_ACT_STOP_EXECUTION) return TRUE if(isnull(msg)) - to_chat(user, "'[params]' isn't a valid parameter for [key].") + to_chat(user, "'[emote_arg]' isn't a valid parameter for [key].") return TRUE msg = replace_pronoun(user, msg) @@ -230,13 +230,13 @@ * Try to run an emote, checking can_run_emote once before executing the emote itself. * * * user - User of the emote - * * params - Params of the emote to be passed to run_emote + * * params - An optional extra argument included after the emote key. * * type_override - emote type to override the existing one with, if given. * * intentional - Whether or not the emote was triggered intentionally (if false, the emote was forced by code). * * Returns TRUE if the emote was able to be run (or failed successfully), or FALSE if the emote is unusable. */ -/datum/emote/proc/try_run_emote(mob/user, params, type_override, intentional = FALSE) +/datum/emote/proc/try_run_emote(mob/user, emote_arg, type_override, intentional = FALSE) // You can use this signal to block execution of emotes from components/other sources. var/sig_res = SEND_SIGNAL(user, COMSIG_MOB_PREEMOTE, key, intentional) switch(sig_res) @@ -245,9 +245,18 @@ if(COMPONENT_BLOCK_EMOTE_SILENT) return TRUE - . = run_emote(user, params, type_override, intentional) + . = run_emote(user, emote_arg, type_override, intentional) // safeguard in case these get modified + reset_emote() + +/** + * Reset the emote back to its original state. + * Necessary if you've made modifications to the emote itself over the course of its + * execution, as emotes are singletons, and changes would be reflected on every usage of the emote. + */ +/datum/emote/proc/reset_emote() + SHOULD_CALL_PARENT(TRUE) message = initial(message) message_param = initial(message_param) @@ -421,6 +430,9 @@ */ /datum/emote/proc/select_param(mob/user, params, substitution, base_message) + if(target_behavior == EMOTE_TARGET_BHVR_IGNORE) + return base_message + if(target_behavior == EMOTE_TARGET_BHVR_RAW) return replacetext(substitution, "%t", params) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 243d35ae95b8..8076376b3fe3 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -1793,6 +1793,7 @@ //Initialisation procs /mob/proc/mind_initialize() + SHOULD_CALL_PARENT(TRUE) if(mind) mind.key = key else @@ -1804,6 +1805,7 @@ if(!mind.name) mind.name = real_name mind.current = src + SEND_SIGNAL(src, COMSIG_MIND_INITIALIZE) //HUMAN /mob/living/carbon/human/mind_initialize() diff --git a/code/datums/outfits/outfit.dm b/code/datums/outfits/outfit.dm index 230aef4f95f3..6b481b09daaf 100644 --- a/code/datums/outfits/outfit.dm +++ b/code/datums/outfits/outfit.dm @@ -50,7 +50,20 @@ /datum/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) //to be overriden for toggling internals, id binding, access etc - return + SHOULD_CALL_PARENT(TRUE) + if(visualsOnly) + return + + if(H.mind) + on_mind_initialize(H) + return + RegisterSignal(H, COMSIG_MIND_INITIALIZE, PROC_REF(on_mind_initialize)) + +// Guaranteed access to mind, will never be called if visualsOnly = TRUE +/datum/outfit/proc/on_mind_initialize(mob/living/carbon/human/H) + SIGNAL_HANDLER // COMSIG_MIND_INITIALIZE + SHOULD_CALL_PARENT(TRUE) + UnregisterSignal(H, COMSIG_MIND_INITIALIZE) // prevent this call from being called multiple times on a human /datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE) pre_equip(H, visualsOnly) diff --git a/code/datums/outfits/outfit_admin.dm b/code/datums/outfits/outfit_admin.dm index 3ca49b9f3dff..fc314422c378 100644 --- a/code/datums/outfits/outfit_admin.dm +++ b/code/datums/outfits/outfit_admin.dm @@ -3,21 +3,15 @@ /datum/outfit/admin/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) . = ..() - if(!visualsOnly && H.mind) - H.mind.assigned_role = name - H.job = name - -/datum/outfit/admin/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - . = ..() - if(visualsOnly) return - if(H.mind) - H.mind.offstation_role = TRUE - else - H.RegisterSignal(H, COMSIG_HUMAN_LOGIN, TYPE_PROC_REF(/mob/living/carbon/human, apply_offstation_roles)) + H.job = name +/datum/outfit/admin/on_mind_initialize(mob/living/carbon/human/H) + . = ..() + H.mind.assigned_role = name + H.mind.offstation_role = TRUE /proc/apply_to_card(obj/item/card/id/I, mob/living/carbon/human/H, list/access = list(), rank, special_icon) if(!istype(I) || !istype(H)) @@ -1254,17 +1248,17 @@ if(istype(I)) apply_to_card(I, H, get_all_accesses(), "Ancient One", "data") - if(H.mind) - if(!H.mind.has_antag_datum(/datum/antagonist/vampire)) - H.mind.make_vampire(TRUE) - var/datum/antagonist/vampire/V = H.mind.has_antag_datum(/datum/antagonist/vampire) - V.bloodusable = 9999 - V.bloodtotal = 9999 - V.add_subclass(SUBCLASS_ANCIENT, FALSE) - H.dna.SetSEState(GLOB.jumpblock, TRUE) - singlemutcheck(H, GLOB.jumpblock, MUTCHK_FORCED) - H.update_mutations() - H.gene_stability = 100 +/datum/outfit/admin/ancient_vampire/on_mind_initialize(mob/living/carbon/human/H) + . = ..() + H.mind.make_vampire() + var/datum/antagonist/vampire/V = H.mind.has_antag_datum(/datum/antagonist/vampire) + V.bloodusable = 9999 + V.bloodtotal = 9999 + V.add_subclass(SUBCLASS_ANCIENT, FALSE) + H.dna.SetSEState(GLOB.jumpblock, TRUE) + singlemutcheck(H, GLOB.jumpblock, MUTCHK_FORCED) + H.update_mutations() + H.gene_stability = 100 /datum/outfit/admin/wizard name = "Blue Wizard" @@ -1494,10 +1488,6 @@ H.real_name = "Unknown" //Enforcers sacrifice their name to Oblivion for their power - for(var/spell_path in spell_paths) - var/S = new spell_path - H.mind.AddSpell(S) - var/obj/item/clothing/suit/hooded/oblivion/robes = H.wear_suit if(istype(robes)) robes.ToggleHood() @@ -1506,6 +1496,12 @@ if(istype(I)) apply_to_card(I, H, get_all_accesses(), "Oblivion Enforcer") +/datum/outfit/admin/enforcer/on_mind_initialize(mob/living/carbon/human/H) + . = ..() + for(var/spell_path in spell_paths) + var/S = new spell_path + H.mind.AddSpell(S) + /datum/outfit/admin/viper name = "Solar Federation Viper Infiltrator" diff --git a/code/datums/particles.dm b/code/datums/particles.dm new file mode 100644 index 000000000000..2162198a05c6 --- /dev/null +++ b/code/datums/particles.dm @@ -0,0 +1,105 @@ +/* + MARK: Impact debris + smoke +*/ + +/particles/debris + icon = 'icons/effects/particles/generic_particles.dmi' + width = 500 + height = 500 + count = 10 + spawning = 10 + lifespan = 0.5 SECONDS + fade = 0.3 SECONDS + drift = generator(GEN_CIRCLE, 0, 7) + scale = 0.3 + velocity = list(50, 0) + friction = generator(GEN_NUM, 0.1, 0.15) + spin = generator(GEN_NUM, -20, 20) + +/particles/impact_smoke + icon = 'icons/effects/effects.dmi' + icon_state = "smoke" + width = 500 + height = 500 + count = 20 + spawning = 20 + lifespan = 0.8 SECONDS + fade = 10 SECONDS + grow = 0.1 + scale = 0.2 + spin = generator(GEN_NUM, -20, 20) + velocity = list(50, 0) + friction = generator(GEN_NUM, 0.1, 0.5) + +/* + MARK: Explosion smoke +*/ + +/particles/explosion_smoke + icon = 'icons/effects/96x96.dmi' + icon_state = "smoke3" + width = 1000 + height = 1000 + count = 45 + spawning = 45 + gradient = list("#FA9632", "#C3630C", "#333333", "#808080", "#FFFFFF") + lifespan = 2.5 SECONDS + fade = 2 SECONDS + color = generator(GEN_NUM, 0, 0.25) + color_change = generator(GEN_NUM, 0.04, 0.05) + velocity = generator(GEN_CIRCLE, 15, 15) + drift = generator(GEN_CIRCLE, 0, 1, NORMAL_RAND) + spin = generator(GEN_NUM, -20, 20) + friction = generator(GEN_NUM, 0.1, 0.5) + gravity = list(1, 2) + scale = 0.25 + grow = 0.05 + +/particles/explosion_smoke/deva + scale = 0.5 + velocity = generator(GEN_CIRCLE, 23, 23) + +/particles/explosion_smoke/small + count = 15 + spawning = 15 + scale = 0.25 + velocity = generator(GEN_CIRCLE, 10, 10) + +/particles/smoke_wave + icon = 'icons/effects/96x96.dmi' + icon_state = "smoke3" + width = 750 + height = 750 + count = 75 + spawning = 75 + lifespan = 3 SECONDS + fade = 6 SECONDS + gradient = list("#BA9F6D", "#808080", "#FFFFFF") + color = generator(GEN_NUM, 0, 0.25) + color_change = generator(GEN_NUM, 0.08, 0.07) + velocity = generator(GEN_CIRCLE, 15, 15) + rotation = generator(GEN_NUM, -45, 45) + scale = 0.15 + grow = 0.05 + friction = 0.1 + +/particles/smoke_wave/small + count = 45 + spawning = 45 + scale = 0.05 + lifespan = 2 SECONDS + fade = 5 SECONDS + +/particles/sparks_outwards + icon = 'icons/effects/64x64.dmi' + icon_state = "flare" + width = 750 + height = 750 + count = 40 + spawning = 20 + lifespan = 5 SECONDS + fade = 2 SECONDS + position = generator(GEN_SPHERE, 8, 8) + velocity = generator(GEN_CIRCLE, 30, 30) + scale = 0.1 + friction = 0.1 diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 8920b4d44f00..6479678f2efc 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -69,6 +69,20 @@ user.remove_status_effect(type) highfived.remove_status_effect(type) +/datum/status_effect/high_five/proc/wiz_effect(mob/living/carbon/user, mob/living/carbon/highfived) + user.status_flags |= GODMODE + highfived.status_flags |= GODMODE + explosion(get_turf(user), 5, 2, 1, 3, cause = id) + // explosions have a spawn so this makes sure that we don't get gibbed + addtimer(CALLBACK(src, PROC_REF(wiz_cleanup), user, highfived), 0.3 SECONDS) // I want to be sure this lasts long enough, with lag. + add_attack_logs(user, highfived, "caused a wizard [id] explosion") + +/datum/status_effect/high_five/proc/post_start() + return + +/datum/status_effect/high_five/proc/regular_effect(mob/living/carbon/user, mob/living/carbon/highfived) + user.visible_message("[user.name] and [highfived.name] [success]") + /datum/status_effect/high_five/on_apply() if(!iscarbon(owner)) return FALSE @@ -82,25 +96,23 @@ continue if(is_wiz && iswizard(C)) user.visible_message("[user.name] и [C.name] [critical_success]") - user.status_flags |= GODMODE - C.status_flags |= GODMODE - explosion(get_turf(user), 5, 2, 1, 3, cause = id) - // explosions have a spawn so this makes sure that we don't get gibbed - addtimer(CALLBACK(src, PROC_REF(wiz_cleanup), user, C), 0.3 SECONDS) //I want to be sure this lasts long enough, with lag. - add_attack_logs(user, C, "caused a wizard [id] explosion") + wiz_effect(user, C) both_wiz = TRUE user.do_attack_animation(C, no_effect = TRUE) C.do_attack_animation(user, no_effect = TRUE) playsound(user, sound_effect, 80) if(!both_wiz) - user.visible_message("[user.name] и [C.name] [success]") + regular_effect(user, C) user.remove_status_effect(type) C.remove_status_effect(type) return FALSE + // We can return to break out of the loop here so we don't auto-remove (which causes the timer on the wizard highfive to break) + // This is safe because we only pass the continue if we don't have the status effect return TRUE // DO NOT AUTOREMOVE owner.custom_emote(EMOTE_VISIBLE, request) owner.create_point_bubble_from_path(item_path, FALSE) + post_start() /datum/status_effect/high_five/on_timeout() owner.visible_message("[owner] [get_missed_message()]") diff --git a/code/datums/uplink_items/uplink_general.dm b/code/datums/uplink_items/uplink_general.dm index c55eefdd2077..8fe7955fed50 100644 --- a/code/datums/uplink_items/uplink_general.dm +++ b/code/datums/uplink_items/uplink_general.dm @@ -605,7 +605,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/device_tools/bonerepair name = "Prototype Nanite Autoinjector" - desc = "Stolen prototype full body repair nanites. On injection it will shut down body systems as it revitilizes limbs and organs." + desc = "Stolen prototype full body repair nanites. On injection it will shut down body systems as it revitilizes limbs and organs. Heals organics organs, cybernetic organs, and limbs to fully operational conditions." reference = "NCAI" item = /obj/item/reagent_containers/hypospray/autoinjector/nanocalcium cost = 10 diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm index 3584e4089787..662b9ed349a8 100644 --- a/code/datums/wires/wires.dm +++ b/code/datums/wires/wires.dm @@ -106,7 +106,8 @@ if(ishuman(user)) var/mob/living/carbon/human/H = user var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes) - if(eyes && HAS_TRAIT(H, TRAIT_COLORBLIND)) // Check if the human has colorblindness. + var/obj/item/clothing/glasses/glasses = H.get_item_by_slot(SLOT_HUD_GLASSES) + if(eyes && HAS_TRAIT(H, TRAIT_COLORBLIND) && (!glasses || !glasses.correct_wires)) // Check if the human has colorblindness. replace_colors = eyes.replace_colours // Get the colorblind replacement colors list. var/list/wires_list = list() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 5a7fd8a98a0b..7b85b1d2b30a 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1164,6 +1164,7 @@ GLOBAL_LIST_EMPTY(blood_splatter_icons) if(curturf) .["Jump to turf"] = "?_src_=holder;adminplayerobservecoodjump=1;X=[curturf.x];Y=[curturf.y];Z=[curturf.z]" .["Add reagent"] = "?_src_=vars;addreagent=[UID()]" + .["Edit reagents"] = "?_src_=vars;editreagents=[UID()]" .["Trigger explosion"] = "?_src_=vars;explode=[UID()]" .["Trigger EM pulse"] = "?_src_=vars;emp=[UID()]" diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 29124ecc5031..0d48b4f514ee 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -339,8 +339,6 @@ ~~~~~~~~~~~~~~~~~~~~~*/ /obj/mecha/proc/diag_hud_set_mechhealth() var/image/holder = hud_list[DIAG_MECH_HUD] - var/icon/I = icon(icon, icon_state, dir) - holder.pixel_y = I.Height() - world.icon_size holder.icon_state = "huddiag[RoundDiagBar(obj_integrity/max_integrity)]" /obj/mecha/proc/diag_hud_set_mechcell() diff --git a/code/game/dna/mutations/monkey_mutation.dm b/code/game/dna/mutations/monkey_mutation.dm index 18334b1bd917..d1c4d7f960b9 100644 --- a/code/game/dna/mutations/monkey_mutation.dm +++ b/code/game/dna/mutations/monkey_mutation.dm @@ -29,18 +29,17 @@ H.set_species(has_primitive_form, keep_missing_bodyparts = TRUE) new /obj/effect/temp_visual/monkeyify(H.loc) - sleep(22) + addtimer(CALLBACK(src, PROC_REF(finish_monkeyize), H, !has_primitive_form), 2.2 SECONDS) +/datum/mutation/monkey/proc/finish_monkeyize(mob/living/carbon/human/H, should_gib) H.invisibility = initial(H.invisibility) - if(!has_primitive_form) //If the pre-change mob in question has no primitive set, this is going to be messy. + if(should_gib) //If the pre-change mob in question has no primitive set, this is going to be messy. H.gib() return REMOVE_TRAITS_IN(H, TRANSFORMING_TRAIT) to_chat(H, "You are now a [H.dna.species.name].") - return H - /datum/mutation/monkey/deactivate(mob/living/carbon/human/H) ..() if(!istype(H)) @@ -63,11 +62,13 @@ H.set_species(has_greater_form, keep_missing_bodyparts = TRUE) new /obj/effect/temp_visual/monkeyify/humanify(H.loc) - sleep(22) + addtimer(CALLBACK(src, PROC_REF(finish_unmonkeyize), H, !has_greater_form), 2.2 SECONDS) + +/datum/mutation/monkey/proc/finish_unmonkeyize(mob/living/carbon/human/H, should_gib) REMOVE_TRAITS_IN(H, TRANSFORMING_TRAIT) H.invisibility = initial(H.invisibility) - if(!has_greater_form) //If the pre-change mob in question has no primitive set, this is going to be messy. + if(should_gib) //If the pre-change mob in question has no primitive set, this is going to be messy. H.gib() return @@ -76,4 +77,3 @@ to_chat(H, "You are now a [H.dna.species.name].") - return H diff --git a/code/game/dna/mutations/mutation_powers.dm b/code/game/dna/mutations/mutation_powers.dm index da930664a2ce..d25a11adfd77 100644 --- a/code/game/dna/mutations/mutation_powers.dm +++ b/code/game/dna/mutations/mutation_powers.dm @@ -478,6 +478,7 @@ invocation_type = "none" action_icon_state = "genetic_jump" + var/leap_distance = 10 /datum/spell/leap/create_new_targeting() return new /datum/spell_targeting/self @@ -510,15 +511,25 @@ user.layer = 9 user.flying = TRUE - for(var/i=0, i<10, i++) + for(var/i in 1 to leap_distance) + var/turf/hit_turf = get_step(user, user.dir) + var/atom/hit_atom = get_blocking_atom(hit_turf) + if(hit_atom) + hit_atom.hit_by_thrown_mob(user, damage = 10) + break + step(user, user.dir) - if(i < 5) user.pixel_y += 8 - else user.pixel_y -= 8 + if(i < 6) + user.pixel_y += 8 + else + user.pixel_y -= 8 sleep(1) + user.flying = prevFlying + user.pixel_y = 0 // In case leap was varedited to be longer or shorter if(HAS_TRAIT(user, TRAIT_FAT) && prob(66)) - user.visible_message("[user.name] crashes due to [user.p_their()] heavy weight!") + user.visible_message("[user.name] crashes due to [user.p_their()] heavy weight!") //playsound(user.loc, 'zhit.wav', 50, 1) user.AdjustWeakened(20 SECONDS) user.AdjustStunned(10 SECONDS) @@ -541,6 +552,24 @@ container.pixel_x = 0 container.pixel_y = 0 +/datum/spell/leap/proc/get_blocking_atom(turf/turf_to_check) + if(!turf_to_check) + return FALSE + + if(turf_to_check.density) + return turf_to_check + + for(var/atom/movable/hit_thing in turf_to_check) + if(isliving(hit_thing)) + var/mob/living/hit_mob = hit_thing + return hit_mob.density + + if(isobj(hit_thing)) + var/obj/hit_obj = hit_thing + return hit_obj.density + + return FALSE + //////////////////////////////////////////////////////////////////////// // WAS: /datum/bioEffect/polymorphism diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 397a78d41ebe..0ab79fd1ab52 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -438,14 +438,14 @@ /proc/get_nuke_code() var/nukecode = "ERROR" - for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines) + for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list) if(bomb && bomb.r_code && is_station_level(bomb.z)) nukecode = bomb.r_code return nukecode /proc/get_nuke_status() var/nuke_status = NUKE_MISSING - for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines) + for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list) if(is_station_level(bomb.z)) nuke_status = NUKE_CORE_MISSING if(bomb.core) diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm index 9d85e02c7383..6e7eefce904f 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm @@ -3,7 +3,62 @@ #define MIND_DEVICE_MESSAGE 1 #define MIND_DEVICE_CONTROL 2 -//AGENT VEST +#define BATON_STUN 0 +#define BATON_SLEEP 1 +#define BATON_CUFF 2 +#define BATON_PROBE 3 +#define BATON_MODES 4 + +/* +CONTENTS: +1. AGENT GEAR +2. SCIENTIST GEAR +3. ENGINEERING TOOLS +4. MEDICAL TOOLS +5. JANITORIAL TOOLS +6. STRUCTURES +*/ + +// Setting up abductor exclusivity. +/obj/item/abductor + name = "generic abductor item" + icon = 'icons/obj/abductor.dmi' + desc = "You are not supposed to be able to see this. If you can see this, please make an issue report on GitHub." + +/obj/item/abductor/proc/AbductorCheck(user) + if(isabductor(user)) + return TRUE + to_chat(user, "You can't figure how this works!") + return FALSE + +/obj/item/abductor/proc/ScientistCheck(user) + if(!AbductorCheck(user)) + return FALSE + + var/mob/living/carbon/human/H = user + var/datum/species/abductor/S = H.dna.species + if(S.scientist) + return TRUE + to_chat(user, "You're not trained to use this!") + return FALSE + +///////////////////////////////////////// +/////////////// AGENT GEAR ////////////// +///////////////////////////////////////// +/obj/item/clothing/head/helmet/abductor + name = "agent headgear" + desc = "Abduct with style - spiky style. Prevents digital tracking." + icon_state = "alienhelmet" + item_state = "alienhelmet" + blockTracking = 1 + origin_tech = "materials=7;magnets=4;abductor=3" + flags = BLOCKHAIR + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE + + sprite_sheets = list( + "Vox" = 'icons/mob/clothing/species/vox/head.dmi' + ) + /obj/item/clothing/suit/armor/abductor/vest name = "agent vest" desc = "A vest outfitted with advanced stealth technology. It has two modes - combat and stealth." @@ -129,113 +184,6 @@ break return ..() -/obj/item/abductor - icon = 'icons/obj/abductor.dmi' - -/obj/item/abductor/proc/AbductorCheck(user) - if(isabductor(user)) - return TRUE - to_chat(user, "You can't figure how this works!") - return FALSE - -/obj/item/abductor/proc/ScientistCheck(user) - if(!AbductorCheck(user)) - return FALSE - - var/mob/living/carbon/human/H = user - var/datum/species/abductor/S = H.dna.species - if(S.scientist) - return TRUE - to_chat(user, "You're not trained to use this!") - return FALSE - -/obj/item/abductor/gizmo - name = "science tool" - desc = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras." - icon_state = "gizmo_scan" - item_state = "gizmo" - origin_tech = "engineering=7;magnets=4;bluespace=4;abductor=3" - var/mode = GIZMO_SCAN - var/mob/living/marked = null - var/obj/machinery/abductor/console/console - -/obj/item/abductor/gizmo/attack_self(mob/user) - if(!ScientistCheck(user)) - return - if(!console) - to_chat(user, "The device is not linked to a console!") - return - - if(mode == GIZMO_SCAN) - mode = GIZMO_MARK - icon_state = "gizmo_mark" - else - mode = GIZMO_SCAN - icon_state = "gizmo_scan" - to_chat(user, "You switch the device to [mode==GIZMO_SCAN? "SCAN": "MARK"] MODE") - -/obj/item/abductor/gizmo/attack(mob/living/M, mob/user) - if(!ScientistCheck(user)) - return - if(!console) - to_chat(user, "The device is not linked to console!") - return - - switch(mode) - if(GIZMO_SCAN) - scan(M, user) - if(GIZMO_MARK) - mark(M, user) - - -/obj/item/abductor/gizmo/afterattack(atom/target, mob/living/user, flag, params) - if(flag) - return - if(!ScientistCheck(user)) - return - if(!console) - to_chat(user, "The device is not linked to console!") - return - - switch(mode) - if(GIZMO_SCAN) - scan(target, user) - if(GIZMO_MARK) - mark(target, user) - -/obj/item/abductor/gizmo/proc/scan(atom/target, mob/living/user) - if(ishuman(target)) - console.AddSnapshot(target) - to_chat(user, "You scan [target] and add [target.p_them()] to the database.") - -/obj/item/abductor/gizmo/proc/mark(atom/target, mob/living/user) - if(marked == target) - to_chat(user, "This specimen is already marked!") - return - if(ishuman(target)) - if(isabductor(target)) - marked = target - to_chat(user, "You mark [target] for future retrieval.") - else - prepare(target,user) - else - prepare(target,user) - -/obj/item/abductor/gizmo/proc/prepare(atom/target, mob/living/user) - if(get_dist(target,user)>1) - to_chat(user, "You need to be next to the specimen to prepare it for transport!") - return - to_chat(user, "You begin preparing [target] for transport...") - if(do_after(user, 100, target = target)) - marked = target - to_chat(user, "You finish preparing [target] for transport.") - -/obj/item/abductor/gizmo/Destroy() - if(console) - console.gizmo = null - return ..() - - /obj/item/abductor/silencer name = "abductor silencer" desc = "A compact device used to shut down communications equipment." @@ -277,75 +225,6 @@ R.listening = FALSE // Prevents the radio from buzzing due to the EMP, preserving possible stealthiness. R.emp_act(1) -/obj/item/abductor/mind_device - name = "mental interface device" - desc = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, or to send a command to a test subject with a charged gland." - icon_state = "mind_device_message" - item_state = "silencer" - var/mode = MIND_DEVICE_MESSAGE - -/obj/item/abductor/mind_device/attack_self(mob/user) - if(!ScientistCheck(user)) - return - - if(mode == MIND_DEVICE_MESSAGE) - mode = MIND_DEVICE_CONTROL - icon_state = "mind_device_control" - else - mode = MIND_DEVICE_MESSAGE - icon_state = "mind_device_message" - to_chat(user, "You switch the device to [mode == MIND_DEVICE_MESSAGE ? "TRANSMISSION" : "COMMAND"] MODE") - -/obj/item/abductor/mind_device/afterattack(atom/target, mob/living/user, flag, params) - if(!ScientistCheck(user)) - return - - switch(mode) - if(MIND_DEVICE_CONTROL) - mind_control(target, user) - if(MIND_DEVICE_MESSAGE) - mind_message(target, user) - -/obj/item/abductor/mind_device/proc/mind_control(atom/target, mob/living/user) - if(iscarbon(target)) - var/mob/living/carbon/C = target - var/obj/item/organ/internal/heart/gland/G = C.get_organ_slot("heart") - if(!istype(G)) - to_chat(user, "Your target does not have an experimental gland!") - return - if(!G.mind_control_uses) - to_chat(user, "Your target's gland is spent!") - return - if(G.active_mind_control) - to_chat(user, "Your target is already under a mind-controlling influence!") - return - - var/command = tgui_input_text(user, "Enter the command for your target to follow. Uses Left: [G.mind_control_uses], Duration: [DisplayTimeText(G.mind_control_duration)]", "Enter command") - if(!command) - return - if(QDELETED(user) || user.get_active_hand() != src || loc != user) - return - if(QDELETED(G)) - return - G.mind_control(command, user) - to_chat(user, "You send the command to your target.") - -/obj/item/abductor/mind_device/proc/mind_message(atom/target, mob/living/user) - if(isliving(target)) - var/mob/living/L = target - if(L.stat == DEAD) - to_chat(user, "Your target is dead!") - return - var/message = tgui_input_text(user, "Write a message to send to your target's brain.", "Enter message") - if(!message) - return - if(QDELETED(L) || L.stat == DEAD) - return - - to_chat(L, "You hear a voice in your head saying: [message]") - to_chat(user, "You send the message to your target.") - log_say("[key_name(user)] sent an abductor mind message to [key_name(L)]: '[message]'", user) - /obj/item/gun/energy/alien name = "alien pistol" desc = "A complicated gun that fires bursts of high-intensity radiation." @@ -357,41 +236,6 @@ trigger_guard = TRIGGER_GUARD_ALLOW_ALL can_holster = TRUE -/obj/item/paper/abductor - name = "Dissection Guide" - icon_state = "alienpaper_words" - info = {"Dissection for Dummies
-
- 1.Acquire fresh specimen.
- 2.Put the specimen on operating table.
- 3.Apply scalpel to the chest, preparing for experimental dissection.
- 4.Apply scalpel to specimen's torso.
- 5.Clamp bleeders on specimen's torso with a hemostat.
- 6.Retract skin of specimen's torso with a retractor.
- 7.Saw through the specimen's torso with a saw.
- 8.Apply retractor again to specimen's torso.
- 9.Search through the specimen's torso with your hands to remove any superfluous organs.
- 10.Insert replacement gland (Retrieve one from gland storage).
- 11.Cauterize the patient's torso with a cautery.
- 12.Consider dressing the specimen back to not disturb the habitat.
- 13.Put the specimen in the experiment machinery.
- 14.Choose one of the machine options. The target will be analyzed and teleported to the selected drop-off point.
- 15.You will receive one supply credit, and the subject will be counted towards your quota.
-
-Congratulations! You are now trained for invasive xenobiology research!"} - -/obj/item/paper/abductor/update_icon_state() - return - -/obj/item/paper/abductor/AltClick() - return - -#define BATON_STUN 0 -#define BATON_SLEEP 1 -#define BATON_CUFF 2 -#define BATON_PROBE 3 -#define BATON_MODES 4 - /obj/item/abductor_baton name = "advanced baton" desc = "A quad-mode baton used for incapacitation and restraining of specimens." @@ -590,6 +434,281 @@ Congratulations! You are now trained for invasive xenobiology research!"} /obj/item/radio/headset/abductor/screwdriver_act() return// Stops humans from disassembling abductor headsets. +///////////////////////////////////////// +///////////// SCIENTIST GEAR //////////// +///////////////////////////////////////// +/obj/item/abductor/gizmo + name = "science tool" + desc = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras." + icon_state = "gizmo_scan" + item_state = "gizmo" + origin_tech = "engineering=7;magnets=4;bluespace=4;abductor=3" + var/mode = GIZMO_SCAN + var/mob/living/marked = null + var/obj/machinery/abductor/console/console + +/obj/item/abductor/gizmo/attack_self(mob/user) + if(!ScientistCheck(user)) + return + if(!console) + to_chat(user, "The device is not linked to a console!") + return + + if(mode == GIZMO_SCAN) + mode = GIZMO_MARK + icon_state = "gizmo_mark" + else + mode = GIZMO_SCAN + icon_state = "gizmo_scan" + to_chat(user, "You switch the device to [mode==GIZMO_SCAN? "SCAN": "MARK"] MODE") + +/obj/item/abductor/gizmo/attack(mob/living/M, mob/user) + if(!ScientistCheck(user)) + return + if(!console) + to_chat(user, "The device is not linked to console!") + return + + switch(mode) + if(GIZMO_SCAN) + scan(M, user) + if(GIZMO_MARK) + mark(M, user) + +/obj/item/abductor/gizmo/afterattack(atom/target, mob/living/user, flag, params) + if(flag) + return + if(!ScientistCheck(user)) + return + if(!console) + to_chat(user, "The device is not linked to console!") + return + + switch(mode) + if(GIZMO_SCAN) + scan(target, user) + if(GIZMO_MARK) + mark(target, user) + +/obj/item/abductor/gizmo/proc/scan(atom/target, mob/living/user) + if(ishuman(target)) + console.AddSnapshot(target) + to_chat(user, "You scan [target] and add [target.p_them()] to the database.") + +/obj/item/abductor/gizmo/proc/mark(atom/target, mob/living/user) + if(marked == target) + to_chat(user, "This specimen is already marked!") + return + if(ishuman(target)) + if(isabductor(target)) + marked = target + to_chat(user, "You mark [target] for future retrieval.") + else + prepare(target,user) + else + prepare(target,user) + +/obj/item/abductor/gizmo/proc/prepare(atom/target, mob/living/user) + if(get_dist(target,user)>1) + to_chat(user, "You need to be next to the specimen to prepare it for transport!") + return + to_chat(user, "You begin preparing [target] for transport...") + if(do_after(user, 100, target = target)) + marked = target + to_chat(user, "You finish preparing [target] for transport.") + +/obj/item/abductor/gizmo/Destroy() + if(console) + console.gizmo = null + return ..() + +/obj/item/abductor/mind_device + name = "mental interface device" + desc = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, or to send a command to a test subject with a charged gland." + icon_state = "mind_device_message" + item_state = "silencer" + var/mode = MIND_DEVICE_MESSAGE + +/obj/item/abductor/mind_device/attack_self(mob/user) + if(!ScientistCheck(user)) + return + + if(mode == MIND_DEVICE_MESSAGE) + mode = MIND_DEVICE_CONTROL + icon_state = "mind_device_control" + else + mode = MIND_DEVICE_MESSAGE + icon_state = "mind_device_message" + to_chat(user, "You switch the device to [mode == MIND_DEVICE_MESSAGE ? "TRANSMISSION" : "COMMAND"] MODE") + +/obj/item/abductor/mind_device/afterattack(atom/target, mob/living/user, flag, params) + if(!ScientistCheck(user)) + return + + switch(mode) + if(MIND_DEVICE_CONTROL) + mind_control(target, user) + if(MIND_DEVICE_MESSAGE) + mind_message(target, user) + +/obj/item/abductor/mind_device/proc/mind_control(atom/target, mob/living/user) + if(iscarbon(target)) + var/mob/living/carbon/C = target + var/obj/item/organ/internal/heart/gland/G = C.get_organ_slot("heart") + if(!istype(G)) + to_chat(user, "Your target does not have an experimental gland!") + return + if(!G.mind_control_uses) + to_chat(user, "Your target's gland is spent!") + return + if(G.active_mind_control) + to_chat(user, "Your target is already under a mind-controlling influence!") + return + + var/command = tgui_input_text(user, "Enter the command for your target to follow. Uses Left: [G.mind_control_uses], Duration: [DisplayTimeText(G.mind_control_duration)]", "Enter command") + if(!command) + return + if(QDELETED(user) || user.get_active_hand() != src || loc != user) + return + if(QDELETED(G)) + return + G.mind_control(command, user) + to_chat(user, "You send the command to your target.") + +/obj/item/abductor/mind_device/proc/mind_message(atom/target, mob/living/user) + if(isliving(target)) + var/mob/living/L = target + if(L.stat == DEAD) + to_chat(user, "Your target is dead!") + return + var/message = tgui_input_text(user, "Write a message to send to your target's brain.", "Enter message") + if(!message) + return + if(QDELETED(L) || L.stat == DEAD) + return + + to_chat(L, "You hear a voice in your head saying: [message]") + to_chat(user, "You send the message to your target.") + log_say("[key_name(user)] sent an abductor mind message to [key_name(L)]: '[message]'", user) + +/obj/item/paper/abductor + name = "Dissection Guide" + icon_state = "alienpaper_words" + info = {"Dissection for Dummies
+
+ 1.Acquire fresh specimen.
+ 2.Put the specimen on operating table.
+ 3.Apply scalpel to the chest, preparing for experimental dissection.
+ 4.Apply scalpel to specimen's torso.
+ 5.Clamp bleeders on specimen's torso with a hemostat.
+ 6.Retract skin of specimen's torso with a retractor.
+ 7.Saw through the specimen's torso with a saw.
+ 8.Apply retractor again to specimen's torso.
+ 9.Search through the specimen's torso with your hands to remove any superfluous organs.
+ 10.Insert replacement gland (Retrieve one from gland storage).
+ 11.Cauterize the patient's torso with a cautery.
+ 12.Consider dressing the specimen back to not disturb the habitat.
+ 13.Put the specimen in the experiment machinery.
+ 14.Choose one of the machine options. The target will be analyzed and teleported to the selected drop-off point.
+ 15.You will receive one supply credit, and the subject will be counted towards your quota.
+
+Congratulations! You are now trained for invasive xenobiology research!"} + +/obj/item/paper/abductor/update_icon_state() + return + +/obj/item/paper/abductor/AltClick() + return + +///////////////////////////////////////// +/////////// ENGINEERING TOOLS /////////// +///////////////////////////////////////// +/obj/item/screwdriver/abductor + name = "alien screwdriver" + desc = "An ultrasonic screwdriver." + icon = 'icons/obj/abductor.dmi' + icon_state = "screwdriver" + usesound = 'sound/items/pshoom.ogg' + toolspeed = 0.1 + random_color = FALSE + +/obj/item/wrench/abductor + name = "alien wrench" + desc = "A polarized wrench. It causes anything placed between the jaws to turn." + icon = 'icons/obj/abductor.dmi' + icon_state = "wrench" + usesound = 'sound/effects/empulse.ogg' + toolspeed = 0.1 + origin_tech = "materials=5;engineering=5;abductor=3" + +/obj/item/weldingtool/abductor + name = "alien welding tool" + desc = "An alien welding tool. Whatever fuel it uses, it never runs out." + icon = 'icons/obj/abductor.dmi' + icon_state = "welder" + toolspeed = 0.1 + w_class = WEIGHT_CLASS_SMALL + light_intensity = 0 + origin_tech = "plasmatech=5;engineering=5;abductor=3" + requires_fuel = FALSE + refills_over_time = TRUE + low_fuel_changes_icon = FALSE + +/obj/item/crowbar/abductor + name = "alien crowbar" + desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." + icon = 'icons/obj/abductor.dmi' + icon_state = "crowbar" + usesound = 'sound/weapons/sonic_jackhammer.ogg' + toolspeed = 0.1 + w_class = WEIGHT_CLASS_SMALL + origin_tech = "combat=4;engineering=4;abductor=3" + +/obj/item/wirecutters/abductor + name = "alien wirecutters" + desc = "Extremely sharp wirecutters, made out of a silvery-green metal." + icon = 'icons/obj/abductor.dmi' + icon_state = "cutters" + toolspeed = 0.1 + origin_tech = "materials=5;engineering=4;abductor=3" + random_color = FALSE + +/obj/item/wirecutters/abductor/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SHOW_WIRE_INFO, ROUNDSTART_TRAIT) + +/obj/item/multitool/abductor + name = "alien multitool" + desc = "An omni-technological interface." + icon = 'icons/obj/abductor.dmi' + icon_state = "multitool" + toolspeed = 0.1 + w_class = WEIGHT_CLASS_SMALL + origin_tech = "magnets=5;engineering=5;abductor=3" + +/obj/item/multitool/abductor/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SHOW_WIRE_INFO, ROUNDSTART_TRAIT) + +/obj/item/storage/belt/military/abductor + name = "agent belt" + desc = "A belt used by abductor agents." + icon = 'icons/obj/abductor.dmi' + icon_state = "belt" + item_state = "security" + +/obj/item/storage/belt/military/abductor/full/populate_contents() + new /obj/item/screwdriver/abductor(src) + new /obj/item/wrench/abductor(src) + new /obj/item/weldingtool/abductor(src) + new /obj/item/crowbar/abductor(src) + new /obj/item/wirecutters/abductor(src) + new /obj/item/multitool/abductor(src) + new /obj/item/stack/cable_coil(src, 30, COLOR_WHITE) + +///////////////////////////////////////// +/////////// MEDICAL TOOLS /////////////// +///////////////////////////////////////// /obj/item/scalpel/alien name = "alien scalpel" desc = "It's a gleaming sharp knife made out of silvery-green metal." @@ -641,7 +760,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} /obj/item/FixOVein/alien name = "alien FixOVein" - desc = "Bloodless aliens would totally know how to stop internal bleeding...right?" + desc = "Bloodless aliens would totally know how to stop internal bleeding... Right?" icon = 'icons/obj/abductor.dmi' origin_tech = "materials=2;biotech=2;abductor=2" toolspeed = 0.25 @@ -653,21 +772,89 @@ Congratulations! You are now trained for invasive xenobiology research!"} origin_tech = "materials=2;biotech=2;abductor=2" toolspeed = 0.25 -/obj/item/clothing/head/helmet/abductor - name = "agent headgear" - desc = "Abduct with style - spiky style. Prevents digital tracking." - icon_state = "alienhelmet" - item_state = "alienhelmet" - blockTracking = 1 - origin_tech = "materials=7;magnets=4;abductor=3" - flags = BLOCKHAIR - flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE +///////////////////////////////////////// +//////////// JANITORIAL TOOLS /////////// +///////////////////////////////////////// +/obj/item/mop/advanced/abductor + name = "alien mop" + desc = "A collapsible mop clearly used by aliens to clean up any evidence of a close encounter. The head produces a constant supply of water when run over a surface, seemingly out of nowhere." + icon = 'icons/obj/abductor.dmi' + icon_state = "mop_abductor" + mopcap = 100 + origin_tech = "materials=3;engineering=3;abductor=3" + refill_rate = 50 + refill_reagent = "water" + mopspeed = 10 + +/obj/item/soap/syndie/abductor + name = "alien soap" + desc = "Even bloodless aliens need to wash the grime off. Smells like gunpowder." + icon = 'icons/obj/abductor.dmi' + icon_state = "soap_abductor" - sprite_sheets = list( - "Vox" = 'icons/mob/clothing/species/vox/head.dmi' +/obj/item/lightreplacer/bluespace/abductor + name = "alien light replacer" + desc = "It's important to keep all the mysterious lights on a UFO functional when flying over backwater country." + icon = 'icons/obj/abductor.dmi' + icon_state = "lightreplacer_abductor" + origin_tech = "magnets=3;engineering=4;abductor=3" + max_uses = 40 + uses = 20 + +/obj/item/melee/flyswatter/abductor + name = "alien flyswatter" + desc = "For killing alien insects, obviously." + icon = 'icons/obj/abductor.dmi' + icon_state = "flyswatter_abductor" + item_state = "flyswatter_abductor" + origin_tech = "abductor=1" + force = 2 // Twice as powerful thanks to alien technology! + throwforce = 2 + +/obj/item/reagent_containers/spray/cleaner/safety/abductor // Essentially an Advanced Space Cleaner, but abductor-themed. For the implant. + name = "alien space cleaner" + desc = "An alien spray bottle contaning alien-brand non-foaming space cleaner! It only accepts space cleaner." + icon = 'icons/obj/abductor.dmi' + icon_state = "cleaner_abductor" + item_state = "cleaner_abductor" + volume = 500 + spray_maxrange = 3 + spray_currentrange = 3 + list_reagents = list("cleaner" = 500) + +/obj/item/storage/belt/janitor/abductor + name = "alien janibelt" + desc = "A belt used to hold out-of-this-world cleaning supplies! Used by abductors to keep their ships clean." + icon = 'icons/obj/abductor.dmi' + icon_state = "janibelt_abductor" + item_state = "security" + storage_slots = 7 + can_hold = list( + /obj/item/grenade/chem_grenade/cleaner, + /obj/item/lightreplacer, + /obj/item/flashlight, + /obj/item/reagent_containers/spray, + /obj/item/soap, + /obj/item/holosign_creator/janitor, + /obj/item/melee/flyswatter, + /obj/item/storage/bag/trash, + /obj/item/push_broom, + /obj/item/door_remote/janikeyring, + /obj/item/mop/advanced/abductor ) -// Operating Table / Beds / Lockers +/obj/item/storage/belt/janitor/abductor/full/populate_contents() + new /obj/item/mop/advanced/abductor(src) + new /obj/item/soap/syndie/abductor(src) + new /obj/item/lightreplacer/bluespace/abductor(src) + new /obj/item/storage/bag/trash/bluespace(src) + new /obj/item/melee/flyswatter/abductor(src) + new /obj/item/reagent_containers/spray/cleaner/safety/abductor(src) + new /obj/item/holosign_creator/janitor(src) + +///////////////////////////////////////// +/////////////// STRUCTURES ////////////// +///////////////////////////////////////// /obj/structure/bed/abductor name = "resting contraption" desc = "This looks similar to contraptions from earth. Could aliens be stealing our technology?" diff --git a/code/game/gamemodes/miniantags/abduction/abduction_outfits.dm b/code/game/gamemodes/miniantags/abduction/abduction_outfits.dm index 15cf5eeacde8..82a903afa37c 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction_outfits.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction_outfits.dm @@ -50,7 +50,6 @@ /datum/outfit/abductor/scientist name = "Abductor Scientist" - backpack_contents = list( /obj/item/abductor/gizmo = 1 ) diff --git a/code/game/gamemodes/nuclear/nuclear_challenge.dm b/code/game/gamemodes/nuclear/nuclear_challenge.dm index 34c20a462e13..dcbe941dd2a3 100644 --- a/code/game/gamemodes/nuclear/nuclear_challenge.dm +++ b/code/game/gamemodes/nuclear/nuclear_challenge.dm @@ -84,7 +84,7 @@ if(declaring_war) to_chat(user, "You are already in the process of declaring war! Make your mind up.") return FALSE - if(length(GLOB.player_list) < CHALLENGE_MIN_PLAYERS) + if(length(get_living_players(exclude_nonhuman = FALSE, exclude_offstation = TRUE)) < CHALLENGE_MIN_PLAYERS) to_chat(user, "The enemy crew is too small to be worth declaring war on.") return FALSE if(!is_admin_level(user.z)) diff --git a/code/game/jobs/job/central.dm b/code/game/jobs/job/central.dm index 287c910fd69e..c5ba161c6ce6 100644 --- a/code/game/jobs/job/central.dm +++ b/code/game/jobs/job/central.dm @@ -41,10 +41,8 @@ /obj/item/organ/internal/cyberimp/arm/combat/centcom ) -/datum/outfit/job/ntnavyofficer/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/ntnavyofficer/on_mind_initialize(mob/living/carbon/human/H) . = ..() - if(visualsOnly) - return H.mind.offstation_role = TRUE // CC Officials who lead ERTs, Death Squads, etc. @@ -97,10 +95,8 @@ /obj/item/organ/internal/cyberimp/arm/combat/centcom ) -/datum/outfit/job/ntspecops/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) +/datum/outfit/job/ntspecops/on_mind_initialize(mob/living/carbon/human/H) . = ..() - if(visualsOnly) - return H.mind.offstation_role = TRUE /datum/job/ntspecops/solgovspecops @@ -121,4 +117,7 @@ if(istype(I)) apply_to_card(I, H, get_centcom_access(name), name, "lifetimeid") H.sec_hud_set_ID() + +/datum/outfit/job/ntspecops/solgovspecops/on_mind_initialize(mob/living/carbon/human/H) + . = ..() H.mind.offstation_role = TRUE diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index f18261f10bc8..88bce93f022e 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -215,6 +215,7 @@ gear_leftovers += G /datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + . = ..() if(visualsOnly) return @@ -283,3 +284,16 @@ PDA.ownjob = C.assignment PDA.ownrank = C.rank PDA.name = "КПК-[H.real_name] ([PDA.ownjob])" + +/datum/outfit/job/on_mind_initialize(mob/living/carbon/human/H) + . = ..() + var/obj/item/card/id/id = H.wear_id + if(!id) + return + var/datum/job/J = SSjobs.GetJobType(jobtype) + if(!J) + J = SSjobs.GetJob(H.job) + id.assignment = H.mind.role_alt_title ? H.mind.role_alt_title : J.title + if(!H.mind.initial_account) + return + id.associated_account_number = H.mind.initial_account.account_number diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm index db3f8a74454a..939bca690832 100644 --- a/code/game/jobs/job/support.dm +++ b/code/game/jobs/job/support.dm @@ -202,6 +202,9 @@ singlemutcheck(H, GLOB.soberblock, MUTCHK_FORCED) H.dna.default_blocks.Add(GLOB.soberblock) H.check_mutations = 1 + +/datum/outfit/job/bartender/on_mind_initialize(mob/living/carbon/human/H) + . = ..() ADD_TRAIT(H.mind, TRAIT_TABLE_LEAP, ROUNDSTART_TRAIT) ADD_TRAIT(H.mind, TRAIT_SLEIGHT_OF_HAND, ROUNDSTART_TRAIT) @@ -236,12 +239,10 @@ /obj/item/paper/chef=1,\ /obj/item/book/manual/wiki/chef_recipes=1) -/datum/outfit/job/chef/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - ..() - if(visualsOnly) - return +/datum/outfit/job/chef/on_mind_initialize(mob/living/carbon/human/H) + . = ..() var/datum/martial_art/cqc/under_siege/justacook = new - justacook.teach(H) + justacook.teach(H) // requires mind ADD_TRAIT(H.mind, TRAIT_TABLE_LEAP, ROUNDSTART_TRAIT) @@ -419,12 +420,14 @@ if(visualsOnly) return - if(H.mind) - H.mind.AddSpell(new /datum/spell/aoe/conjure/build/mime_wall(null)) - H.mind.AddSpell(new /datum/spell/mime/speak(null)) - H.mind.miming = 1 qdel(H.GetComponent(/datum/component/footstep)) +/datum/outfit/job/mime/on_mind_initialize(mob/living/carbon/human/H) + . = ..() + H.mind.AddSpell(new /datum/spell/aoe/conjure/build/mime_wall(null)) + H.mind.AddSpell(new /datum/spell/mime/speak(null)) + H.mind.miming = TRUE + /datum/job/janitor title = "Janitor" flag = JOB_JANITOR @@ -488,7 +491,7 @@ /datum/outfit/job/librarian/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) ..() - if(!H.mind) + if(visualsOnly) return for(var/la in GLOB.all_languages) var/datum/language/new_language = GLOB.all_languages[la] diff --git a/code/game/jobs/job/support_chaplain.dm b/code/game/jobs/job/support_chaplain.dm index cd5827e82012..14c328c08661 100644 --- a/code/game/jobs/job/support_chaplain.dm +++ b/code/game/jobs/job/support_chaplain.dm @@ -32,11 +32,12 @@ if(visualsOnly) return - if(istype(H.mind)) - ADD_TRAIT(H.mind, TRAIT_HOLY, ROUNDSTART_TRAIT) - INVOKE_ASYNC(src, PROC_REF(religion_pick), H) +/datum/outfit/job/chaplain/on_mind_initialize(mob/living/carbon/human/H) + . = ..() + ADD_TRAIT(H.mind, TRAIT_HOLY, ROUNDSTART_TRAIT) + /datum/outfit/job/chaplain/proc/religion_pick(mob/living/carbon/human/user) var/obj/item/storage/bible/B = new /obj/item/storage/bible(get_turf(user)) B.customisable = TRUE // Only the initial bible is customisable diff --git a/code/game/jobs/job/syndicate_jobs.dm b/code/game/jobs/job/syndicate_jobs.dm index 2ac9d04a26f4..cb9bc60aa19b 100644 --- a/code/game/jobs/job/syndicate_jobs.dm +++ b/code/game/jobs/job/syndicate_jobs.dm @@ -55,8 +55,11 @@ U.implant(H) U.hidden_uplink.uses = 2500 H.faction += "syndicate" + +/datum/outfit/job/syndicateofficer/on_mind_initialize(mob/living/carbon/human/H) + . = ..() var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS] opshud.join_hud(H.mind.current) H.mind.offstation_role = TRUE set_antag_hud(H.mind.current, "hudoperative") - H.regenerate_icons() + INVOKE_ASYNC(H, TYPE_PROC_REF(/mob/living/carbon/human, regenerate_icons)) diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm index 93332e05f690..c1d333e8c4a3 100644 --- a/code/game/mecha/working/ripley.dm +++ b/code/game/mecha/working/ripley.dm @@ -16,8 +16,16 @@ wreckage = /obj/structure/mecha_wreckage/ripley var/list/cargo = new var/cargo_capacity = 15 + + /// How many goliath hides does the Ripley have? Does not stack with other armor var/hides = 0 + /// How many drake hides does the Ripley have? Does not stack with other armor + var/drake_hides = 0 + + /// How many plates does the Ripley have? Does not stack with other armor + var/plates = 0 + /obj/mecha/working/ripley/Move() . = ..() if(.) @@ -33,10 +41,14 @@ ore.forceMove(ore_box) /obj/mecha/working/ripley/Destroy() - for(var/i=1, i <= hides, i++) - new /obj/item/stack/sheet/animalhide/goliath_hide(loc) //If a goliath-plated ripley gets killed, all the plates drop + for(var/i in 1 to hides) + new /obj/item/stack/sheet/animalhide/goliath_hide(get_turf(src)) //If a armor-plated ripley gets killed, all the armor drop + for(var/i in 1 to plates) + new /obj/item/stack/sheet/animalhide/armor_plate(get_turf(src)) + for(var/i in 1 to drake_hides) + new /obj/item/stack/sheet/animalhide/ashdrake(get_turf(src)) for(var/atom/movable/A in cargo) - A.forceMove(loc) + A.forceMove(get_turf(src)) step_rand(A) cargo.Cut() return ..() @@ -55,22 +67,58 @@ /obj/mecha/working/ripley/update_desc() . = ..() - if(!hides) // Just in case if hides are somehow removed + if(!hides && !plates && !drake_hides) // Just in case if armor is removed desc = initial(desc) return - if(hides == 3) - desc = "Autonomous Power Loader Unit. It's wearing a fearsome carapace entirely composed of goliath hide plates - its pilot must be an experienced monster hunter." - else - desc = "Autonomous Power Loader Unit. Its armour is enhanced with some goliath hide plates." + + // Goliath hides + if(hides) + if(hides == HIDES_COVERED_FULL) + desc = "Autonomous Power Loader Unit. It's wearing a fearsome carapace entirely composed of goliath hide plates - its pilot must be an experienced monster hunter." + else + desc = "Autonomous Power Loader Unit. Its armour is enhanced with some goliath hide plates." + return + + // Metal plates + if(plates) + if(plates == PLATES_COVERED_FULL) + desc = "Autonomous Power Loader Unit. Its armor is completely lined with metal plating." + else + desc = "Autonomous Power Loader Unit. Its armor is reinforced with some metal plating." + return + + // Drake hides + if(drake_hides) + if(drake_hides == DRAKE_HIDES_COVERED_FULL) + desc = "Autonomous Power Loader Unit. Its every corner is covered in ancient hide, creating a powerful shield. The pilot of this exosuit must be prepared for battles on the level of legend." + if(drake_hides == DRAKE_HIDES_COVERED_MODERATE) + desc = "Autonomous Power Loader Unit. Its armor is adorned with dragon hide plates, instilling fear in its enemies and guarding its pilot." + if(drake_hides == DRAKE_HIDES_COVERED_SLIGHT) + desc = "Autonomous Power Loader Unit. The armor of this exosuit only touches the mythical: a few plates of dragon hide adorn its plating like rare warrior trophies." + return /obj/mecha/working/ripley/update_overlays() . = ..() - if(!hides) - return - if(hides == 3) - . += occupant ? "ripley-g-full" : "ripley-g-full-open" - else - . += occupant ? "ripley-g" : "ripley-g-open" +// hides + if(hides) + if(hides == HIDES_COVERED_FULL) + . += occupant ? "ripley-g-full" : "ripley-g-full-open" + else + . += occupant ? "ripley-g" : "ripley-g-open" +//plates + if(plates) + if(plates == PLATES_COVERED_FULL) + . += occupant ? "ripley-m-full" : "ripley-m-full-open" + else + . += occupant ? "ripley-m" : "ripley-m-open" +//drake hides + if(drake_hides) + if(drake_hides == DRAKE_HIDES_COVERED_FULL) + . += occupant ? "ripley-d-full" : "ripley-d-full-open" + else if(drake_hides == DRAKE_HIDES_COVERED_MODERATE) + . += occupant ? "ripley-d-2" : "ripley-d-2-open" + else if(drake_hides == DRAKE_HIDES_COVERED_SLIGHT) + . += occupant ? "ripley-d" : "ripley-d-open" /obj/mecha/working/ripley/firefighter desc = "A standard APLU chassis that was refitted with additional thermal protection and a cistern." diff --git a/code/game/mecha/working/working.dm b/code/game/mecha/working/working.dm index 3e45148ef51e..c9e7d99ac08d 100644 --- a/code/game/mecha/working/working.dm +++ b/code/game/mecha/working/working.dm @@ -1,2 +1,3 @@ /obj/mecha/working internal_damage_threshold = 60 + diff --git a/code/game/objects/effects/effect_system/effects_explosion.dm b/code/game/objects/effects/effect_system/effects_explosion.dm index a3b15f322a5a..3247946bb392 100644 --- a/code/game/objects/effects/effect_system/effects_explosion.dm +++ b/code/game/objects/effects/effect_system/effects_explosion.dm @@ -19,41 +19,3 @@ for(var/j in 1 to steps_amt) sleep(1) step(expl,direct) - -/obj/effect/explosion - name = "explosive particles" - icon = 'icons/effects/96x96.dmi' - icon_state = "explosion" - opacity = TRUE - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - pixel_x = -32 - pixel_y = -32 - -/obj/effect/explosion/New() - ..() - QDEL_IN(src, 10) - -/datum/effect_system/explosion - -/datum/effect_system/explosion/set_up(loca) - if(isturf(loca)) - location = loca - else - location = get_turf(loca) - -/datum/effect_system/explosion/start() - new/obj/effect/explosion(location) - var/datum/effect_system/expl_particles/P = new/datum/effect_system/expl_particles() - P.set_up(10, 0, location) - P.start() - -/datum/effect_system/explosion/smoke - -/datum/effect_system/explosion/smoke/proc/create_smoke() - var/datum/effect_system/smoke_spread/S = new - S.set_up(5, FALSE, location, null) - S.start() - -/datum/effect_system/explosion/smoke/start() - ..() - addtimer(CALLBACK(src, PROC_REF(create_smoke)), 5) diff --git a/code/game/objects/effects/temporary_visuals/explosion_temp_visuals.dm b/code/game/objects/effects/temporary_visuals/explosion_temp_visuals.dm new file mode 100644 index 000000000000..9b6b318758ad --- /dev/null +++ b/code/game/objects/effects/temporary_visuals/explosion_temp_visuals.dm @@ -0,0 +1,64 @@ +/obj/effect/temp_visual/explosion + name = "boom" + icon = 'icons/effects/96x96.dmi' + icon_state = "explosion2" + duration = 6 SECONDS + /// Smoke wave particle holder + var/obj/effect/abstract/particle_holder/smoke_wave + /// Explosion smoke particle holder + var/obj/effect/abstract/particle_holder/explosion_smoke + /// Sparks particle holder + var/obj/effect/abstract/particle_holder/sparks + +/obj/effect/temp_visual/explosion/Initialize(mapload, radius, color, small = FALSE, large = FALSE) + . = ..() + set_light(radius, radius, LIGHT_COLOR_ORANGE) + generate_particles(radius, small, large) + var/image/I = image(icon, src, icon_state, 10, -32, -32) + var/matrix/rotate = matrix() + rotate.Turn(rand(0, 359)) + I.transform = rotate + overlays += I // We use an overlay so the explosion and light source are both in the correct location plus so the particles don't rotate with the explosion + icon_state = null + +/// Generate the particles +/obj/effect/temp_visual/explosion/proc/generate_particles(radius, small = FALSE, large = FALSE) + if(small) + smoke_wave = new(src, /particles/smoke_wave/small) + else + smoke_wave = new(src, /particles/smoke_wave) + + if(large) + explosion_smoke = new(src, /particles/explosion_smoke/deva) + else if(small) + explosion_smoke = new(src, /particles/explosion_smoke/small) + else + explosion_smoke = new(src, /particles/explosion_smoke) + + sparks = new(src, /particles/sparks_outwards) + + if(large) + smoke_wave.particles.velocity = generator(GEN_CIRCLE, 6 * radius, 6 * radius) + else if(small) + smoke_wave.particles.velocity = generator(GEN_CIRCLE, 3 * radius, 3 * radius) + else + smoke_wave.particles.velocity = generator(GEN_CIRCLE, 5 * radius, 5 * radius) + + explosion_smoke.layer = layer + 0.1 + sparks.particles.velocity = generator(GEN_CIRCLE, 8 * radius, 8 * radius) + + // The reason for these timers is to set the count to 0 + // This causes any particle systems to not spawn in new particles, but not delete the currently existing ones + addtimer(CALLBACK(src, PROC_REF(set_count_short)), 1 SECONDS) + +/obj/effect/temp_visual/explosion/proc/set_count_short() + remove_light() + explosion_smoke.particles.count = 0 + sparks.particles.count = 0 + smoke_wave.particles.count = 0 + +/obj/effect/temp_visual/explosion/Destroy() + QDEL_NULL(smoke_wave) + QDEL_NULL(explosion_smoke) + QDEL_NULL(sparks) + return ..() diff --git a/code/game/objects/effects/temporary_visuals/misc_visuals.dm b/code/game/objects/effects/temporary_visuals/misc_visuals.dm index 1a8a23ee9378..77cdaa73bf46 100644 --- a/code/game/objects/effects/temporary_visuals/misc_visuals.dm +++ b/code/game/objects/effects/temporary_visuals/misc_visuals.dm @@ -231,16 +231,12 @@ layer = ABOVE_MOB_LAYER duration = 4 -/obj/effect/temp_visual/explosion +/obj/effect/temp_visual/pka_explosion name = "explosion" icon = 'icons/effects/96x96.dmi' - icon_state = "explosion" + icon_state = "explosionfast" pixel_x = -32 pixel_y = -32 - duration = 8 - -/obj/effect/temp_visual/explosion/fast - icon_state = "explosionfast" duration = 4 /obj/effect/temp_visual/heart diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index 3720150cd1df..1c6b50e64fef 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -109,14 +109,12 @@ if(creaking_explosion) // 5 seconds after the bang, the station begins to creak addtimer(CALLBACK(M, TYPE_PROC_REF(/mob, playsound_local), epicenter, null, rand(FREQ_LOWER, FREQ_UPPER), 1, frequency, null, null, FALSE, hull_creaking_sound, 0), CREAK_DELAY) - if(heavy_impact_range > 1) - var/datum/effect_system/explosion/E - if(smoke) - E = new /datum/effect_system/explosion/smoke - else - E = new - E.set_up(epicenter) - E.start() + if(devastation_range > 0) + new /obj/effect/temp_visual/explosion(epicenter, max_range, FALSE, TRUE) + else if(heavy_impact_range > 0) + new /obj/effect/temp_visual/explosion(epicenter, max_range, FALSE, FALSE) + else if(light_impact_range > 0) + new /obj/effect/temp_visual/explosion(epicenter, max_range, TRUE, FALSE) var/list/affected_turfs = spiral_range_turfs(max_range, epicenter) diff --git a/code/game/objects/items/robot/cyborg_gripper.dm b/code/game/objects/items/robot/cyborg_gripper.dm new file mode 100644 index 000000000000..59409c56fa32 --- /dev/null +++ b/code/game/objects/items/robot/cyborg_gripper.dm @@ -0,0 +1,231 @@ +/* CONTENTS: +0. generic define gripper +1. UNIVERSAL GRIPPER +2. MEDICAL GRIPPER +3. SERVICE GRIPPER +4. ENGINEERING GRIPPER +*/ + +// Generic gripper. This should never appear anywhere. +/obj/item/gripper + name = "generic gripper item" + desc = "If you can see this, make an issue report to Github. Something has gone wrong!" + icon = 'icons/obj/device.dmi' + icon_state = "gripper" + actions_types = list(/datum/action/item_action/drop_gripped_item) + /// Set to TRUE to allow interaction with light fixtures and cell-containing machinery. + var/engineering_machine_interaction = FALSE + /// Set to TRUE to allow the gripper to shake people awake/help them up. + var/can_help_up = FALSE + /// Defines what items the gripper can carry. + var/list/can_hold = list() + /// Set to TRUE to allow ANY item to be held, bypassing can_hold checks. + var/can_hold_all_items = FALSE + /// The item currently being held. + var/obj/item/gripped_item + +/obj/item/gripper/examine(mob/user) + . = ..() + if(!gripped_item) + . += "[src] is empty." + return + . += "[src] is currently holding [gripped_item]." + +/obj/item/gripper/examine_more(mob/user) + . = ..() + . += {"Cyborg grippers are well-developed, and despite some anatomical differences that manifest in some models, they can be used just as effectively as a regular hand with enough practice. + +Companies like Nanotrasen use software to limit the items that a cyborg can manipulate to a specific pre-defined list, \ +as part of their multi-layered protections to try and eliminate the chance of a hypothetical synthetic uprising, not wishing to see a repeat of the IPC uprising in 2525."} + + +/obj/item/gripper/Initialize(mapload) + . = ..() + can_hold = typecacheof(can_hold) + +/obj/item/gripper/ui_action_click(mob/user) + drop_gripped_item(user) + +/obj/item/gripper/proc/drop_gripped_item(mob/user, silent = FALSE) + if(!gripped_item) + to_chat(user, "[src] is empty.") + return + if(!silent) + to_chat(user, "You drop [gripped_item].") + gripped_item.forceMove(get_turf(src)) + gripped_item = null + +/obj/item/gripper/attack_self(mob/user) + if(!gripped_item) + to_chat(user, "[src] is empty.") + return + gripped_item.attack_self(user) + +/obj/item/gripper/attack(mob/living/carbon/M, mob/living/carbon/user) + return + +// This is required to ensure that the forceMove checks on some objects don't rip the gripper out of the borg's inventory and toss it on the floor. That would hurt, a lot! +/obj/item/gripper/forceMove(atom/destination) + return + +/obj/item/gripper/afterattack(atom/target, mob/living/user, proximity, params) + //Target is invalid or we are not adjacent. + if(!target || !proximity) + return FALSE + // Shake people awake, get them on their feet. + if(ishuman(target) && can_help_up) + var/mob/living/carbon/human/pickup_target = target + if(!IS_HORIZONTAL(pickup_target)) + return + pickup_target.AdjustSleeping(-10 SECONDS) + pickup_target.AdjustParalysis(-6 SECONDS) + pickup_target.AdjustStunned(-6 SECONDS) + pickup_target.AdjustWeakened(-6 SECONDS) + pickup_target.AdjustKnockDown(-6 SECONDS) + pickup_target.adjustStaminaLoss(-10) + pickup_target.resting = FALSE + pickup_target.stand_up() + playsound(user.loc, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) + user.visible_message( + "[user] shakes [pickup_target] trying to wake [pickup_target.p_them()] up!", + "You shake [pickup_target] trying to wake [pickup_target.p_them()] up!" + ) + return FALSE + //Already have an item. + if(gripped_item) + + //Pass the attack on to the target. This might delete/relocate gripped_item. + if(!target.attackby(gripped_item, user, params)) + // If the attackby didn't resolve or delete the target or gripped_item, afterattack + // (Certain things, such as mountable frames, rely on afterattack) + gripped_item?.afterattack(target, user, 1, params) + + //If gripped_item either didn't get deleted, or it failed to be transfered to its target + if(!gripped_item && length(contents)) + gripped_item = contents[1] + return FALSE + else if(gripped_item && !contents.len) + gripped_item = null + + //Check that we're not pocketing a mob. + else if(isitem(target)) + var/obj/item/I = target + // Make sure the item is something the gripper can hold + if(can_hold_all_items || is_type_in_typecache(I, can_hold)) + to_chat(user, "You collect [I].") + I.forceMove(src) + gripped_item = I + return TRUE + + to_chat(user, "You hold your gripper over [target], but no matter how hard you try, you cannot make yourself grab it.") + return FALSE + + // Everything past this point requires being able to engineer. + if(!engineering_machine_interaction) + return + // APC cells. + if(istype(target, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = target + if(A.opened && A.cell) + gripped_item = A.cell + + A.cell.add_fingerprint(user) + A.cell.update_icon() + A.cell.forceMove(src) + A.cell = null + + A.charging = APC_NOT_CHARGING + A.update_icon() + + user.visible_message("[user] removes the power cell from [A]!", "You remove the power cell.") + // Cell Chargers + else if(istype(target, /obj/machinery/cell_charger)) + var/obj/machinery/cell_charger/cell_charger = target + if(cell_charger.charging) + gripped_item = cell_charger.charging + cell_charger.charging.add_fingerprint(user) + cell_charger.charging.forceMove(src) + cell_charger.removecell() + // Putting lights in fixtures. + else if(istype(target, /obj/machinery/light)) + var/obj/machinery/light/light = target + var/obj/item/light/L = light.drop_light_tube() + L.forceMove(src) + gripped_item = L + user.visible_message("[user] removes the light from the fixture.", "You dislodge the light from the fixture.") + + return TRUE + +//////////////////////////////// +// MARK: UNIVERSAL GRIPPER +//////////////////////////////// +/// Universal gripper. Not supplied to any cyborg by default. Could be varedited onto a borg for event stuff. Functions almost like a real hand! +/obj/item/gripper/universal + name = "cyborg gripper" + desc = "A grasping tool for cyborgs. This one is not restricted by any restraining software, allowing it to handle any object the user wishes." + // It's UNIVERSAL so it has all functions enabled. + engineering_machine_interaction = TRUE + can_help_up = TRUE + can_hold_all_items = TRUE + +//////////////////////////////// +// MARK: MEDICAL GRIPPER +//////////////////////////////// +// For medical borgs, for doing medical stuff! +// Not giving this anything to hold yet, but stuff may be added in the future. Organs/implants are currently viewed as too strong to hold. +/obj/item/gripper/medical + name = "medical gripper" + desc = "A grasping tool for cyborgs. This one is covered with hygenic medical-grade silicone rubber. \ + Use it to help patients up once surgery is complete, or to substitute for hands in surgical operations." + can_help_up = TRUE + // REMOVE actions_types from here if you add a can_hold list for this gripper! + actions_types = list() + +//////////////////////////////// +// MARK: SERVICE GRIPPER +//////////////////////////////// +// For service borgs. To make them slightly better at their job. +/obj/item/gripper/service + name = "service gripper" + desc = "A grasping tool for cyborgs. This version is made from hygenic easy-clean material. Maybe some day you'll be able to grab food with it..." + // For waking up drunkards. + can_help_up = TRUE + // Everything in this list is currently for either playing games or otherwise assisting the crew in mundane, non-impactful ways. + can_hold = list( + /obj/item/deck, + /obj/item/cardhand, + /obj/item/coin, + /obj/item/paper, + /obj/item/photo, + /obj/item/toy/plushie + ) + +//////////////////////////////// +// MARK: ENGINEERING GRIPPER +//////////////////////////////// +// For engineering and sabotage borgs, and drones. +/obj/item/gripper/engineering + name = "engineering gripper" + desc = "A grasping tool for cyborgs. This version can hold a wide variety of constructon components for use in engineering work." + engineering_machine_interaction = TRUE + can_hold = list( + /obj/item/firealarm_electronics, + /obj/item/airalarm_electronics, + /obj/item/airlock_electronics, + /obj/item/firelock_electronics, + /obj/item/intercom_electronics, + /obj/item/apc_electronics, + /obj/item/tracker_electronics, + /obj/item/stock_parts, + /obj/item/vending_refill, + /obj/item/mounted/frame, + /obj/item/assembly/prox_sensor, + /obj/item/assembly/igniter, + /obj/item/rack_parts, + /obj/item/camera_assembly, + /obj/item/tank, + /obj/item/circuitboard, + /obj/item/stack/ore/bluespace_crystal, + /obj/item/stack/tile/light, + /obj/item/light + ) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 28cad65e92f1..245656352e44 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -486,3 +486,24 @@ return for(var/obj/item/reagent_containers/borghypo/F in R.module.modules) F.emag_act() + +/obj/item/borg/upgrade/abductor_jani + name = "janitorial cyborg abductor upgrade" + desc = "An experimental upgrade that replaces a janitorial cyborg's tools with the abductor versions." + icon_state = "abductor_mod" + origin_tech = "biotech=6;materials=6;abductor=3" + require_module = TRUE + module_type = /obj/item/robot_module/janitor + items_to_replace = list( + /obj/item/mop/advanced/cyborg = /obj/item/mop/advanced/abductor, + /obj/item/soap = /obj/item/soap/syndie/abductor, + /obj/item/lightreplacer/cyborg = /obj/item/lightreplacer/bluespace/abductor, + /obj/item/melee/flyswatter = /obj/item/melee/flyswatter/abductor + ) + items_to_add = list( + /obj/item/reagent_containers/spray/cleaner/safety/abductor + ) + special_rechargables = list( + /obj/item/reagent_containers/spray/cleaner/safety/abductor, + /obj/item/lightreplacer/bluespace/abductor + ) diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index f91e4b8d75b9..266974088d24 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -178,7 +178,7 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( /obj/item/stack/sheet/animalhide/goliath_hide name = "goliath hide plates" - desc = "Pieces of a goliath's rocky hide, these might be able to make your suit a bit more durable to attack from the local fauna." + desc = "Pieces of a goliath's rocky hide, these might be able to make your miner equipment such as suits, plasmaman helmets, borgs and Ripley class exosuits a bit more durable to attack from the local fauna." icon = 'icons/obj/stacks/organic.dmi' icon_state = "goliath_hide" item_state = "goliath_hide" @@ -198,41 +198,80 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( if(is_type_in_typecache(target, goliath_platable_armor_typecache)) var/obj/item/clothing/C = target var/datum/armor/current_armor = C.armor - if(current_armor.getRating(MELEE) < 60) - C.armor = current_armor.setRating(melee_value = min(current_armor.getRating(MELEE) + 10, 60)) + if(current_armor.getRating(MELEE) < 75) + if(!use(1)) + to_chat(user, "You dont have enough [src] for this!") + return + C.armor = current_armor.setRating(melee_value = min(current_armor.getRating(MELEE) + 15, 75)) to_chat(user, "You strengthen [target], improving its resistance against melee attacks.") use(1) else to_chat(user, "You can't improve [C] any further!") else if(istype(target, /obj/mecha/working/ripley)) var/obj/mecha/working/ripley/D = target - if(D.hides < 3) + if(D.hides < HIDES_COVERED_FULL && !D.plates && !D.drake_hides) + if(!use(1)) + to_chat(user, "You dont have enough [src] for this!") + return D.hides++ - D.armor = D.armor.setRating(melee_value = min(D.armor.getRating(MELEE) + 10, 70)) - D.armor = D.armor.setRating(bullet_value = min(D.armor.getRating(BULLET) + 5, 50)) - D.armor = D.armor.setRating(laser_value = min(D.armor.getRating(LASER) + 5, 50)) - to_chat(user, "You strengthen [target], improving its resistance against melee attacks.") + D.armor = D.armor.setRating(melee_value = min(D.armor.getRating(MELEE) + 25, 115)) + D.armor = D.armor.setRating(bullet_value = min(D.armor.getRating(BULLET) + 7, 60)) + D.armor = D.armor.setRating(laser_value = min(D.armor.getRating(LASER) + 7, 60)) + to_chat(user, "You strengthen [target], improving its resistance against attacks.") D.update_appearance(UPDATE_DESC|UPDATE_OVERLAYS) - use(1) else to_chat(user, "You can't improve [D] any further!") else if(isrobot(target)) var/mob/living/silicon/robot/R = target if(istype(R.module, /obj/item/robot_module/miner)) var/datum/armor/current_armor = R.armor - if(current_armor.getRating(MELEE) < 60) - R.armor = current_armor.setRating(melee_value = min(current_armor.getRating(MELEE) + 10, 60)) + if(current_armor.getRating(MELEE) < 75) + if(!use(1)) + to_chat(user, "You dont have enough [src] for this!") + return + R.armor = current_armor.setRating(melee_value = min(current_armor.getRating(MELEE) + 15, 75)) to_chat(user, "You strengthen [target], improving its resistance against melee attacks.") - use(1) else to_chat(user, "You can't improve [R] any further!") else to_chat(user, "[R]'s armor can not be improved!") +/obj/item/stack/sheet/animalhide/armor_plate + name = "armor plate" + desc = "This piece of metal can be attached to the mech itself, enhancing its protective characteristics. Unfortunately, only working class exosuits have notches for such armor." + icon = 'icons/mecha/mecha_equipment.dmi' + icon_state = "armor_plate" + item_state = "armor_plate" + singular_name = "armor plate" + flags = NOBLUDGEON + w_class = WEIGHT_CLASS_NORMAL + layer = MOB_LAYER + +/obj/item/stack/sheet/animalhide/armor_plate/afterattack(atom/target, mob/user, proximity_flag) + if(!proximity_flag) + return + if(istype(target, /obj/mecha/working/ripley)) + var/obj/mecha/working/ripley/D = target + if(D.plates < PLATES_COVERED_FULL && !D.hides && !D.drake_hides) + if(!use(1)) + to_chat(user, "You dont have enough [src] for this!") + return + use(1) + D.plates++ + D.armor = D.armor.setRating(melee_value = min(D.armor.getRating(MELEE) + 10, 70)) + D.armor = D.armor.setRating(bullet_value = min(D.armor.getRating(BULLET) + 4, 50)) + D.armor = D.armor.setRating(laser_value = min(D.armor.getRating(LASER) + 4, 50)) + to_chat(user, "You strengthen [target], improving its resistance against attacks.") + D.update_appearance(UPDATE_DESC|UPDATE_OVERLAYS) + else + to_chat(user, "You can't improve [D] any further!") + +/obj/item/stack/sheet/animalhide/armor_plate/attackby(obj/item/W, mob/user, params) + return // no steel leather for ya /obj/item/stack/sheet/animalhide/ashdrake name = "ash drake hide" - desc = "The strong, scaled hide of an ash drake." + desc = "The strong, scaled hide of an ash drake. Can be attached to the mech itself, greatly enhancing its protective characteristics. Unfortunately, only working class exosuits have notches for such armor." icon = 'icons/obj/stacks/organic.dmi' icon_state = "dragon_hide" item_state = "dragon_hide" @@ -242,9 +281,30 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( layer = MOB_LAYER dynamic_icon_state = TRUE +/obj/item/stack/sheet/animalhide/ashdrake/afterattack(atom/target, mob/user, proximity_flag) + if(!proximity_flag) + return + if(istype(target, /obj/mecha/working/ripley)) + var/obj/mecha/working/ripley/D = target + if(D.drake_hides < DRAKE_HIDES_COVERED_FULL && !D.hides && !D.plates) + if(!use(1)) + to_chat(user, "You dont have enough [src] for this!") + return + use(1) + D.drake_hides++ + D.max_integrity += 50 + D.obj_integrity += 50 + D.armor = D.armor.setRating(melee_value = min(D.armor.getRating(MELEE) + 45, 175)) // 77.7% melee armor maximum + D.armor = D.armor.setRating(bullet_value = min(D.armor.getRating(BULLET) + 7, 60)) + D.armor = D.armor.setRating(laser_value = min(D.armor.getRating(LASER) + 7, 60)) + to_chat(user, "You strengthen [target], improving its resistance against attacks.") + D.update_appearance(UPDATE_DESC|UPDATE_OVERLAYS) + else + to_chat(user, "You can't improve [D] any further!") + //Step one - dehairing. -/obj/item/stack/sheet/animalhide/attackby(obj/item/W as obj, mob/user as mob, params) +/obj/item/stack/sheet/animalhide/attackby(obj/item/W, mob/user, params) if(W.sharp) user.visible_message("[user] starts cutting hair off \the [src].", "You start cutting the hair off \the [src]...", "You hear the sound of a knife rubbing against flesh.") if(do_after(user, 50 * W.toolspeed, target = src)) diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 206c971bd863..33a29c0fa15f 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -215,6 +215,7 @@ GLOBAL_LIST_INIT(wood_recipes, list( new /datum/stack_recipe("rake", /obj/item/cultivator/rake, 5, time = 1 SECONDS), new /datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/glass/bucket/wooden, 3, time = 1 SECONDS), new /datum/stack_recipe("firebrand", /obj/item/match/firebrand, 2, time = 10 SECONDS), + new /datum/stack_recipe("notice board", /obj/item/mounted/noticeboard, 5, time = 5 SECONDS), null, new /datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20), new /datum/stack_recipe_list("wood structures", list( diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm index 4d58d09d2119..c53a55e217a1 100644 --- a/code/game/objects/items/tools/crowbar.dm +++ b/code/game/objects/items/tools/crowbar.dm @@ -35,16 +35,6 @@ toolspeed = 0.5 resistance_flags = FIRE_PROOF | ACID_PROOF -/obj/item/crowbar/abductor - name = "alien crowbar" - desc = "A hard-light crowbar. It appears to pry by itself, without any effort required." - icon = 'icons/obj/abductor.dmi' - usesound = 'sound/weapons/sonic_jackhammer.ogg' - icon_state = "crowbar" - toolspeed = 0.1 - w_class = WEIGHT_CLASS_SMALL - origin_tech = "combat=4;engineering=4;abductor=3" - /obj/item/crowbar/small name = "miniature titanium crowbar" desc = "A tiny, lightweight titanium crowbar. It fits handily in your pocket." diff --git a/code/game/objects/items/tools/multitool.dm b/code/game/objects/items/tools/multitool.dm index a44742ade66f..080d58d57dc9 100644 --- a/code/game/objects/items/tools/multitool.dm +++ b/code/game/objects/items/tools/multitool.dm @@ -171,19 +171,6 @@ . = ..() ADD_TRAIT(src, TRAIT_SHOW_WIRE_INFO, ROUNDSTART_TRAIT) // Drones are linked to the station -/obj/item/multitool/abductor - name = "alien multitool" - desc = "An omni-technological interface." - icon = 'icons/obj/abductor.dmi' - icon_state = "multitool" - toolspeed = 0.1 - w_class = WEIGHT_CLASS_SMALL - origin_tech = "magnets=5;engineering=5;abductor=3" - -/obj/item/multitool/abductor/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_SHOW_WIRE_INFO, ROUNDSTART_TRAIT) - #undef PROXIMITY_NONE #undef PROXIMITY_ON_SCREEN #undef PROXIMITY_NEAR diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index 6f0587188fa2..b9a79fbcfdda 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -90,15 +90,6 @@ return BRUTELOSS -/obj/item/screwdriver/abductor - name = "alien screwdriver" - desc = "An ultrasonic screwdriver." - icon = 'icons/obj/abductor.dmi' - icon_state = "screwdriver" - usesound = 'sound/items/pshoom.ogg' - toolspeed = 0.1 - random_color = FALSE - /obj/item/screwdriver/power name = "hand drill" desc = "A simple hand drill with a screwdriver bit attached." diff --git a/code/game/objects/items/tools/welder.dm b/code/game/objects/items/tools/welder.dm index f4a03f9a6326..239d13fd9a7c 100644 --- a/code/game/objects/items/tools/welder.dm +++ b/code/game/objects/items/tools/welder.dm @@ -275,19 +275,6 @@ materials = list(MAT_METAL = 200, MAT_GLASS = 50) low_fuel_changes_icon = FALSE -/obj/item/weldingtool/abductor - name = "alien welding tool" - desc = "An alien welding tool. Whatever fuel it uses, it never runs out." - icon = 'icons/obj/abductor.dmi' - icon_state = "welder" - toolspeed = 0.1 - w_class = WEIGHT_CLASS_SMALL - light_intensity = 0 - origin_tech = "plasmatech=5;engineering=5;abductor=3" - requires_fuel = FALSE - refills_over_time = TRUE - low_fuel_changes_icon = FALSE - /obj/item/weldingtool/hugetank name = "upgraded welding tool" desc = "An upgraded welder based off the industrial welder." diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm index f0b6f20aacca..7a2d0f8db308 100644 --- a/code/game/objects/items/tools/wirecutters.dm +++ b/code/game/objects/items/tools/wirecutters.dm @@ -98,19 +98,6 @@ random_color = FALSE resistance_flags = FIRE_PROOF | ACID_PROOF -/obj/item/wirecutters/abductor - name = "alien wirecutters" - desc = "Extremely sharp wirecutters, made out of a silvery-green metal." - icon = 'icons/obj/abductor.dmi' - icon_state = "cutters" - toolspeed = 0.1 - origin_tech = "materials=5;engineering=4;abductor=3" - random_color = FALSE - -/obj/item/wirecutters/abductor/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_SHOW_WIRE_INFO, ROUNDSTART_TRAIT) - /obj/item/wirecutters/cyborg name = "wirecutters" desc = "This cuts wires." diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm index 06188fd22444..64e9b3fe5992 100644 --- a/code/game/objects/items/tools/wrench.dm +++ b/code/game/objects/items/tools/wrench.dm @@ -54,15 +54,6 @@ toolspeed = 0.5 resistance_flags = FIRE_PROOF | ACID_PROOF -/obj/item/wrench/abductor - name = "alien wrench" - desc = "A polarized wrench. It causes anything placed between the jaws to turn." - icon = 'icons/obj/abductor.dmi' - icon_state = "wrench" - usesound = 'sound/effects/empulse.ogg' - toolspeed = 0.1 - origin_tech = "materials=5;engineering=5;abductor=3" - /obj/item/wrench/power name = "hand drill" desc = "A simple powered drill with a bolt bit." diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm index 2306002dc48f..a41b32954488 100644 --- a/code/game/objects/items/weapons/explosives.dm +++ b/code/game/objects/items/weapons/explosives.dm @@ -13,14 +13,19 @@ var/obj/item/assembly/nadeassembly = null var/assemblyattacher var/notify_admins = TRUE + /// C4 overlay to put on target + var/mutable_appearance/plastic_overlay + /// Target of the overlay, not neccicarly the thing the C4 is attached to! + var/atom/plastic_overlay_target /obj/item/grenade/plastic/Initialize(mapload) . = ..() - image_overlay = image('icons/obj/grenade.dmi', "[item_state]2") + plastic_overlay = mutable_appearance(icon, "[item_state]2", HIGH_OBJ_LAYER) /obj/item/grenade/plastic/Destroy() QDEL_NULL(nadeassembly) target = null + plastic_overlay_target = null return ..() /obj/item/grenade/plastic/attackby(obj/item/I, mob/user, params) @@ -74,7 +79,7 @@ return to_chat(user, "You start planting [src].[isnull(nadeassembly) ? " The timer is set to [det_time]..." : ""]") - if(do_after(user, 5 SECONDS * toolspeed, target = AM)) + if(do_after(user, 1.5 SECONDS * toolspeed, target = AM)) if(!user.unEquip(src)) return target = AM @@ -84,7 +89,26 @@ message_admins("[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at ([target.x],[target.y],[target.z] - JMP) with [det_time] second fuse", 0, 1) log_game("[key_name(user)] planted [name] on [target.name] at ([target.x],[target.y],[target.z]) with [det_time] second fuse") - AddComponent(/datum/component/persistent_overlay, image_overlay, target) + plastic_overlay.layer = HIGH_OBJ_LAYER + if(isturf(target) || istype(target, /obj/machinery/door)) + plastic_overlay_target = new /obj/effect/plastic(get_turf(user)) + else + plastic_overlay_target = target + if(isliving(target)) + plastic_overlay.layer = ABOVE_ALL_MOB_LAYER + if(plastic_overlay_target != target) + switch(plastic_overlay_target.x - target.x) + if(-1) + plastic_overlay.pixel_x += 32 + if(1) + plastic_overlay.pixel_x -= 32 + switch(plastic_overlay_target.y - target.y) + if(-1) + plastic_overlay.pixel_y += 32 + if(1) + plastic_overlay.pixel_y -= 32 + plastic_overlay_target.add_overlay(plastic_overlay) + if(!nadeassembly) to_chat(user, "You plant the bomb. Timer counting down from [det_time].") addtimer(CALLBACK(src, PROC_REF(prime)), det_time SECONDS) @@ -146,6 +170,10 @@ /obj/item/grenade/plastic/c4/prime() var/turf/location + if(plastic_overlay_target && !QDELETED(plastic_overlay_target)) + plastic_overlay_target.cut_overlay(plastic_overlay, TRUE) + if(istype(plastic_overlay_target, /obj/effect/plastic)) + qdel(plastic_overlay_target) if(target) if(!QDELETED(target)) location = get_turf(target) @@ -211,6 +239,10 @@ /obj/item/grenade/plastic/c4/thermite/prime() var/turf/location + if(plastic_overlay_target && !QDELETED(plastic_overlay_target)) + plastic_overlay_target.cut_overlay(plastic_overlay, TRUE) + if(istype(plastic_overlay_target, /obj/effect/plastic)) + qdel(plastic_overlay_target) if(target) if(!QDELETED(target)) location = get_turf(target) @@ -235,3 +267,7 @@ M.adjust_fire_stacks(2) M.IgniteMob() qdel(src) + +//Used so the effect is visable for overlay purposes, but not show on right click with a broken sprite +/obj/effect/plastic + mouse_opacity = MOUSE_OPACITY_TRANSPARENT diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index 9d11690e376f..0750631f1ba2 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -457,22 +457,6 @@ new /obj/item/grenade/empgrenade(src) // Two of each new /obj/item/grenade/syndieminibomb(src) // One minibomb -/obj/item/storage/belt/military/abductor - name = "agent belt" - desc = "A belt used by abductor agents." - icon = 'icons/obj/abductor.dmi' - icon_state = "belt" - item_state = "security" - -/obj/item/storage/belt/military/abductor/full/populate_contents() - new /obj/item/screwdriver/abductor(src) - new /obj/item/wrench/abductor(src) - new /obj/item/weldingtool/abductor(src) - new /obj/item/crowbar/abductor(src) - new /obj/item/wirecutters/abductor(src) - new /obj/item/multitool/abductor(src) - new /obj/item/stack/cable_coil(src, 30, COLOR_WHITE) - /obj/item/storage/belt/military/assault name = "assault belt" desc = "A tactical assault belt." diff --git a/code/game/objects/mail.dm b/code/game/objects/mail.dm index 6e23945bb58b..2f2eec45cf94 100644 --- a/code/game/objects/mail.dm +++ b/code/game/objects/mail.dm @@ -242,6 +242,8 @@ origin_tech = "magnets=1" /// The reference to the envelope that is currently stored in the mail scanner. It will be cleared upon confirming a correct delivery var/obj/item/envelope/saved + /// How far away can the scanner scan mail or people + var/scanner_range = 7 /obj/item/mail_scanner/examine(mob/user) . = ..() @@ -251,6 +253,9 @@ return /obj/item/mail_scanner/afterattack(atom/A, mob/user) + if(get_dist(A, user) > scanner_range) + to_chat(user, "The scanner doesn't reach that far!") + return if(istype(A, /obj/item/envelope)) var/obj/item/envelope/envelope = A if(envelope.has_been_scanned) diff --git a/code/game/objects/structures/depot_structures.dm b/code/game/objects/structures/depot_structures.dm index 42ace74d7f0f..4d3a1919a496 100644 --- a/code/game/objects/structures/depot_structures.dm +++ b/code/game/objects/structures/depot_structures.dm @@ -113,7 +113,7 @@ M.gib() for(var/obj/mecha/E in range(30, T)) E.take_damage(E.max_integrity) - explosion(get_turf(src), 25, 35, 45, 55, 1, 1, 60, 0, 0) + explosion(get_turf(src), 25, 35, 45, 55, 1, 1, 60, 0) STOP_PROCESSING(SSobj, src) qdel(src) diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm index dc855f327fcc..d094f279d636 100644 --- a/code/game/objects/structures/janicart.dm +++ b/code/game/objects/structures/janicart.dm @@ -90,7 +90,7 @@ else if(mybag) mybag.attackby(I, user, params) else - to_chat(usr, "You cannot interface your modules [src]!") + to_chat(usr, "You cannot interface your modules with [src]!") /obj/structure/janitorialcart/crowbar_act(mob/living/user, obj/item/I) . = TRUE diff --git a/code/game/objects/structures/mop_bucket.dm b/code/game/objects/structures/mop_bucket.dm index 5317afba5e9d..1a5d501f77af 100644 --- a/code/game/objects/structures/mop_bucket.dm +++ b/code/game/objects/structures/mop_bucket.dm @@ -24,6 +24,9 @@ return ..() /obj/structure/mopbucket/attackby(obj/item/W as obj, mob/user as mob, params) + if(W.is_robot_module()) + to_chat(user, "You cannot interface your modules with [src]!") + return if(istype(W, /obj/item/mop)) var/obj/item/mop/M = W if(M.reagents.total_volume < M.reagents.maximum_volume) diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm index 6666de7ee619..eeb179d870da 100644 --- a/code/game/objects/structures/noticeboard.dm +++ b/code/game/objects/structures/noticeboard.dm @@ -1,82 +1,143 @@ +#define MAX_NOTICES 5 + +/obj/item/mounted/noticeboard + name = "notice board" + desc = "A board for pinning important notices upon." + icon = 'icons/obj/stationobjs.dmi' + icon_state = "noticeboard" + w_class = WEIGHT_CLASS_BULKY + +/obj/item/mounted/noticeboard/do_build(turf/on_wall, mob/user) + new /obj/structure/noticeboard(get_turf(user), get_dir(on_wall, user), building = TRUE) + qdel(src) + /obj/structure/noticeboard name = "notice board" desc = "A board for pinning important notices upon." icon = 'icons/obj/stationobjs.dmi' - icon_state = "nboard00" + icon_state = "noticeboard-5" density = FALSE anchored = TRUE max_integrity = 150 var/notices = 0 +/obj/structure/noticeboard/New(turf/loc, direction, building = FALSE) + . = ..() + if(building) + setDir(direction) + set_pixel_offsets_from_dir(-32, 32, -30, 30) + update_icon(UPDATE_ICON_STATE) + /obj/structure/noticeboard/Initialize() - ..() - for(var/obj/item/I in loc) - if(notices > 4) break - if(istype(I, /obj/item/paper)) - I.loc = src - notices++ - icon_state = "nboard0[notices]" - -//attaching papers!! -/obj/structure/noticeboard/attackby(obj/item/O as obj, mob/user as mob, params) - if(istype(O, /obj/item/paper)) - if(notices < 5) - O.add_fingerprint(user) - add_fingerprint(user) - user.drop_item() - O.loc = src + . = ..() + for(var/obj/item/paper in loc) + if(notices >= MAX_NOTICES) + break + if(istype(paper, /obj/item/paper)) + paper.loc = src notices++ - icon_state = "nboard0[notices]" //update sprite - to_chat(user, "You pin the paper to the noticeboard.") - else + update_icon(UPDATE_ICON_STATE) + +/obj/structure/noticeboard/update_icon_state() + if(notices) + icon_state = "noticeboard-[notices]" + return + icon_state = "noticeboard" + +/obj/structure/noticeboard/attack_hand(mob/user) + ui_interact(user) + +/obj/structure/noticeboard/attack_ghost(mob/user) + ui_interact(user) + +/obj/structure/noticeboard/ui_state(mob/user) + return GLOB.default_state + +/obj/structure/noticeboard/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Noticeboard", name) + ui.set_autoupdate(FALSE) + ui.open() + +/obj/structure/noticeboard/ui_data(mob/user) + var/list/data = list() + + var/list/pinned_papers = list() + for(var/obj/item/paper/paper in src) + pinned_papers += list(list( + "name" = paper.name, + "contents" = paper.info, + "ref" = paper.UID(), + )) + data["papers"] = pinned_papers + + return data + +/obj/structure/noticeboard/ui_act(action, params, datum/tgui/ui) + if(..()) + return + . = TRUE + + add_fingerprint(usr) + switch(action) + if("interact") + if(usr.stat || usr.restrained()) + return + var/obj/item/paper/paper = locate(params["paper"]) + if(!paper && paper.loc != src) + return + var/obj/item/held_item = usr.get_active_hand() + if(is_pen(held_item)) + paper.attackby(held_item, usr) + return + else + usr.put_in_hands(paper) + paper.add_fingerprint(usr) + notices-- + to_chat(usr, "You take a [paper.name] out of [src].") + update_icon(UPDATE_ICON_STATE) + if("showFull") + var/obj/item/paper/paper = locate(params["paper"]) + if(!paper && paper.loc != src) + return + paper.show_content(usr) + return + +/obj/structure/noticeboard/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/paper)) + if(notices >= MAX_NOTICES) to_chat(user, "You reach to pin your paper to the board but hesitate. You are certain your paper will not be seen among the many others already attached.") + return + if(!user.drop_item()) + return + I.forceMove(src) + notices++ + to_chat(user, "You pin the paper to the noticeboard.") + update_icon(UPDATE_ICON_STATE) + add_fingerprint(user) + SStgui.update_uis(src) return + return ..() -/obj/structure/noticeboard/attack_hand(user as mob) - var/dat = "Noticeboard
" - for(var/obj/item/paper/P in src) - dat += "[P.name] Write Remove
" - user << browse("Notices[dat]","window=noticeboard") - onclose(user, "noticeboard") +/obj/structure/noticeboard/wrench_act(mob/living/user, obj/item/I) + if(user.a_intent != INTENT_HELP) + return + . = TRUE + if(!(flags & NODECONSTRUCT)) + WRENCH_UNANCHOR_WALL_MESSAGE + I.play_tool_sound(user, I.tool_volume) + deconstruct(TRUE) /obj/structure/noticeboard/deconstruct(disassembled = TRUE) - if(!(flags & NODECONSTRUCT)) - new /obj/item/stack/sheet/metal (loc, 1) + if(flags & NODECONSTRUCT) + return + if(notices) + for(var/I in contents) + var/obj/item/paper/notice = I + notice.forceMove(loc) + new /obj/item/mounted/noticeboard(loc) qdel(src) -/obj/structure/noticeboard/Topic(href, href_list) - ..() - usr.set_machine(src) - if(href_list["remove"]) - if((usr.stat || usr.restrained())) //For when a player is handcuffed while they have the notice window open - return - var/obj/item/P = locate(href_list["remove"]) - if(P && P.loc == src) - P.loc = get_turf(src) //dump paper on the floor because you're a clumsy fuck - P.add_fingerprint(usr) - add_fingerprint(usr) - notices-- - icon_state = "nboard0[notices]" - - if(href_list["write"]) - if((usr.stat || usr.restrained())) //For when a player is handcuffed while they have the notice window open - return - var/obj/item/P = locate(href_list["write"]) - - if((P && P.loc == src)) //ifthe paper's on the board - if(is_pen(usr.r_hand)) //and you're holding a pen - add_fingerprint(usr) - P.attackby(usr.r_hand, usr) //then do ittttt - else - if(is_pen(usr.l_hand)) //check other hand for pen - add_fingerprint(usr) - P.attackby(usr.l_hand, usr) - else - to_chat(usr, "You'll need something to write with!") - - if(href_list["read"]) - var/obj/item/paper/P = locate(href_list["read"]) - if(P && P.loc == src) - P.show_content(usr) - return +#undef MAX_NOTICES diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm index 5cff309495b8..ddfc3b8fb645 100644 --- a/code/game/objects/structures/transit_tubes/station.dm +++ b/code/game/objects/structures/transit_tubes/station.dm @@ -33,6 +33,11 @@ STOP_PROCESSING(SSobj, src) return ..() +/obj/structure/transit_tube/station/examine(mob/user) + . = ..() + . += "While in transit, hold the directional key matching the pod's direction to skip a station." + . += "While at a station, press a directional key to quickly leave the station in that direction." + /obj/structure/transit_tube/station/init_tube_dirs() // Tube station directions are simply 90 to either side of // the exit. @@ -47,7 +52,19 @@ tube_dirs = list(NORTH, SOUTH) boarding_dir = reverse_direction(dir) -/obj/structure/transit_tube/station/should_stop_pod(pod, from_dir) +/obj/structure/transit_tube/station/should_stop_pod(obj/structure/transit_tube_pod/pod, from_dir) + for(var/atom/atom in pod.contents) + var/client/client = CLIENT_FROM_VAR(atom) + if(!client) + return + + for(var/held_key in client.input_data.keys_held) + if(held_key in client.movement_kb_dirs) + var/held_dir = client.movement_kb_dirs[held_key] + // if they're holding a different direction down, + // stop to let them get out/change direction + return held_dir != from_dir + return TRUE /obj/structure/transit_tube/station/Bumped(mob/living/L) @@ -187,6 +204,9 @@ reverse_launch = TRUE uninstalled_type = /obj/structure/transit_tube_construction/terminus +/obj/structure/transit_tube/station/reverse/should_stop_pod(obj/structure/transit_tube_pod/pod, from_dir) + return TRUE + /obj/structure/transit_tube/station/reverse/init_tube_dirs() tube_dirs = list(turn(dir, -90)) boarding_dir = reverse_direction(dir) @@ -260,6 +280,9 @@ base_icon_state = "terminusdispenser0" uninstalled_type = /obj/structure/transit_tube_construction/terminus/dispenser +/obj/structure/transit_tube/station/dispenser/reverse/should_stop_pod(obj/structure/transit_tube_pod/pod, from_dir) + return TRUE + /obj/structure/transit_tube/station/dispenser/reverse/init_tube_dirs() tube_dirs = list(turn(dir, -90)) boarding_dir = reverse_direction(dir) diff --git a/code/game/objects/structures/transit_tubes/transit_tube.dm b/code/game/objects/structures/transit_tubes/transit_tube.dm index aad4e1038186..ad0fbabd901e 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube.dm @@ -58,7 +58,7 @@ return // Called to check if a pod should stop upon entering this tube. -/obj/structure/transit_tube/proc/should_stop_pod(pod, from_dir) +/obj/structure/transit_tube/proc/should_stop_pod(obj/structure/transit_tube_pod/pod, from_dir) return FALSE // Called when a pod stops in this tube section. @@ -274,18 +274,3 @@ tube_dirs = list(EAST, NORTHWEST, SOUTHWEST) if(WEST) tube_dirs = list(WEST, SOUTHEAST, NORTHEAST) - - -// cosmetic "cap" for tubes. Note that tubes can't enter this. -/obj/structure/transit_tube/cap - icon_state = "cap" - -/obj/structure/transit_tube/cap/init_tube_dirs() - tube_dirs = list(turn(dir, 180)) // back the way we came - -/obj/structure/transit_tube/cap/has_entrance(from_dir) - return FALSE - -/obj/structure/transit_tube/cap/create_tube_overlay() - // cap sprites already have overlays - return diff --git a/code/game/turfs/simulated/floor/asteroid_floors.dm b/code/game/turfs/simulated/floor/asteroid_floors.dm index 440f2643f923..aadfe6c447aa 100644 --- a/code/game/turfs/simulated/floor/asteroid_floors.dm +++ b/code/game/turfs/simulated/floor/asteroid_floors.dm @@ -146,16 +146,16 @@ ///////Surface. The surface is warm, but survivable without a suit. Internals are required. The floors break to chasms, which drop you into the underground. /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE planetary_atmos = TRUE baseturf = /turf/simulated/floor/lava/mapping_lava /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface_hard - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE planetary_atmos = TRUE color = COLOR_FLOOR_HARD_ROCK baseturf = /turf/simulated/floor/lava/lava_land_surface @@ -199,9 +199,9 @@ GLOBAL_LIST_INIT(megafauna_spawn_list, list(/mob/living/simple_animal/hostile/me data_having_type = /turf/simulated/floor/plating/asteroid/airless/cave/volcanic/has_data turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE /// subtype for producing a tunnel with given data /turf/simulated/floor/plating/asteroid/airless/cave/volcanic/has_data diff --git a/code/game/turfs/simulated/floor/chasm.dm b/code/game/turfs/simulated/floor/chasm.dm index b157d90ce11c..ffacfcf3ea80 100644 --- a/code/game/turfs/simulated/floor/chasm.dm +++ b/code/game/turfs/simulated/floor/chasm.dm @@ -173,9 +173,9 @@ drop_z = z - 1 /turf/simulated/floor/chasm/straight_down/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE planetary_atmos = TRUE baseturf = /turf/simulated/floor/chasm/straight_down/lava_land_surface //Chasms should not turn into lava light_range = 2 diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index d50da939c832..310b171bc0c9 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -17,7 +17,7 @@ if(!I.use_tool(src, user, 0, volume = I.tool_volume)) return remove_tile(user, FALSE, FALSE) - + /turf/simulated/floor/wood/get_broken_states() return list("wood-broken", "wood-broken2", "wood-broken3", "wood-broken4", "wood-broken5", "wood-broken6", "wood-broken7") @@ -53,9 +53,9 @@ temperature = 180 /turf/simulated/floor/wood/lavaland_air - nitrogen = 14 - oxygen = 8 - temperature = 500 + nitrogen = LAVALAND_NITROGEN + oxygen = LAVALAND_OXYGEN + temperature = LAVALAND_TEMPERATURE // Grass /turf/simulated/floor/grass diff --git a/code/game/turfs/simulated/floor/indestructible.dm b/code/game/turfs/simulated/floor/indestructible.dm index 6d43bd23a863..43b99723b428 100644 --- a/code/game/turfs/simulated/floor/indestructible.dm +++ b/code/game/turfs/simulated/floor/indestructible.dm @@ -44,9 +44,9 @@ icon = 'icons/turf/floors.dmi' icon_state = "necro1" baseturf = /turf/simulated/floor/indestructible/necropolis - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE planetary_atmos = TRUE footstep = FOOTSTEP_LAVA barefootstep = FOOTSTEP_LAVA @@ -69,9 +69,9 @@ icon = 'icons/turf/floors/boss_floors.dmi' icon_state = "boss" baseturf = /turf/simulated/floor/indestructible/boss - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE planetary_atmos = TRUE /turf/simulated/floor/indestructible/boss/air @@ -83,9 +83,9 @@ name = "floor" icon = 'icons/turf/floors/hierophant_floor.dmi' icon_state = "floor" - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE planetary_atmos = TRUE smoothing_flags = SMOOTH_CORNERS diff --git a/code/game/turfs/simulated/floor/lava.dm b/code/game/turfs/simulated/floor/lava.dm index 8d32d83a35e8..08ec20fb8f73 100644 --- a/code/game/turfs/simulated/floor/lava.dm +++ b/code/game/turfs/simulated/floor/lava.dm @@ -160,9 +160,9 @@ return /turf/simulated/floor/lava/lava_land_surface - temperature = 500 - oxygen = 8 - nitrogen = 14 + temperature = LAVALAND_TEMPERATURE + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN planetary_atmos = TRUE baseturf = /turf/simulated/floor/chasm/straight_down/lava_land_surface @@ -256,9 +256,9 @@ icon_state = "mappinglava" base_icon_state = "mappinglava" baseturf = /turf/simulated/floor/lava/mapping_lava - temperature = 500 - oxygen = 8 - nitrogen = 14 + temperature = LAVALAND_TEMPERATURE + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN planetary_atmos = TRUE diff --git a/code/game/turfs/simulated/floor/mineral_floors.dm b/code/game/turfs/simulated/floor/mineral_floors.dm index f1fb94e507f8..aa6ea18b283d 100644 --- a/code/game/turfs/simulated/floor/mineral_floors.dm +++ b/code/game/turfs/simulated/floor/mineral_floors.dm @@ -287,6 +287,6 @@ return //unburnable /turf/simulated/floor/plating/abductor/lavaland_air - temperature = 500 - oxygen = 8 - nitrogen = 14 + temperature = LAVALAND_TEMPERATURE + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm index 5bd564b6b785..01452e749908 100644 --- a/code/game/turfs/simulated/floor/misc_floor.dm +++ b/code/game/turfs/simulated/floor/misc_floor.dm @@ -4,9 +4,9 @@ smoothing_flags = NONE /turf/simulated/floor/vault/lavaland_air - temperature = 500 - oxygen = 8 - nitrogen = 14 + temperature = LAVALAND_TEMPERATURE + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN planetary_atmos = TRUE baseturf = /turf/simulated/floor/chasm/straight_down/lava_land_surface @@ -146,9 +146,9 @@ return /turf/simulated/floor/noslip/lavaland - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE planetary_atmos = TRUE /turf/simulated/floor/lubed @@ -234,9 +234,9 @@ uses_overlay = FALSE /turf/simulated/floor/clockwork/lavaland_air - nitrogen = 14 - oxygen = 8 - temperature = 500 + nitrogen = LAVALAND_NITROGEN + oxygen = LAVALAND_OXYGEN + temperature = LAVALAND_TEMPERATURE /turf/simulated/floor/catwalk name = "catwalk" diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 6fd8d12ffede..61b11391ba6d 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -170,9 +170,9 @@ name = "plating" /turf/simulated/floor/plating/lavaland_air - temperature = 500 - oxygen = 8 - nitrogen = 14 + temperature = LAVALAND_TEMPERATURE + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN /turf/simulated/floor/engine name = "reinforced floor" @@ -253,9 +253,9 @@ return /turf/simulated/floor/engine/cult/lavaland_air - nitrogen = 14 - oxygen = 8 - temperature = 500 + nitrogen = LAVALAND_NITROGEN + oxygen = LAVALAND_OXYGEN + temperature = LAVALAND_TEMPERATURE //air filled floors; used in atmos pressure chambers diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index a090a32cbcf4..9116c66a5341 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -280,9 +280,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/lava/mapping_lava - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 mineralSpawnChanceList = list( /turf/simulated/mineral/uranium/volcanic = 35, /turf/simulated/mineral/diamond/volcanic = 30, /turf/simulated/mineral/gold/volcanic = 45, /turf/simulated/mineral/titanium/volcanic = 45, @@ -300,9 +300,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/lava/mapping_lava - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 mineralChance = 10 @@ -329,9 +329,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/lava/mapping_lava - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 mineralSpawnChanceList = list( /turf/simulated/mineral/uranium/volcanic = 3, /turf/simulated/mineral/diamond/volcanic = 1, /turf/simulated/mineral/gold/volcanic = 8, /turf/simulated/mineral/titanium/volcanic = 8, @@ -349,9 +349,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/uranium @@ -364,9 +364,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/diamond @@ -379,9 +379,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/gold @@ -394,9 +394,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/silver @@ -409,9 +409,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/titanium @@ -424,9 +424,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/plasma @@ -439,9 +439,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/clown @@ -455,9 +455,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/mime @@ -470,9 +470,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/bscrystal @@ -486,18 +486,18 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 /turf/simulated/mineral/volcanic environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt baseturf = /turf/simulated/floor/plating/asteroid/basalt - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE /turf/simulated/mineral/volcanic/lava_land_surface environment_type = "basalt" @@ -570,7 +570,7 @@ var/turf/bombturf = get_turf(src) mineralAmt = 0 stage = GIBTONITE_DETONATE - explosion(bombturf,1,3,5, adminlog = notify_admins) + explosion(bombturf, 1, 3, 5, adminlog = notify_admins) /turf/simulated/mineral/gibtonite/proc/defuse() if(stage == GIBTONITE_ACTIVE) @@ -610,9 +610,9 @@ environment_type = "basalt" turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface baseturf = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface - oxygen = 8 - nitrogen = 14 - temperature = 500 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE defer_change = 1 #undef GIBTONITE_UNSTRUCK diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 680cd80c053d..bf5889937229 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -369,8 +369,8 @@ if(try_wallmount(I, user, params)) return - // The magnetic gripper does a separate attackby, so bail from this one - if(istype(I, /obj/item/gripper_engineering)) + // The cyborg gripper does a separate attackby, so bail from this one + if(istype(I, /obj/item/gripper)) return return ..() diff --git a/code/modules/admin/reagents_editor.dm b/code/modules/admin/reagents_editor.dm new file mode 100644 index 000000000000..058bff14336f --- /dev/null +++ b/code/modules/admin/reagents_editor.dm @@ -0,0 +1,103 @@ +/datum/reagents_editor + var/atom/target + /// Indexed by target.UID + var/static/list/datum/reagents_editor/editors = list() + +/datum/reagents_editor/New(atom/target) + src.target = target + +/datum/reagents_editor/ui_state(mob/user) + return GLOB.admin_state + +/datum/reagents_editor/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ReagentsEditor") + ui.open() + ui.set_autoupdate(FALSE) + +/datum/reagents_editor/ui_close(mob/user) + var/open_uis = SStgui.open_uis_by_src[src.UID()] + if(isnull(open_uis) || !islist(open_uis) || length(open_uis) <= 1) + // Remove after everyone closes UI to avoid memory leak + editors -= target.UID() + +/datum/reagents_editor/ui_static_data(mob/user) + . = ..() + + var/list/reagents_information = list() + .["reagentsInformation"] = reagents_information + for(var/id in GLOB.chemical_reagents_list) + var/datum/reagent/R = GLOB.chemical_reagents_list[id] + reagents_information[id] = list( + "name" = R.name, + ) + +/datum/reagents_editor/ui_data(mob/user) + . = ..() + + var/list/reagents = list() + .["reagents"] = reagents + for(var/datum/reagent/R in target.reagents.reagent_list) + reagents[R.id] = list( + "volume" = R.volume, + "uid" = R.UID(), + ) + +// This interface intentionally emulates VV. +// It should, therefore, doesn't place restrictions on any actions, which includes but +// is not limited to: adding a reagent which overfills the container and adding blood +// with a non-existent blood type. It may also do things unconventionally, such as +// directly appending reagents to the list rather than using reagents.add_reagent to +// bypass reagent reactions. +/datum/reagents_editor/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + + if(.) + return + + . = TRUE + + switch(action) + if("add_reagent") + var/reagent_id = params["reagentID"] + var/datum/reagent/reagent_prototype = GLOB.chemical_reagents_list[reagent_id] + if(isnull(reagent_prototype)) + return FALSE + var/new_volume = tgui_input_number(ui.user, "How much units of the reagent do you want to add?", "Add Reagent", 0, 1E100, -1E100) + var/datum/reagent/reagent = target.reagents.get_reagent_by_id(reagent_id) + if(isnull(reagent)) + reagent = new reagent_prototype.type() + reagent.holder = target.reagents + reagent.on_new() + if(ishuman(target) && target.reagents.can_metabolize(target, reagent)) + reagent.on_mob_add(target) + target.reagents.reagent_list += reagent + + reagent.volume = new_volume + + if("edit_volume") + var/reagent_uid = params["uid"] + var/datum/reagent/reagent = locateUID(reagent_uid) + if(isnull(reagent)) + return FALSE + var/new_volume = tgui_input_number(ui.user, "How much units of the reagent do you want to be in the container?", "Edit Reagent Volume", 0, 1E100, -1E100) + if(isnull(new_volume)) + return + reagent.volume = new_volume + + if("delete_reagent") + var/reagent_uid = params["uid"] + var/datum/reagent/reagent = locateUID(reagent_uid) + if(isnull(reagent)) + return FALSE + target.reagents.reagent_list -= reagent + + if("update_total") + target.reagents.update_total() + + if("react_reagents") + target.reagents.handle_reactions() + + else + . = FALSE diff --git a/code/modules/admin/sql_notes.dm b/code/modules/admin/sql_notes.dm index ef0253f972a4..35da1e5dcbfd 100644 --- a/code/modules/admin/sql_notes.dm +++ b/code/modules/admin/sql_notes.dm @@ -112,7 +112,8 @@ adminckey = query_find_note_del.item[3] qdel(query_find_note_del) - var/datum/db_query/query_del_note = SSdbcore.NewQuery("DELETE FROM notes WHERE id=:note_id", list( + var/datum/db_query/query_del_note = SSdbcore.NewQuery("UPDATE notes SET deleted=1, deletedby=:ckey WHERE id=:note_id", list( + "ckey" = usr.ckey, "note_id" = note_id )) if(!query_del_note.warn_execute()) @@ -193,7 +194,7 @@ var/target_sql_ckey = ckey(target_ckey) var/datum/db_query/query_get_notes = SSdbcore.NewQuery({" SELECT id, timestamp, notetext, adminckey, last_editor, server, crew_playtime, round_id, automated - FROM notes WHERE ckey=:targetkey ORDER BY timestamp"}, list( + FROM notes WHERE ckey=:targetkey AND deleted=0 ORDER BY timestamp"}, list( "targetkey" = target_sql_ckey )) if(!query_get_notes.warn_execute()) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 61114aaa0b6f..debd1b9ab1f0 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2062,6 +2062,7 @@ ptypes += "Shamebrero" ptypes += "Nugget" ptypes += "Bread" + ptypes += "Rod" var/punishment = input(owner, "How would you like to smite [M]?", "Its good to be baaaad...", "") as null|anything in ptypes if(!(punishment in ptypes)) return @@ -2185,7 +2186,6 @@ to_chat(H, "You feel as if your limbs are being ripped from your body!") addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living/carbon/human, make_nugget)), 6 SECONDS) logmsg = "nugget" - if("Bread") var/mob/living/simple_animal/shade/sword/bread/breadshade = new(H.loc) var/bready = pick(/obj/item/food/snacks/customizable/cook/bread, /obj/item/food/snacks/sliceable/meatbread, /obj/item/food/snacks/sliceable/xenomeatbread, /obj/item/food/snacks/sliceable/spidermeatbread, /obj/item/food/snacks/sliceable/bananabread, /obj/item/food/snacks/sliceable/tofubread, /obj/item/food/snacks/sliceable/bread, /obj/item/food/snacks/sliceable/creamcheesebread, /obj/item/food/snacks/sliceable/banarnarbread, /obj/item/food/snacks/flatbread, /obj/item/food/snacks/baguette) @@ -2196,6 +2196,13 @@ qdel(H) logmsg = "baked" to_chat(breadshade, "Get bready for combat, you've been baked into a piece of bread! Before you break down and rye thinking that your life is over, people are after you waiting for a snack! If you'd rather not be toast, lunge away from any hungry crew else you bite the crust. At the yeast you may survive a little longer...") + if("Rod") + + var/starting_turf_x = M.x + rand(10, 15) * pick(1, -1) + var/starting_turf_y = M.y + rand(10, 15) * pick(1, -1) + var/turf/start = locate(starting_turf_x, starting_turf_y, M.z) + + new /obj/effect/immovablerod/smite(start, M) if(logmsg) log_admin("[key_name(owner)] smited [key_name(M)] with: [logmsg]") message_admins("[key_name_admin(owner)] smited [key_name_admin(M)] with: [logmsg]") diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index 92046497f33b..db28efaa163d 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -209,8 +209,6 @@ if(our_excited_group) last_share_check() -#define LAVALAND_TEMPERATURE 500 - if(planetary_atmos) //share our air with the "atmosphere" "above" the turf var/datum/gas_mixture/G = new G.oxygen = oxygen @@ -219,7 +217,7 @@ G.toxins = toxins G.sleeping_agent = sleeping_agent G.agent_b = agent_b - G.temperature = LAVALAND_TEMPERATURE // Temperature is modified at runtime; we only care about the turf's initial temperature + G.temperature = initial(temperature) // Temperature is modified at runtime; we only care about the turf's initial temperature G.archive() if(!air.compare(G)) if(!our_excited_group) @@ -229,8 +227,6 @@ air.share(G, adjacent_turfs_length) last_share_check() -#undef LAVALAND_TEMPERATURE - air.react() update_visuals() diff --git a/code/modules/awaymissions/mission_code/beach.dm b/code/modules/awaymissions/mission_code/beach.dm index 0fc750def0b4..980dd94765c8 100644 --- a/code/modules/awaymissions/mission_code/beach.dm +++ b/code/modules/awaymissions/mission_code/beach.dm @@ -114,9 +114,9 @@ linkedcontroller.decalinpool += A /turf/simulated/floor/beach/away/water/lavaland_air - nitrogen = 14 - oxygen = 8 - temperature = 500 + nitrogen = LAVALAND_NITROGEN + oxygen = LAVALAND_OXYGEN + temperature = LAVALAND_TEMPERATURE planetary_atmos = TRUE /// for boundary "walls" diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index e66ed538b06e..28575df9f219 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -1259,6 +1259,17 @@ debug_variables(stat_item) message_admins("Admin [key_name_admin(usr)] is debugging the [stat_item] [class].") +/client/proc/try_open_reagent_editor(atom/target) + var/target_UID = target.UID() + var/datum/reagents_editor/editor + // editors is static, it can be accessed using a null reference + editor = editor.editors[target_UID] + if(!editor) + editor = new /datum/reagents_editor(target) + editor.editors[target_UID] = editor + + editor.ui_interact(mob) + #undef LIMITER_SIZE #undef CURRENT_SECOND #undef SECOND_COUNT diff --git a/code/modules/client/preference/character.dm b/code/modules/client/preference/character.dm index 2f025b3ef22b..24c893ba9339 100644 --- a/code/modules/client/preference/character.dm +++ b/code/modules/client/preference/character.dm @@ -634,8 +634,10 @@ randomize_eyes_color() if(S.bodyflags & HAS_SKIN_COLOR) randomize_skin_color() - backbag = 2 + backbag = pick(GLOB.backbaglist) age = rand(S.min_age, S.max_age) + physique = pick(GLOB.character_physiques) + height = pick(GLOB.character_heights) /datum/character_save/proc/randomize_hair_color(target = "hair") diff --git a/code/modules/client/preference/link_processing.dm b/code/modules/client/preference/link_processing.dm index 9d7b78b6e239..97fcca317d17 100644 --- a/code/modules/client/preference/link_processing.dm +++ b/code/modules/client/preference/link_processing.dm @@ -691,12 +691,12 @@ if("physique") var/new_physique = tgui_input_list(user, "Choose your descriptor for how built your character is on glance.", "Character Preference", GLOB.character_physiques) - if(new_physique) + if(new_physique in GLOB.character_physiques) active_character.physique = new_physique if("height") var/new_height = tgui_input_list(user, "Choose your descriptor for how tall your character is on glance.", "Character Preference", GLOB.character_heights) - if(new_height) + if(new_height in GLOB.character_heights) active_character.height = new_height if("flavor_text") diff --git a/code/modules/client/preference/loadout/loadout_racial.dm b/code/modules/client/preference/loadout/loadout_racial.dm index 128bfdd3c293..4b576e96daa0 100644 --- a/code/modules/client/preference/loadout/loadout_racial.dm +++ b/code/modules/client/preference/loadout/loadout_racial.dm @@ -17,43 +17,11 @@ cost = 1 /datum/gear/racial/taj - display_name = "Embroidered veil" - description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races." - path = /obj/item/clothing/glasses/tajblind + display_name = "Tajaran veil" + description = "A common traditional nano-fiber veil worn by many Tajaran. It is rare and offensive to see it on other races. Can be combined with various other eyewear." + path = /obj/item/clothing/glasses/hud/tajblind slot = SLOT_HUD_GLASSES -/datum/gear/racial/taj/sec - display_name = "Sleek veil" - description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races. This one has an in-built security HUD." - path = /obj/item/clothing/glasses/hud/security/tajblind - allowed_roles = list("Head of Security", "Warden", "Security Officer", "Internal Affairs Agent", "Magistrate", "Detective") - cost = 2 - -/datum/gear/racial/taj/med - display_name = "Lightweight veil" - description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races. This one has an in-built medical HUD." - path = /obj/item/clothing/glasses/hud/health/tajblind - allowed_roles = list("Chief Medical Officer", "Medical Doctor", "Chemist", "Psychiatrist", "Paramedic", "Virologist", "Coroner") - cost = 2 - -/datum/gear/racial/taj/sci - display_name = "Hi-tech veil" - description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races." - path = /obj/item/clothing/glasses/tajblind/sci - cost = 2 - -/datum/gear/racial/taj/eng - display_name = "Industrial veil" - description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races." - path = /obj/item/clothing/glasses/tajblind/eng - cost = 2 - -/datum/gear/racial/taj/cargo - display_name = "Khaki veil" - description = "A common traditional nano-fiber veil worn by many Tajaran, It is rare and offensive to see it on other races. It is light and comfy!" - path = /obj/item/clothing/glasses/tajblind/cargo - cost = 2 - /datum/gear/racial/footwraps display_name = "Cloth footwraps" path = /obj/item/clothing/shoes/footwraps diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 9bceb98e8a51..a4836dcdaa3d 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -219,6 +219,8 @@ var/list/color_view = null//overrides client.color while worn var/prescription = FALSE var/prescription_upgradable = FALSE + /// Overrides colorblindness when interacting with wires + var/correct_wires = FALSE var/over_mask = FALSE //Whether or not the eyewear is rendered above the mask. Purely cosmetic. strip_delay = 20 // but seperated to allow items to protect but not impair vision, like space helmets put_on_delay = 25 diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 38667b158bb0..3f763b55d91a 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -530,51 +530,3 @@ icon_state = "cybereye-red" item_state = "eyepatch" flags = NODROP - -/obj/item/clothing/glasses/tajblind - name = "embroidered veil" - desc = "An Ahdominian made veil that allows the user to see while obscuring their eyes." - icon_state = "tajblind" - item_state = "tajblind" - flags_cover = GLASSESCOVERSEYES - actions_types = list(/datum/action/item_action/toggle) - up = FALSE - tint = FLASH_PROTECTION_NONE - prescription_upgradable = TRUE - - sprite_sheets = list( - "Vox" = 'icons/mob/clothing/species/vox/eyes.dmi', - "Grey" = 'icons/mob/clothing/species/grey/eyes.dmi', - "Drask" = 'icons/mob/clothing/species/drask/eyes.dmi' - ) - -/obj/item/clothing/glasses/tajblind/eng - name = "industrial veil" - icon_state = "tajblind_engi" - item_state = "tajblind_engi" - -/obj/item/clothing/glasses/tajblind/sci - name = "hi-tech veil" - icon_state = "tajblind_sci" - item_state = "tajblind_sci" - -/obj/item/clothing/glasses/tajblind/cargo - name = "khaki veil" - icon_state = "tajblind_cargo" - item_state = "tajblind_cargo" - -/obj/item/clothing/glasses/tajblind/attack_self() - toggle_veil() - -/obj/item/clothing/glasses/proc/toggle_veil() - if(HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED) || usr.incapacitated()) - return - up = !up - if(up) - tint = 3 - else - tint = initial(tint) - to_chat(usr, up ? "You deactivate [src], obscuring your vision." : "You activate [src], allowing you to see.") - var/mob/living/carbon/user = usr - user.update_tint() - user.update_inv_glasses() diff --git a/code/modules/clothing/glasses/hudglasses.dm b/code/modules/clothing/glasses/hudglasses.dm index a87eedd9ea8e..b45c9d9c4479 100644 --- a/code/modules/clothing/glasses/hudglasses.dm +++ b/code/modules/clothing/glasses/hudglasses.dm @@ -172,41 +172,6 @@ see_in_dark = 8 lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE -/obj/item/clothing/glasses/hud/security/tajblind - name = "sleek veil" - desc = "An Ahdominian made veil that allows the user to see while obscuring their eyes. This one has an in-built security HUD." - icon_state = "tajblind_sec" - item_state = "tajblind_sec" - flash_protect = FLASH_PROTECTION_FLASH - flags_cover = GLASSESCOVERSEYES - actions_types = list(/datum/action/item_action/toggle) - up = FALSE - - sprite_sheets = list( - "Vox" = 'icons/mob/clothing/species/vox/eyes.dmi' - ) - -/obj/item/clothing/glasses/hud/security/tajblind/attack_self() - toggle_veil() - -/obj/item/clothing/glasses/hud/health/tajblind - name = "lightweight veil" - desc = "An Ahdominian made veil that allows the user to see while obscuring their eyes. This one has an installed medical HUD." - icon_state = "tajblind_med" - item_state = "tajblind_med" - flags_cover = GLASSESCOVERSEYES - actions_types = list(/datum/action/item_action/toggle) - up = FALSE - - sprite_sheets = list( - "Vox" = 'icons/mob/clothing/species/vox/eyes.dmi', - "Grey" = 'icons/mob/clothing/species/grey/eyes.dmi', - "Drask" = 'icons/mob/clothing/species/drask/eyes.dmi' - ) - -/obj/item/clothing/glasses/hud/health/tajblind/attack_self() - toggle_veil() - /obj/item/clothing/glasses/hud/skills name = "skills HUD" desc = "A heads-up display capable of showing the employment history records of NT crew members." diff --git a/code/modules/clothing/glasses/tajblind.dm b/code/modules/clothing/glasses/tajblind.dm new file mode 100644 index 000000000000..306652a4a9f0 --- /dev/null +++ b/code/modules/clothing/glasses/tajblind.dm @@ -0,0 +1,193 @@ +#define MODE_OFF "veiled" +#define MODE_NATURAL "natural sight" +#define MODE_CORRECTION "correction" + +/obj/item/clothing/glasses/hud/tajblind + name = "\improper Tajaran veil" + desc = "A sleek, high-tech Tajaran veil, adapted from ancient designs and important to their culture and spirituality.
\ + Can switch between three modes: Sight-blocking veiled mode, transparent natural sight mode and colorblindness correction mode." + icon_state = "tajblind" + item_state = "tajblind" + actions_types = list(/datum/action/item_action/toggle) + color_view = MATRIX_STANDARD + correct_wires = TRUE + var/list/modes = list(MODE_OFF = MODE_NATURAL, MODE_NATURAL = MODE_CORRECTION, MODE_CORRECTION = MODE_OFF) + var/selected_mode = MODE_CORRECTION + + sprite_sheets = list( + "Vox" = 'icons/mob/clothing/species/vox/eyes.dmi', + "Grey" = 'icons/mob/clothing/species/grey/eyes.dmi' + ) + +/obj/item/clothing/glasses/hud/tajblind/attack_self(mob/user) + toggle_veil(user, TRUE) + +/obj/item/clothing/glasses/hud/tajblind/proc/toggle_veil(mob/user, voluntary) + var/mob/living/carbon/human/H = user + selected_mode = modes[selected_mode] + to_chat(user, "[voluntary ? "You turn the veil" : "The veil turns"] [selected_mode ? "to [selected_mode] mode" : "off"][voluntary ? "." : "!"]") + + switch(selected_mode) + if(MODE_OFF) + tint = TINT_BLIND + flash_protect = FLASH_PROTECTION_WELDER + color_view = null + correct_wires = FALSE + + if(MODE_NATURAL) + tint = initial(tint) + flash_protect = initial(flash_protect) + color_view = null + + if(MODE_CORRECTION) + tint = initial(tint) + flash_protect = initial(flash_protect) + color_view = MATRIX_STANDARD + correct_wires = TRUE + + if(ishuman(H) && H.glasses == src) + H.update_sight() + H.update_client_colour() + +/obj/item/clothing/glasses/hud/tajblind/examine_more(mob/user) + . = ..() + . += "Tajaran Veils have long been an important part of their spirituality and culture, suppressed by the Overseers and making a strong return after the civil war. Tajaran believe that to see one’s eyes is to see their soul, and thus the more spiritual Tajara wear veils to conceal their eyes from everyone but the ones closest to them.
\ + These current designs are adapted from recreations of the ancient veils, created by the Alchemists Guild. Technologically advanced and created to help Tajara adapt to life in the larger galactic community, they have systems built-in that allow them to have holographic huds, as well as corrective technology to help Tajaran overcome their genetic tritanopia colour blindness.
\ + Availability on the wider market is highly restricted as a result of their cultural importance, as well as the patent held by the Alchemists Guild, and the lenses are very hard to reverse engineer. Popular theories suggest this as a result of the unique materials available on Adhomai, or the inability to recreate the light conditions of the Tajara homeworld." + +/obj/item/clothing/glasses/hud/tajblind/meson + name = "\improper Tajaran engineering meson veil" + icon_state = "tajblind_engi" + item_state = "tajblind_engi" + +/obj/item/clothing/glasses/hud/tajblind/meson/Initialize() + ..() + desc += "
It has an optical meson scanner integrated into it." + +/obj/item/clothing/glasses/hud/tajblind/meson/equipped(mob/user, slot, initial) + . = ..() + if(slot == SLOT_HUD_GLASSES) + ADD_TRAIT(user, TRAIT_MESON_VISION, "meson_glasses[UID()]") + +/obj/item/clothing/glasses/hud/tajblind/meson/dropped(mob/user) + . = ..() + if(user) + REMOVE_TRAIT(user, TRAIT_MESON_VISION, "meson_glasses[UID()]") + +/obj/item/clothing/glasses/hud/tajblind/meson/cargo + name = "\improper Tajaran mining meson veil" + icon_state = "tajblind_cargo" + item_state = "tajblind_cargo" + +/obj/item/clothing/glasses/hud/tajblind/sci + name = "\improper Tajaran scientific veil" + icon_state = "tajblind_sci" + item_state = "tajblind_sci" + scan_reagents = 1 + actions_types = list(/datum/action/item_action/toggle, /datum/action/item_action/toggle_research_scanner) + +/obj/item/clothing/glasses/hud/tajblind/sci/Initialize() + ..() + desc += "
It has science goggles integrated into it." + +/obj/item/clothing/glasses/hud/tajblind/sci/item_action_slot_check(slot) + if(slot == SLOT_HUD_GLASSES) + return TRUE + +/obj/item/clothing/glasses/hud/tajblind/med + name = "\improper Tajaran medical veil" + icon_state = "tajblind_med" + item_state = "tajblind_med" + hud_types = DATA_HUD_MEDICAL_ADVANCED + examine_extensions = list(EXAMINE_HUD_MEDICAL_READ) + +/obj/item/clothing/glasses/hud/tajblind/med/Initialize() + ..() + desc += "
It has a health HUD integrated into it." + +/obj/item/clothing/glasses/hud/tajblind/sec + name = "\improper Tajaran security veil" + icon_state = "tajblind_sec" + item_state = "tajblind_sec" + hud_types = DATA_HUD_SECURITY_ADVANCED + examine_extensions = list(EXAMINE_HUD_SECURITY_READ) + +/obj/item/clothing/glasses/hud/tajblind/sec/Initialize() + ..() + desc += "
It has a security HUD integrated into it." + +/obj/item/clothing/glasses/hud/tajblind/shaded + name = "shaded Tajaran veil" + flash_protect = FLASH_PROTECTION_FLASH + tint = FLASH_PROTECTION_FLASH + +/obj/item/clothing/glasses/hud/tajblind/shaded/Initialize() + ..() + desc += "
It has an in-built flash protection." + +/obj/item/clothing/glasses/hud/tajblind/shaded/meson + name = "shaded Tajaran engineering meson veil" + icon_state = "tajblind_engi" + item_state = "tajblind_engi" + +/obj/item/clothing/glasses/hud/tajblind/shaded/meson/Initialize() + ..() + desc += "
It has an optical meson scanner integrated into it." + +/obj/item/clothing/glasses/hud/tajblind/shaded/meson/equipped(mob/user, slot, initial) + . = ..() + if(slot == SLOT_HUD_GLASSES) + ADD_TRAIT(user, TRAIT_MESON_VISION, "meson_glasses[UID()]") + +/obj/item/clothing/glasses/hud/tajblind/shaded/meson/dropped(mob/user) + . = ..() + if(user) + REMOVE_TRAIT(user, TRAIT_MESON_VISION, "meson_glasses[UID()]") + + +/obj/item/clothing/glasses/hud/tajblind/shaded/meson/cargo + name = "shaded Tajaran mining meson veil" + icon_state = "tajblind_cargo" + item_state = "tajblind_cargo" + +/obj/item/clothing/glasses/hud/tajblind/shaded/sci + name = "shaded Tajaran scientific veil" + icon_state = "tajblind_sci" + item_state = "tajblind_sci" + scan_reagents = 1 + actions_types = list(/datum/action/item_action/toggle, /datum/action/item_action/toggle_research_scanner) + +/obj/item/clothing/glasses/hud/tajblind/shaded/sci/Initialize() + ..() + desc += "
It has science goggles integrated into it." + +/obj/item/clothing/glasses/hud/tajblind/shaded/sci/item_action_slot_check(slot) + if(slot == SLOT_HUD_GLASSES) + return TRUE + +/obj/item/clothing/glasses/hud/tajblind/shaded/med + name = "shaded Tajaran medical veil" + icon_state = "tajblind_med" + item_state = "tajblind_med" + hud_types = DATA_HUD_MEDICAL_ADVANCED + examine_extensions = list(EXAMINE_HUD_MEDICAL_READ) + +/obj/item/clothing/glasses/hud/tajblind/shaded/med/Initialize() + ..() + desc += "
It has a health HUD integrated into it." + +/obj/item/clothing/glasses/hud/tajblind/shaded/sec + name = "shaded Tajaran security veil" + icon_state = "tajblind_sec" + item_state = "tajblind_sec" + see_in_dark = 1 + hud_types = DATA_HUD_SECURITY_ADVANCED + examine_extensions = list(EXAMINE_HUD_SECURITY_READ) + +/obj/item/clothing/glasses/hud/tajblind/shaded/sec/Initialize() + ..() + desc += "
It has a security HUD integrated into it." + +#undef MODE_OFF +#undef MODE_NATURAL +#undef MODE_CORRECTION diff --git a/code/modules/crafting/tailoring.dm b/code/modules/crafting/tailoring.dm index eca646a91e87..51e0a616a28b 100644 --- a/code/modules/crafting/tailoring.dm +++ b/code/modules/crafting/tailoring.dm @@ -305,6 +305,254 @@ reqs = list(/obj/item/clothing/glasses/sunglasses/reagent = 1) category = CAT_CLOTHING +/datum/crafting_recipe/shaded_tajblind + name = "Shaded Tajaran veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/shaded) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/sunglasses = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/sunglasses) + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + +/datum/crafting_recipe/shaded_tajblind_removal + name = "Shaded Tajaran veil removal" + result = list(/obj/item/clothing/glasses/sunglasses, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/shaded = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_tajblind_removal/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind/shaded) + +/datum/crafting_recipe/engi_tajblind + name = "Tajaran engineering meson veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/meson) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/meson = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/engi_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + blacklist += subtypesof(/obj/item/clothing/glasses/meson) + +/datum/crafting_recipe/engi_tajblind_removal + name = "Tajaran engineering meson removal" + result = list(/obj/item/clothing/glasses/meson, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/meson = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/engi_tajblind_removal/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind/meson) + +/datum/crafting_recipe/shaded_engi_tajblind + name = "Shaded Tajaran engineering meson veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/shaded/meson) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/meson/sunglasses = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_engi_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + +/datum/crafting_recipe/shaded_engi_tajblind_removal + name = "Shaded Tajaran engineering meson veil removal" + result = list(/obj/item/clothing/glasses/meson/sunglasses, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/shaded/meson = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_engi_tajblind_removal/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind/shaded/meson) + +/datum/crafting_recipe/cargo_tajblind + name = "Tajaran mining meson veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/meson/cargo) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/meson = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/cargo_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + blacklist += subtypesof(/obj/item/clothing/glasses/meson) + +/datum/crafting_recipe/cargo_tajblind_removal + name = "Tajaran mining meson veil removal" + result = list(/obj/item/clothing/glasses/meson, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/meson/cargo = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_cargo_tajblind + name = "Shaded Tajaran mining meson veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/shaded/meson/cargo) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/meson/sunglasses = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_cargo_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + +/datum/crafting_recipe/shaded_cargo_tajblind_removal + name = "Shaded Tajaran mining meson veil removal" + result = list(/obj/item/clothing/glasses/meson/sunglasses, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/shaded/meson/cargo = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/sci_tajblind + name = "Tajaran scientific veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/sci) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/science = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/sci_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + +/datum/crafting_recipe/sci_tajblind_removal + name = "Tajaran scientific veil removal" + result = list(/obj/item/clothing/glasses/science, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/sci = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_sci_tajblind + name = "Shaded Tajaran scientific veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/shaded/sci) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/sunglasses/reagent = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_sci_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + +/datum/crafting_recipe/shaded_sci_tajblind_removal + name = "Shaded Tajaran scientific veil removal" + result = list(/obj/item/clothing/glasses/sunglasses/reagent, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/shaded/sci = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/med_tajblind + name = "Tajaran medical veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/med) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/health = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/med_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + blacklist += subtypesof(/obj/item/clothing/glasses/hud/health) + +/datum/crafting_recipe/med_tajblind_removal + name = "Tajaran medical veil removal" + result = list(/obj/item/clothing/glasses/hud/health, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/med = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_med_tajblind + name = "Shaded Tajaran medical veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/shaded/med) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/health/sunglasses = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_med_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + +/datum/crafting_recipe/shaded_med_tajblind_removal + name = "Shaded Tajaran medical veil removal" + result = list(/obj/item/clothing/glasses/hud/health/sunglasses, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/shaded/med = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/sec_tajblind + name = "Tajaran security veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/sec) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/security = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/sec_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + blacklist += subtypesof(/obj/item/clothing/glasses/hud/security) + +/datum/crafting_recipe/sec_tajblind_removal + name = "Tajaran security veil removal" + result = list(/obj/item/clothing/glasses/hud/security, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/sec = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_sec_tajblind + name = "Shaded Tajaran security veil" + result = list(/obj/item/clothing/glasses/hud/tajblind/shaded/sec) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/security/sunglasses = 1, + /obj/item/clothing/glasses/hud/tajblind = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/shaded_sec_tajblind/New() + ..() + blacklist += subtypesof(/obj/item/clothing/glasses/hud/tajblind) + +/datum/crafting_recipe/shaded_sec_tajblind_removal + name = "Shaded Tajaran security veil removal" + result = list(/obj/item/clothing/glasses/hud/security/sunglasses, /obj/item/clothing/glasses/hud/tajblind) + time = 2 SECONDS + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list(/obj/item/clothing/glasses/hud/tajblind/shaded/sec = 1) + category = CAT_CLOTHING + /datum/crafting_recipe/ghostsheet name = "Ghost Sheet" result = list(/obj/item/clothing/suit/ghost_sheet) diff --git a/code/modules/events/blob/blob_mobs.dm b/code/modules/events/blob/blob_mobs.dm index 84061c550582..8a7bb881dfc9 100644 --- a/code/modules/events/blob/blob_mobs.dm +++ b/code/modules/events/blob/blob_mobs.dm @@ -84,6 +84,7 @@ if(istype(linked_node)) factory = linked_node factory.spores += src + GLOB.spores_active++ /mob/living/simple_animal/hostile/blob/blobspore/Life(seconds, times_fired) @@ -151,6 +152,7 @@ if(oldguy) oldguy.forceMove(get_turf(src)) oldguy = null + GLOB.spores_active-- return ..() diff --git a/code/modules/events/blob/blob_structures/factory.dm b/code/modules/events/blob/blob_structures/factory.dm index 6bbf5d34f59c..13d7e44a9ecc 100644 --- a/code/modules/events/blob/blob_structures/factory.dm +++ b/code/modules/events/blob/blob_structures/factory.dm @@ -1,3 +1,5 @@ +GLOBAL_VAR_INIT(spores_active, 0) +#define MAX_GLOBAL_SPORES 25 /obj/structure/blob/factory name = "factory blob" icon = 'icons/mob/blob.dmi' @@ -5,7 +7,7 @@ max_integrity = 200 point_return = 18 var/list/spores = list() - var/max_spores = 3 + var/max_spores = 5 var/spore_delay = 0 /obj/structure/blob/factory/Destroy() @@ -16,12 +18,14 @@ return ..() /obj/structure/blob/factory/run_action() - if(length(spores) >= max_spores) + if(length(spores) >= max_spores || GLOB.spores_active >= MAX_GLOBAL_SPORES) return if(spore_delay > world.time) return flick("blob_factory_glow", src) - spore_delay = world.time + 100 // 10 seconds + spore_delay = world.time + 10 SECONDS var/mob/living/simple_animal/hostile/blob/blobspore/BS = new/mob/living/simple_animal/hostile/blob/blobspore(src.loc, src) if(overmind) overmind.add_mob_to_overmind(BS) + +#undef MAX_GLOBAL_SPORES diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index fb29937efbb1..187848e662bf 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -20,7 +20,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 new /obj/effect/immovablerod/event(startT, endT) /obj/effect/immovablerod - name = "Immovable Rod" + name = "\improper Immovable Rod" desc = "What the fuck is that?" icon = 'icons/obj/objects.dmi' icon_state = "immrod" @@ -28,23 +28,28 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 density = TRUE anchored = TRUE var/z_original = 0 - var/destination var/notify = TRUE var/move_delay = 1 + var/atom/start + var/atom/end -/obj/effect/immovablerod/New(atom/start, atom/end, delay) +/obj/effect/immovablerod/New(atom/_start, atom/_end, delay) . = ..() + start = _start + end = _end loc = start z_original = z - destination = end move_delay = delay if(notify) notify_ghosts("\A [src] is inbound!", enter_link="(Click to follow)", source = src, action = NOTIFY_FOLLOW) GLOB.poi_list |= src + head_towards_dest() + +/obj/effect/immovablerod/proc/head_towards_dest() if(end?.z == z_original) - walk_towards(src, destination, move_delay) + walk_towards(src, end, move_delay) /obj/effect/immovablerod/Topic(href, href_list) if(href_list["follow"]) @@ -76,13 +81,13 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 if(isturf(clong) || isobj(clong)) if(clong.density) - clong.ex_act(2) + clong.ex_act(EXPLODE_HEAVY) else if(ismob(clong)) if(ishuman(clong)) var/mob/living/carbon/human/H = clong - H.visible_message("[H.name] is penetrated by an immovable rod!" , - "The rod penetrates you!" , + H.visible_message("[H.name] is penetrated by an immovable rod!", + "The rod penetrates you!", "You hear a CLANG!") H.adjustBruteLoss(160) if(clong.density || prob(10)) @@ -100,12 +105,33 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 var/turf/simulated/floor/T = get_turf(oldloc) if(istype(T)) T.ex_act(EXPLODE_HEAVY) - if(loc == destination) + if(loc == end) qdel(src) /obj/effect/immovablerod/deadchat_plays(mode = DEADCHAT_DEMOCRACY_MODE, cooldown = 6 SECONDS) return AddComponent(/datum/component/deadchat_control/immovable_rod, mode, list(), cooldown) +/obj/effect/immovablerod/smite + /// The target that we're gonna aim for between start and end + var/obj/effect/portal/exit + +/obj/effect/immovablerod/smite/New(atom/_start, atom/_end) + new /obj/effect/portal(start, lifespan = 2 SECONDS) + return ..() + +/obj/effect/immovablerod/smite/Move() + . = ..() + if(get_turf(src) == get_turf(end)) + // our exit condition: get outta there kowalski + var/target_turf = get_ranged_target_turf(src, dir, rand(1, 10)) + start = loc + walk(src, 0) + exit = new /obj/effect/portal(target_turf, lifespan = 2 SECONDS) + walk_towards(src, exit, move_delay) + else if(locate(exit) in get_turf(src)) + QDEL_NULL(exit) + qdel(src) + /** * Rod will walk towards edge turf in the specified direction. * @@ -113,5 +139,5 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 * * direction - The direction to walk the rod towards: NORTH, SOUTH, EAST, WEST. */ /obj/effect/immovablerod/proc/walk_in_direction(direction) - destination = get_edge_target_turf(src, direction) - walk_towards(src, destination) + end = get_edge_target_turf(src, direction) + walk_towards(src, end, move_delay) diff --git a/code/modules/food_and_drinks/food/foods/baked_goods.dm b/code/modules/food_and_drinks/food/foods/baked_goods.dm index 903e25d32db8..dfcfbf50f4bb 100644 --- a/code/modules/food_and_drinks/food/foods/baked_goods.dm +++ b/code/modules/food_and_drinks/food/foods/baked_goods.dm @@ -16,6 +16,7 @@ filling_color = "#FFD675" list_reagents = list("nutriment" = 20, "oculine" = 10, "vitamin" = 5) tastes = list("cake" = 5, "sweetness" = 2, "carrot" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/carrotcakeslice name = "carrot cake slice" @@ -39,6 +40,7 @@ bitesize = 3 list_reagents = list("protein" = 10, "nutriment" = 10, "mannitol" = 10, "vitamin" = 5) tastes = list("cake" = 5, "sweetness" = 2, "brains" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/braincakeslice name = "brain cake slice" @@ -61,6 +63,7 @@ bitesize = 3 list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("cake" = 4, "cream cheese" = 3) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/cheesecakeslice name = "cheese cake slice" @@ -83,6 +86,7 @@ filling_color = "#F7EDD5" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("cake" = 5, "vanilla" = 1, "sweetness" = 2) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/plaincakeslice name = "vanilla cake slice" @@ -105,6 +109,7 @@ filling_color = "#FADA8E" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("cake" = 5, "sweetness" = 2, "oranges" = 2) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/orangecakeslice name = "orange cake slice" @@ -127,6 +132,7 @@ filling_color = "#FADA8E" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("cake" = 5, "sweetness" = 2, "banana" = 2) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/bananacakeslice name = "banana cake slice" @@ -149,6 +155,7 @@ filling_color = "#CBFA8E" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("cake" = 5, "sweetness" = 2, "unbearable sourness" = 2) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/limecakeslice name = "lime cake slice" @@ -171,6 +178,7 @@ filling_color = "#FAFA8E" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("cake" = 5, "sweetness" = 2, "sourness" = 2) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/lemoncakeslice name = "lemon cake slice" @@ -193,6 +201,7 @@ filling_color = "#805930" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("cake" = 5, "sweetness" = 1, "chocolate" = 4) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/chocolatecakeslice name = "chocolate cake slice" @@ -215,6 +224,7 @@ bitesize = 3 list_reagents = list("nutriment" = 20, "sprinkles" = 10, "vitamin" = 5) tastes = list("cake" = 5, "sweetness" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/birthdaycakeslice name = "birthday cake slice" @@ -237,6 +247,7 @@ filling_color = "#EBF5B8" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("cake" = 5, "sweetness" = 1, "apple" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/applecakeslice name = "apple cake slice" @@ -369,6 +380,7 @@ filling_color = "#43DE18" list_reagents = list("nutriment" = 10, "vitamin" = 2) tastes = list("pie" = 1, "meat" = 1, "acid" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/applepie diff --git a/code/modules/food_and_drinks/food/foods/bread.dm b/code/modules/food_and_drinks/food/foods/bread.dm index e81ee938ff9c..89382e1e1b94 100644 --- a/code/modules/food_and_drinks/food/foods/bread.dm +++ b/code/modules/food_and_drinks/food/foods/bread.dm @@ -13,6 +13,7 @@ filling_color = "#FF7575" list_reagents = list("protein" = 20, "nutriment" = 10, "vitamin" = 5) tastes = list("bread" = 10, "meat" = 10) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/meatbreadslice name = "meatbread slice" @@ -32,6 +33,7 @@ filling_color = "#8AFF75" list_reagents = list("protein" = 20, "nutriment" = 10, "vitamin" = 5) tastes = list("bread" = 10, "acid" = 10) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/xenomeatbreadslice name = "xenomeatbread slice" @@ -39,6 +41,7 @@ icon = 'icons/obj/food/burgerbread.dmi' icon_state = "xenobreadslice" filling_color = "#8AFF75" + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/sliceable/spidermeatbread name = "spider meat loaf" @@ -49,6 +52,7 @@ slices_num = 5 list_reagents = list("protein" = 20, "nutriment" = 10, "toxin" = 15, "vitamin" = 5) tastes = list("bread" = 10, "cobwebs" = 5) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/spidermeatbreadslice name = "spider meat bread slice" @@ -57,6 +61,7 @@ icon_state = "spidermeatslice" tastes = list("bread" = 10, "cobwebs" = 5) list_reagents = list("toxin" = 2) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/sliceable/bananabread name = "banana-nut bread" @@ -68,6 +73,7 @@ filling_color = "#EDE5AD" list_reagents = list("banana" = 20, "nutriment" = 20) tastes = list("bread" = 10, "banana" = 5) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/bananabreadslice name = "banana-nut bread slice" @@ -88,6 +94,7 @@ filling_color = "#F7FFE0" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("bread" = 10, "tofu" = 10) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/tofubreadslice name = "tofubread slice" @@ -107,6 +114,7 @@ filling_color = "#FFE396" list_reagents = list("nutriment" = 10) tastes = list("bread" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/breadslice name = "bread slice" @@ -128,6 +136,7 @@ filling_color = "#FFF896" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("bread" = 10, "cheese" = 10) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/creamcheesebreadslice name = "cream cheese bread slice" @@ -149,6 +158,7 @@ filling_color = "#6F0000" list_reagents = list("nutriment" = 20, "vitamin" = 5) tastes = list("heresy" = 10, "banana" = 10) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/banarnarbreadslice name = "banarnarbread slice" @@ -225,6 +235,7 @@ bitesize = 3 list_reagents = list("nutriment" = 3) tastes = list("toast" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/jelliedtoast name = "jellied toast" diff --git a/code/modules/food_and_drinks/food/foods/candy.dm b/code/modules/food_and_drinks/food/foods/candy.dm index 80cbfc5ee20b..a6a65499b020 100644 --- a/code/modules/food_and_drinks/food/foods/candy.dm +++ b/code/modules/food_and_drinks/food/foods/candy.dm @@ -125,6 +125,7 @@ filling_color = "#FFFFFF" bitesize = 4 list_reagents = list("sugar" = 15) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/candy/candybar name = "candy" @@ -155,6 +156,7 @@ filling_color = "#FFFFFF" bitesize = 3 list_reagents = list("sugar" = 10) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/candy/gummyworm name = "gummy worm" @@ -163,6 +165,7 @@ filling_color = "#FFFFFF" bitesize = 3 list_reagents = list("sugar" = 10) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/candy/jellybean name = "jelly bean" @@ -171,6 +174,7 @@ filling_color = "#FFFFFF" bitesize = 3 list_reagents = list("sugar" = 10) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/candy/jawbreaker name = "jawbreaker" diff --git a/code/modules/food_and_drinks/food/foods/frozen.dm b/code/modules/food_and_drinks/food/foods/frozen.dm index dd117fbaecb1..89824dd503c3 100644 --- a/code/modules/food_and_drinks/food/foods/frozen.dm +++ b/code/modules/food_and_drinks/food/foods/frozen.dm @@ -21,6 +21,7 @@ bitesize = 3 list_reagents = list("nutriment" = 20, "sugar" = 5, "vitamin" = 5, "banana" = 15) tastes = list("cake" = 5, "sweetness" = 2, "banana" = 1, "sad clowns" = 1, "ice-cream" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/frozen/clowncakeslice name = "clown cake slice" @@ -155,6 +156,7 @@ trash = /obj/item/reagent_containers/drinks/sillycup list_reagents = list("water" = 10, "ice" = 5) tastes = list("cold water" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/frozen/snowcone/apple name = "apple snowcone" diff --git a/code/modules/food_and_drinks/food/foods/meat.dm b/code/modules/food_and_drinks/food/foods/meat.dm index e5a34bad7a31..c3341fcaab16 100644 --- a/code/modules/food_and_drinks/food/foods/meat.dm +++ b/code/modules/food_and_drinks/food/foods/meat.dm @@ -47,6 +47,12 @@ desc = "Much meatier than monkey meat." list_reagents = list("nutriment" = 5, "vitamin" = 1) +/obj/item/food/snacks/meat/kangaroo + name = "kangaroo meat" + desc = "Extremely muscular and tender meat." + list_reagents = list("protein" = 4, "iron" = 5, "vitamin" = 1) + tastes = list("a punch in the face" = 1, "fowl" = 3) + /obj/item/food/snacks/meat/monkey //same as plain meat @@ -284,6 +290,7 @@ bitesize = 4 list_reagents = list("nutriment" = 6) tastes = list("cobwebs" = 1, "the colour green" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/boiledspiderleg name = "boiled spider leg" @@ -294,6 +301,7 @@ bitesize = 3 list_reagents = list("nutriment" = 3, "capsaicin" = 2) tastes = list("cobwebs" = 1, "hot peppers" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/wingfangchu name = "wing fang chu" @@ -304,6 +312,7 @@ filling_color = "#43DE18" list_reagents = list("nutriment" = 6, "soysauce" = 5, "vitamin" = 2) tastes = list("soy" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/goliath_steak name = "goliath steak" @@ -314,6 +323,7 @@ trash = null list_reagents = list("protein" = 6, "vitamin" = 2) tastes = list("meat" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/fried_vox name = "Kentucky Fried Vox" @@ -323,6 +333,7 @@ trash = /obj/item/trash/fried_vox list_reagents = list("nutriment" = 3, "protein" = 5) tastes = list("quills" = 1, "the shoal" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE ////////////////////// // Cubes // @@ -553,6 +564,7 @@ slices_num = 6 list_reagents = list("protein" = 24, "nutriment" = 18, "vitamin" = 5) tastes = list("turkey" = 2, "stuffing" = 2) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/turkeyslice name = "turkey serving" diff --git a/code/modules/food_and_drinks/food/foods/misc_food.dm b/code/modules/food_and_drinks/food/foods/misc_food.dm index a65b1bcf3fa3..7d5b6bcf6b07 100644 --- a/code/modules/food_and_drinks/food/foods/misc_food.dm +++ b/code/modules/food_and_drinks/food/foods/misc_food.dm @@ -277,6 +277,7 @@ bitesize = 3 list_reagents = list("slimejelly" = 5) tastes = list("jelly" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/popcorn name = "popcorn" diff --git a/code/modules/food_and_drinks/food/foods/pizza.dm b/code/modules/food_and_drinks/food/foods/pizza.dm index 9cdc5cddb6f7..9cdfabe8f6ec 100644 --- a/code/modules/food_and_drinks/food/foods/pizza.dm +++ b/code/modules/food_and_drinks/food/foods/pizza.dm @@ -16,6 +16,7 @@ icon_state = "margheritapizza" slice_path = /obj/item/food/snacks/margheritapizzaslice list_reagents = list("nutriment" = 30, "tomatojuice" = 6, "vitamin" = 5) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/margheritapizzaslice name = "margherita slice" @@ -34,6 +35,7 @@ slice_path = /obj/item/food/snacks/meatpizzaslice list_reagents = list("protein" = 30, "tomatojuice" = 6, "vitamin" = 8) tastes = list("crust" = 1, "cheese" = 1, "meat" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/meatpizzaslice name = "meat pizza slice" @@ -52,6 +54,7 @@ slice_path = /obj/item/food/snacks/mushroompizzaslice list_reagents = list("plantmatter" = 30, "vitamin" = 5) tastes = list("crust" = 1, "cheese" = 1, "mushroom" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/mushroompizzaslice name = "mushroom pizza slice" @@ -70,6 +73,7 @@ slice_path = /obj/item/food/snacks/vegetablepizzaslice list_reagents = list("plantmatter" = 25, "tomatojuice" = 6, "oculine" = 12, "vitamin" = 5) tastes = list("crust" = 1, "tomato" = 1, "carrot" = 1, "vegetables" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/vegetablepizzaslice name = "vegetable pizza slice" @@ -88,6 +92,7 @@ slice_path = /obj/item/food/snacks/hawaiianpizzaslice list_reagents = list("protein" = 15, "tomatojuice" = 6, "plantmatter" = 20, "pineapplejuice" = 6, "vitamin" = 5) tastes = list("crust" = 1, "cheese" = 1, "pineapple" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/hawaiianpizzaslice name = "hawaiian pizza slice" @@ -107,6 +112,7 @@ list_reagents = list("nutriment" = 40, "vitamin" = 5) //More nutriment because carbs, but it's not any more vitaminicious filling_color = "#ffe45d" tastes = list("crust" = 1, "cheese" = 2, "pasta" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/macpizzaslice name = "mac 'n' cheese pizza slice" @@ -126,6 +132,7 @@ list_reagents = list("protein" = 30, "tomatojuice" = 6, "vitamin" = 8) filling_color = "#ffe45d" tastes = list("cheese" = 3, "pepperoni" = 3, "grease" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/pepperonipizzaslice name = "pepperoni pizza slice" @@ -143,6 +150,7 @@ icon_state = "cheesepizza" slice_path = /obj/item/food/snacks/cheesepizzaslice list_reagents = list("nutriment" = 40, "tomatojuice" = 6, "vitamin" = 5) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/cheesepizzaslice name = "cheese pizza slice" @@ -161,6 +169,7 @@ slice_path = /obj/item/food/snacks/donkpocketpizzaslice list_reagents = list("nutriment" = 35, "tomatojuice" = 6, "vitamin" = 2, "weak_omnizine" = 6) tastes = list("crust" = 1, "meat" = 1, "laziness" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/donkpocketpizzaslice name = "donk-pocket pizza slice" @@ -179,6 +188,7 @@ slice_path = /obj/item/food/snacks/dankpizzaslice list_reagents = list("nutriment" = 30, "tomatojuice" = 6, "vitamin" = 5, "cbd" = 6, "thc" = 6) tastes = list("crust" = 1, "cheese" = 1, "special herbs" = 2) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/dankpizzaslice name = "dank pizza slice" @@ -197,6 +207,7 @@ slice_path = /obj/item/food/snacks/firecrackerpizzaslice list_reagents = list("nutriment" = 30, "vitamin" = 5, "capsaicin" = 12) tastes = list("crust" = 1, "cheese" = 1, "HOTNESS" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/firecrackerpizzaslice name = "firecracker pizza slice" @@ -215,6 +226,7 @@ slice_path = /obj/item/food/snacks/pestopizzaslice list_reagents = list("nutriment" = 30, "tomatojuice" = 12, "vitamin" = 5, "wasabi" = 12) tastes = list("tomato" = 1, "cheese" = 1, "wasabi" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/pestopizzaslice name = "\"pesto\" pizza slice" @@ -233,6 +245,7 @@ slice_path = /obj/item/food/snacks/garlicpizzaslice list_reagents = list("plantmatter" = 30, "vitamin" = 5, "garlic" = 12) tastes = list("crust" = 1, "cheese" = 1, "garlic" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/garlicpizzaslice name = "garlic pizza slice" diff --git a/code/modules/food_and_drinks/food/foods/sandwiches.dm b/code/modules/food_and_drinks/food/foods/sandwiches.dm index 77f1a8092ec7..cefe18469afb 100644 --- a/code/modules/food_and_drinks/food/foods/sandwiches.dm +++ b/code/modules/food_and_drinks/food/foods/sandwiches.dm @@ -38,6 +38,7 @@ bitesize = 3 list_reagents = list("nutriment" = 6, "vitamin" = 1) tastes = list("bun" = 4, "ectoplasm" = 2) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/human var/hname = "" @@ -93,6 +94,7 @@ bitesize = 3 list_reagents = list("nutriment" = 6, "vitamin" = 1) tastes = list("bun" = 4, "acid" = 4) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/burger/clown name = "clown burger" @@ -102,6 +104,7 @@ bitesize = 3 list_reagents = list("nutriment" = 6, "vitamin" = 1) tastes = list("bun" = 4, "banana" = 1, "magic" = 2) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/burger/mime name = "mime burger" @@ -111,6 +114,7 @@ bitesize = 3 list_reagents = list("nutriment" = 6, "vitamin" = 1) tastes = list("bun" = 4, "silence" = 2) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/burger/baseball name = "home run baseball burger" @@ -120,6 +124,7 @@ bitesize = 3 list_reagents = list("nutriment" = 6, "vitamin" = 1) tastes = list("bun" = 4, "a homerun" = 3) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/burger/spell name = "spell burger" @@ -129,6 +134,7 @@ bitesize = 3 list_reagents = list("nutriment" = 6, "vitamin" = 1) tastes = list("bun" = 4, "magic" = 2) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/burger/bigbite name = "BigBite burger" @@ -148,6 +154,7 @@ bitesize = 7 list_reagents = list("nutriment" = 40, "vitamin" = 5) tastes = list("bun" = 4, "meat" = 2, "cheese" = 2, "type two diabetes" = 10) + goal_difficulty = FOOD_GOAL_HARD /obj/item/food/snacks/burger/crazy name = "crazy hamburger" @@ -157,6 +164,7 @@ bitesize = 3 list_reagents = list("nutriment" = 10, "vitamin" = 2, "capsaicin" = 3, "condensedcapsaicin" = 2) tastes = list("bun" = 2, "meat" = 4, "cheese" = 2, "beef soaked in chili" = 3, "a smoking flare" = 2) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/burger/ppatty/white name = "white pretty patty" @@ -285,6 +293,7 @@ bitesize = 3 list_reagents = list("nutriment" = 3, "protein" = 6, "vitamin" = 2) tastes = list("bun" = 1, "meat" = 1, "salmon" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/burger/fivealarm name = "five alarm burger" @@ -401,6 +410,7 @@ icon_state = "notasandwich" list_reagents = list("nutriment" = 6, "vitamin" = 6) tastes = list("nothing suspicious" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/wrap name = "egg wrap" diff --git a/code/modules/food_and_drinks/food/foods/seafood.dm b/code/modules/food_and_drinks/food/foods/seafood.dm index 69f88b307ecd..a4529b88ae06 100644 --- a/code/modules/food_and_drinks/food/foods/seafood.dm +++ b/code/modules/food_and_drinks/food/foods/seafood.dm @@ -149,6 +149,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8) tastes = list("shrimp" = 1, "rice" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_Ebi name = "ebi sushi" @@ -170,6 +171,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8, "protein" = 4) tastes = list("salmon roe" = 1, "rice" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_Ikura name = "ikura sushi" @@ -191,6 +193,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8) tastes = list("raw salmon" = 1, "rice" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_Sake name = "sake sushi" @@ -212,6 +215,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8) tastes = list("smoked salmon" = 1, "rice" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_SmokedSalmon name = "smoked salmon sushi" @@ -233,6 +237,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8) tastes = list("egg" = 1, "rice" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_Tamago name = "tamago sushi" @@ -254,6 +259,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8) tastes = list("fried tofu" = 1, "rice" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_Inari name = "inari sushi" @@ -275,6 +281,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8, "protein" = 4) tastes = list("goldfish roe" = 1, "rice" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_Masago name = "masago sushi" @@ -296,6 +303,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8, "protein" = 4) tastes = list("shark roe" = 1, "rice" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_Tobiko name = "tobiko sushi" @@ -317,6 +325,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8, "protein" = 4) tastes = list("shark roe" = 1, "rice" = 1, "egg" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_TobikoEgg name = "tobiko and egg sushi" @@ -338,6 +347,7 @@ bitesize = 3 list_reagents = list("nutriment" = 8) tastes = list("catfish" = 1, "rice" = 1, "seaweed" = 1) + goal_difficulty = FOOD_GOAL_DUPLICATE /obj/item/food/snacks/sushi_Tai name = "tai sushi" diff --git a/code/modules/food_and_drinks/food/foods/soups.dm b/code/modules/food_and_drinks/food/foods/soups.dm index e2c4df37a92a..e7b4db67565e 100644 --- a/code/modules/food_and_drinks/food/foods/soups.dm +++ b/code/modules/food_and_drinks/food/foods/soups.dm @@ -47,6 +47,7 @@ filling_color = "#C4FBFF" list_reagents = list("nutriment" = 4, "banana" = 5, "water" = 5, "vitamin" = 8) tastes = list("a bad joke" = 1) + goal_difficulty = FOOD_GOAL_EXCESSIVE /obj/item/food/snacks/soup/vegetablesoup name = "vegetable soup" @@ -317,3 +318,4 @@ filling_color = "#FF3C00" list_reagents = list("nutriment" = 5, "tomatojuice" = 2, "protein" = 2) tastes = list("tomato" = 1, "chili" = 1, "meat" = 1, "sad clowns" = 4) + goal_difficulty = FOOD_GOAL_EXCESSIVE diff --git a/code/modules/food_and_drinks/food_base.dm b/code/modules/food_and_drinks/food_base.dm index d748c00e5bd8..21c53fbad007 100644 --- a/code/modules/food_and_drinks/food_base.dm +++ b/code/modules/food_and_drinks/food_base.dm @@ -29,9 +29,9 @@ var/temperature_min = 0 // To limit the temperature of a reagent container can attain when exposed to heat/cold var/temperature_max = 10000 - // How difficult is this food for the kitchen to make? - // Affects the quantity of food that is requested by CC. - var/goal_difficulty = REAGENT_GOAL_SKIP + /// How difficult is this food for the kitchen to make? + /// Affects the quantity of food that is requested by CC. + var/goal_difficulty = FOOD_GOAL_SKIP /obj/item/food/Initialize(mapload) . = ..() diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm index 6364f1629b01..98f22590080c 100644 --- a/code/modules/hydroponics/grown/towercap.dm +++ b/code/modules/hydroponics/grown/towercap.dm @@ -16,6 +16,7 @@ icon_dead = "towercap-dead" genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism) mutatelist = list(/obj/item/seeds/tower/steel) + reagents_add = list("carbon" = 0.2) /obj/item/seeds/tower/steel name = "pack of steel-cap mycelium" @@ -25,6 +26,7 @@ plantname = "Steel Caps" product = /obj/item/grown/log/steel mutatelist = list() + reagents_add = list("iron" = 0.5) rarity = 20 diff --git a/code/modules/martial_arts/combos/judo/goldenblast.dm b/code/modules/martial_arts/combos/judo/goldenblast.dm new file mode 100644 index 000000000000..7e46aeb4cc61 --- /dev/null +++ b/code/modules/martial_arts/combos/judo/goldenblast.dm @@ -0,0 +1,21 @@ +/datum/martial_combo/judo/goldenblast + // This is incredibly stupid. I love it. + name = "Golden Blast" + steps = list(MARTIAL_COMBO_STEP_HELP, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_HELP, MARTIAL_COMBO_STEP_GRAB, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_GRAB, MARTIAL_COMBO_STEP_HELP, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_DISARM, MARTIAL_COMBO_STEP_GRAB, MARTIAL_COMBO_STEP_HELP) + explaination_text = "Through use of a martial arts form, you can stun a foe with life energy. Or by overcharging the belt's nanites. Take your Pick." + combo_text_override = "Help, Disarm, Help, Grab, Disarm, Disarm, Grab, Help, Disarm, Disarm, Grab, Help" + +/datum/martial_combo/judo/goldenblast/perform_combo(mob/living/carbon/human/user, mob/living/target, datum/martial_art/MA) + target.visible_message("[user] blasts [target] with energy, sending [target.p_them()] to the ground!", \ + "[user] makes strange hand gestures, screams wildly and prods you directly in the chest! You feel the wrath of the GOLDEN BOLT surge through your body! You've been utterly robusted!") + playsound(get_turf(target), 'sound/weapons/taser.ogg', 55, TRUE, -1) + playsound(get_turf(target), 'sound/weapons/tase.ogg', 55, TRUE, -1) + target.SpinAnimation(10, 1) + do_sparks(5, FALSE, target) + user.say("GOLDEN BLAST!") + playsound(get_turf(user), 'sound/weapons/goldenblast.ogg', 60, TRUE, -1) + target.apply_damage(120, STAMINA) + target.KnockDown(30 SECONDS) + target.SetConfused(30 SECONDS) + add_attack_logs(user, target, "Melee attacked with martial-art [src] : Golden Blast", ATKLOG_ALL) + return MARTIAL_COMBO_DONE diff --git a/code/modules/martial_arts/combos/judo/wheelthrow.dm b/code/modules/martial_arts/combos/judo/wheelthrow.dm index 6759093d1362..96af978a480a 100644 --- a/code/modules/martial_arts/combos/judo/wheelthrow.dm +++ b/code/modules/martial_arts/combos/judo/wheelthrow.dm @@ -11,7 +11,7 @@ "[user] throws you over [user.p_their()] shoulder, slamming you into the ground!") playsound(get_turf(user), 'sound/magic/tail_swing.ogg', 40, TRUE, -1) target.SpinAnimation(10, 1) - target.apply_damage(200, STAMINA) + target.apply_damage(120, STAMINA) target.KnockDown(15 SECONDS) target.SetConfused(10 SECONDS) add_attack_logs(user, target, "Melee attacked with martial-art [src] : Wheel Throw", ATKLOG_ALL) diff --git a/code/modules/martial_arts/judo.dm b/code/modules/martial_arts/judo.dm index 6fc113321b0d..158154098706 100644 --- a/code/modules/martial_arts/judo.dm +++ b/code/modules/martial_arts/judo.dm @@ -2,7 +2,7 @@ name = "Corporate Judo" has_explaination_verb = TRUE no_baton = TRUE - combos = list(/datum/martial_combo/judo/discombobulate, /datum/martial_combo/judo/eyepoke, /datum/martial_combo/judo/judothrow, /datum/martial_combo/judo/armbar, /datum/martial_combo/judo/wheelthrow) + combos = list(/datum/martial_combo/judo/discombobulate, /datum/martial_combo/judo/eyepoke, /datum/martial_combo/judo/judothrow, /datum/martial_combo/judo/armbar, /datum/martial_combo/judo/wheelthrow, /datum/martial_combo/judo/goldenblast) weight = 5 //takes priority over boxing and drunkneness, less priority than krav or CQC/carp no_baton_reason = "The baton feels off balance in your hand due to your judo training!" can_horizontally_grab = FALSE diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index 47f9ab77c8cc..e4ce7921dcaa 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -213,7 +213,7 @@ "You insert [I] into [src].") return - else if(istype(I, /obj/item/gripper_engineering)) + else if(istype(I, /obj/item/gripper)) if(!try_refill_storage(user)) to_chat(user, "You fail to retrieve any sheets from [src].") return diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 8d1bfef8a8ce..f2a6374bc3dc 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -317,11 +317,11 @@ GLOBAL_LIST_INIT(sand_recipes, list(\ spawn(det_time) if(primed) if(quality == GIBTONITE_QUALITY_HIGH) - explosion(src.loc,2,4,9,adminlog = notify_admins) + explosion(loc, 2, 4, 9, adminlog = notify_admins) if(quality == GIBTONITE_QUALITY_MEDIUM) - explosion(src.loc,1,2,5,adminlog = notify_admins) + explosion(loc, 1, 2, 5, adminlog = notify_admins) if(quality == GIBTONITE_QUALITY_LOW) - explosion(src.loc,-1,1,3,adminlog = notify_admins) + explosion(loc, -1, 1, 3, adminlog = notify_admins) qdel(src) diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 37a3e94cf277..3d0491e12792 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -7,6 +7,7 @@ maxHealth = 25 health = 25 + butcher_results = list(/obj/item/food/snacks/monstermeat/xenomeat = 1) density = FALSE var/temperature_resistance = T0C+75 diff --git a/code/modules/mob/living/carbon/human/human_emote.dm b/code/modules/mob/living/carbon/human/human_emote.dm index 7aa5659f99fa..a4814fd39e6f 100644 --- a/code/modules/mob/living/carbon/human/human_emote.dm +++ b/code/modules/mob/living/carbon/human/human_emote.dm @@ -375,6 +375,8 @@ cooldown = 5 SECONDS /// Status effect to apply when this emote is used. Should be a subtype var/status = STATUS_EFFECT_HIGHFIVE + /// title override, used for the re-use message. + var/action_name /datum/emote/living/carbon/human/highfive/can_run_emote(mob/user, status_check, intentional) . = ..() @@ -382,12 +384,17 @@ if(user_carbon.restrained()) return FALSE +/datum/emote/living/carbon/human/highfive/proc/set_status(mob/living/carbon/user) + return user.apply_status_effect(status) + /datum/emote/living/carbon/human/highfive/run_emote(mob/user, params, type_override, intentional) var/mob/living/carbon/user_carbon = user if(user_carbon.has_status_effect(status)) - user.visible_message("[user.name] слегка взмахивает своей рукой, нетерпеливо ожидая, когда кто-нибудь даст пять.") + user.visible_message("[user.name] shakes [user.p_their()] hand around slightly, impatiently waiting for someone to [!isnull(action_name) ? action_name : key].") + return TRUE + var/datum/result = set_status(user) + if(QDELETED(result)) return TRUE - user_carbon.apply_status_effect(status) return ..() @@ -401,6 +408,39 @@ key_third_person = "handshakes" status = STATUS_EFFECT_HANDSHAKE +/datum/emote/living/carbon/human/highfive/rps + key = "rps" + param_desc = "r,p,s" + hands_use_check = TRUE + status = STATUS_EFFECT_RPS + action_name = "play rock-paper-scissors with" + target_behavior = EMOTE_TARGET_BHVR_IGNORE + /// If the user used parameters, the move that will be made. + var/move + +/datum/emote/living/carbon/human/highfive/rps/run_emote(mob/user, emote_arg, type_override, intentional) + switch(lowertext(emote_arg)) + if("r", "rock") + move = RPS_EMOTE_ROCK + if("p", "paper") + move = RPS_EMOTE_PAPER + if("s", "scissors") + move = RPS_EMOTE_SCISSORS + + // if it's an invalid emote param, just fall through and let them select + + return ..() + +/datum/emote/living/carbon/human/highfive/rps/set_status(mob/living/carbon/user) + if(!isnull(move)) + // if they supplied a valid parameter, use that for the move + return user.apply_status_effect(status, move) + return user.apply_status_effect(status) + +/datum/emote/living/carbon/human/highfive/rps/reset_emote() + ..() + move = initial(move) + /datum/emote/living/carbon/human/snap key = "snap" key_third_person = "snaps" @@ -453,7 +493,6 @@ mob_type_allowed_typecache = list(/mob/living/carbon/human) hands_use_check = TRUE - ///////// // Species-specific emotes diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index 2c3d81904c3c..eade62cabf0e 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -1967,7 +1967,3 @@ Eyes need to have significantly high darksight to shine unless the mob has the X set category = "IC" update_flavor_text() - -/mob/living/carbon/human/proc/apply_offstation_roles(source) - SIGNAL_HANDLER - mind.offstation_role = TRUE diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 09e6f0a9abeb..af2367049209 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -1,162 +1,3 @@ -//Simple borg hand. -//Limited use. -/// This isn't a drone item, also in engineering cyborg kits -/obj/item/gripper_engineering - name = "magnetic gripper" - desc = "A simple grasping tool for synthetic assets." - icon = 'icons/obj/device.dmi' - icon_state = "gripper" - actions_types = list(/datum/action/item_action/drop_gripped_item) - - //Has a list of items that it can hold. - var/list/can_hold = list( - /obj/item/firealarm_electronics, - /obj/item/airalarm_electronics, - /obj/item/airlock_electronics, - /obj/item/firelock_electronics, - /obj/item/intercom_electronics, - /obj/item/apc_electronics, - /obj/item/tracker_electronics, - /obj/item/stock_parts, - /obj/item/vending_refill, - /obj/item/mounted/frame/light_fixture, - /obj/item/mounted/frame/apc_frame, - /obj/item/mounted/frame/alarm_frame, - /obj/item/mounted/frame/firealarm, - /obj/item/mounted/frame/display/newscaster_frame, - /obj/item/mounted/frame/intercom, - /obj/item/mounted/frame/extinguisher, - /obj/item/mounted/frame/light_switch, - /obj/item/assembly/prox_sensor, - /obj/item/rack_parts, - /obj/item/camera_assembly, - /obj/item/tank, - /obj/item/circuitboard, - /obj/item/stack/tile/light, - /obj/item/stack/ore/bluespace_crystal, - /obj/item/assembly/igniter, - /obj/item/light - ) - - //Item currently being held. - var/obj/item/gripped_item = null - -/obj/item/gripper_medical - name = "medical gripper" - desc = "A grasping tool used to help patients up once surgery is complete, or to substitute for hands in surgical operations." - icon = 'icons/obj/device.dmi' - icon_state = "gripper" - - -/obj/item/gripper_medical/afterattack(atom/target, mob/living/user, proximity, params) - if(!proximity || !target || !ishuman(target)) - return - var/mob/living/carbon/human/pickup_target = target - if(!IS_HORIZONTAL(pickup_target)) - return - pickup_target.AdjustSleeping(-10 SECONDS) - pickup_target.AdjustParalysis(-6 SECONDS) - pickup_target.AdjustStunned(-6 SECONDS) - pickup_target.AdjustWeakened(-6 SECONDS) - pickup_target.AdjustKnockDown(-6 SECONDS) - pickup_target.stand_up() - playsound(user.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - user.visible_message( \ - "[user] shakes [pickup_target] trying to wake [pickup_target.p_them()] up!",\ - "You shake [pickup_target] trying to wake [pickup_target.p_them()] up!",\ - ) - -/obj/item/gripper_engineering/Initialize(mapload) - . = ..() - can_hold = typecacheof(can_hold) - -/obj/item/gripper_engineering/ui_action_click(mob/user) - drop_gripped_item() - -/obj/item/gripper_engineering/attack_self(mob/user) - if(!gripped_item) - to_chat(user, "[src] is empty.") - return - gripped_item.attack_self(user) - -/obj/item/gripper_engineering/proc/drop_gripped_item(silent = FALSE) - if(!gripped_item) - return - if(!silent) - to_chat(loc, "You drop [gripped_item].") - gripped_item.forceMove(get_turf(src)) - gripped_item = null - -/obj/item/gripper_engineering/attack(mob/living/carbon/M, mob/living/carbon/user) - return - -/// Grippers are snowflakey so this is needed to to prevent forceMoving grippers after `if(!user.drop_item())` checks done in certain attackby's. // What does this even MEAN - GDN -/obj/item/gripper_engineering/forceMove(atom/destination) - return - -/obj/item/gripper_engineering/afterattack(atom/target, mob/living/user, proximity, params) - if(!target || !proximity) //Target is invalid or we are not adjacent. - return FALSE - - if(gripped_item) //Already have an item. - - //Pass the attack on to the target. This might delete/relocate gripped_item. - if(!target.attackby(gripped_item, user, params)) - // If the attackby didn't resolve or delete the target or gripped_item, afterattack - // (Certain things, such as mountable frames, rely on afterattack) - gripped_item?.afterattack(target, user, 1, params) - - //If gripped_item either didn't get deleted, or it failed to be transfered to its target - if(!gripped_item && length(contents)) - gripped_item = contents[1] - return FALSE - else if(gripped_item && !length(contents)) - gripped_item = null - - else if(isitem(target)) //Check that we're not pocketing a mob. - var/obj/item/I = target - if(is_type_in_typecache(I, can_hold)) // Make sure the item is something the gripper can hold - to_chat(user, "You collect [I].") - I.forceMove(src) - gripped_item = I - else - to_chat(user, "Your gripper cannot hold [target].") - return FALSE - - else if(istype(target,/obj/machinery/power/apc)) - var/obj/machinery/power/apc/A = target - if(A.opened) - if(A.cell) - - gripped_item = A.cell - - A.cell.add_fingerprint(user) - A.cell.update_icon() - A.cell.forceMove(src) - A.cell = null - - A.charging = APC_NOT_CHARGING - A.update_icon() - - user.visible_message("[user] removes the power cell from [A]!", "You remove the power cell.") - - else if(istype(target, /obj/machinery/cell_charger)) - var/obj/machinery/cell_charger/cell_charger = target - if(cell_charger.charging) - gripped_item = cell_charger.charging - cell_charger.charging.add_fingerprint(user) - cell_charger.charging.forceMove(src) - cell_charger.removecell() - - else if(istype(target, /obj/machinery/light)) - var/obj/machinery/light/light = target - var/obj/item/light/L = light.drop_light_tube() - L.forceMove(src) - gripped_item = L - user.visible_message("[user] removes the light from the fixture.", "You dislodge the light from the fixture.") - - return TRUE - /obj/item/matter_decompiler name = "matter decompiler" desc = "Eating trash, bits of glass, or other debris will replenish your stores." diff --git a/code/modules/mob/living/silicon/robot/robot_inventory.dm b/code/modules/mob/living/silicon/robot/robot_inventory.dm index 3e89737f9628..29cbd551747f 100644 --- a/code/modules/mob/living/silicon/robot/robot_inventory.dm +++ b/code/modules/mob/living/silicon/robot/robot_inventory.dm @@ -116,7 +116,7 @@ return 0 /mob/living/silicon/robot/drop_item() - var/obj/item/gripper_engineering/G = get_active_hand() + var/obj/item/gripper/G = get_active_hand() if(istype(G)) G.drop_gripped_item(silent = TRUE) return TRUE // The gripper is special because it has a normal item inside that we can drop. diff --git a/code/modules/mob/living/silicon/robot/robot_mob.dm b/code/modules/mob/living/silicon/robot/robot_mob.dm index 34ee687b95e7..201d684b363c 100644 --- a/code/modules/mob/living/silicon/robot/robot_mob.dm +++ b/code/modules/mob/living/silicon/robot/robot_mob.dm @@ -1698,7 +1698,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( /// Used in `robot.dm` when the user presses "Q" by default. /mob/living/silicon/robot/proc/on_drop_hotkey_press() - var/obj/item/gripper_engineering/G = get_active_hand() + var/obj/item/gripper/G = get_active_hand() if(istype(G) && G.gripped_item) G.drop_gripped_item() // if the active module is a gripper, try to drop its held item. else diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 58345615762d..352c05b28087 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -354,7 +354,7 @@ /obj/item/stack/medical/ointment/advanced/cyborg, /obj/item/stack/medical/splint/cyborg, /obj/item/stack/nanopaste/cyborg, - /obj/item/gripper_medical + /obj/item/gripper/medical ) malf_modules = list(/obj/item/gun/syringemalf) special_rechargables = list( @@ -362,6 +362,11 @@ /obj/item/gun/syringemalf ) +/obj/item/robot_module/medical/handle_death(mob/living/silicon/robot/R, gibbed) + var/obj/item/gripper/medical/G = locate(/obj/item/gripper/medical) in modules + if(G) + G.drop_gripped_item(silent = TRUE) + // Disable safeties on the borg's defib. /obj/item/robot_module/medical/emag_act(mob/user) . = ..() @@ -451,7 +456,7 @@ /obj/item/analyzer, /obj/item/geiger_counter/cyborg, /obj/item/holosign_creator/engineering, - /obj/item/gripper_engineering, + /obj/item/gripper/engineering, /obj/item/matter_decompiler, /obj/item/painter, /obj/item/areaeditor/blueprints/cyborg, @@ -471,7 +476,7 @@ special_rechargables = list(/obj/item/extinguisher, /obj/item/weldingtool/largetank/cyborg, /obj/item/gun/energy/emitter/cyborg) /obj/item/robot_module/engineering/handle_death(mob/living/silicon/robot/R, gibbed) - var/obj/item/gripper_engineering/G = locate(/obj/item/gripper_engineering) in modules + var/obj/item/gripper/engineering/G = locate(/obj/item/gripper/engineering) in modules if(G) G.drop_gripped_item(silent = TRUE) @@ -513,7 +518,8 @@ /obj/item/mop/advanced/cyborg, /obj/item/lightreplacer/cyborg, /obj/item/holosign_creator/janitor, - /obj/item/extinguisher/mini + /obj/item/extinguisher/mini, + /obj/item/melee/flyswatter ) emag_override_modules = list(/obj/item/reagent_containers/spray/cyborg_lube) emag_modules = list(/obj/item/reagent_containers/spray/cyborg_facid, /obj/item/malfbroom) @@ -603,7 +609,8 @@ /obj/item/reagent_containers/dropper/cyborg, /obj/item/lighter/zippo, /obj/item/storage/bag/tray/cyborg, - /obj/item/reagent_containers/drinks/shaker + /obj/item/reagent_containers/drinks/shaker, + /obj/item/gripper/service ) emag_override_modules = list(/obj/item/reagent_containers/drinks/cans/beer/sleepy_beer) emag_modules = list(/obj/item/restraints/handcuffs/cable/zipties/cyborg, /obj/item/instrument/guitar/cyborg) @@ -614,6 +621,10 @@ /obj/item/gun/projectile/shotgun/automatic/combat/cyborg ) +/obj/item/robot_module/butler/handle_death(mob/living/silicon/robot/R, gibbed) + var/obj/item/gripper/service/G = locate(/obj/item/gripper/service) in modules + if(G) + G.drop_gripped_item(silent = TRUE) // This is a special type of beer given when emagged, one sip and the target falls asleep. /obj/item/reagent_containers/drinks/cans/beer/sleepy_beer @@ -705,7 +716,7 @@ /obj/item/gun/projectile/revolver/grenadelauncher/multi/cyborg, /obj/item/card/emag, /obj/item/crowbar/cyborg/red, - /obj/item/pinpointer/operative + /obj/item/pinpointer/operative, ) // Sydicate medical cyborg module. @@ -738,7 +749,7 @@ /obj/item/stack/nanopaste/cyborg/syndicate, /obj/item/gun/medbeam, /obj/item/extinguisher/mini, - /obj/item/gripper_medical + /obj/item/gripper/medical, ) special_rechargables = list(/obj/item/extinguisher/mini) @@ -759,7 +770,7 @@ /obj/item/multitool/cyborg, /obj/item/t_scanner, /obj/item/analyzer, - /obj/item/gripper_engineering, + /obj/item/gripper/engineering, /obj/item/melee/energy/sword/cyborg, /obj/item/card/emag, /obj/item/borg_chameleon, @@ -845,7 +856,7 @@ /obj/item/wirecutters/cyborg/drone, /obj/item/multitool/cyborg/drone, /obj/item/lightreplacer/cyborg, - /obj/item/gripper_engineering, + /obj/item/gripper/engineering, /obj/item/matter_decompiler, /obj/item/reagent_containers/spray/cleaner/drone, /obj/item/soap, @@ -869,7 +880,7 @@ ) /obj/item/robot_module/drone/handle_death(mob/living/silicon/robot/R, gibbed) - var/obj/item/gripper_engineering/G = locate(/obj/item/gripper_engineering) in modules + var/obj/item/gripper/engineering/G = locate(/obj/item/gripper/engineering) in modules if(G) G.drop_gripped_item(silent = TRUE) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 2d6389a548fd..e1c52a5e3012 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -400,51 +400,63 @@ if(allowed(user) && !open && !emagged) locked = !locked to_chat(user, "Controls are now [locked ? "locked." : "unlocked."]") + return + if(emagged) + to_chat(user, "ERROR") + if(open) + to_chat(user, "Please close the access panel before locking it.") else - if(emagged) - to_chat(user, "ERROR") - if(open) - to_chat(user, "Please close the access panel before locking it.") - else - to_chat(user, "Access denied.") - else if(istype(W, /obj/item/paicard)) + to_chat(user, "Access denied.") + return + + if(istype(W, /obj/item/paicard)) if(paicard) to_chat(user, "A [paicard] is already inserted!") - else if(allow_pai && !key) - if(!locked && !open && !hijacked) - var/obj/item/paicard/card = W - if(card.pai && card.pai.mind) - if(!card.pai.ckey || jobban_isbanned(card.pai, ROLE_SENTIENT)) - to_chat(user, "[W] is unable to establish a connection to [src].") - return - if(!user.drop_item()) - return - W.forceMove(src) - paicard = card - user.visible_message("[user] inserts [W] into [src]!","You insert [W] into [src].") - paicard.pai.mind.transfer_to(src) - to_chat(src, "You sense your form change as you are uploaded into [src].") - bot_name = name - name = paicard.pai.name - faction = user.faction - add_attack_logs(user, paicard.pai, "Uploaded to [src.bot_name]") - else - to_chat(user, "[W] is inactive.") - else - to_chat(user, "The personality slot is locked.") - else + return + + if(!allow_pai || key) to_chat(user, "[src] is not compatible with [W].") - else if(istype(W, /obj/item/hemostat) && paicard) + return + + if(locked || open || hijacked) + to_chat(user, "The personality slot is locked.") + return + + var/obj/item/paicard/card = W + if(!card.pai?.mind) + to_chat(user, "[W] is inactive.") + return + + if(!card.pai.ckey || jobban_isbanned(card.pai, ROLE_SENTIENT)) + to_chat(user, "[W] is unable to establish a connection to [src].") + return + + if(!user.drop_item()) + return + + W.forceMove(src) + paicard = card + user.visible_message("[user] inserts [W] into [src]!", "You insert [W] into [src].") + paicard.pai.mind.transfer_to(src) + to_chat(src, "You sense your form change as you are uploaded into [src].") + bot_name = name + name = paicard.pai.name + faction = user.faction + add_attack_logs(user, paicard.pai, "Uploaded to [src.bot_name]") + return + + if(istype(W, /obj/item/hemostat) && paicard) if(open) to_chat(user, "Close the access panel before manipulating the personality slot!") - else - to_chat(user, "You attempt to pull [paicard] free...") - if(do_after(user, 30 * W.toolspeed, target = src)) - if(paicard) - user.visible_message("[user] uses [W] to pull [paicard] out of [bot_name]!","You pull [paicard] out of [bot_name] with [W].") - ejectpai(user) - else - return ..() + return + + to_chat(user, "You attempt to pull [paicard] free...") + if(do_after(user, 30 * W.toolspeed, target = src)) + if(paicard) + user.visible_message("[user] uses [W] to pull [paicard] out of [bot_name]!","You pull [paicard] out of [bot_name] with [W].") + ejectpai(user) + return + return ..() /mob/living/simple_animal/bot/screwdriver_act(mob/living/user, obj/item/I) if(user.a_intent == INTENT_HARM) diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm index 79e1145eee3c..eafab4122475 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/kangaroo.dm @@ -13,6 +13,7 @@ emote_hear = list("bark") maxHealth = 150 health = 150 + butcher_results = list(/obj/item/food/snacks/meat/kangaroo = 6) harm_intent_damage = 3 melee_damage_lower = 5 // avg damage 12.5 without kick, (12.5+12.5+60)/3=25 with kick melee_damage_upper = 20 diff --git a/code/modules/power/engines/singularity/singularity.dm b/code/modules/power/engines/singularity/singularity.dm index b00a030a16ea..de8de552f88e 100644 --- a/code/modules/power/engines/singularity/singularity.dm +++ b/code/modules/power/engines/singularity/singularity.dm @@ -21,15 +21,20 @@ move_resist = INFINITY //no, you don't get to push the singulo. Not even you OP wizard gateway statues var/consume_range = 0 //How many tiles out do we eat var/event_chance = 15 //Prob for event each tick - var/target = null //its target. moves towards the target if it has one var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing var/last_warning var/consumedSupermatter = FALSE //If the singularity has eaten a supermatter shard and can go to stage six var/warps_projectiles = TRUE var/obj/effect/warp_effect/supermatter/warp resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF + /// The target of the singularity. It will wander slowly towards this, and pick another target once it reaches it. + var/target = null + /// If there is a syndicate beacon, the singularity will move quickly towards it. + var/beacon_target = null /// Whether or not we've pinged ghosts var/isnt_shutting_down = FALSE + /// Init list that has all the areas that we can possibly move to, to reduce processing impact + var/list/all_possible_areas = list() /obj/singularity/Initialize(mapload, starting_energy = 50) . = ..() @@ -45,8 +50,9 @@ GLOB.singularities += src for(var/obj/machinery/power/singularity_beacon/singubeacon in GLOB.machines) if(singubeacon.active) - target = singubeacon + beacon_target = singubeacon break + all_possible_areas = findUnrestrictedEventArea() /obj/singularity/Destroy() STOP_PROCESSING(SSobj, src) @@ -323,6 +329,10 @@ return +/obj/singularity/proc/assign_target() + var/area/where_to_move = pick(all_possible_areas) // Grabs a random area that isn't restricted + var/turf/target_area_turfs = get_area_turfs(where_to_move) // Grabs the turfs from said area + target = pick(target_area_turfs) // Grabs a single turf from the entire list /obj/singularity/proc/move(force_move = 0) if(!move_self) @@ -330,11 +340,14 @@ var/movement_dir = pick(GLOB.alldirs - last_failed_movement) + if(get_turf(src) == target || !target) + assign_target() if(force_move) movement_dir = force_move - - if(target && prob(60)) - movement_dir = get_dir(src,target) //moves to a singulo beacon, if there is one + if(target && prob(20)) + movement_dir = get_dir(src, target) //moves to a random spot on the map + if(beacon_target && prob(60)) + movement_dir = get_dir(src, target) //moves to a singulo beacon, if there is one step(src, movement_dir) diff --git a/code/modules/power/engines/tesla/energy_ball.dm b/code/modules/power/engines/tesla/energy_ball.dm index 79274c669159..7e526501faf6 100644 --- a/code/modules/power/engines/tesla/energy_ball.dm +++ b/code/modules/power/engines/tesla/energy_ball.dm @@ -39,8 +39,6 @@ var/movement_dir /// Variable that defines whether it has a field generator close enough var/has_close_field = FALSE - /// Init list that has all the areas that we can possibly move to, to reduce processing impact - var/list/all_possible_areas = list() /// How many tiles do we move per movement step? var/steps_per_move = 8 diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 114fa03cfb6d..4c2220793e6d 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -439,7 +439,7 @@ /obj/item/borg/upgrade/modkit/aoe/projectile_strike(obj/item/projectile/kinetic/K, turf/target_turf, atom/target, obj/item/gun/energy/kinetic_accelerator/KA) if(stats_stolen) return - new /obj/effect/temp_visual/explosion/fast(target_turf) + new /obj/effect/temp_visual/pka_explosion(target_turf) if(turf_aoe) for(var/T in RANGE_TURFS(1, target_turf) - target_turf) if(ismineralturf(T) && !is_ancient_rock(T)) diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 1b299dd77fc0..77f5b742d2cb 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -74,11 +74,13 @@ weapon_weight = WEAPON_HEAVY w_class = WEIGHT_CLASS_BULKY ammo_type = list(/obj/item/ammo_casing/energy/disabler/smg) - burst_size = 2 - fire_delay = 2.5 shaded_charge = TRUE can_holster = FALSE +/obj/item/gun/energy/disabler/smg/Initialize(mapload) + . = ..() + AddComponent(/datum/component/automatic_fire, 0.15 SECONDS, allow_akimbo = FALSE) + /obj/item/gun/energy/disabler/cyborg name = "cyborg disabler" desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating." diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index d9879a9f46e9..c1d5716c5366 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -332,10 +332,15 @@ fire_sound = 'sound/weapons/gunshots/gunshot_lascarbine.ogg' magin_sound = 'sound/weapons/gun_interactions/batrifle_magin.ogg' magout_sound = 'sound/weapons/gun_interactions/batrifle_magout.ogg' + actions_types = list() can_suppress = FALSE - burst_size = 2 + burst_size = 1 execution_speed = 5 SECONDS +/obj/item/gun/projectile/automatic/lasercarbine/Initialize(mapload) + . = ..() + AddComponent(/datum/component/automatic_fire, 0.15 SECONDS, allow_akimbo = FALSE) + /obj/item/gun/projectile/automatic/lasercarbine/update_icon_state() icon_state = "lasercarbine[magazine ? "-[CEILING(get_ammo(0)/5, 1)*5]" : ""]" item_state = "lasercarbine[magazine ? "-[CEILING(get_ammo(0)/5, 1)*5]" : ""]" diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm index 9c50158c7b01..587e65bf0837 100644 --- a/code/modules/projectiles/guns/projectile/saw.dm +++ b/code/modules/projectiles/guns/projectile/saw.dm @@ -12,9 +12,14 @@ magin_sound = 'sound/weapons/gun_interactions/lmg_magin.ogg' magout_sound = 'sound/weapons/gun_interactions/lmg_magout.ogg' var/cover_open = FALSE + actions_types = list() can_suppress = FALSE - burst_size = 3 - fire_delay = 1 + burst_size = 1 + spread = 7 + +/obj/item/gun/projectile/automatic/l6_saw/Initialize(mapload) + . = ..() + AddComponent(/datum/component/automatic_fire, 0.2 SECONDS) /obj/item/gun/projectile/automatic/l6_saw/attack_self(mob/user) cover_open = !cover_open diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index 09ed6ed24ef4..645ed9f05243 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -21,7 +21,7 @@ /obj/item/stack/sheet/metal = list("iron" = 20), /obj/item/stack/rods = list("iron" = 10), /obj/item/stack/sheet/plasteel = list("iron" = 20, "plasma_dust" = 20), - /obj/item/stack/sheet/wood = list("carbon" = 20), + /obj/item/stack/sheet/wood = list("carbon" = 4), /obj/item/stack/sheet/glass = list("silicon" = 20), /obj/item/stack/sheet/rglass = list("silicon" = 20, "iron" = 20), /obj/item/stack/sheet/mineral/uranium = list("uranium" = 20), @@ -30,10 +30,6 @@ /obj/item/stack/sheet/mineral/silver = list("silver" = 20), /obj/item/stack/sheet/mineral/gold = list("gold" = 20), - /obj/item/grown/nettle/basic = list("wasabi" = 0), - /obj/item/grown/nettle/death = list("facid" = 0, "sacid" = 0), - /obj/item/grown/novaflower = list("capsaicin" = 0, "condensedcapsaicin" = 0), - // Blender Stuff /obj/item/food/snacks/grown/tomato = list("ketchup" = 0), /obj/item/food/snacks/grown/wheat = list("flour" = -5), @@ -56,7 +52,8 @@ /obj/item/food = list(), /obj/item/reagent_containers/pill = list(), /obj/item/reagent_containers/patch = list(), - /obj/item/clothing/mask/cigarette = list() + /obj/item/clothing/mask/cigarette = list(), + /obj/item/grown = list() ) var/list/juice_items = list ( @@ -439,21 +436,54 @@ var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume var/amount = special_blend[r_id] - if(amount <= 0) - if(amount == 0) - if(O.reagents.has_reagent("nutriment")) - beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("nutriment") * efficiency, space)) - O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) - if(O.reagents.has_reagent("plantmatter")) - beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("plantmatter") * efficiency, space)) - O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space)) - else - if(O.reagents.has_reagent("nutriment")) - beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("nutriment") * abs(amount) * efficiency), space)) - O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) - if(O.reagents.has_reagent("plantmatter")) - beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("plantmatter") * abs(amount) * efficiency), space)) - O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space)) + + if(amount == 0) + if(O.reagents.has_reagent("nutriment")) + beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("nutriment") * efficiency, space)) + O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) + if(O.reagents.has_reagent("plantmatter")) + beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("plantmatter") * efficiency, space)) + O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space)) + else if(amount < 0) + if(O.reagents.has_reagent("nutriment")) + beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("nutriment") * abs(amount) * efficiency), space)) + O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) + if(O.reagents.has_reagent("plantmatter")) + beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("plantmatter") * abs(amount) * efficiency), space)) + O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space)) + else + O.reagents.trans_id_to(beaker, r_id, min(amount, space)) + + if(beaker.reagents.holder_full()) + break + + O.reagents.trans_to(beaker, O.reagents.total_volume) + + if(!O.reagents.total_volume) + remove_object(O) + if(beaker.reagents.holder_full()) + return + // Inedible Plants + for(var/obj/item/grown/O in holdingitems) + var/list/special_blend = get_special_blend(O) + for(var/r_id in special_blend) + var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume + var/amount = special_blend[r_id] + + if(amount == 0) + if(O.reagents.has_reagent("nutriment")) + beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("nutriment") * efficiency, space)) + O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) + if(O.reagents.has_reagent("plantmatter")) + beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount("plantmatter") * efficiency, space)) + O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space)) + else if(amount < 0) + if(O.reagents.has_reagent("nutriment")) + beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("nutriment") * abs(amount) * efficiency), space)) + O.reagents.remove_reagent("nutriment", min(O.reagents.get_reagent_amount("nutriment"), space)) + if(O.reagents.has_reagent("plantmatter")) + beaker.reagents.add_reagent(r_id, min(round(O.reagents.get_reagent_amount("plantmatter") * abs(amount) * efficiency), space)) + O.reagents.remove_reagent("plantmatter", min(O.reagents.get_reagent_amount("plantmatter"), space)) else O.reagents.trans_id_to(beaker, r_id, min(amount, space)) @@ -488,26 +518,6 @@ if(beaker.reagents.holder_full()) return - // Plants - for(var/obj/item/grown/O in holdingitems) - var/list/special_blend = get_special_blend(O) - for(var/r_id in special_blend) - var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume - var/amount = special_blend[r_id] - - if(amount == 0) - if(O.reagents.has_reagent(r_id)) - beaker.reagents.add_reagent(r_id, min(O.reagents.get_reagent_amount(r_id) * efficiency, space)) - else - beaker.reagents.add_reagent(r_id, min(amount * efficiency, space)) - - if(beaker.reagents.holder_full()) - break - - remove_object(O) - if(beaker.reagents.holder_full()) - return - // Slime Extracts for(var/obj/item/slime_extract/O in holdingitems) var/space = beaker.reagents.maximum_volume - beaker.reagents.total_volume diff --git a/code/modules/reagents/chemistry/reagents/alcohol.dm b/code/modules/reagents/chemistry/reagents/alcohol.dm index f5fc09e778da..fa8761a520a7 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol.dm @@ -163,7 +163,7 @@ drink_name = "Glass of Mojito" drink_desc = "Fresh from Spesscuba." taste_description = "mojito" - goal_difficulty = REAGENT_GOAL_EASY + goal_difficulty = REAGENT_GOAL_NORMAL /datum/reagent/consumable/ethanol/vodka name = "Vodka" @@ -776,7 +776,7 @@ drink_name = "Demons Blood" drink_desc = "Just looking at this thing makes the hair at the back of your neck stand up." taste_description = "evil" - goal_difficulty = REAGENT_GOAL_EASY + goal_difficulty = REAGENT_GOAL_HARD /datum/reagent/consumable/ethanol/vodkatonic name = "Vodka and Tonic" @@ -1529,7 +1529,7 @@ drink_desc = "A sawed-off cola bottle filled with Fernet Cola. You can hear cuarteto music coming from the inside." taste_description = "low class heaven" remove_nutrition = 1 - goal_difficulty = REAGENT_GOAL_EASY + goal_difficulty = REAGENT_GOAL_EXCESSIVE /datum/reagent/consumable/ethanol/gimlet name = "Gimlet" @@ -1553,7 +1553,7 @@ drink_name = "Sidecar" drink_desc = "You can smell the citrus from here!" taste_description = "smooth cognac and tart citrus" - goal_difficulty = REAGENT_GOAL_HARD + goal_difficulty = REAGENT_GOAL_EASY /datum/reagent/consumable/ethanol/whiskey_sour name = "Whiskey Sour" @@ -1577,7 +1577,7 @@ drink_name = "Mint Julep" drink_desc = "A dainty glass of whiskey and mint on the rocks. Perfect for summer!" taste_description = "sweet and cooling mint" - goal_difficulty = REAGENT_GOAL_EASY + goal_difficulty = REAGENT_GOAL_NORMAL /datum/reagent/consumable/ethanol/pina_colada name = "Pina Colada" diff --git a/code/modules/reagents/chemistry/reagents/drugs.dm b/code/modules/reagents/chemistry/reagents/drugs.dm index ee4a091a22f5..cf4d29a17c31 100644 --- a/code/modules/reagents/chemistry/reagents/drugs.dm +++ b/code/modules/reagents/chemistry/reagents/drugs.dm @@ -453,7 +453,7 @@ taste_description = "WAAAAGH" var/bonus_damage = 2 goal_department = "Science" - goal_difficulty = REAGENT_GOAL_HARD + goal_difficulty = REAGENT_GOAL_EXCESSIVE /datum/reagent/bath_salts/on_mob_add(mob/living/L) if(ishuman(L)) diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm index 0c1b82d9d0c0..eac48e6f3904 100644 --- a/code/modules/reagents/chemistry/reagents/medicine.dm +++ b/code/modules/reagents/chemistry/reagents/medicine.dm @@ -1508,7 +1508,8 @@ metabolization_rate = 0.5 harmless = FALSE taste_description = "2 minutes of suffering" - var/list/stimulant_list = list("methamphetamine", "crank", "bath_salts", "stimulative_agent", "stimulants", "mephedrone") + process_flags = ORGANIC | SYNTHETIC + var/list/stimulant_list = list("methamphetamine", "crank", "bath_salts", "stimulative_agent", "stimulants", "mephedrone", "ultralube", "surge", "surge_plus", "combatlube") /datum/reagent/medicine/nanocalcium/on_mob_life(mob/living/carbon/human/M) var/update_flags = STATUS_UPDATE_NONE @@ -1521,7 +1522,7 @@ if(1 to 19) M.AdjustJitter(8 SECONDS) if(prob(10)) - to_chat(M, "Your skin feels hot and your veins are on fire!") + to_chat(M, "You feel great pain from the nanomachines inside you!") update_flags |= M.adjustFireLoss(1 * REAGENTS_EFFECT_MULTIPLIER, FALSE) for(var/datum/reagent/R in M.reagents.reagent_list) if(stimulant_list.Find(R.id)) @@ -1549,7 +1550,10 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M for(var/obj/item/organ/internal/I in M.internal_organs) // 60 healing to all internal organs. - I.heal_internal_damage(4) + I.heal_internal_damage(4, TRUE) + if(istype(I, /obj/item/organ/internal/cyberimp)) // Fix disabled implants like the ipc charging implant + var/obj/item/organ/internal/cyberimp/crit = I + crit.crit_fail = FALSE if(H.blood_volume < BLOOD_VOLUME_NORMAL * 0.7)// If below 70% blood, regenerate 150 units total H.blood_volume += 10 for(var/datum/disease/critical/heart_failure/HF in H.viruses) @@ -1559,8 +1563,8 @@ if(M.health < 40) update_flags |= M.adjustOxyLoss(-5 * REAGENTS_EFFECT_MULTIPLIER, FALSE) update_flags |= M.adjustToxLoss(-1 * REAGENTS_EFFECT_MULTIPLIER, FALSE) - update_flags |= M.adjustBruteLoss(-3 * REAGENTS_EFFECT_MULTIPLIER, FALSE) - update_flags |= M.adjustFireLoss(-3 * REAGENTS_EFFECT_MULTIPLIER, FALSE) + update_flags |= M.adjustBruteLoss(-3 * REAGENTS_EFFECT_MULTIPLIER, FALSE, robotic = TRUE) + update_flags |= M.adjustFireLoss(-3 * REAGENTS_EFFECT_MULTIPLIER, FALSE, robotic = TRUE) else if(prob(25)) to_chat(M, "Your skin feels like it is ripping apart and your veins are on fire!") //It is experimental and does cause scars, after all. diff --git a/code/modules/reagents/chemistry/reagents_holder.dm b/code/modules/reagents/chemistry/reagents_holder.dm index 413b54262bee..a1319d355e83 100644 --- a/code/modules/reagents/chemistry/reagents_holder.dm +++ b/code/modules/reagents/chemistry/reagents_holder.dm @@ -810,6 +810,15 @@ /datum/reagents/proc/get_reagent(type) . = locate(type) in reagent_list +/datum/reagents/proc/get_reagent_by_id(id) + var/list/cached_reagents = reagent_list + for(var/A in cached_reagents) + var/datum/reagent/R = A + if(R.id == id) + return R + + return + /datum/reagents/proc/remove_all_type(reagent_type, amount, strict = FALSE, safety = TRUE) // Removes all reagent of X type. @strict set to 1 determines whether the childs of the type are included. if(!isnum(amount)) return TRUE diff --git a/code/modules/research/designs/janitorial_designs.dm b/code/modules/research/designs/janitorial_designs.dm index 4743fb63a17f..f744f2d02b34 100644 --- a/code/modules/research/designs/janitorial_designs.dm +++ b/code/modules/research/designs/janitorial_designs.dm @@ -50,3 +50,33 @@ materials = list(MAT_METAL = 1500, MAT_SILVER = 150, MAT_GLASS = 6000, MAT_BLUESPACE = 300) build_path = /obj/item/lightreplacer/bluespace category = list("Janitorial") + +/datum/design/abductor_mop + name = "Alien Mop" + desc = "An advanced mop obtained through Abductor technology." + id = "alien_mop" + req_tech = list("materials" = 5, "engineering" = 5, "abductor" = 3) + build_type = PROTOLATHE + materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500, MAT_DIAMOND = 1000) + build_path = /obj/item/mop/advanced/abductor + category = list("Janitorial") + +/datum/design/abductor_light_replacer + name = "Alien Light Replacer" + desc = "An advanced light replacer obtained through Abductor technology." + id = "alien_light_replacer" + req_tech = list("bluespace" = 7, "materials" = 5, "engineering" = 5, "abductor" = 3) + build_type = PROTOLATHE + materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500, MAT_DIAMOND = 1000) + build_path = /obj/item/lightreplacer/bluespace/abductor + category = list("Janitorial") + +/datum/design/abductor_flyswatter + name = "Alien Flyswatter" + desc = "An advanced flyswatter obtained through Abductor technology." + id = "alien_flyswatter" + req_tech = list("combat" = 5, "abductor" = 1) + build_type = PROTOLATHE + materials = list(MAT_METAL = 2000, MAT_SILVER = 1500, MAT_PLASMA = 500, MAT_TITANIUM = 1500, MAT_DIAMOND = 1000) + build_path = /obj/item/melee/flyswatter/abductor + category = list("Janitorial") diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 1de90e4c64d8..19fc64619885 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -793,18 +793,18 @@ category = list("Exosuit Equipment") /datum/design/mech_ccw_armor - name = "Exosuit Module (Reactive Armor Booster Module)" + name = "Exosuit Module (Melee Armor Booster Module)" desc = "Exosuit-mounted armor booster." id = "mech_ccw_armor" build_type = MECHFAB - req_tech = list("materials" = 5, "combat" = 4) + req_tech = list("materials" = 5, "combat" = 5, "engineering"=3) build_path = /obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster materials = list(MAT_METAL=20000,MAT_SILVER=5000) construction_time = 10 SECONDS category = list("Exosuit Equipment") /datum/design/mech_proj_armor - name = "Exosuit Module (Reflective Armor Booster Module)" + name = "Exosuit Module (Ranged Armor Booster Module)" desc = "Exosuit-mounted armor booster." id = "mech_proj_armor" build_type = MECHFAB @@ -814,6 +814,17 @@ construction_time = 10 SECONDS category = list("Exosuit Equipment") +/datum/design/mech_armor_plate + name = "Exosuit Mining Armor Plate" + desc = "This piece of metal can be attached to the mech itself, enhancing its protective characteristics. Unfortunately, only working class exosuits have notches for such armor." + id = "mech_plate_armor" + build_type = MECHFAB + req_tech = list("materials" = 5, "combat" = 5, "engineering" = 3) + build_path = /obj/item/stack/sheet/animalhide/armor_plate + materials = list(MAT_METAL = 20000, MAT_TITANIUM = 5000) + construction_time = 10 SECONDS + category = list("Exosuit Equipment") + /datum/design/mech_repair_droid name = "Exosuit Module (Repair Droid Module)" desc = "Automated Repair Droid. BEEP BOOP" @@ -1080,6 +1091,16 @@ construction_time = 12 SECONDS category = list("Cyborg Upgrade Modules") +/datum/design/borg_upgrade_abductor_jani + name = "Cyborg Upgrade (Abductor Janitorial Equipment)" + id = "borg_upgade_abductor_jani" + build_type = MECHFAB + build_path = /obj/item/borg/upgrade/abductor_jani + req_tech = list("biotech" = 7, "materials" = 7, "abductor" = 3) + materials = list(MAT_METAL = 10000, MAT_SILVER = 7500, MAT_PLASMA = 2500, MAT_TITANIUM = 7500, MAT_DIAMOND = 5000) //Base abductor jani tools *5 + construction_time = 12 SECONDS + category = list("Cyborg Upgrade Modules") + /datum/design/borg_upgrade_lavaproof name = "Cyborg Upgrade (Lavaproof Chassis)" id = "borg_upgrade_lavaproof" diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index ff3c7b741b4f..b929547aa27e 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -416,7 +416,7 @@ /datum/design/cyberimp_toolset_abductor name = "Abductor Toolset Implant" - desc = "An alien toolset, designed to be installed on subject's arm." + desc = "An alien toolset, designed to be installed on the subject's arm." id = "ci-hacking" req_tech = list("materials" = 6, "engineering" = 6, "plasmatech" = 6, "abductor" = 4) build_type = PROTOLATHE | MECHFAB @@ -425,6 +425,17 @@ build_path = /obj/item/organ/internal/cyberimp/arm/toolset_abductor category = list("Medical") +/datum/design/cyberimp_janitorial_abductor + name = "Abductor Janitorial Toolset Implant" + desc = "An alien janitorial toolset, designed to be installed on the subject's arm." + id = "ci-jani-abductor" + req_tech = list("materials" = 6, "engineering" = 6, "biotech" = 6, "abductor" = 3) + build_type = PROTOLATHE | MECHFAB + materials = list(MAT_METAL = 20000, MAT_SILVER = 10000, MAT_PLASMA = 9000, MAT_TITANIUM = 8000, MAT_DIAMOND = 8000) + construction_time = 20 SECONDS + build_path = /obj/item/organ/internal/cyberimp/arm/janitorial_abductor + category = list("Medical") + /datum/design/cyberimp_jani_hud name = "Janitor HUD Implant" desc = "These cybernetic eye implants will display a filth HUD over everything you see. Wiggle eyes to control." diff --git a/code/modules/ruins/syndicate_space_base.dm b/code/modules/ruins/syndicate_space_base.dm index bd51a8c30717..bcae22e6d6c5 100644 --- a/code/modules/ruins/syndicate_space_base.dm +++ b/code/modules/ruins/syndicate_space_base.dm @@ -61,6 +61,7 @@ ) /datum/outfit/spacebase_syndicate/post_equip(mob/living/carbon/human/H) + . = ..() H.faction |= "syndicate" var/random_name = random_name(pick(MALE,FEMALE), H.dna.species.name) H.rename_character(H.real_name, random_name) diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index 6fdcf267a140..9853fc4e78bc 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -294,6 +294,7 @@ var/msg = "
---[station_time_timestamp()]---

" var/list/credit_changes = list() + var/list/department_messages = list() for(var/datum/economy/line_item/item in manifest.line_items) if(!credit_changes[item.account]) credit_changes[item.account] = 0 @@ -306,6 +307,13 @@ else msg += "[item.account.account_name] [item.credits]: [item.reason]
" + if(item.requests_console_department) + if(!department_messages[item.requests_console_department]) + department_messages[item.requests_console_department] = list() + if(!department_messages[item.requests_console_department][item.reason]) + department_messages[item.requests_console_department][item.reason] = 0 + department_messages[item.requests_console_department][item.reason]++ + for(var/datum/money_account/account in credit_changes) if(account.account_type == ACCOUNT_TYPE_DEPARTMENT) SSblackbox.record_feedback("tally", "cargo profits", credit_changes[account], "[account.account_name]") @@ -317,6 +325,15 @@ else GLOB.station_money_database.charge_account(account, -credit_changes[account], "Supply Shuttle Fine", "Central Command Supply Master", allow_overdraft = TRUE, supress_log = FALSE) + for(var/department in department_messages) + var/list/rc_message = list() + for(var/message_piece in department_messages[department]) + var/count = "" + if(department_messages[department][message_piece] > 1) + count = " (x[department_messages[department][message_piece]])" + rc_message += "[message_piece][count]" + send_requests_console_message(rc_message, "Central Command", department, "Stamped with the Central Command rubber stamp.", "Verified by the Central Command receiving department.", RQ_NORMALPRIORITY) + SSeconomy.centcom_message += "[msg]
" manifest = new @@ -802,6 +819,7 @@ /datum/economy/line_item var/datum/money_account/account + var/requests_console_department var/credits var/reason var/zero_is_good = FALSE diff --git a/code/modules/station_goals/secondary/botany/kudzu_goal.dm b/code/modules/station_goals/secondary/botany/kudzu_goal.dm index 68387c00754d..d77445775a1d 100644 --- a/code/modules/station_goals/secondary/botany/kudzu_goal.dm +++ b/code/modules/station_goals/secondary/botany/kudzu_goal.dm @@ -65,6 +65,7 @@ item.account = GLOB.station_money_database.get_account_by_department(DEPARTMENT_SERVICE) item.credits = 0 item.reason = "[AM] does not have the right traits." + item.requests_console_department = "Hydroponics" manifest.line_items += item return COMSIG_CARGO_SELL_WRONG @@ -79,27 +80,12 @@ update_item.credits = 0 update_item.zero_is_good = TRUE update_item.reason = "Received [sent_this_shipment] useful samples of kudzu seeds." + update_item.requests_console_department = "Hydroponics" manifest.line_items += update_item if(sent < needed) return - var/datum/economy/line_item/supply_item = new - supply_item.account = SSeconomy.cargo_account - supply_item.credits = SSeconomy.credits_per_kudzu_goal / 3 - supply_item.reason = "Secondary goal complete: [needed] samples of kudzu seeds." - manifest.line_items += supply_item - - var/datum/economy/line_item/department_item = new - department_item.account = GLOB.station_money_database.get_account_by_department(DEPARTMENT_SERVICE) - department_item.credits = SSeconomy.credits_per_kudzu_goal / 3 - department_item.reason = "Secondary goal complete: [needed] samples of kudzu seeds." - manifest.line_items += department_item - - var/datum/economy/line_item/personal_item = new - personal_item.account = personal_account || department_item.account - personal_item.credits = SSeconomy.credits_per_kudzu_goal / 3 - personal_item.reason = "Secondary goal complete: [needed] samples of kudzu seeds." - manifest.line_items += personal_item + three_way_reward(manifest, "Hydroponics", GLOB.station_money_database.get_account_by_department(DEPARTMENT_SERVICE), SSeconomy.credits_per_kudzu_goal, "Secondary goal complete: [needed] samples of kudzu seeds.") return TRUE diff --git a/code/modules/station_goals/secondary/kitchen/random_bulk_food.dm b/code/modules/station_goals/secondary/kitchen/random_bulk_food.dm index 7580945d7113..cc3296af2f17 100644 --- a/code/modules/station_goals/secondary/kitchen/random_bulk_food.dm +++ b/code/modules/station_goals/secondary/kitchen/random_bulk_food.dm @@ -13,6 +13,8 @@ var/obj/item/food/snacks/candidate = S if(initial(candidate.goal_difficulty) == FOOD_GOAL_SKIP) continue + if(initial(candidate.goal_difficulty) == FOOD_GOAL_EXCESSIVE) + continue valid_food += candidate if(!valid_food) @@ -83,6 +85,7 @@ update_item.credits = 0 update_item.zero_is_good = TRUE update_item.reason = "Received [sent_this_shipment] servings of [initial(food_type.name)]." + update_item.requests_console_department = "Kitchen" manifest.line_items += update_item if(sent < needed) diff --git a/code/modules/station_goals/secondary/kitchen/variety_food.dm b/code/modules/station_goals/secondary/kitchen/variety_food.dm new file mode 100644 index 000000000000..66144ba24779 --- /dev/null +++ b/code/modules/station_goals/secondary/kitchen/variety_food.dm @@ -0,0 +1,117 @@ +/datum/station_goal/secondary/variety_food + name = "Variety of Food" + progress_type = /datum/secondary_goal_progress/variety_food + department = "Kitchen" + abstract = FALSE + /// How many different types of food are needed. + var/different_types = 10 + /// How many of each food type are needed. + var/amount_per = 3 + var/department_account + var/generic_name_plural = "dishes" + var/reward + +/datum/station_goal/secondary/variety_food/randomize_params() + ..() + department_account = GLOB.station_money_database.get_account_by_department(DEPARTMENT_SERVICE) + report_message = "We're holding a fundraising banquet, and we need a suitable spread of food for it. Send us at least [amount_per] servings of [different_types] different dishes." + +/datum/station_goal/secondary/variety_food/Initialize(requester_account) + reward = SSeconomy.credits_per_variety_food_goal + ..() + admin_desc = "[amount_per] units of [different_types] [generic_name_plural]" + +/datum/secondary_goal_progress/variety_food + var/list/foods_sent = list() + var/department + var/needed + var/amount_per + var/department_account + var/reward + var/generic_name_plural + +/datum/secondary_goal_progress/variety_food/configure(datum/station_goal/secondary/variety_food/goal) + ..() + department = goal.department + needed = goal.different_types + amount_per = goal.amount_per + department_account = goal.department_account + reward = goal.reward + generic_name_plural = goal.generic_name_plural + +/datum/secondary_goal_progress/variety_food/Copy() + var/datum/secondary_goal_progress/variety_food/copy = ..() + copy.foods_sent = foods_sent.Copy() + copy.department = department + copy.needed = needed + copy.amount_per = amount_per + // These ones aren't really needed in the intended use case, they're + // just here in case someone uses this method somewhere else. + copy.department_account = department_account + copy.reward = reward + copy.generic_name_plural = generic_name_plural + return copy + +/datum/secondary_goal_progress/variety_food/update(obj/item/food/food, datum/economy/cargo_shuttle_manifest/manifest = null) + // Not in a matching personal crate? Ignore. + if(!check_personal_crate(food)) + return + + // Not food? Ignore. + if(!istype(food)) + return + + // No easy foods allowed. + if(food.goal_difficulty == FOOD_GOAL_SKIP) + if(!manifest) + return COMSIG_CARGO_SELL_WRONG + SSblackbox.record_feedback("nested tally", "secondary goals", 1, list(goal_name, "boring foods")) + var/datum/economy/line_item/item = new + item.account = department_account + item.credits = 0 + item.reason = "We don't need [food.name]. Send something better." + item.requests_console_department = "Kitchen" + manifest.line_items += item + return COMSIG_CARGO_SELL_WRONG + + if(foods_sent[food.type] >= amount_per) + if(!manifest) + return COMSIG_CARGO_SELL_WRONG + SSblackbox.record_feedback("nested tally", "secondary goals", 1, list(goal_name, "repeat foods")) + var/datum/economy/line_item/item = new + item.account = department_account + item.credits = 0 + item.reason = "You already sent us enough [food.name]." + item.requests_console_department = "Kitchen" + manifest.line_items += item + return COMSIG_CARGO_SELL_WRONG + + if(!foods_sent[food.type]) + foods_sent[food.type] = 0 + foods_sent[food.type]++ + + if(!manifest) + return COMSIG_CARGO_SELL_PRIORITY + SSblackbox.record_feedback("nested tally", "secondary goals", 1, list(goal_name, "valid foods")) + SSblackbox.record_feedback("nested tally", "secondary goals", 1, list(goal_name, "foods", initial(food.name))) + var/datum/economy/line_item/item = new() + item.account = department_account + item.credits = 0 + item.reason = "Received [initial(food.name)]." + item.zero_is_good = TRUE + item.requests_console_department = "Kitchen" + manifest.line_items += item + return COMSIG_CARGO_SELL_PRIORITY + +/datum/secondary_goal_progress/variety_food/check_complete(datum/economy/cargo_shuttle_manifest/manifest) + var/complete_foods = 0 + for(var/food_type in foods_sent) + if(foods_sent[food_type] >= amount_per) + complete_foods++ + SSblackbox.record_feedback("nested tally", "secondary goals", 1, list(goal_name, "complete foods")) + + if(complete_foods < needed) + return FALSE + + three_way_reward(manifest, department, department_account, reward, "Secondary goal complete: [needed] different [generic_name_plural].") + return TRUE diff --git a/code/modules/station_goals/secondary/random_bulk_reagent.dm b/code/modules/station_goals/secondary/random_bulk_reagent.dm index 8dc35f4fd58f..f1b6e9fc17a2 100644 --- a/code/modules/station_goals/secondary/random_bulk_reagent.dm +++ b/code/modules/station_goals/secondary/random_bulk_reagent.dm @@ -17,6 +17,10 @@ if(initial(candidate.goal_department) != department) continue if(initial(candidate.goal_difficulty) == REAGENT_GOAL_SKIP) + // Too easy, don't want. + continue + if(initial(candidate.goal_difficulty) == REAGENT_GOAL_EXCESSIVE) + // Too hard, don't ask for. continue valid_reagents += candidate @@ -84,6 +88,7 @@ item.account = department_account item.credits = 0 item.reason = "Received [amount] units of [initial(reagent_type.name)]." + item.requests_console_department = department item.zero_is_good = TRUE manifest.line_items += item diff --git a/code/modules/station_goals/secondary/science/random_ripley.dm b/code/modules/station_goals/secondary/science/random_ripley.dm index 113b5c4601b7..33d63b6cf32b 100644 --- a/code/modules/station_goals/secondary/science/random_ripley.dm +++ b/code/modules/station_goals/secondary/science/random_ripley.dm @@ -70,8 +70,8 @@ extra_item.account = SSeconomy.cargo_account extra_item.credits = SSeconomy.credits_per_mech extra_item.reason = "We already got the mech we needed, but we'll take this one at the usual price." + extra_item.requests_console_department = "Robotics" manifest.line_items += extra_item - send_requests_console_message(extra_item.reason, "Central Command", "Robotics", "Stamped with the Central Command rubber stamp.", null, RQ_NORMALPRIORITY) return COMSIG_CARGO_SELL_PRIORITY | COMSIG_CARGO_IS_SECURED var/remaining_needs = modules.Copy() @@ -89,9 +89,9 @@ var/datum/economy/line_item/wrong_item = new wrong_item.account = SSeconomy.cargo_account wrong_item.credits = SSeconomy.credits_per_mech - wrong_item.reason = "That's not the equipment we needed, but it's still a mech" + wrong_item.reason = "That's not the equipment we needed, but it's still a mech, so we'll take it at the usual price." + wrong_item.requests_console_department = "Robotics" manifest.line_items += wrong_item - send_requests_console_message(wrong_item.reason + ", so we sent the usual amount to your supply account.", "Central Command", "Robotics", "Stamped with the Central Command rubber stamp.", null, RQ_NORMALPRIORITY) return COMSIG_CARGO_SELL_PRIORITY | COMSIG_CARGO_IS_SECURED sent = TRUE diff --git a/code/modules/station_goals/secondary/secondary_goal_tracker.dm b/code/modules/station_goals/secondary/secondary_goal_tracker.dm index 498c42159205..edee8140029e 100644 --- a/code/modules/station_goals/secondary/secondary_goal_tracker.dm +++ b/code/modules/station_goals/secondary/secondary_goal_tracker.dm @@ -129,6 +129,6 @@ personal_item.account = personal_account || department_account personal_item.credits = reward / 3 personal_item.reason = message + personal_item.requests_console_department = department manifest.line_items += personal_item - send_requests_console_message(message, "Central Command", department, "Stamped with the Central Command rubber stamp.", null, RQ_NORMALPRIORITY) diff --git a/code/modules/station_goals/secondary/variety_reagent.dm b/code/modules/station_goals/secondary/variety_reagent.dm index 19cff7feb5b2..14665b20a8c6 100644 --- a/code/modules/station_goals/secondary/variety_reagent.dm +++ b/code/modules/station_goals/secondary/variety_reagent.dm @@ -68,8 +68,8 @@ item.account = department_account item.credits = 0 item.reason = "That [reagent.name] seems to be mixed with something else. Send it by itself, please." + item.requests_console_department = department manifest.line_items += item - send_requests_console_message(item.reason, "Central Command", department, "Stamped with the Central Command rubber stamp.", null, RQ_NORMALPRIORITY) return COMSIG_CARGO_SELL_WRONG // No easy reagents allowed. @@ -81,8 +81,8 @@ item.account = department_account item.credits = 0 item.reason = "We don't need [reagent.name]. Send something better." + item.requests_console_department = department manifest.line_items += item - send_requests_console_message(item.reason, "Central Command", department, "Stamped with the Central Command rubber stamp.", null, RQ_NORMALPRIORITY) return COMSIG_CARGO_SELL_WRONG // Make sure there's enough. @@ -94,8 +94,8 @@ item.account = department_account item.credits = 0 item.reason = "That batch of [reagent.name] was too small; send at least [amount_per] units." + item.requests_console_department = department manifest.line_items += item - send_requests_console_message(item.reason, "Central Command", department, "Stamped with the Central Command rubber stamp.", null, RQ_NORMALPRIORITY) return COMSIG_CARGO_SELL_WRONG if(reagents_sent[reagent.id]) @@ -106,8 +106,8 @@ item.account = department_account item.credits = 0 item.reason = "You already sent us [reagent.name]." + item.requests_console_department = department manifest.line_items += item - send_requests_console_message(item.reason, "Central Command", department, "Stamped with the Central Command rubber stamp.", null, RQ_NORMALPRIORITY) return COMSIG_CARGO_SELL_WRONG reagents_sent[reagent.id] = TRUE @@ -120,9 +120,9 @@ item.account = department_account item.credits = 0 item.reason = "Received [initial(reagent.name)]." + item.requests_console_department = department item.zero_is_good = TRUE manifest.line_items += item - send_requests_console_message(item.reason, "Central Command", department, "Stamped with the Central Command rubber stamp.", null, RQ_NORMALPRIORITY) return COMSIG_CARGO_SELL_PRIORITY /datum/secondary_goal_progress/variety_reagent/check_complete(datum/economy/cargo_shuttle_manifest/manifest) diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm index 2c7806b9dcea..f28c4636559f 100644 --- a/code/modules/surgery/organs/augments_arms.dm +++ b/code/modules/surgery/organs/augments_arms.dm @@ -250,6 +250,17 @@ /obj/item/organ/internal/cyberimp/arm/toolset_abductor/l parent_organ = "l_arm" +/obj/item/organ/internal/cyberimp/arm/janitorial_abductor + name = "alien janitorial toolset implant" + desc = "A set of alien janitorial tools, designed to be installed on subject's arm." + origin_tech = "materials=5;engineering=5;biotech=5;powerstorage=4;abductor=3" + contents = newlist(/obj/item/mop/advanced/abductor, /obj/item/soap/syndie/abductor, /obj/item/lightreplacer/bluespace/abductor, /obj/item/holosign_creator/janitor, /obj/item/melee/flyswatter/abductor, /obj/item/reagent_containers/spray/cleaner/safety/abductor) + action_icon = list(/datum/action/item_action/organ_action/toggle = 'icons/obj/abductor.dmi') + action_icon_state = list(/datum/action/item_action/organ_action/toggle = "janibelt_abductor") + +/obj/item/organ/internal/cyberimp/arm/janitorial_abductor/l + parent_organ = "l_arm" + /obj/item/organ/internal/cyberimp/arm/esword name = "arm-mounted energy blade" desc = "An illegal, and highly dangerous cybernetic implant that can project a deadly blade of concentrated enregy." diff --git a/code/modules/surgery/organs/organ_extractor.dm b/code/modules/surgery/organs/organ_extractor.dm index 02f54d36d631..efa581b8bc3e 100644 --- a/code/modules/surgery/organs/organ_extractor.dm +++ b/code/modules/surgery/organs/organ_extractor.dm @@ -140,6 +140,9 @@ if(replaced) //Lets not destroy someones brain fully by putting someone elses brain in that slot. replaced.remove(C) replaced.forceMove(get_turf(src)) + if(istype(storedorgan, /obj/item/organ/internal/heart) && ((/obj/item/organ/internal/cyberimp/brain/sensory_enhancer in C.internal_organs) || C.reagents.addiction_threshold_accumulated[/datum/reagent/mephedrone])) + storedorgan.damage = 40 // Damage the heart so you can't endlessly OD for cheap easily. + to_chat(user, "CAUTION: Crystalized mephedrone has bounced off the drill into [storedorgan], causing internal damage!") storedorgan.insert(C) playsound(get_turf(C), 'sound/weapons/circsawhit.ogg', 50, TRUE) storedorgan = null diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index fbc2ef271303..6f22fb035011 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -216,7 +216,7 @@ if(accept_hand) if(!tool) success = TRUE - if(isrobot(user) && istype(tool, /obj/item/gripper_medical)) + if(isrobot(user) && istype(tool, /obj/item/gripper/medical)) success = TRUE if(accept_any_item) diff --git a/config/example/config.toml b/config/example/config.toml index ed561a319583..ea3a81652741 100644 --- a/config/example/config.toml +++ b/config/example/config.toml @@ -179,7 +179,7 @@ ipc_screens = [ # Enable/disable the database on a whole sql_enabled = false # SQL version. If this is a mismatch, round start will be delayed -sql_version = 552206 +sql_version = 562206 # SQL server address. Can be an IP or DNS name sql_address = "127.0.0.1" # SQL server port diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index 7746a3d06d03..ca835f752889 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/mecha/mecha.dmi b/icons/mecha/mecha.dmi index 9d5db73c394c..6c058ef94167 100644 Binary files a/icons/mecha/mecha.dmi and b/icons/mecha/mecha.dmi differ diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi index f8626a6d6bb1..d0d67fc81ae3 100644 Binary files a/icons/mecha/mecha_equipment.dmi and b/icons/mecha/mecha_equipment.dmi differ diff --git a/icons/mob/inhands/equipment/custodial_lefthand.dmi b/icons/mob/inhands/equipment/custodial_lefthand.dmi index 884b23465cb9..c4f2e189a210 100644 Binary files a/icons/mob/inhands/equipment/custodial_lefthand.dmi and b/icons/mob/inhands/equipment/custodial_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/custodial_righthand.dmi b/icons/mob/inhands/equipment/custodial_righthand.dmi index 8ddb7703cf66..4db565e94ba1 100644 Binary files a/icons/mob/inhands/equipment/custodial_righthand.dmi and b/icons/mob/inhands/equipment/custodial_righthand.dmi differ diff --git a/icons/mob/inhands/weapons_lefthand.dmi b/icons/mob/inhands/weapons_lefthand.dmi index a5c22c4cef80..6815485c27bc 100644 Binary files a/icons/mob/inhands/weapons_lefthand.dmi and b/icons/mob/inhands/weapons_lefthand.dmi differ diff --git a/icons/mob/inhands/weapons_righthand.dmi b/icons/mob/inhands/weapons_righthand.dmi index afcbe22ddcc3..612365aed42c 100644 Binary files a/icons/mob/inhands/weapons_righthand.dmi and b/icons/mob/inhands/weapons_righthand.dmi differ diff --git a/icons/obj/abductor.dmi b/icons/obj/abductor.dmi index ba5ee59349d1..48de9bc18581 100644 Binary files a/icons/obj/abductor.dmi and b/icons/obj/abductor.dmi differ diff --git a/icons/obj/stationobjs.dmi b/icons/obj/stationobjs.dmi index 6bce8d4a243b..6da7f5315653 100644 Binary files a/icons/obj/stationobjs.dmi and b/icons/obj/stationobjs.dmi differ diff --git a/modular_ss220/jobs/code/objects/medical_job_objects.dm b/modular_ss220/jobs/code/objects/medical_job_objects.dm index 253c25a5aa49..0090302fe1bd 100644 --- a/modular_ss220/jobs/code/objects/medical_job_objects.dm +++ b/modular_ss220/jobs/code/objects/medical_job_objects.dm @@ -37,10 +37,6 @@ . = ..() allowed_roles |= GLOB.medical_positions_ss220 -/datum/gear/racial/taj/med/New() - . = ..() - allowed_roles |= GLOB.medical_positions_ss220 - /datum/gear/suit/coat/job/med/New() . = ..() allowed_roles |= GLOB.medical_positions_ss220 diff --git a/modular_ss220/jobs/code/objects/security_job_objects.dm b/modular_ss220/jobs/code/objects/security_job_objects.dm index f25df87d296f..eabc804e49a1 100644 --- a/modular_ss220/jobs/code/objects/security_job_objects.dm +++ b/modular_ss220/jobs/code/objects/security_job_objects.dm @@ -38,10 +38,6 @@ . = ..() allowed_roles |= GLOB.security_positions_ss220 -/datum/gear/racial/taj/sec/New() - . = ..() - allowed_roles |= GLOB.security_positions_ss220 - /datum/gear/suit/coat/job/sec/New() . = ..() allowed_roles |= GLOB.security_positions_ss220 diff --git a/modular_ss220/silicons/code/items/gripper.dm b/modular_ss220/silicons/code/items/gripper.dm index 8da623777ed8..f5187e3e7e56 100644 --- a/modular_ss220/silicons/code/items/gripper.dm +++ b/modular_ss220/silicons/code/items/gripper.dm @@ -1,24 +1,7 @@ -// Simple borg hand. -// Limited use. -/obj/item/gripper - name = "magnetic gripper" - desc = "A simple grasping tool for synthetic assets." - icon = 'icons/obj/device.dmi' - icon_state = "gripper" - - actions_types = list(/datum/action/item_action/drop_gripped_item) - - // Has a list of items that it can hold. - var/list/can_hold = list( - /obj/item/firealarm_electronics, - /obj/item/airalarm_electronics, - /obj/item/airlock_electronics, - /obj/item/firelock_electronics, - /obj/item/intercom_electronics, - /obj/item/apc_electronics, - /obj/item/tracker_electronics, - /obj/item/stock_parts, - /obj/item/vending_refill, +/* Different Grippers */ +/obj/item/gripper/engineering/Initialize(mapload) + . = ..() + can_hold |= list( /obj/item/mounted/frame/light_fixture, /obj/item/mounted/frame/apc_frame, /obj/item/mounted/frame/alarm_frame, @@ -27,54 +10,37 @@ /obj/item/mounted/frame/intercom, /obj/item/mounted/frame/extinguisher, /obj/item/mounted/frame/light_switch, - /obj/item/assembly/prox_sensor, - /obj/item/rack_parts, - /obj/item/camera_assembly, - /obj/item/tank, - /obj/item/circuitboard, - /obj/item/stack/tile/light, - /obj/item/stack/ore/bluespace_crystal, - /obj/item/assembly/igniter, /obj/item/flash, ) - // Item currently being held. - var/obj/item/gripped_item = null - - -// =================== -// different grippers -// =================== /obj/item/gripper/medical name = "medical gripper" desc = "A grasping tool used to hold organs and help patients up once surgery is complete." - can_hold = list(/obj/item/organ, - /obj/item/reagent_containers/iv_bag, - /obj/item/robot_parts, - /obj/item/stack/sheet/mineral/plasma, // for repair plasmamans - /obj/item/mmi, - /obj/item/reagent_containers/pill, - /obj/item/reagent_containers/patch, - /obj/item/reagent_containers/drinks, - /obj/item/reagent_containers/glass, - /obj/item/reagent_containers/syringe, - ) + can_hold = list( + /obj/item/organ, + /obj/item/reagent_containers/iv_bag, + /obj/item/robot_parts, + /obj/item/stack/sheet/mineral/plasma, // for repair plasmamans + /obj/item/mmi, + /obj/item/reagent_containers/pill, + /obj/item/reagent_containers/patch, + /obj/item/reagent_containers/drinks, + /obj/item/reagent_containers/glass, + /obj/item/reagent_containers/syringe, + ) /obj/item/gripper/medical/attack_self(mob/user) return -/obj/item/gripper/service - name = "Card gripper" - desc = "A grasping tool used to take IDs for paying taxes and waking up drunken crewmates" - can_hold = list(/obj/item/card, - /obj/item/camera_film, - /obj/item/paper, - /obj/item/photo, - /obj/item/toy/plushie, - /obj/item/disk/data, - /obj/item/disk/design_disk, - /obj/item/disk/plantgene, - ) +/obj/item/gripper/service/Initialize(mapload) + . = ..() + can_hold |= list( + /obj/item/card, + /obj/item/camera_film, + /obj/item/disk/data, + /obj/item/disk/design_disk, + /obj/item/disk/plantgene, + ) /obj/item/gripper/nuclear name = "Nuclear gripper" @@ -83,10 +49,7 @@ icon_state = "diskgripper" can_hold = list(/obj/item/disk/nuclear) - -// =================== -// procs -// =================== +/* Procs */ /obj/item/gripper/Initialize(mapload) . = ..() can_hold = typecacheof(can_hold) @@ -120,15 +83,6 @@ if(QDELETED(gripped_item)) // if item was dissasembled we need to clear the pointer drop_gripped_item(TRUE) // silent = TRUE to prevent "You drop X" message from appearing without actually dropping anything -/obj/item/gripper/proc/drop_gripped_item(silent = FALSE) - if(!gripped_item) - return FALSE - if(!silent) - to_chat(loc, span_warning("You drop [gripped_item].")) - gripped_item.forceMove(get_turf(src)) - gripped_item = null - return TRUE - /obj/item/gripper/attack(mob/living/carbon/M, mob/living/carbon/user) return @@ -211,10 +165,7 @@ return TRUE - -// =================== -// interactions -// =================== +/* Interactions */ /turf/simulated/wall/attackby(obj/item/I, mob/user, params) // The magnetic gripper does a separate attackby, so bail from this one if(istype(I, /obj/item/gripper)) diff --git a/modular_ss220/silicons/code/robot_items.dm b/modular_ss220/silicons/code/robot_items.dm index 622935a76d21..d9a55610b451 100644 --- a/modular_ss220/silicons/code/robot_items.dm +++ b/modular_ss220/silicons/code/robot_items.dm @@ -1,19 +1,10 @@ -// ============= -// ENGINEER -// ============= - - - +/* Engineer */ // Небольшой багфикс "непрозрачного открытого шлюза" /obj/structure/inflatable/door/operate() . = ..() opacity = FALSE - -// ============= -// MEDICAL -// ============= - +/* Medical */ /obj/item/reagent_containers/borghypo/basic/Initialize(mapload) . = ..() reagent_ids |= list("sal_acid", "charcoal") @@ -26,11 +17,7 @@ total_reagents = 60 maximum_reagents = 60 - - -// ============= -// SERVICE -// ============= +/* Service */ /obj/item/rsf/attack_self(mob/user) if(..() && power_mode >= 3000) power_mode /= 2 @@ -59,10 +46,4 @@ else to_chat(user, span_warning("[bicon(src)]No account connected to send transactions to.<")) return TRUE - // if(isrobot(user)) - // card_account = attempt_account_access(id_card.associated_account_number, pin_needed = FALSE) . = ..() - -// ============= -// MINER -// ============= diff --git a/modular_ss220/silicons/code/robot_modules.dm b/modular_ss220/silicons/code/robot_modules.dm index b3f7159cf3b9..0d74b3a441b6 100644 --- a/modular_ss220/silicons/code/robot_modules.dm +++ b/modular_ss220/silicons/code/robot_modules.dm @@ -1,21 +1,15 @@ -// drone - +// Drone /obj/item/robot_module/drone/Initialize(mapload) . = ..() - basic_modules.Remove(/obj/item/gripper_engineering) basic_modules |= list( - /obj/item/gripper, /obj/item/holosign_creator/atmos, ) -// robots - +// Robots /obj/item/robot_module/engineering/Initialize(mapload) . = ..() - basic_modules.Remove(/obj/item/gripper_engineering) basic_modules |= list( /obj/item/lightreplacer/cyborg, - /obj/item/gripper, /obj/item/inflatable/cyborg, /obj/item/inflatable/cyborg/door, /obj/item/gps/cyborg, @@ -23,11 +17,10 @@ /obj/item/robot_module/medical/Initialize(mapload) . = ..() - basic_modules.Remove(/obj/item/gripper_medical, /obj/item/reagent_containers/borghypo) + basic_modules.Remove(/obj/item/reagent_containers/borghypo) basic_modules |= list( /obj/item/gps/cyborg, /obj/item/rlf, - /obj/item/gripper/medical, /obj/item/reagent_containers/borghypo/basic, ) @@ -35,7 +28,6 @@ . = ..() basic_modules |= list( /obj/item/gps/cyborg, - /obj/item/gripper/service, /obj/item/eftpos/cyborg, ) @@ -52,7 +44,6 @@ ) // Syndicate - /obj/item/robot_module/syndicate/Initialize(mapload) . = ..() basic_modules |= list( @@ -61,26 +52,22 @@ /obj/item/robot_module/syndicate_medical/Initialize(mapload) . = ..() - basic_modules.Remove(/obj/item/gripper_medical) basic_modules |= list( /obj/item/gps/cyborg, /obj/item/rlf, - /obj/item/gripper/medical, /obj/item/gripper/nuclear, ) /obj/item/robot_module/syndicate_saboteur/Initialize(mapload) . = ..() - basic_modules.Remove(/obj/item/gripper_engineering) basic_modules |= list( - /obj/item/gripper, + /obj/item/gripper/engineering, /obj/item/gripper/nuclear, /obj/item/holosign_creator/atmos, ) // Admin Spawns - /obj/item/robot_module/deathsquad/Initialize(mapload) . = ..() basic_modules |= list( diff --git a/paradise.dme b/paradise.dme index 7d7dc5ea39b7..0f0e18d0c1c7 100644 --- a/paradise.dme +++ b/paradise.dme @@ -87,6 +87,7 @@ #include "code\__DEFINES\martial_arts.dm" #include "code\__DEFINES\MC.dm" #include "code\__DEFINES\mecha_defines.dm" +#include "code\__DEFINES\mecha_hides.dm" #include "code\__DEFINES\medal.dm" #include "code\__DEFINES\misc_defines.dm" #include "code\__DEFINES\mob_defines.dm" @@ -374,6 +375,7 @@ #include "code\datums\mixed.dm" #include "code\datums\movement_detector.dm" #include "code\datums\mutable_appearance.dm" +#include "code\datums\particles.dm" #include "code\datums\pathfinding_mover.dm" #include "code\datums\periodic_news.dm" #include "code\datums\pipe_datums.dm" @@ -992,6 +994,7 @@ #include "code\game\objects\effects\spawners\windowspawner.dm" #include "code\game\objects\effects\temporary_visuals\clockcult.dm" #include "code\game\objects\effects\temporary_visuals\cult_visuals.dm" +#include "code\game\objects\effects\temporary_visuals\explosion_temp_visuals.dm" #include "code\game\objects\effects\temporary_visuals\misc_visuals.dm" #include "code\game\objects\effects\temporary_visuals\muzzle_flashes.dm" #include "code\game\objects\effects\temporary_visuals\temporary_visual.dm" @@ -1076,6 +1079,7 @@ #include "code\game\objects\items\mountable_frames\mountables.dm" #include "code\game\objects\items\mountable_frames\newscaster_frame.dm" #include "code\game\objects\items\robot\ai_upgrades.dm" +#include "code\game\objects\items\robot\cyborg_gripper.dm" #include "code\game\objects\items\robot\robot_items.dm" #include "code\game\objects\items\robot\robot_parts.dm" #include "code\game\objects\items\robot\robot_upgrades.dm" @@ -1367,6 +1371,7 @@ #include "code\modules\admin\mute.dm" #include "code\modules\admin\outfits.dm" #include "code\modules\admin\player_panel.dm" +#include "code\modules\admin\reagents_editor.dm" #include "code\modules\admin\secrets.dm" #include "code\modules\admin\sql_notes.dm" #include "code\modules\admin\topic.dm" @@ -1659,6 +1664,7 @@ #include "code\modules\clothing\glasses\glasses.dm" #include "code\modules\clothing\glasses\hudglasses.dm" #include "code\modules\clothing\glasses\hudgoggles.dm" +#include "code\modules\clothing\glasses\tajblind.dm" #include "code\modules\clothing\gloves\boxing_gloves.dm" #include "code\modules\clothing\gloves\colored_gloves.dm" #include "code\modules\clothing\gloves\misc_gloves.dm" @@ -2011,6 +2017,7 @@ #include "code\modules\martial_arts\combos\judo\armbar.dm" #include "code\modules\martial_arts\combos\judo\discombobulate.dm" #include "code\modules\martial_arts\combos\judo\eyepoke.dm" +#include "code\modules\martial_arts\combos\judo\goldenblast.dm" #include "code\modules\martial_arts\combos\judo\judothrow.dm" #include "code\modules\martial_arts\combos\judo\wheelthrow.dm" #include "code\modules\martial_arts\combos\krav_maga\leg_sweep.dm" @@ -2746,6 +2753,7 @@ #include "code\modules\station_goals\secondary\botany\kudzu_goal.dm" #include "code\modules\station_goals\secondary\kitchen\random_bulk_condiment.dm" #include "code\modules\station_goals\secondary\kitchen\random_bulk_food.dm" +#include "code\modules\station_goals\secondary\kitchen\variety_food.dm" #include "code\modules\station_goals\secondary\medical\random_bulk_medicine.dm" #include "code\modules\station_goals\secondary\medical\variety_medicine.dm" #include "code\modules\station_goals\secondary\science\random_bulk_chemical.dm" diff --git a/sound/weapons/goldenblast.ogg b/sound/weapons/goldenblast.ogg new file mode 100644 index 000000000000..90dd9a004059 Binary files /dev/null and b/sound/weapons/goldenblast.ogg differ diff --git a/tgui/packages/tgui/index.js b/tgui/packages/tgui/index.js index ab86b58ef1a0..2496b2c49613 100644 --- a/tgui/packages/tgui/index.js +++ b/tgui/packages/tgui/index.js @@ -20,6 +20,7 @@ import './styles/themes/securestorage.scss'; import './styles/themes/security.scss'; import './styles/themes/syndicate.scss'; import './styles/themes/nologo.scss'; +import './styles/themes/noticeboard.scss'; import { perf } from 'common/perf'; import { setupHotReloading } from 'tgui-dev-server/link/client.cjs'; diff --git a/tgui/packages/tgui/interfaces/Noticeboard.tsx b/tgui/packages/tgui/interfaces/Noticeboard.tsx new file mode 100644 index 000000000000..6a1af16434f1 --- /dev/null +++ b/tgui/packages/tgui/interfaces/Noticeboard.tsx @@ -0,0 +1,44 @@ +import { decodeHtmlEntities } from 'common/string'; +import { useBackend } from '../backend'; +import { Section, Stack } from '../components'; +import { Window } from '../layouts'; + +type NoticeData = { + papers: Paper[]; +}; + +type Paper = { + name: string; + contents: string; + ref: string; +}; + +export const Noticeboard = (props, context) => { + const { act, data } = useBackend(context); + const { papers } = data; + return ( + + + + {papers.map((paper) => ( + act('interact', { paper: paper.ref })} + onContextMenu={(event) => { + event.preventDefault(); + act('showFull', { paper: paper.ref }); + }} + > +
+ {decodeHtmlEntities(paper.contents)} +
+
+ ))} +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/NumberInputModal.tsx b/tgui/packages/tgui/interfaces/NumberInputModal.tsx index 3a1d1fde9851..1426f5e67440 100644 --- a/tgui/packages/tgui/interfaces/NumberInputModal.tsx +++ b/tgui/packages/tgui/interfaces/NumberInputModal.tsx @@ -34,7 +34,11 @@ export const NumberInputModal = (props, context) => { }; // Dynamically changes the window height based on the message. const windowHeight = - 120 + (message.length > 30 ? Math.ceil(message.length / 3) : 0); + 140 + + Math.max( + Math.ceil(message.length / 3), + message.length > 0 && large_buttons ? 5 : 0 + ); return ( diff --git a/tgui/packages/tgui/interfaces/ReagentsEditor.tsx b/tgui/packages/tgui/interfaces/ReagentsEditor.tsx new file mode 100644 index 000000000000..e4fa714f1496 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ReagentsEditor.tsx @@ -0,0 +1,205 @@ +import { Component } from 'inferno'; +import { useBackend } from '../backend'; +import { Button, Icon, Input, Section, Stack, Table } from '../components'; +import { Window } from '../layouts'; +import { createSearch } from 'common/string'; + +type StaticReagentInformation = { + name: string; +}; + +type VolatileReagentInformation = { + volume: number | null; + uid: string; +}; + +type FilteredReagentInformation = StaticReagentInformation & { + id: string; +} & Partial; + +type StaticData = { + reagentsInformation: Record; +}; + +type VolatileData = { + reagents: Record; +}; + +type ReagentsEditorData = StaticData & VolatileData; + +type ReagentsEditorState = { + searchText: string; +}; + +// The linter is raising false-positives for unused state +/* eslint-disable react/no-unused-state */ +export class ReagentsEditor extends Component<{}, ReagentsEditorState> { + constructor(props: {}) { + super(props); + this.state = { + searchText: '', + }; + } + + handleSearchChange = (e: Event) => { + const target = e.target as HTMLInputElement; + this.setState({ searchText: target.value }); + }; + + override render(props: {}, state: ReagentsEditorState, context: unknown) { + const { + act, + data: { reagentsInformation, reagents: reagentsInContainer }, + } = useBackend(this.context); + + let reagents = Object.entries(reagentsInContainer) + .map( + ([reagentID, reagent]): FilteredReagentInformation => ({ + ...reagent, + ...reagentsInformation[reagentID], + id: reagentID, + }) + ) + .sort((a, b) => a.name.localeCompare(b.name)); + if (state.searchText !== '') { + reagents = reagents.concat( + Object.entries(reagentsInformation) + .filter( + ([reagentID, _]) => reagentsInContainer[reagentID] === undefined + ) + .map( + ([reagentID, reagent]): FilteredReagentInformation => ({ + ...reagent, + id: reagentID, + }) + ) + .sort((a, b) => a.name.localeCompare(b.name)) + ); + } + + const reagentsRows = reagents + .filter(({ id: reagentID, name }) => + createSearch(state.searchText, () => `${reagentID}|${name}`)({}) + ) + .map((reagent) => { + const { volume, uid } = reagent; + return volume === undefined ? ( + + ) : ( + + ); + }); + + return ( + + +
+ + + + + + + +
+
+
+ ); + } +} + +// Row for a reagent with non-zero volume +const PresentReagentRow = ( + { + reagent: { id: reagentID, name, uid, volume }, + }: { reagent: FilteredReagentInformation }, + context: unknown +) => { + const { act } = useBackend(context); + return ( + + +
+ + act('delete_reagent', { + uid, + }) + } + mr="0.5em" + /> +
+ + {volume === null ? `NULL` : `${volume}u`} + +
+ + {reagentID} ({name}) + +
+ ); +}; + +// Row for a reagent with zero volume +const AbsentReagentRow = ( + { reagent: { id: reagentID, name } }: { reagent: FilteredReagentInformation }, + context: unknown +) => { + const { act } = useBackend(context); + return ( + + +