diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm index 5c35c78274..6893a41517 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_alien_nest.dmm @@ -34,11 +34,6 @@ /obj/structure/alien/weeds, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/xenonest) -"ai" = ( -/obj/structure/alien/weeds, -/obj/structure/alien/egg, -/turf/open/floor/plating/asteroid/basalt/lava_land_surface, -/area/ruin/unpowered/xenonest) "aj" = ( /obj/structure/alien/weeds, /obj/structure/bed/nest, @@ -1219,12 +1214,12 @@ an ac ac aJ -ag +af ag ac ac ar -ai +ag ac an an @@ -1269,7 +1264,7 @@ an an ac Dd -ai +ag ak ag af @@ -1298,10 +1293,10 @@ aa ab ac ac -ai +ag ag at -ai +ag ac ag at @@ -1401,7 +1396,7 @@ ab ac af ag -af +ag ag af ac @@ -1807,7 +1802,7 @@ bD (25,1,1) = {" ab ac -ai +ag ag JM ag @@ -1816,7 +1811,7 @@ ac ag ar ag -ai +ag ac ab ab @@ -1860,7 +1855,7 @@ ab ac ac af -ai +ag af ag aF diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm index 7ad773e601..63d2acdf46 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_ash_walker1.dmm @@ -173,6 +173,7 @@ /obj/structure/stone_tile{ dir = 4 }, +/obj/item/t_scanner/adv_mining_scanner/lesser, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/ash_walkers) "aC" = ( @@ -186,6 +187,7 @@ }, /obj/structure/closet/crate/medical, /obj/item/storage/firstaid/regular, +/obj/item/storage/firstaid/ancient, /obj/item/reagent_containers/blood/random, /obj/item/reagent_containers/blood/lizard, /obj/item/reagent_containers/blood/lizard, @@ -269,6 +271,7 @@ /area/ruin/unpowered/ash_walkers) "aP" = ( /obj/structure/stone_tile, +/obj/item/shard, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/ash_walkers) "aQ" = ( @@ -575,6 +578,7 @@ /obj/item/stack/sheet/mineral/wood, /obj/item/stack/sheet/mineral/wood, /obj/item/seeds/tower, +/obj/item/seeds/tower, /turf/open/indestructible/boss, /area/ruin/unpowered/ash_walkers) "bx" = ( @@ -1086,7 +1090,7 @@ dir = 8 }, /obj/structure/table/wood, -/obj/item/twohanded/spear, +/obj/item/kitchen/knife/combat/bone, /turf/open/indestructible/boss, /area/ruin/unpowered/ash_walkers) "cN" = ( @@ -1142,6 +1146,7 @@ /obj/structure/stone_tile{ dir = 1 }, +/obj/item/surgical_drapes, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/ruin/unpowered/ash_walkers) "cX" = ( @@ -1301,6 +1306,7 @@ }, /obj/structure/stone_tile/center, /obj/effect/mapping_helpers/no_lava, +/obj/item/hatchet, /turf/open/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "du" = ( @@ -1392,6 +1398,18 @@ }, /turf/closed/mineral/volcanic/lava_land_surface, /area/lavaland/surface/outdoors) +"nS" = ( +/obj/item/toy/cards/deck/syndicate, +/turf/closed/mineral/volcanic/lava_land_surface, +/area/lavaland/surface/outdoors) +"Bv" = ( +/obj/structure/stone_tile{ + dir = 1 + }, +/obj/effect/mapping_helpers/no_lava, +/obj/item/cultivator, +/turf/open/floor/plating/asteroid/basalt/lava_land_surface, +/area/lavaland/surface/outdoors) (1,1,1) = {" aa @@ -1407,7 +1425,7 @@ ah ah aa aa -ah +nS ah ah ah @@ -1558,7 +1576,7 @@ ba bn bz ak -cb +Bv df bX co diff --git a/_maps/RandomRuins/SpaceRuins/deepstorage.dmm b/_maps/RandomRuins/SpaceRuins/deepstorage.dmm index 0ff30453f2..bf4f0dbfa6 100644 --- a/_maps/RandomRuins/SpaceRuins/deepstorage.dmm +++ b/_maps/RandomRuins/SpaceRuins/deepstorage.dmm @@ -170,6 +170,8 @@ /obj/item/storage/box/monkeycubes, /obj/item/storage/toolbox/drone, /obj/item/storage/toolbox/drone, +/obj/item/storage/fancy/candle_box, +/obj/item/storage/fancy/candle_box, /obj/effect/turf_decal/delivery, /obj/effect/decal/cleanable/dirt, /turf/open/floor/plasteel, diff --git a/_maps/shuttles/whiteship_box.dmm b/_maps/shuttles/whiteship_box.dmm index 8dc007ec95..0404cede34 100644 --- a/_maps/shuttles/whiteship_box.dmm +++ b/_maps/shuttles/whiteship_box.dmm @@ -15,6 +15,7 @@ "ae" = ( /obj/machinery/door/airlock/external, /obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/structure/fans/tiny, /obj/docking_port/mobile{ callTime = 250; dheight = 0; @@ -148,6 +149,7 @@ /area/shuttle/abandoned/crew) "ap" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, @@ -737,6 +739,7 @@ /obj/effect/turf_decal/bot, /obj/item/reagent_containers/glass/bucket, /obj/item/mop, +/obj/item/assembly/prox_sensor, /obj/item/storage/bag/trash{ pixel_x = 6 }, @@ -954,6 +957,7 @@ /area/shuttle/abandoned/engine) "bm" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/decal/cleanable/dirt{ desc = "A thin layer of dust coating the floor."; name = "dust" @@ -1130,6 +1134,7 @@ /area/shuttle/abandoned/bridge) "by" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper, /turf/open/floor/plating, /area/shuttle/abandoned/engine) @@ -2600,6 +2605,7 @@ "do" = ( /obj/machinery/door/airlock/external, /obj/effect/mapping_helpers/airlock/cyclelink_helper, +/obj/structure/fans/tiny, /obj/effect/decal/cleanable/dirt{ desc = "A thin layer of dust coating the floor."; name = "dust" @@ -2670,6 +2676,7 @@ /area/shuttle/abandoned/medbay) "dt" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, diff --git a/_maps/shuttles/whiteship_delta.dmm b/_maps/shuttles/whiteship_delta.dmm index 160f6adfd5..cc8eb19bab 100644 --- a/_maps/shuttles/whiteship_delta.dmm +++ b/_maps/shuttles/whiteship_delta.dmm @@ -19,6 +19,7 @@ /area/shuttle/abandoned/crew) "ad" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/docking_port/mobile{ callTime = 250; @@ -443,6 +444,7 @@ name = "E.V.A Access" }, /turf/open/floor/plasteel, +/obj/structure/fans/tiny, /area/shuttle/abandoned/crew) "aK" = ( /obj/effect/decal/cleanable/dirt{ @@ -628,6 +630,7 @@ name = "E.V.A Access" }, /obj/effect/decal/cleanable/dirt, +/obj/structure/fans/tiny, /turf/open/floor/plasteel, /area/shuttle/abandoned/bar) "aX" = ( @@ -2531,6 +2534,7 @@ /obj/machinery/door/airlock/external/glass{ name = "E.V.A Access" }, +/obj/structure/fans/tiny, /obj/effect/decal/cleanable/dirt{ desc = "A thin layer of dust coating the floor."; name = "dust" @@ -2555,6 +2559,7 @@ /obj/machinery/door/airlock/external/glass{ name = "E.V.A Access" }, +/obj/structure/fans/tiny, /turf/open/floor/plasteel, /area/shuttle/abandoned/cargo) "ds" = ( @@ -2782,6 +2787,7 @@ /area/shuttle/abandoned/medbay) "dI" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/effect/decal/cleanable/dirt{ desc = "A thin layer of dust coating the floor."; @@ -3103,6 +3109,7 @@ /area/shuttle/abandoned/cargo) "eb" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, diff --git a/_maps/shuttles/whiteship_meta.dmm b/_maps/shuttles/whiteship_meta.dmm index a7f977c34e..84fff43a44 100644 --- a/_maps/shuttles/whiteship_meta.dmm +++ b/_maps/shuttles/whiteship_meta.dmm @@ -34,6 +34,7 @@ /area/shuttle/abandoned/crew) "ah" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/docking_port/mobile{ callTime = 250; @@ -458,6 +459,7 @@ /area/shuttle/abandoned/crew) "aI" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, @@ -583,6 +585,7 @@ name = "dust" }, /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 }, @@ -704,6 +707,7 @@ name = "dust" }, /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, @@ -1893,6 +1897,7 @@ /area/shuttle/abandoned/bridge) "ch" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 }, @@ -1915,6 +1920,7 @@ /area/shuttle/abandoned/engine) "cj" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, @@ -3094,6 +3100,7 @@ name = "dust" }, /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 4 }, @@ -3164,6 +3171,7 @@ name = "dust" }, /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 8 }, @@ -3432,6 +3440,7 @@ /obj/item/shovel, /obj/item/pickaxe, /obj/item/storage/box/lights/mixed, +/obj/item/storage/box/lights/mixed, /obj/item/mining_scanner, /obj/effect/turf_decal/bot, /turf/open/floor/plating, @@ -3514,6 +3523,7 @@ /area/shuttle/abandoned/bar) "dP" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper, /obj/effect/decal/cleanable/dirt{ desc = "A thin layer of dust coating the floor."; @@ -3808,6 +3818,7 @@ /area/shuttle/abandoned/cargo) "ej" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /obj/effect/mapping_helpers/airlock/cyclelink_helper{ dir = 1 }, diff --git a/_maps/shuttles/whiteship_pubby.dmm b/_maps/shuttles/whiteship_pubby.dmm index 11214ef260..fef3918e1d 100644 --- a/_maps/shuttles/whiteship_pubby.dmm +++ b/_maps/shuttles/whiteship_pubby.dmm @@ -15,6 +15,7 @@ /obj/machinery/door/airlock/public/glass{ name = "Shuttle Airlock" }, +/obj/structure/fans/tiny, /turf/open/floor/plasteel/dark, /area/shuttle/abandoned) "e" = ( @@ -96,6 +97,7 @@ preferred_direction = 1; width = 9 }, +/obj/structure/fans/tiny, /turf/open/floor/plasteel/dark, /area/shuttle/abandoned) "p" = ( diff --git a/code/__DEFINES/_tick.dm b/code/__DEFINES/_tick.dm index 20eb648fe6..10b815e547 100644 --- a/code/__DEFINES/_tick.dm +++ b/code/__DEFINES/_tick.dm @@ -7,4 +7,7 @@ #define TICK_USAGE_REAL world.tick_usage //to be used where the result isn't checked #define TICK_CHECK ( TICK_USAGE > Master.current_ticklimit ) -#define CHECK_TICK if TICK_CHECK stoplag() +#define CHECK_TICK ( TICK_CHECK ? stoplag() : 0 ) + +#define TICK_CHECK_HIGH_PRIORITY ( TICK_USAGE > 95 ) +#define CHECK_TICK_HIGH_PRIORITY ( TICK_CHECK_HIGH_PRIORITY? stoplag() : 0 ) diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 1b64ce7e6c..ad9aef5a8b 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -4,6 +4,11 @@ #define ALL (~0) //For convenience. #define NONE 0 +//for convenience +#define ENABLE_BITFIELD(variable, flag) (variable |= (flag)) +#define DISABLE_BITFIELD(variable, flag) (variable &= ~(flag)) +#define CHECK_BITFIELD(variable, flag) (variable & flag) + GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768)) // for /datum/var/datum_flags diff --git a/code/__DEFINES/lighting.dm b/code/__DEFINES/lighting.dm index 5db5c979e8..13dccc74fe 100644 --- a/code/__DEFINES/lighting.dm +++ b/code/__DEFINES/lighting.dm @@ -34,6 +34,7 @@ #define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250) #define LIGHT_COLOR_BLUEGREEN "#7DE1AF" //Light blueish green. rgb(125, 225, 175) +#define LIGHT_COLOR_PALEBLUE "#7DAFE1" //A pale blue-ish color. rgb(125, 175, 225) #define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225) #define LIGHT_COLOR_LIGHT_CYAN "#40CEFF" //More-saturated cyan. rgb(64, 206, 255) #define LIGHT_COLOR_DARK_BLUE "#6496FA" //Saturated blue. rgb(51, 117, 248) diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index 3e638f1e2e..d344f7f010 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -74,7 +74,7 @@ #define ISINRANGE(val, min, max) (min <= val && val <= max) // Same as above, exclusive. -#define ISINRANGE_EX(val, min, max) (min < val && val > max) +#define ISINRANGE_EX(val, min, max) (min < val && val < max) #define ISINTEGER(x) (round(x) == x) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 0cc1131df2..7301284ee4 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -98,8 +98,9 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s //Security levels #define SEC_LEVEL_GREEN 0 #define SEC_LEVEL_BLUE 1 -#define SEC_LEVEL_RED 2 -#define SEC_LEVEL_DELTA 3 +#define SEC_LEVEL_AMBER 2 +#define SEC_LEVEL_RED 3 +#define SEC_LEVEL_DELTA 4 //some arbitrary defines to be used by self-pruning global lists. (see master_controller) #define PROCESS_KILL 26 //Used to trigger removal from a processing list diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm index 3ffb583332..5fe65af8f3 100644 --- a/code/__HELPERS/time.dm +++ b/code/__HELPERS/time.dm @@ -63,96 +63,29 @@ GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0) //Takes a value of time in deciseconds. //Returns a text value of that number in hours, minutes, or seconds. -/proc/DisplayTimeText(time_value, truncate = FALSE) - var/second = (time_value)*0.1 - var/second_adjusted = null - var/second_rounded = FALSE - var/minute = null - var/hour = null - var/day = null - +/proc/DisplayTimeText(time_value, round_seconds_to = 0.1) + var/second = FLOOR(time_value * 0.1, round_seconds_to) if(!second) - return "0 seconds" - if(second >= 60) - minute = FLOOR(second/60, 1) - second = round(second - (minute*60), 0.1) - second_rounded = TRUE - if(second) //check if we still have seconds remaining to format, or if everything went into minute. - second_adjusted = round(second) //used to prevent '1 seconds' being shown - if(day || hour || minute) - if(second_adjusted == 1 && second >= 1) - second = " and 1 second" - else if(second > 1) - second = " and [second_adjusted] seconds" - else //shows a fraction if seconds is < 1 - if(second_rounded) //no sense rounding again if it's already done - second = " and [second] seconds" - else - second = " and [round(second, 0.1)] seconds" - else - if(second_adjusted == 1 && second >= 1) - second = "[truncate ? "second" : "1 second"]" - else if(second > 1) - second = "[second_adjusted] seconds" - else - if(second_rounded) - second = "[second] seconds" - else - second = "[round(second, 0.1)] seconds" - else - second = null - - if(!minute) - return "[second]" - if(minute >= 60) - hour = FLOOR(minute/60, 1) - minute = (minute - (hour*60)) - if(minute) //alot simpler from here since you don't have to worry about fractions - if(minute != 1) - if((day || hour) && second) - minute = ", [minute] minutes" - else if((day || hour) && !second) - minute = " and [minute] minutes" - else - minute = "[minute] minutes" - else - if((day || hour) && second) - minute = ", 1 minute" - else if((day || hour) && !second) - minute = " and 1 minute" - else - minute = "[truncate ? "minute" : "1 minute"]" - else - minute = null - - if(!hour) - return "[minute][second]" - if(hour >= 24) - day = FLOOR(hour/24, 1) - hour = (hour - (day*24)) + return "right now" + if(second < 60) + return "[second] second[(second != 1)? "s":""]" + var/minute = FLOOR(second / 60, 1) + second = FLOOR(MODULUS(second, 60), round_seconds_to) + var/secondT + if(second) + secondT = " and [second] second[(second != 1)? "s":""]" + if(minute < 60) + return "[minute] minute[(minute != 1)? "s":""][secondT]" + var/hour = FLOOR(minute / 60, 1) + minute = MODULUS(minute, 60) + var/minuteT + if(minute) + minuteT = " and [minute] minute[(minute != 1)? "s":""]" + if(hour < 24) + return "[hour] hour[(hour != 1)? "s":""][minuteT][secondT]" + var/day = FLOOR(hour / 24, 1) + hour = MODULUS(hour, 24) + var/hourT if(hour) - if(hour != 1) - if(day && (minute || second)) - hour = ", [hour] hours" - else if(day && (!minute || !second)) - hour = " and [hour] hours" - else - hour = "[hour] hours" - else - if(day && (minute || second)) - hour = ", 1 hour" - else if(day && (!minute || !second)) - hour = " and 1 hour" - else - hour = "[truncate ? "hour" : "1 hour"]" - else - hour = null - - if(!day) - return "[hour][minute][second]" - if(day > 1) - day = "[day] days" - else - day = "[truncate ? "day" : "1 day"]" - - return "[day][hour][minute][second]" + hourT = " and [hour] hour[(hour != 1)? "s":""]" + return "[day] day[(day != 1)? "s":""][hourT][minuteT][secondT]" diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 620c592d93..2f69b63ae9 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1239,6 +1239,20 @@ GLOBAL_REAL_VAR(list/stack_trace_storage) pixel_x = initialpixelx pixel_y = initialpixely +/atom/proc/do_jiggle(targetangle = 45) + var/matrix/OM = matrix(transform) + var/matrix/M = matrix(transform) + M.Turn(pick(-targetangle, targetangle)) + animate(src, transform = M, time = 10, easing = ELASTIC_EASING) + animate(src, transform = OM, time = 10, easing = ELASTIC_EASING) + +/atom/proc/do_squish(squishx = 1.2, squishy = 0.6) + var/matrix/OM = matrix(transform) + var/matrix/M = matrix(transform) + M.Scale(squishx, squishy) + animate(src, transform = M, time = 10, easing = BOUNCE_EASING) + animate(src, transform = OM, time = 10, easing = BOUNCE_EASING) + /proc/weightclass2text(var/w_class) switch(w_class) if(WEIGHT_CLASS_TINY) @@ -1530,4 +1544,4 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) . = list() for(var/i in L) if(condition.Invoke(i)) - . |= i \ No newline at end of file + . |= i diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm index ab98db1620..f216b025f8 100644 --- a/code/controllers/configuration/entries/game_options.dm +++ b/code/controllers/configuration/entries/game_options.dm @@ -162,16 +162,22 @@ config_entry_value = "All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced." /datum/config_entry/string/alert_blue_upto - config_entry_value = "The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted." + config_entry_value = "The station has received reliable information about potential threats to the station. Security staff may have weapons visible, random searches are permitted." /datum/config_entry/string/alert_blue_downto - config_entry_value = "The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed." + config_entry_value = "Significant confirmed threats have been neutralized. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still permitted." + +/datum/config_entry/string/alert_amber_upto + config_entry_value = "There are significant confirmed threats to the station. Security staff may have weapons unholstered at all times. Random searches are allowed and advised." + +/datum/config_entry/string/alert_amber_downto + config_entry_value = "The immediate threat has passed. Security is no longer authorized to use lethal force, but may continue to have weapons drawn. Access requirements have been restored." /datum/config_entry/string/alert_red_upto - config_entry_value = "There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised." + config_entry_value = "There is an immediate serious threat to the station. Security is now authorized to use lethal force. Additionally, access requirements on some machines have been lifted." /datum/config_entry/string/alert_red_downto - config_entry_value = "The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised." + config_entry_value = "The station's destruction has been averted. There is still however an immediate serious threat to the station. Security is still authorized to use lethal force." /datum/config_entry/string/alert_delta config_entry_value = "Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill." diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 53f03ebfff..595e1d9ca0 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -7,6 +7,9 @@ /datum/config_entry/string/servername // server name (the name of the game window) +/datum/config_entry/string/servertagline + config_entry_value = "We forgot to set the server's tagline in config.txt" + /datum/config_entry/string/serversqlname // short form server name used for the DB /datum/config_entry/string/stationname // station name (the name of the station in-game) diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index 32d87425ff..8402a0150e 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -281,7 +281,10 @@ SUBSYSTEM_DEF(shuttle) if(emergency.timeLeft(1) < emergencyCallTime) return if(SEC_LEVEL_BLUE) - if(emergency.timeLeft(1) < emergencyCallTime * 0.5) + if(emergency.timeLeft(1) < emergencyCallTime * 0.6) + return + if(SEC_LEVEL_AMBER) + if(emergency.timeLeft(1) < emergencyCallTime * 0.4) return else if(emergency.timeLeft(1) < emergencyCallTime * 0.25) diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm index a1fd15b806..05105dca1e 100644 --- a/code/controllers/subsystem/traumas.dm +++ b/code/controllers/subsystem/traumas.dm @@ -14,7 +14,7 @@ SUBSYSTEM_DEF(traumas) //phobia types is to pull from randomly for brain traumas, e.g. conspiracies is for special assignment only phobia_types = list("spiders", "space", "security", "clowns", "greytide", "lizards", "skeletons", "snakes", "robots", "doctors", "authority", "the supernatural", - "aliens", "strangers", "birds", "falling", "anime", "mimes" + "aliens", "strangers", "birds", "falling", "anime", "mimes", "cats" ) phobia_words = list("spiders" = strings(PHOBIA_FILE, "spiders"), @@ -35,7 +35,8 @@ SUBSYSTEM_DEF(traumas) "birds" = strings(PHOBIA_FILE, "birds"), "falling" = strings(PHOBIA_FILE, "falling"), "anime" = strings(PHOBIA_FILE, "anime"), - "mimes" = strings(PHOBIA_FILE, "mimes") + "mimes" = strings(PHOBIA_FILE, "mimes"), + "cats" = strings(PHOBIA_FILE, "cats") ) phobia_mobs = list("spiders" = typecacheof(list(/mob/living/simple_animal/hostile/poison/giant_spider)), @@ -54,7 +55,8 @@ SUBSYSTEM_DEF(traumas) /mob/living/simple_animal/pet/penguin)), "birds" = typecacheof(list(/mob/living/simple_animal/parrot, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken, /mob/living/simple_animal/pet/penguin)), - "anime" = typecacheof(list(/mob/living/simple_animal/hostile/guardian)) + "anime" = typecacheof(list(/mob/living/simple_animal/hostile/guardian)), + "cats"= typecacheof(list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/pet/cat, /mob/living/simple_animal/hostile/cat_butcherer)) ) @@ -152,7 +154,10 @@ SUBSYSTEM_DEF(traumas) /obj/item/storage/backpack/mime, /obj/item/reagent_containers/food/snacks/grown/banana/mime, /obj/item/grown/bananapeel/mimanapeel, /obj/item/cartridge/virus/mime, /obj/item/clothing/shoes/sneakers/mime, /obj/item/bedsheet/mime, /obj/item/reagent_containers/food/snacks/burger/mime, /obj/item/clothing/head/beret, /obj/item/clothing/mask/gas/sexymime, - /obj/item/clothing/under/sexymime, /obj/item/toy/figure/mime, /obj/item/toy/crayon/mime, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced, /obj/mecha/combat/reticence)) + /obj/item/clothing/under/sexymime, /obj/item/toy/figure/mime, /obj/item/toy/crayon/mime, /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/silenced, /obj/mecha/combat/reticence)), + + "cats" = typecacheof(list(/obj/item/organ/ears/cat, /obj/item/organ/tail/cat, /obj/item/laser_pointer, /obj/item/toy/cattoy, /obj/item/clothing/head/kitty, + /obj/item/clothing/head/collectable/kitty, /obj/item/melee/chainofcommand/tailwhip/kitty, /obj/item/stack/sheet/animalhide/cat)) ) phobia_turfs = list("space" = typecacheof(list(/turf/open/space, /turf/open/floor/holofloor/space, /turf/open/floor/fakespace)), @@ -170,7 +175,8 @@ SUBSYSTEM_DEF(traumas) "the supernatural" = typecacheof(list(/datum/species/golem/clockwork, /datum/species/golem/runic)), "aliens" = typecacheof(list(/datum/species/abductor, /datum/species/jelly, /datum/species/pod, /datum/species/shadow)), - "anime" = typecacheof(list(/datum/species/human/felinid)) + "anime" = typecacheof(list(/datum/species/human/felinid)), + "cats" = typecacheof(list(/datum/species/human/felinid)) ) return ..() diff --git a/code/datums/components/storage/concrete/pockets.dm b/code/datums/components/storage/concrete/pockets.dm index 6610b9aa2b..3d03c2adbd 100644 --- a/code/datums/components/storage/concrete/pockets.dm +++ b/code/datums/components/storage/concrete/pockets.dm @@ -34,6 +34,7 @@ /datum/component/storage/concrete/pockets/shoes/Initialize() . = ..() + cant_hold = typecacheof(list(/obj/item/screwdriver/power)) can_hold = typecacheof(list( /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, /obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector, @@ -44,6 +45,7 @@ /datum/component/storage/concrete/pockets/shoes/clown/Initialize() . = ..() + cant_hold = typecacheof(list(/obj/item/screwdriver/power)) can_hold = typecacheof(list( /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, /obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector, diff --git a/code/datums/components/storage/concrete/rped.dm b/code/datums/components/storage/concrete/rped.dm index adf08b089b..e1cc4ff6ae 100644 --- a/code/datums/components/storage/concrete/rped.dm +++ b/code/datums/components/storage/concrete/rped.dm @@ -5,7 +5,7 @@ click_gather = TRUE max_w_class = WEIGHT_CLASS_NORMAL max_combined_w_class = 100 - max_items = 75 + max_items = 100 display_numerical_stacking = TRUE /datum/component/storage/concrete/rped/can_be_inserted(obj/item/I, stop_messages, mob/M) @@ -22,7 +22,7 @@ click_gather = TRUE max_w_class = WEIGHT_CLASS_BULKY // can fit vending refills max_combined_w_class = 800 - max_items = 325 + max_items = 350 display_numerical_stacking = TRUE /datum/component/storage/concrete/bluespace/rped/can_be_inserted(obj/item/I, stop_messages, mob/M) @@ -31,3 +31,6 @@ if (!stop_messages) to_chat(M, "[parent] only accepts machine parts!") return FALSE + +/datum/component/storage/concrete/cyborg/rped + max_items = 150 diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 55af26b6b2..bb3c584cb9 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -169,10 +169,12 @@ if(locked) to_chat(M, "[parent] seems to be locked!") return FALSE + var/atom/A = parent var/obj/item/I = O if(collection_mode == COLLECT_ONE) if(can_be_inserted(I, null, M)) handle_item_insertion(I, null, M) + A.do_squish() return if(!isturf(I.loc)) return @@ -189,6 +191,7 @@ stoplag(1) qdel(progress) to_chat(M, "You put everything you could [insert_preposition] [parent].") + A.do_squish(1.4, 0.4) /datum/component/storage/proc/handle_mass_item_insertion(list/things, datum/component/storage/src_object, mob/user, datum/progressbar/progress) var/atom/source_real_location = src_object.real_location() @@ -246,6 +249,7 @@ while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress))) stoplag(1) qdel(progress) + A.do_squish(0.8, 1.2) /datum/component/storage/proc/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress, trigger_on_found = TRUE) var/atom/real_location = real_location() @@ -455,6 +459,7 @@ return FALSE if(dump_destination.storage_contents_dump_act(src, M)) playsound(A, "rustle", 50, 1, -5) + A.do_squish(0.8, 1.2) return TRUE return FALSE @@ -473,6 +478,8 @@ return TRUE return FALSE handle_item_insertion(I, FALSE, M) + var/atom/A = parent + A.do_squish() /datum/component/storage/proc/return_inv(recursive) var/list/ret = list() @@ -514,6 +521,7 @@ if(A.loc != M) return playsound(A, "rustle", 50, 1, -5) + A.do_jiggle() if(istype(over_object, /obj/screen/inventory/hand)) var/obj/screen/inventory/hand/H = over_object M.putItemFromInventoryInHandIfPossible(A, H.held_index) @@ -539,6 +547,8 @@ if(!L.incapacitated() && I == L.get_active_held_item()) if(!SEND_SIGNAL(I, COMSIG_CONTAINS_STORAGE) && can_be_inserted(I, FALSE)) //If it has storage it should be trying to dump, not insert. handle_item_insertion(I, FALSE, L) + var/atom/A = parent + A.do_squish() //This proc return 1 if the item can be picked up and 0 if it can't. //Set the stop_messages to stop it from printing messages @@ -712,6 +722,7 @@ to_chat(user, "[parent] seems to be locked!") else show_to(user) + A.do_jiggle() /datum/component/storage/proc/signal_on_pickup(datum/source, mob/user) var/atom/A = parent @@ -732,16 +743,30 @@ return hide_from(target) /datum/component/storage/proc/on_alt_click(datum/source, mob/user) - if(!isliving(user) || user.incapacitated() || !quickdraw || locked || !user.CanReach(parent)) + if(!isliving(user) || !user.CanReach(parent)) return - var/obj/item/I = locate() in real_location() - if(!I) + if(locked) + to_chat(user, "[parent] seems to be locked!") return - remove_from_storage(I, get_turf(user)) - if(!user.put_in_hands(I)) - to_chat(user, "You fumble for [I] and it falls on the floor.") + + var/atom/A = parent + if(!quickdraw) + A.add_fingerprint(user) + user_show_to_mob(user) + playsound(A, "rustle", 50, 1, -5) + return + + if(!user.incapacitated()) + var/obj/item/I = locate() in real_location() + if(!I) + return + A.add_fingerprint(user) + remove_from_storage(I, get_turf(user)) + if(!user.put_in_hands(I)) + to_chat(user, "You fumble for [I] and it falls on the floor.") + return + user.visible_message("[user] draws [I] from [parent]!", "You draw [I] from [parent].") return - user.visible_message("[user] draws [I] from [parent]!", "You draw [I] from [parent].") /datum/component/storage/proc/action_trigger(datum/signal_source, datum/action/source) gather_mode_switch(source.owner) diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index d41cf4381c..dd8ee1b166 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -51,7 +51,7 @@ /obj/screen/alert/status_effect/vanguard name = "Vanguard" - desc = "You're absorbing stuns! 25% of all stuns taken will affect you after this effect ends." + desc = "You're absorbing stuns! Your stamina is greatly increased, but not infinite. 25% of all stuns taken will affect you after this effect ends." icon_state = "vanguard" alerttooltipstyle = "clockcult" @@ -75,6 +75,7 @@ owner.visible_message("[owner] begins to faintly glow!", "You will absorb all stuns for the next twenty seconds.") owner.SetStun(0, FALSE) owner.SetKnockdown(0) + owner.setStaminaLoss(0, FALSE) progbar = new(owner, duration, owner) progbar.bar.color = list("#FAE48C", "#FAE48C", "#FAE48C", rgb(0,0,0)) progbar.update(duration - world.time) diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index dbbbf54cda..407a24a8c6 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -269,14 +269,32 @@ /datum/quirk/phobia name = "Phobia" - desc = "You've had a traumatic past, that has scared you for life while dealing with your greatest fear." + desc = "You've had a traumatic past, one that has scarred you for life, and cripples you when dealing with your greatest fears." value = -2 // It can hardstun you. You can be a job that your phobia targets... - gain_text = "You feel your fears manifest themselfs." - lose_text = "You feel your fears fade away." - medical_record_text = "Patient has an extreme or irrational fear of or aversion to something." + gain_text = "You begin to tremble as an immeasurable fear grips your mind." + lose_text = "Your confidence wipes away the fear that had been plaguing you." + medical_record_text = "Patient has an extreme or irrational fear and aversion to an undefined stimuli." var/datum/brain_trauma/mild/phobia/phobia - + /datum/quirk/phobia/add() var/mob/living/carbon/human/H = quirk_holder phobia = new H.gain_trauma(phobia, TRAUMA_RESILIENCE_SURGERY) + +/datum/quirk/mute + name = "Mute" + desc = "Due to some accident, medical condition, or simply by choice, you are completely unable to speak." + value = -2 //HALP MAINTS + mob_trait = TRAIT_MUTE + gain_text = "You find yourself unable to speak!" + lose_text = "You feel a growing strength in your vocal chords." + medical_record_text = "Functionally mute, patient is unable to use their voice in any capacity." + +/datum/quirk/mute/add() + var/mob/living/carbon/human/H = quirk_holder + H.gain_trauma(TRAIT_MUTE, TRAUMA_RESILIENCE_SURGERY) + +/datum/quirk/mute/on_process() + if(quirk_holder.mind && LAZYLEN(quirk_holder.mind.antag_datums)) + to_chat(quirk_holder, "Your antagonistic nature has caused your voice to be heard.") + qdel(src) diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm index 173f7e6b33..345212cc1b 100644 --- a/code/datums/weather/weather_types/ash_storm.dm +++ b/code/datums/weather/weather_types/ash_storm.dm @@ -93,6 +93,10 @@ /datum/weather/ash_storm/weather_act(mob/living/L) if(is_ash_immune(L)) return + if(is_species(L, /datum/species/lizard/ashwalker)) + if(L.getStaminaLoss() <= STAMINA_SOFTCRIT) + L.adjustStaminaLossBuffered(4) + return L.adjustFireLoss(4) diff --git a/code/game/area/areas/centcom.dm b/code/game/area/areas/centcom.dm index d5c8a8c841..1241b7a240 100644 --- a/code/game/area/areas/centcom.dm +++ b/code/game/area/areas/centcom.dm @@ -29,6 +29,13 @@ /area/centcom/holding name = "Holding Facility" +/area/centcom/vip + name = "VIP Zone" + dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + /area/centcom/winterball + name = "winterball Zone" + dynamic_lighting = DYNAMIC_LIGHTING_DISABLED + /area/centcom/supplypod name = "Supplypod Facility" icon_state = "supplypod" diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index ba840d0771..e56f6d366c 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -622,8 +622,12 @@ else if(direction & WEST) pixel_x_diff = -8 - animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, time = 2) - animate(src, pixel_x = pixel_x - pixel_x_diff, pixel_y = pixel_y - pixel_y_diff, time = 2) + var/matrix/OM = matrix(transform) + var/matrix/M = matrix(transform) + M.Turn(pixel_x_diff ? pixel_x_diff*2 : pick(-16, 16)) + + animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff, transform = M, time = 2) + animate(src, pixel_x = pixel_x - pixel_x_diff, pixel_y = pixel_y - pixel_y_diff, transform = OM, time = 2) /atom/movable/proc/do_item_attack_animation(atom/A, visual_effect_icon, obj/item/used_item) var/image/I diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm index f0ccf235ae..1478079d37 100644 --- a/code/game/gamemodes/clock_cult/clock_cult.dm +++ b/code/game/gamemodes/clock_cult/clock_cult.dm @@ -37,6 +37,7 @@ Credit where due: 4. PJB3005 from /vg/ for the failed continuation PR 5. Xhuis from /tg/ for coding the first iteration of the mode, and the new, reworked version 6. ChangelingRain from /tg/ for maintaining the gamemode for months after its release prior to its rework +7. Clockwork cult code as of now, at least the one being pulled from Citadel Station's master branch, is being, or already is, fixed by Coolgat3 and Avunia. */ @@ -267,7 +268,7 @@ Credit where due: //Servant of Ratvar outfit /datum/outfit/servant_of_ratvar name = "Servant of Ratvar" - uniform = /obj/item/clothing/under/chameleon/ratvar + uniform = /obj/item/clothing/under/rank/engineer //no more chameleon suit for them, as requested shoes = /obj/item/clothing/shoes/sneakers/black back = /obj/item/storage/backpack ears = /obj/item/radio/headset diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 5029eaa03a..09047b05a9 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -36,7 +36,7 @@ /////////////////////////// /datum/game_mode/revolution/announce() to_chat(world, "The current game mode is - Revolution!") - to_chat(world, "Some crewmembers are attempting to start a revolution!
\nRevolutionaries - Kill the Captain, HoP, HoS, CE, RD and CMO. Convert other crewmembers (excluding the heads of staff, and security officers) to your cause by flashing them. Protect your leaders.
\nPersonnel - Protect the heads of staff. Kill the leaders of the revolution, and brainwash the other revolutionaries (by beating them in the head).
") + to_chat(world, "Some crewmembers are attempting to start a revolution!
\nRevolutionaries - Kill the Captain, HoP, HoS, CE, RD, QM and CMO. Convert other crewmembers (excluding the heads of staff, and security officers) to your cause by flashing them. Protect your leaders.
\nPersonnel - Protect the heads of staff. Kill the leaders of the revolution, and brainwash the other revolutionaries (by beating them in the head).
") /////////////////////////////////////////////////////////////////////////////// diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 4d3fd006d8..7137f28185 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -212,6 +212,17 @@ icon_state = "sleeper_s" controls_inside = TRUE +/obj/machinery/sleeper/syndie/Initialize() + . = ..() + component_parts = list() + component_parts += new /obj/item/circuitboard/machine/sleeper(null) + component_parts += new /obj/item/stock_parts/matter_bin/super(null) + component_parts += new /obj/item/stock_parts/manipulator/pico(null) + component_parts += new /obj/item/stack/sheet/glass(null) + component_parts += new /obj/item/stack/sheet/glass(null) + component_parts += new /obj/item/stack/cable_coil(null) + RefreshParts() + /obj/machinery/sleeper/syndie/fullupgrade/Initialize() . = ..() component_parts = list() diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 88f609c7f5..42ac9726bf 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -6,53 +6,116 @@ icon_screen = "invaders" clockwork = TRUE //it'd look weird var/list/prizes = list( - /obj/item/storage/box/snappops = 2, - /obj/item/toy/talking/AI = 2, - /obj/item/toy/talking/codex_gigas = 2, - /obj/item/clothing/under/syndicate/tacticool = 2, - /obj/item/toy/sword = 2, - /obj/item/toy/gun = 2, - /obj/item/gun/ballistic/shotgun/toy/crossbow = 2, - /obj/item/storage/box/fakesyndiesuit = 2, - /obj/item/storage/crayons = 2, - /obj/item/toy/spinningtoy = 2, - /obj/item/toy/prize/ripley = 1, - /obj/item/toy/prize/fireripley = 1, - /obj/item/toy/prize/deathripley = 1, - /obj/item/toy/prize/gygax = 1, - /obj/item/toy/prize/durand = 1, - /obj/item/toy/prize/honk = 1, - /obj/item/toy/prize/marauder = 1, - /obj/item/toy/prize/seraph = 1, - /obj/item/toy/prize/mauler = 1, - /obj/item/toy/prize/odysseus = 1, - /obj/item/toy/prize/phazon = 1, - /obj/item/toy/prize/reticence = 1, - /obj/item/toy/cards/deck = 2, - /obj/item/toy/nuke = 2, - /obj/item/toy/minimeteor = 2, - /obj/item/toy/redbutton = 2, - /obj/item/toy/talking/owl = 2, - /obj/item/toy/talking/griffin = 2, - /obj/item/coin/antagtoken = 2, - /obj/item/stack/tile/fakespace/loaded = 2, - /obj/item/stack/tile/fakepit/loaded = 2, - /obj/item/toy/toy_xeno = 2, - /obj/item/storage/box/actionfigure = 1, - /obj/item/restraints/handcuffs/fake = 2, - /obj/item/grenade/chem_grenade/glitter/pink = 1, - /obj/item/grenade/chem_grenade/glitter/blue = 1, - /obj/item/grenade/chem_grenade/glitter/white = 1, - /obj/item/toy/eightball = 2, - /obj/item/toy/windupToolbox = 2, - /obj/item/toy/clockwork_watch = 2, - /obj/item/toy/toy_dagger = 2, - /obj/item/extendohand/acme = 1, - /obj/item/hot_potato/harmless/toy = 1, - /obj/item/card/emagfake = 1, - /obj/item/clothing/shoes/wheelys = 2, - /obj/item/clothing/shoes/kindleKicks = 2, - /obj/item/storage/belt/military/snack = 2 + /obj/item/storage/box/snappops = 8, + /obj/item/toy/talking/AI = 8, + /obj/item/toy/talking/codex_gigas = 8, + /obj/item/clothing/under/syndicate/tacticool = 8, + /obj/item/toy/sword = 8, + /obj/item/toy/gun = 8, + /obj/item/gun/ballistic/shotgun/toy/crossbow = 8, + /obj/item/storage/box/fakesyndiesuit = 8, + /obj/item/storage/crayons = 8, + /obj/item/toy/spinningtoy = 8, + /obj/item/toy/prize/ripley = 4, + /obj/item/toy/prize/fireripley = 4, + /obj/item/toy/prize/deathripley = 4, + /obj/item/toy/prize/gygax = 4, + /obj/item/toy/prize/durand = 4, + /obj/item/toy/prize/honk = 4, + /obj/item/toy/prize/marauder = 4, + /obj/item/toy/prize/seraph = 4, + /obj/item/toy/prize/mauler = 4, + /obj/item/toy/prize/odysseus = 4, + /obj/item/toy/prize/phazon = 4, + /obj/item/toy/prize/reticence = 4, + /obj/item/toy/cards/deck = 8, + /obj/item/toy/nuke = 8, + /obj/item/toy/minimeteor = 8, + /obj/item/toy/redbutton = 8, + /obj/item/toy/talking/owl = 8, + /obj/item/toy/talking/griffin = 8, + /obj/item/coin/antagtoken = 8, + /obj/item/stack/tile/fakespace/loaded = 8, + /obj/item/stack/tile/fakepit/loaded = 8, + /obj/item/toy/toy_xeno = 8, + /obj/item/storage/box/actionfigure = 4, + /obj/item/restraints/handcuffs/fake = 8, + /obj/item/grenade/chem_grenade/glitter/pink = 4, + /obj/item/grenade/chem_grenade/glitter/blue = 4, + /obj/item/grenade/chem_grenade/glitter/white = 4, + /obj/item/toy/eightball = 8, + /obj/item/toy/windupToolbox = 8, + /obj/item/toy/clockwork_watch = 8, + /obj/item/toy/toy_dagger = 8, + /obj/item/extendohand/acme = 4, + /obj/item/hot_potato/harmless/toy = 4, + /obj/item/card/emagfake = 4, + /obj/item/clothing/shoes/wheelys = 8, + /obj/item/clothing/shoes/kindleKicks = 8, + /obj/item/storage/belt/military/snack = 8, + /obj/item/toy/plush/lizardplushie = 1, + /obj/item/toy/plush/lizardplushie/durgit = 1, + /obj/item/toy/plush/lizardplushie/rio = 1, + /obj/item/toy/plush/lizardplushie/urinsu = 1, + /obj/item/toy/plush/lizardplushie/arfrehn = 1, + /obj/item/toy/plush/lizardplushie/soars = 1, + /obj/item/toy/plush/lizardplushie/ghostie = 1, + /obj/item/toy/plush/lizardplushie/amber = 1, + /obj/item/toy/plush/lizardplushie/cyan = 1, + /obj/item/toy/plush/lizardplushie/meena = 1, + /obj/item/toy/plush/lizardplushie/stalks = 1, + /obj/item/toy/plush/lizardplushie/kobold = 1, + /obj/item/toy/plush/lizardplushie/gorgi = 1, + /obj/item/toy/plush/lizardplushie/almaz = 1, + /obj/item/toy/plush/snakeplushie/sasha = 1, + /obj/item/toy/plush/snakeplushie/shay = 1, + /obj/item/toy/plush/snakeplushie/vulken = 1, + /obj/item/toy/plush/mothplushie = 1, + /obj/item/toy/plush/mothplushie/bumble = 1, + /obj/item/toy/plush/mothplushie/nameko = 1, + /obj/item/toy/plush/mothplushie/suru = 1, + /obj/item/toy/plush/xeno = 1, + /obj/item/toy/plush/lampplushie = 1, + /obj/item/toy/plush/borgplushie = 1, + /obj/item/toy/plush/borgplushie/medihound = 1, + /obj/item/toy/plush/borgplushie/scrubpuppy = 1, + /obj/item/toy/plush/borgplushie/seeking = 1, + /obj/item/toy/plush/borgplushie/neeb = 1, + /obj/item/toy/plush/bird = 1, + /obj/item/toy/plush/bird/esela = 1, + /obj/item/toy/plush/bird/jahonna = 1, + /obj/item/toy/plush/bird/krick = 1, + /obj/item/toy/plush/bird/birddi = 1, + /obj/item/toy/plush/bird/jewel = 1, + /obj/item/toy/plush/mammal = 1, + /obj/item/toy/plush/mammal/dubious = 1, + /obj/item/toy/plush/mammal/gladwyn = 1, + /obj/item/toy/plush/mammal/gavin = 1, + /obj/item/toy/plush/mammal/blep = 1, + /obj/item/toy/plush/mammal/circe = 1, + /obj/item/toy/plush/mammal/pavel = 1, + /obj/item/toy/plush/mammal/oten = 1, + /obj/item/toy/plush/mammal/ray = 1, + /obj/item/toy/plush/mammal/dawud = 1, + /obj/item/toy/plush/mammal/edgar = 1, + /obj/item/toy/plush/mammal/frank = 1, + /obj/item/toy/plush/mammal/poojawa = 1, + /obj/item/toy/plush/mammal/hazel = 1, + /obj/item/toy/plush/mammal/jermaine = 1, + /obj/item/toy/plush/mammal/gunther = 1, + /obj/item/toy/plush/mammal/fox = 1, + /obj/item/toy/plush/mammal/zed = 1, + /obj/item/toy/plush/mammal/dog = 1, + /obj/item/toy/plush/mammal/dog/frost = 1, + /obj/item/toy/plush/mammal/dog/atticus = 1, + /obj/item/toy/plush/mammal/dog/fletch = 1, + /obj/item/toy/plush/mammal/dog/vincent = 1, + /obj/item/toy/plush/mammal/dog/zigfried = 1, + /obj/item/toy/plush/mammal/dog/nikolai = 1, + /obj/item/toy/plush/catgirl = 1, + /obj/item/toy/plush/catgirl/skylar = 1, + /obj/item/toy/plush/catgirl/mikeel = 1, + /obj/item/toy/plush/catgirl/robin = 1 ) light_color = LIGHT_COLOR_GREEN diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 72944d6afe..3b87c923d7 100755 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -108,8 +108,10 @@ tmp_alertlevel = SEC_LEVEL_GREEN if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN - if(tmp_alertlevel > SEC_LEVEL_BLUE) - tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this + if(tmp_alertlevel == SEC_LEVEL_BLUE) + tmp_alertlevel = SEC_LEVEL_BLUE + if(tmp_alertlevel > SEC_LEVEL_AMBER) + tmp_alertlevel = SEC_LEVEL_AMBER //Cannot engage delta with this set_security_level(tmp_alertlevel) if(GLOB.security_level != old_level) to_chat(usr, "Authorization confirmed. Modifying security level.") @@ -390,8 +392,10 @@ tmp_alertlevel = SEC_LEVEL_GREEN if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN - if(tmp_alertlevel > SEC_LEVEL_BLUE) - tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this + if(tmp_alertlevel == SEC_LEVEL_BLUE) + tmp_alertlevel = SEC_LEVEL_BLUE + if(tmp_alertlevel > SEC_LEVEL_AMBER) + tmp_alertlevel = SEC_LEVEL_AMBER //Cannot engage delta with this set_security_level(tmp_alertlevel) if(GLOB.security_level != old_level) //Only notify people if an actual change happened @@ -548,6 +552,7 @@ if(GLOB.security_level == SEC_LEVEL_DELTA) dat += "The self-destruct mechanism is active. Find a way to deactivate the mechanism to lower the alert level or evacuate." else + dat += "Amber
" dat += "Blue
" dat += "Green" if(STATE_CONFIRM_LEVEL) @@ -690,6 +695,7 @@ if(GLOB.security_level == SEC_LEVEL_DELTA) dat += "The self-destruct mechanism is active. Find a way to deactivate the mechanism to lower the alert level or evacuate." else + dat += "Amber
" dat += "Blue
" dat += "Green" diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm index 3a6cf2b922..7beb32eebb 100644 --- a/code/game/machinery/dance_machine.dm +++ b/code/game/machinery/dance_machine.dm @@ -5,7 +5,7 @@ icon_state = "jukebox" verb_say = "states" density = TRUE - req_access = list(ACCESS_BAR) + req_one_access = list(ACCESS_BAR, ACCESS_KITCHEN, ACCESS_HYDROPONICS, ACCESS_ENGINE, ACCESS_CARGO, ACCESS_THEATRE) var/active = FALSE var/list/rangers = list() var/stop = 0 diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index a157f9c485..43e8dff2b9 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -41,6 +41,7 @@ /obj/machinery/suit_storage_unit/engine suit_type = /obj/item/clothing/suit/space/hardsuit/engine mask_type = /obj/item/clothing/mask/breath + storage_type= /obj/item/clothing/shoes/magboots /obj/machinery/suit_storage_unit/ce suit_type = /obj/item/clothing/suit/space/hardsuit/engine/elite diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 6c0795028b..d8c0fbeeb3 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -275,6 +275,18 @@ variance = 25 harmful = TRUE +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/seedscatter + name = "\improper Melon Seed \"Scattershot\"" + desc = "A weapon for combat exosuits. Shoots a spread of pellets, shaped as seed." + icon_state = "mecha_scatter" + equip_cooldown = 30 + projectile = /obj/item/projectile/bullet/seed + projectiles = 4 + projectile_energy_cost = 55 + projectiles_per_shot = 10 + variance = 20 + harmful = TRUE + /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg name = "\improper Ultra AC 2" desc = "A weapon for combat exosuits. Shoots a rapid, three shot burst." diff --git a/code/game/objects/effects/effect_system/effect_system.dm b/code/game/objects/effects/effect_system/effect_system.dm index eb4c562c36..ddc805f3ff 100644 --- a/code/game/objects/effects/effect_system/effect_system.dm +++ b/code/game/objects/effects/effect_system/effect_system.dm @@ -56,6 +56,8 @@ would spawn and follow the beaker, even if it is carried or thrown. /datum/effect_system/proc/generate_effect() if(holder) location = get_turf(holder) + if(location.contents.len > 200) //Bandaid to prevent server crash exploit + return var/obj/effect/E = new effect_type(location) total_effects++ var/direction diff --git a/code/game/objects/effects/glowshroom.dm b/code/game/objects/effects/glowshroom.dm index 13497dfb8a..c009d3ec79 100644 --- a/code/game/objects/effects/glowshroom.dm +++ b/code/game/objects/effects/glowshroom.dm @@ -96,7 +96,7 @@ for(var/turf/open/floor/earth in view(3,src)) if(is_type_in_typecache(earth, blacklisted_glowshroom_turfs)) continue - if(!ownturf.CanAtmosPass(earth)) + if(!disease_air_spread_walk(ownturf, earth)) continue if(spreadsIntoAdjacent || !locate(/obj/structure/glowshroom) in view(1,earth)) possibleLocs += earth diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b01f1bca19..d14065b4c4 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -536,12 +536,16 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own . = ..(target, range, speed, thrower, spin, diagonals_first, callback) - /obj/item/proc/after_throw(datum/callback/callback) if (callback) //call the original callback . = callback.Invoke() throw_speed = initial(throw_speed) //explosions change this. item_flags &= ~IN_INVENTORY + var/matrix/M = matrix(transform) + M.Turn(rand(-170, 170)) + transform = M + pixel_x = rand(-12, 12) + pixel_y = rand(-12, 12) /obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/storage if(!newLoc) diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index a1f6639865..7881c277ff 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -36,6 +36,7 @@ RLD var/no_ammo_message = "The \'Low Ammo\' light on the device blinks yellow." var/has_ammobar = FALSE //controls whether or not does update_icon apply ammo indicator overlays var/ammo_sections = 10 //amount of divisions in the ammo indicator overlay/number of ammo indicator states + var/custom_range = 7 /obj/item/construction/Initialize() . = ..() @@ -75,6 +76,10 @@ RLD loaded = loadwithsheets(W, plasmarglassmultiplier*sheetmultiplier, user) //8 matter for one plasma rglass sheet else if(istype(W, /obj/item/stack/sheet/rglass)) loaded = loadwithsheets(W, rglassmultiplier*sheetmultiplier, user) //6 matter for one rglass sheet + else if(istype(W, /obj/item/stack/rods)) + loaded = loadwithsheets(W, sheetmultiplier * 0.5, user) // 2 matter for 1 rod, as 2 rods are produced from 1 metal + else if(istype(W, /obj/item/stack/tile/plasteel)) + loaded = loadwithsheets(W, sheetmultiplier * 0.25, user) // 1 matter for 1 floortile, as 4 tiles are produced from 1 metal if(loaded) to_chat(user, "[src] now holds [matter]/[max_matter] matter-units.") else @@ -119,7 +124,7 @@ RLD return . /obj/item/construction/proc/range_check(atom/A, mob/user) - if(!(A in view(7, get_turf(user)))) + if(!(A in range(custom_range, get_turf(user)))) to_chat(user, "The \'Out of Range\' light on [src] blinks red.") return FALSE else @@ -445,13 +450,23 @@ RLD matter = 160 /obj/item/construction/rcd/combat - name = "industrial RCD" + name = "Combat RCD" + desc = "A device used to rapidly build and deconstruct. Reload with metal, plasteel, glass or compressed matter cartridges. This RCD has been upgraded to be able to remove Rwalls!" icon_state = "ircd" item_state = "ircd" max_matter = 500 matter = 500 canRturf = TRUE +/obj/item/construction/rcd/industrial + name = "industrial RCD" + icon_state = "ircd" + item_state = "ircd" + max_matter = 500 + matter = 500 + delay_mod = 0.6 + sheetmultiplier = 8 + /obj/item/rcd_ammo name = "compressed matter cartridge" desc = "Highly compressed matter for the RCD." @@ -464,6 +479,8 @@ RLD var/ammoamt = 40 /obj/item/rcd_ammo/large + name = "large compressed matter cartridge" + desc = "Highly compressed matter for the RCD. Has four times the matter packed into the same space as a normal cartridge." materials = list(MAT_METAL=48000, MAT_GLASS=32000) ammoamt = 160 @@ -509,8 +526,9 @@ RLD icon_state = "rld-5" lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' - matter = 200 - max_matter = 200 + matter = 500 + max_matter = 500 + sheetmultiplier = 16 var/mode = LIGHT_MODE actions_types = list(/datum/action/item_action/pick_color) @@ -521,7 +539,7 @@ RLD var/walldelay = 10 var/floordelay = 10 - var/decondelay = 15 + var/decondelay = 10 var/color_choice = null diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index d22ef23291..cbbd7a387a 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -35,6 +35,7 @@ /obj/item/flashlight/attack_self(mob/user) on = !on update_brightness(user) + playsound(user, on ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, 1) for(var/X in actions) var/datum/action/A = X A.UpdateButtonIcon() diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm index 8e391d9559..a57bf47a2e 100644 --- a/code/game/objects/items/extinguisher.dm +++ b/code/game/objects/items/extinguisher.dm @@ -42,6 +42,18 @@ sprite_name = "miniFE" dog_fashion = null +/obj/item/extinguisher/mini/family + name = "pocket fire extinguisher" + desc = "A old fashen pocket fire extinguisher that has been modified with a larger water tank, and a small high-power sprayer. It feels cool to the touch and has a small humming to it..." + icon_state = "miniFE0" + item_state = "miniFE" + throwforce = 1 + w_class = WEIGHT_CLASS_SMALL + force = 2 + max_water = 40 + power = 7 + cooling_power = 3 + /obj/item/extinguisher/Initialize() . = ..() create_reagents(max_water) diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index cc121ab0a3..0b61bba471 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -11,12 +11,45 @@ strip_delay = 80 dog_fashion = null +// CITADEL CHANGES: More variants +/obj/item/clothing/head/helmet/chaplain/bland + icon_state = "knight_generic" + item_state = "knight_generic" + +/obj/item/clothing/head/helmet/chaplain/bland/horned + name = "horned crusader helmet" + desc = "Helfen, Wehren, Heilen." + icon_state = "knight_horned" + item_state = "knight_horned" + +/obj/item/clothing/head/helmet/chaplain/bland/winged + name = "winged crusader helmet" + desc = "Helfen, Wehren, Heilen." + icon_state = "knight_winged" + item_state = "knight_winged" +// CITADEL CHANGES ENDS HERE + /obj/item/clothing/suit/armor/riot/chaplain name = "crusader armour" desc = "God wills it!" icon_state = "knight_templar" item_state = "knight_templar" +// CITADEL CHANGES: More variants +/obj/item/clothing/suit/armor/riot/chaplain/teutonic + desc = "Help, Defend, Heal!" + icon_state = "knight_teutonic" + item_state = "knight_teutonic" + +/obj/item/clothing/suit/armor/riot/chaplain/teutonic/alt + icon_state = "knight_teutonic_alt" + item_state = "knight_teutonic_alt" + +/obj/item/clothing/suit/armor/riot/chaplain/hospitaller + icon_state = "knight_hospitaller" + item_state = "knight_hospitaller" +// CITADEL CHANGES ENDS HERE + /obj/item/holybeacon name = "armaments beacon" desc = "Contains a set of armaments for the chaplain." @@ -60,6 +93,22 @@ new /obj/item/clothing/head/helmet/chaplain(src) new /obj/item/clothing/suit/armor/riot/chaplain(src) +// CITADEL CHANGES: More Variants +/obj/item/storage/box/holy/teutonic + name = "Teutonic Kit" + +/obj/item/storage/box/holy/teutonic/PopulateContents() // It just works + pick(new /obj/item/clothing/head/helmet/chaplain/bland/horned(src), new /obj/item/clothing/head/helmet/chaplain/bland/winged(src)) + pick(new /obj/item/clothing/suit/armor/riot/chaplain/teutonic(src), new /obj/item/clothing/suit/armor/riot/chaplain/teutonic/alt(src)) + +/obj/item/storage/box/holy/hospitaller + name = "Hospitaller Kit" + +/obj/item/storage/box/holy/hospitaller/PopulateContents() + new /obj/item/clothing/head/helmet/chaplain/bland(src) + new /obj/item/clothing/suit/armor/riot/chaplain/hospitaller(src) +// CITADEL CHANGES ENDS HERE + /obj/item/storage/box/holy/student name = "Profane Scholar Kit" @@ -210,7 +259,7 @@ if(QDELETED(src) || !choice || M.stat || !in_range(M, src) || M.restrained() || !M.canmove || reskinned) return - var/A = display_names[choice] // This needs to be on a separate var as list member access is not allowed for new + var/A = display_names[choice] // This needs to be on a separate var as list member access is not allowed for new holy_weapon = new A SSreligion.holy_weapon_type = holy_weapon.type diff --git a/code/game/objects/items/implants/implant_mindshield.dm b/code/game/objects/items/implants/implant_mindshield.dm index 2f76b0cdc3..2c197eb7ec 100644 --- a/code/game/objects/items/implants/implant_mindshield.dm +++ b/code/game/objects/items/implants/implant_mindshield.dm @@ -29,8 +29,12 @@ if(target.mind.has_antag_datum(/datum/antagonist/rev/head) || target.mind.unconvertable) if(!silent) target.visible_message("[target] seems to resist the implant!", "You feel something interfering with your mental conditioning, but you resist it!") + var/obj/item/implanter/I = loc removed(target, 1) qdel(src) + if(istype(I)) + I.imp = null + I.update_icon() return FALSE var/datum/antagonist/rev/rev = target.mind.has_antag_datum(/datum/antagonist/rev) diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm index bf7b0b1b3b..11d6f264b8 100644 --- a/code/game/objects/items/kitchen.dm +++ b/code/game/objects/items/kitchen.dm @@ -176,3 +176,12 @@ user.visible_message("[user] begins flattening [user.p_their()] head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") return BRUTELOSS /* Trays moved to /obj/item/storage/bag */ + +/obj/item/kitchen/knife/scimitar + name = "Scimitar knife" + desc = "A knife used to cleanly butcher. Its razor-sharp edge has been honed for butchering, but has been poorly maintained over the years." + attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/kitchen/knife/scimiar/Initialize() + . = ..() + AddComponent(/datum/component/butchering, 90 - force, 100, force - 60) //bonus chance increases depending on force diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm index c5e92c4706..44ccd7aad5 100644 --- a/code/game/objects/items/mop.dm +++ b/code/game/objects/items/mop.dm @@ -15,7 +15,7 @@ var/mopping = 0 var/mopcount = 0 var/mopcap = 5 - var/mopspeed = 30 + var/stamusage = 5 force_string = "robust... against germs" var/insertable = TRUE @@ -39,6 +39,12 @@ if(!proximity) return + var/mob/living/L = user + + if(istype(L) && L.getStaminaLoss() >= STAMINA_SOFTCRIT) + to_chat(user, "You're too exhausted for that.") + return + if(reagents.total_volume < 1) to_chat(user, "Your mop is dry!") return @@ -49,11 +55,13 @@ return if(T) - user.visible_message("[user] begins to clean \the [T] with [src].", "You begin to clean \the [T] with [src]...") - - if(do_after(user, src.mopspeed, target = T)) - to_chat(user, "You finish mopping.") - clean(T) + user.visible_message("[user] cleans \the [T] with [src].", "You clean \the [T] with [src].") + clean(T) + user.changeNext_move(CLICK_CD_MELEE) + user.do_attack_animation(T, used_item = src) + if(istype(L)) + L.adjustStaminaLossBuffered(stamusage) + playsound(T, "slosh", 50, 1) /obj/effect/attackby(obj/item/I, mob/user, params) @@ -86,7 +94,7 @@ force = 6 throwforce = 8 throw_range = 4 - mopspeed = 20 + stamusage = 2 var/refill_enabled = TRUE //Self-refill toggle for when a janitor decides to mop with something other than water. var/refill_rate = 1 //Rate per process() tick mop refills itself var/refill_reagent = "water" //Determins what reagent to use for refilling, just in case someone wanted to make a HOLY MOP OF PURGING diff --git a/code/game/objects/items/paint.dm b/code/game/objects/items/paint.dm index c81fd08274..a6f5830dd4 100644 --- a/code/game/objects/items/paint.dm +++ b/code/game/objects/items/paint.dm @@ -56,22 +56,34 @@ icon_state = "paint_neutral" /obj/item/paint/anycolor/attack_self(mob/user) - var/t1 = input(user, "Please select a color:", "Locking Computer", null) in list( "red", "blue", "green", "yellow", "violet", "black", "white") + var/t1 = input(user, "Please select a color:", "Locking Computer", null) in list( "red", "pink", "blue", "cyan", "green", "lime", "yellow", "orange", "violet", "purple", "black", "gray", "white") if ((user.get_active_held_item() != src || user.stat || user.restrained())) return switch(t1) if("red") item_color = "C73232" + if("pink") + item_color = "FFC0CD" if("blue") item_color = "5998FF" + if("cyan") + item_color = "00FFFF" if("green") item_color = "2A9C3B" + if("lime") + item_color = "00FF00" if("yellow") item_color = "CFB52B" + if("orange") + item_color = "fFA700" if("violet") item_color = "AE4CCD" + if("purple") + item_color = "800080" if("white") item_color = "FFFFFF" + if("gray") + item_color = "808080" if("black") item_color = "333333" icon_state = "paint_[t1]" diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm index 9b109b5342..2411454ace 100644 --- a/code/game/objects/items/plushes.dm +++ b/code/game/objects/items/plushes.dm @@ -486,13 +486,79 @@ attack_verb = list("clawed", "hissed", "tail slapped") squeak_override = list('sound/weapons/slash.ogg' = 1) +/obj/item/toy/plush/lizardplushie/durgit + icon_state = "durgit" + item_state = "durgit" + squeak_override = list('modular_citadel/sound/voice/weh.ogg' = 1) //Durgit's the origin of the sound + +/obj/item/toy/plush/lizardplushie/rio + icon_state = "rio" + item_state = "rio" + +/obj/item/toy/plush/lizardplushie/urinsu + icon_state = "urinsu" + item_state = "urinsu" + +/obj/item/toy/plush/lizardplushie/arfrehn + icon_state = "arfrehn" + item_state = "arfrehn" + +/obj/item/toy/plush/lizardplushie/soars + icon_state = "soars" + item_state = "soars" + +/obj/item/toy/plush/lizardplushie/ghostie + icon_state = "ghostie" + item_state = "ghostie" + +/obj/item/toy/plush/lizardplushie/amber + icon_state = "amber" + item_state = "amber" + +/obj/item/toy/plush/lizardplushie/cyan + icon_state = "cyan" + item_state = "cyan" + +/obj/item/toy/plush/lizardplushie/meena + icon_state = "meena" + item_state = "meena" + +/obj/item/toy/plush/lizardplushie/stalks + icon_state = "stalks" + item_state = "stalks" + +/obj/item/toy/plush/lizardplushie/kobold + icon_state = "kobold" + item_state = "kobold" + +/obj/item/toy/plush/lizardplushie/gorgi + icon_state = "gorgi" + item_state = "gorgi" + +/obj/item/toy/plush/lizardplushie/almaz + icon_state = "almaz" + item_state = "almaz" + squeak_override = list('modular_citadel/sound/voice/raptor_purr.ogg' = 1) + /obj/item/toy/plush/snakeplushie name = "snake plushie" desc = "An adorable stuffed toy that resembles a snake. Not to be mistaken for the real thing." icon_state = "plushie_snake" item_state = "plushie_snake" attack_verb = list("bitten", "hissed", "tail slapped") - squeak_override = list('sound/weapons/bite.ogg' = 1) + squeak_override = list('sound/voice/lowHiss2.ogg' = 1) + +/obj/item/toy/plush/snakeplushie/sasha + icon_state = "sasha" + item_state = "sasha" + +/obj/item/toy/plush/snakeplushie/shay + icon_state = "shay" + item_state = "shay" + +/obj/item/toy/plush/snakeplushie/vulken + icon_state = "vulken" + item_state = "vulken" /obj/item/toy/plush/nukeplushie name = "operative plushie" @@ -517,6 +583,229 @@ icon_state = "plushie_awake" item_state = "plushie_awake" +/obj/item/toy/plush/mothplushie + name = "insect plushie" + desc = "An adorable stuffed toy that resembles some kind of insect" + icon_state = "cydia" + item_state = "cydia" + squeak_override = list('modular_citadel/sound/voice/mothsqueak.ogg' = 1) + +/obj/item/toy/plush/mothplushie/bumble + icon_state = "bumble" + item_state = "bumble" + +/obj/item/toy/plush/mothplushie/nameko + icon_state = "nameko" + item_state = "nameko" + +/obj/item/toy/plush/mothplushie/suru + icon_state = "suru" + item_state = "suru" + +/obj/item/toy/plush/xeno + name = "xenohybrid plushie" + desc = "An adorable stuffed toy that resmembles a xenomorphic crewmember." + icon_state = "seras" + item_state = "seras" + squeak_override = list('sound/voice/hiss2.ogg' = 1) + +/obj/item/toy/plush/lampplushie + name = "lamp plushie" + desc = "A toy lamp plushie, doesn't actually make light, but it still toggles on and off. Click clack!" + icon_state = "plushie_lamp" + item_state = "plushie_lamp" + attack_verb = list("lit", "flickered", "flashed") + squeak_override = list('sound/weapons/magout.ogg' = 1) + +/obj/item/toy/plush/borgplushie + name = "robot plushie" + desc = "An adorable stuffed toy of a robot." + icon_state = "securityk9" + item_state = "securityk9" + attack_verb = list("beeped", "booped", "pinged") + squeak_override = list('sound/machines/beep.ogg' = 1) + +/obj/item/toy/plush/borgplushie/medihound + icon_state = "medihound" + item_state = "medihound" + +/obj/item/toy/plush/borgplushie/scrubpuppy + icon_state = "scrubpuppy" + item_state = "scrubpuppy" + +/obj/item/toy/plush/borgplushie/seeking + icon_state = "seeking" + item_state = "seeking" + +/obj/item/toy/plush/borgplushie/neeb + icon_state = "neeb" + item_state = "neeb" + +/obj/item/toy/plush/bird + name = "bird plushie" + desc = "An adorable stuffed plushie that resembles an avian." + icon_state = "sylas" + item_state = "sylas" + attack_verb = list("peeped", "beeped", "poofed") + squeak_override = list('modular_citadel/sound/voice/peep.ogg' = 1) + +/obj/item/toy/plush/bird/esela + icon_state = "esela" + item_state = "esela" + +/obj/item/toy/plush/bird/jahonna + icon_state = "jahonna" + item_state = "jahonna" + +/obj/item/toy/plush/bird/krick + icon_state = "krick" + item_state = "krick" + +/obj/item/toy/plush/bird/birddi + icon_state = "birddi" + item_state = "birddi" + +/obj/item/toy/plush/bird/jewel + icon_state = "jewel" + item_state = "jewel" + +/obj/item/toy/plush/mammal + name = "mammal plushie" + desc = "An adorable stuffed toy resembling some sort of mammallian crew member." + icon_state = "faux" + item_state = "faux" + +/obj/item/toy/plush/mammal/dubious + icon_state = "dubious" + item_state = "dubious" + +/obj/item/toy/plush/mammal/gladwyn + icon_state = "gladwyn" + item_state = "gladwyn" + +/obj/item/toy/plush/mammal/gavin + icon_state = "gavin" + item_state = "gavin" + +/obj/item/toy/plush/mammal/blep + icon_state = "blep" + item_state = "blep" + +/obj/item/toy/plush/mammal/circe + icon_state = "circe" + item_state = "circe" + +/obj/item/toy/plush/mammal/pavel + icon_state = "pavel" + item_state = "pavel" + +/obj/item/toy/plush/mammal/oten + icon_state = "oten" + item_state = "oten" + +/obj/item/toy/plush/mammal/ray + icon_state = "ray" + item_state = "ray" + +/obj/item/toy/plush/mammal/dawud + icon_state = "dawud" + item_state = "dawud" + +/obj/item/toy/plush/mammal/edgar + icon_state = "edgar" + item_state = "edgar" + +/obj/item/toy/plush/mammal/frank + icon_state = "frank" + item_state = "frank" + +/obj/item/toy/plush/mammal/poojawa + icon_state = "poojawa" + item_state = "poojawa" + +/obj/item/toy/plush/mammal/hazel + icon_state = "hazel" + item_state = "hazel" + +/obj/item/toy/plush/mammal/joker + icon_state = "joker" + item_state = "joker" + +/obj/item/toy/plush/mammal/jermaine + icon_state = "jermaine" + item_state = "jermaine" + +/obj/item/toy/plush/mammal/gunther + icon_state = "gunther" + item_state = "gunther" + +/obj/item/toy/plush/mammal/fox + icon_state = "fox" + item_state = "fox" + +/obj/item/toy/plush/mammal/zed + icon_state = "zed" + item_state = "zed" + +/obj/item/toy/plush/mammal/dog + desc = "An adorable stuffed toy that resembles a canine." + icon_state = "katlin" + item_state = "katlin" + attack_verb = list("barked", "boofed", "borked") + squeak_override = list( + 'modular_citadel/sound/voice/bark1.ogg' = 1, + 'modular_citadel/sound/voice/bark2.ogg' = 1 + ) + +/obj/item/toy/plush/mammal/dog/frost + icon_state = "frost" + item_state = "frost" + +/obj/item/toy/plush/mammal/dog/atticus + icon_state = "atticus" + item_state = "atticus" + +/obj/item/toy/plush/mammal/dog/fletch + icon_state = "fletch" + item_state = "fletch" + +/obj/item/toy/plush/mammal/dog/vincent + icon_state = "vincent" + item_state = "vincent" + +/obj/item/toy/plush/mammal/dog/zigfried + desc = "An adorable stuffed toy of a very good boy." + icon_state = "zigfried" + item_state = "zigfried" + +/obj/item/toy/plush/mammal/dog/nikolai + icon_state = "nikolai" + item_state = "nikolai" + +/obj/item/toy/plush/catgirl + name = "feline plushie" + desc = "An adorable stuffed toy that resembles a felinid." + icon_state = "bailey" + item_state = "bailey" + attack_verb = list("headbutt", "scritched", "bit") + squeak_override = list('modular_citadel/sound/voice/nya.ogg' = 1) + +/obj/item/toy/plush/catgirl/mikeel + desc = "An adorable stuffed toy of some tauric cat person." + icon_state = "mikeel" + item_state = "mikeel" + +/obj/item/toy/plush/catgirl/skylar + desc = "An adorable stuffed toy that resembles a degenerate." + icon_state = "skylar" + item_state = "skylar" + attack_verb = list("powergamed", "merged", "tabled") + squeak_override = list('sound/effects/meow1.ogg' = 1) + +/obj/item/toy/plush/catgirl/robin + icon_state = "robin" + item_state = "robin" + /obj/item/toy/plush/awakenedplushie/ComponentInitialize() . = ..() AddComponent(/datum/component/edit_complainer) diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 77b669ec52..d3a3ecd5ef 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -266,6 +266,9 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list( if("large") pixel_x = rand(-5, 5) pixel_y = rand(-5, 5) + var/matrix/M = matrix(transform) + M.Turn(rand(-170, 170)) + transform = M /obj/item/shard/afterattack(atom/A as mob|obj, mob/user, proximity) . = ..() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index bbace70bec..e63ddd1c02 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -190,8 +190,10 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 30), \ new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/, 3, time = 10, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("winged wooden chair", /obj/structure/chair/wood/wings, 3, time = 10, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("plywood chair", /obj/structure/chair/comfy/plywood, 4, time = 10, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 50, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 20, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("rustic wooden door", /obj/structure/mineral_door/woodrustic, 10, time = 20, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \ diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 996ee8cd02..25fc96c251 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -441,6 +441,23 @@ new /obj/item/clothing/mask/muzzle(src) new /obj/item/mmi/syndie(src) +/obj/item/storage/backpack/duffelbag/syndie/surgery_adv + name = "advanced surgery duffel bag" + desc = "A large duffel bag for holding surgical tools. Bears the logo of an advanced med-tech firm." + +/obj/item/storage/backpack/duffelbag/syndie/surgery_adv/PopulateContents() + new /obj/item/hemostat/adv(src) + new /obj/item/circular_saw/adv(src) + new /obj/item/scalpel/adv(src) + new /obj/item/retractor/adv(src) + new /obj/item/cautery/adv(src) + new /obj/item/surgicaldrill/adv(src) + new /obj/item/surgical_drapes(src) + new /obj/item/storage/firstaid/tactical(src) + new /obj/item/clothing/suit/straight_jacket(src) + new /obj/item/clothing/mask/muzzle(src) + new /obj/item/mmi/syndie(src) + /obj/item/storage/backpack/duffelbag/syndie/ammo name = "ammunition duffel bag" desc = "A large duffel bag for holding extra weapons ammunition and supplies." diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 7414e0d5c2..8b932cf615 100755 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -168,6 +168,20 @@ /obj/item/pinpointer/crew )) + +/obj/item/storage/belt/medical/surgery_belt_adv + name = "surgical supply belt" + desc = "A specialized belt designed for holding surgical equipment. It seems to have specific pockets for each and every surgical tool you can think of." + +/obj/item/storage/belt/medical/surgery_belt_adv/PopulateContents() + new /obj/item/hemostat/adv(src) + new /obj/item/circular_saw/adv(src) + new /obj/item/scalpel/adv(src) + new /obj/item/retractor/adv(src) + new /obj/item/cautery/adv(src) + new /obj/item/surgicaldrill/adv(src) + new /obj/item/surgical_drapes(src) + /obj/item/storage/belt/security name = "security belt" desc = "Can hold security gear like handcuffs and flashes." diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm index c338f24d26..c795726421 100644 --- a/code/game/objects/items/storage/firstaid.dm +++ b/code/game/objects/items/storage/firstaid.dm @@ -99,6 +99,26 @@ new /obj/item/storage/pill_bottle/charcoal(src) new /obj/item/healthanalyzer(src) +/obj/item/storage/firstaid/radbgone + name = "radiation treatment kit" + desc = "Used to treat minor toxic blood content and major radiation poisoning." + icon_state = "antitoxin" + item_state = "firstaid-toxin" + +/obj/item/storage/firstaid/radbgone/suicide_act(mob/living/carbon/user) + user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!") + return TOXLOSS + +/obj/item/storage/firstaid/radbgone/PopulateContents() + if(empty) + return + new /obj/item/reagent_containers/syringe/charcoal(src) + new /obj/item/storage/pill_bottle/charcoal(src) + new /obj/item/reagent_containers/pill/mutadone(src) + new /obj/item/reagent_containers/pill/antirad(src) + new /obj/item/reagent_containers/food/drinks/bottle/vodka(src) + new /obj/item/healthanalyzer(src) + /obj/item/storage/firstaid/o2 name = "oxygen deprivation treatment kit" desc = "A box full of oxygen goodies." @@ -191,6 +211,14 @@ for(var/i in 1 to 7) new /obj/item/reagent_containers/pill/charcoal(src) +/obj/item/storage/pill_bottle/antirad + name = "bottle of charcoal pills" + desc = "Contains pills used to counter radiation poisoning." + +/obj/item/storage/pill_bottle/anitrad/PopulateContents() + for(var/i in 1 to 5) + new /obj/item/reagent_containers/pill/antirad(src) + /obj/item/storage/pill_bottle/epinephrine name = "bottle of epinephrine pills" desc = "Contains pills used to stabilize patients." diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index 6667cee76a..eb9fc86516 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -84,13 +84,6 @@ //Citadel change buffed to base levels total_mass = 2 -/obj/item/storage/toolbox/mechanical/old/heirloom/afterattack(atom/A, mob/user, proximity) //Citadel Adds massive buff to machinery destruction - . = ..() - if(proximity) - if(isobj(A)) - var/obj/O = A - O.take_damage(20) - /obj/item/storage/toolbox/mechanical/old/heirloom/PopulateContents() return diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm index 73bfda5b58..c263c2669d 100644 --- a/code/game/objects/items/storage/wallets.dm +++ b/code/game/objects/items/storage/wallets.dm @@ -13,6 +13,7 @@ . = ..() GET_COMPONENT(STR, /datum/component/storage) STR.max_items = 4 + STR.cant_hold = typecacheof(list(/obj/item/screwdriver/power)) STR.can_hold = typecacheof(list( /obj/item/stack/spacecash, /obj/item/card, diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 7b52ca7af1..7aaee7c5d4 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1039,6 +1039,7 @@ icon = 'icons/obj/toy.dmi' icon_state = "snowball" throwforce = 12 //pelt your enemies to death with lumps of snow + damtype = STAMINA /obj/item/toy/snowball/afterattack(atom/target as mob|obj|turf|area, mob/user) . = ..() diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 840ca74143..e944eb32da 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -192,6 +192,17 @@ /obj/structure/chair/comfy/lime color = rgb(255,251,0) +/obj/structure/chair/comfy/plywood + name = "plywood chair" + desc = "A relaxing plywood chair." + icon_state = "plywood_chair" + anchored = FALSE + buildstacktype = /obj/item/stack/sheet/mineral/wood + buildstackamount = 4 + +/obj/structure/chair/comfy/plywood/GetArmrest() + return mutable_appearance('icons/obj/chairs.dmi', "plywood_chair_armrest") + /obj/structure/chair/comfy/shuttle name = "shuttle seat" desc = "A comfortable, secure seat. It has a more sturdy looking buckling system, for smoother flights." diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm index d424bcf876..5ef952b139 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm @@ -74,6 +74,7 @@ new /obj/item/door_remote/chief_medical_officer(src) new /obj/item/clothing/neck/petcollar(src) new /obj/item/pet_carrier(src) + new /obj/item/storage/belt/medical/surgery_belt_adv(src) new /obj/item/wallframe/defib_mount(src) new /obj/item/circuitboard/machine/techfab/department/medical(src) new /obj/item/storage/photo_album/CMO(src) @@ -99,4 +100,4 @@ new /obj/item/storage/box/pillbottles(src) new /obj/item/storage/box/pillbottles(src) new /obj/item/storage/box/medsprays(src) - new /obj/item/storage/box/medsprays(src) \ No newline at end of file + new /obj/item/storage/box/medsprays(src) diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm index 7ee0f4dc24..585f60a347 100644 --- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm @@ -63,7 +63,8 @@ /obj/structure/closet/firecloset/PopulateContents() ..() - + if (prob(50)) + new /obj/item/reagent_containers/hypospray/medipen/firelocker(src) new /obj/item/clothing/suit/fire/firefighter(src) new /obj/item/clothing/mask/gas(src) new /obj/item/tank/internals/oxygen/red(src) @@ -71,6 +72,9 @@ new /obj/item/clothing/head/hardhat/red(src) /obj/structure/closet/firecloset/full/PopulateContents() + ..() + if (prob(50)) + new /obj/item/reagent_containers/hypospray/medipen/firelocker(src) new /obj/item/clothing/suit/fire/firefighter(src) new /obj/item/clothing/mask/gas(src) new /obj/item/flashlight(src) @@ -132,6 +136,8 @@ /obj/structure/closet/radiation/PopulateContents() ..() + if(prob(50)) + new /obj/item/storage/firstaid/radbgone(src) new /obj/item/geiger_counter(src) new /obj/item/clothing/suit/radiation(src) new /obj/item/clothing/head/radiation(src) @@ -146,18 +152,38 @@ /obj/structure/closet/bombcloset/PopulateContents() ..() + if(prob(70)) + new /obj/item/screwdriver(src) + if(prob(50)) + new /obj/item/multitool(src) + if(prob(70)) + new /obj/item/wirecutters(src) new /obj/item/clothing/suit/bomb_suit(src) new /obj/item/clothing/under/color/black(src) new /obj/item/clothing/shoes/sneakers/black(src) new /obj/item/clothing/head/bomb_hood(src) /obj/structure/closet/bombcloset/security/PopulateContents() + ..() + if(prob(90)) + new /obj/item/screwdriver(src) + if(prob(70)) + new /obj/item/multitool(src) + if(prob(90)) + new /obj/item/wirecutters(src) new /obj/item/clothing/suit/bomb_suit/security(src) new /obj/item/clothing/under/rank/security(src) new /obj/item/clothing/shoes/jackboots(src) new /obj/item/clothing/head/bomb_hood/security(src) /obj/structure/closet/bombcloset/white/PopulateContents() + ..() + if(prob(50)) + new /obj/item/screwdriver(src) + if(prob(20)) + new /obj/item/multitool(src) + if(prob(50)) + new /obj/item/wirecutters(src) new /obj/item/clothing/suit/bomb_suit/white(src) new /obj/item/clothing/under/color/black(src) new /obj/item/clothing/shoes/sneakers/black(src) diff --git a/code/game/objects/structures/fluff.dm b/code/game/objects/structures/fluff.dm index d9a4406acd..baf0cf312f 100644 --- a/code/game/objects/structures/fluff.dm +++ b/code/game/objects/structures/fluff.dm @@ -70,6 +70,13 @@ desc = "A towering basalt sculpture of a drake. Cracks run down its surface and parts of it have fallen off." icon_state = "drake_statue_falling" +/obj/structure/fluff/lightpost + name = "lightpost" + desc = "A homely lightpost adorned with festive decor." + icon = 'icons/obj/2x2.dmi' + icon_state = "lightpost" + deconstructible = FALSE + layer = EDGED_TURF_LAYER /obj/structure/fluff/bus name = "bus" @@ -167,3 +174,11 @@ desc = "A crudely-made sign with the words 'fok of' written in some sort of red paint." icon = 'icons/obj/fluff.dmi' icon_state = "fokof" + +/obj/structure/fluff/snowlegion + name = "snowlegion" + desc = "Looks like that weird kid with the tiger plushie has been round here again." + icon = 'icons/obj/fluff.dmi' + icon_state = "snowlegion" + anchored = TRUE + deconstructible = FALSE diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 3c9b70e967..13ca421daa 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -223,6 +223,16 @@ max_integrity = 200 rad_insulation = RAD_VERY_LIGHT_INSULATION +/obj/structure/mineral_door/woodrustic + name = "rustic wood door" + icon_state = "woodrustic" + openSound = 'sound/effects/doorcreaky.ogg' + closeSound = 'sound/effects/doorcreaky.ogg' + sheetType = /obj/item/stack/sheet/mineral/wood + sheetAmount = 10 + max_integrity = 200 + rad_insulation = RAD_VERY_LIGHT_INSULATION + /obj/structure/mineral_door/paperframe name = "paper frame door" icon_state = "paperframe" diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 4468cc0ba6..ea2e99d371 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -99,7 +99,7 @@ name = "magic mirror" desc = "Turn and face the strange... face." icon_state = "magic_mirror" - var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombies", "clockwork golem servant", "android", "synth", "mush") + var/list/races_blacklist = list("skeleton", "agent", "angel", "military_synth", "memezombies", "clockwork golem servant", "android", "synth", "mush", "zombie", "memezombie") var/list/choosable_races = list() /obj/structure/mirror/magic/New() diff --git a/code/game/objects/structures/signs/signs_maps.dm b/code/game/objects/structures/signs/signs_maps.dm index 8468516502..f3188b90c2 100644 --- a/code/game/objects/structures/signs/signs_maps.dm +++ b/code/game/objects/structures/signs/signs_maps.dm @@ -45,3 +45,12 @@ name = "command department" desc = "A direction sign, pointing out which way the Command department is." icon_state = "direction_bridge" + +/obj/structure/sign/directions/bar + name = "bar" + desc = "A direction sign, pointing out which way the Bar is." + icon_state = "direction_bar" + /obj/structure/sign/directions/cafe + name = "cafe" + desc = "A direction sign, pointing out which way the Cafe is." + icon_state = "direction_cafe" diff --git a/code/game/sound.dm b/code/game/sound.dm index 84351cdb95..1fafb4f34d 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -200,5 +200,11 @@ 'sound/vore/prey/death_04.ogg','sound/vore/prey/death_05.ogg','sound/vore/prey/death_06.ogg', 'sound/vore/prey/death_07.ogg','sound/vore/prey/death_08.ogg','sound/vore/prey/death_09.ogg', 'sound/vore/prey/death_10.ogg') + if("clang") + soundin = pick('sound/effects/clang1.ogg', 'sound/effects/clang2.ogg') + if("clangsmall") + soundin = pick('sound/effects/clangsmall1.ogg', 'sound/effects/clangsmall2.ogg') + if("slosh") + soundin = pick('sound/effects/slosh1.ogg', 'sound/effects/slosh2.ogg') //END OF CIT CHANGES return soundin diff --git a/code/game/turfs/closed.dm b/code/game/turfs/closed.dm index 2165dbd8db..6297cadc63 100644 --- a/code/game/turfs/closed.dm +++ b/code/game/turfs/closed.dm @@ -49,6 +49,14 @@ baseturfs = /turf/closed/indestructible/sandstone smooth = SMOOTH_TRUE +/turf/closed/indestructible/wood + name = "wooden wall" + desc = "A wall with wooden plating. Stiff." + icon = 'icons/turf/walls/wood_wall.dmi' + icon_state = "wood" + baseturfs = /turf/closed/indestructible/wood + smooth = SMOOTH_TRUE + /turf/closed/indestructible/oldshuttle/corner icon_state = "corner" @@ -76,6 +84,7 @@ icon = 'icons/turf/walls/riveted.dmi' icon_state = "riveted" smooth = SMOOTH_TRUE + explosion_block = INFINITY /turf/closed/indestructible/riveted/uranium icon = 'icons/turf/walls/uranium_wall.dmi' diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 7aa1183512..659a58b2dc 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -49,6 +49,20 @@ if(istype(AM)) playsound(src,sound,50,1) +/turf/open/indestructible/cobble/side + icon_state = "cobble_side" + +/turf/open/indestructible/cobble/corner + icon_state = "cobble_corner" + +/turf/open/indestructible/cobble + name = "cobblestone path" + desc = "A simple but beautiful path made of various sized stones." + icon = 'icons/turf/floors.dmi' + icon_state = "cobble" + baseturfs = /turf/open/indestructible/cobble + tiled_dirt = FALSE + /turf/open/indestructible/necropolis name = "necropolis floor" desc = "It's regarding you suspiciously." diff --git a/code/game/turfs/simulated/river.dm b/code/game/turfs/simulated/river.dm index e451fe4892..83fade33b2 100644 --- a/code/game/turfs/simulated/river.dm +++ b/code/game/turfs/simulated/river.dm @@ -4,11 +4,14 @@ #define RANDOM_LOWER_X 50 #define RANDOM_LOWER_Y 50 +#define RIVERGEN_SAFETY_LOCK 1000000 + /proc/spawn_rivers(target_z, nodes = 4, turf_type = /turf/open/lava/smooth/lava_land_surface, whitelist_area = /area/lavaland/surface/outdoors/unexplored, min_x = RANDOM_LOWER_X, min_y = RANDOM_LOWER_Y, max_x = RANDOM_UPPER_X, max_y = RANDOM_UPPER_Y) var/list/river_nodes = list() var/num_spawned = 0 var/list/possible_locs = block(locate(min_x, min_y, target_z), locate(max_x, max_y, target_z)) - while(num_spawned < nodes && possible_locs.len) + var/safety = 0 + while(num_spawned < nodes && possible_locs.len && (safety++ < RIVERGEN_SAFETY_LOCK)) var/turf/T = pick(possible_locs) var/area/A = get_area(T) if(!istype(A, whitelist_area) || (T.flags_1 & NO_LAVA_GEN_1)) @@ -16,7 +19,8 @@ else river_nodes += new /obj/effect/landmark/river_waypoint(T) num_spawned++ - + + safety = 0 //make some randomly pathing rivers for(var/A in river_nodes) var/obj/effect/landmark/river_waypoint/W = A @@ -30,7 +34,7 @@ break var/detouring = 0 var/cur_dir = get_dir(cur_turf, target_turf) - while(cur_turf != target_turf) + while(cur_turf != target_turf && (safety++ < RIVERGEN_SAFETY_LOCK)) if(detouring) //randomly snake around a bit if(prob(20)) diff --git a/code/game/world.dm b/code/game/world.dm index e83a01e7f2..d8576206dd 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -263,7 +263,7 @@ GLOBAL_VAR(restart_counter) s += "Citadel" //Replace this with something else. Or ever better, delete it and uncomment the game version. CIT CHANGE - modifies the hub entry link s += "" s += ")\]" //CIT CHANGE - encloses the server title in brackets to make the hub entry fancier - s += "
That furry /TG/code server your mother warned you about.
" //CIT CHANGE - adds a tagline! + s += "
[CONFIG_GET(string/servertagline)]
" //CIT CHANGE - adds a tagline! var/n = 0 for (var/mob/M in GLOB.player_list) diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm index 2916d444e5..9adfaada72 100644 --- a/code/modules/admin/chat_commands.dm +++ b/code/modules/admin/chat_commands.dm @@ -102,6 +102,15 @@ GLOBAL_LIST(round_end_notifiees) return "Query produced no output" var/list/text_res = results.Copy(1, 3) var/list/refs = results.len > 3 ? results.Copy(4) : null + if(refs) + var/list/L = list() + for(var/ref in refs) + var/atom/A = locate(ref) + if(A) + L += "[A]" + else + L += "[ref]" + refs = L . = "[text_res.Join("\n")][refs ? "\nRefs: [refs.Join(" ")]" : ""]" /datum/tgs_chat_command/reload_admins diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm index 603e4daf2d..85866d5c51 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm @@ -1,23 +1,195 @@ -// Code taken from /bay/station. -// Modified to allow consequtive querys in one invocation, terminated with ";" +#define SDQL_qdel_datum(d) qdel(d) + +//SDQL2 datumized, /tg/station special! -// Examples /* - -- Will call the proc for all computers in the world, thats dir is 2. - CALL ex_act(EXPLODE_DEVASTATE) ON /obj/machinery/computer IN world WHERE dir == 2 - -- Will open a window with a list of all the closets in the world, with a link to VV them. - SELECT /obj/structure/closet/secure_closet/security/cargo IN world WHERE icon_off == "secoff" - -- Will change all the tube lights to green - UPDATE /obj/machinery/light IN world SET color = "#0F0" WHERE icon_state == "tube1" - -- Will delete all pickaxes. "IN world" is not required. - DELETE /obj/item/pickaxe - -- Will flicker the lights once, then turn all mobs green. The semicolon is important to separate the consecutive querys, but is not required for standard one-query use - CALL flicker(1) ON /obj/machinery/light; UPDATE /mob SET color = "#00cc00" + Welcome admins, badmins and coders alike, to Structured Datum Query Language. + SDQL allows you to powerfully run code on batches of objects (or single objects, it's still unmatched + even there.) + When I say "powerfully" I mean it you're in for a ride. - --You can use operators other than ==, such as >, <=, != and etc.. + Ok so say you want to get a list of every mob. How does one do this? + "SELECT /mob" + This will open a list of every object in world that is a /mob. + And you can VV them if you need. + + What if you want to get every mob on a *specific z-level*? + "SELECT /mob WHERE z == 4" + + What if you want to select every mob on even numbered z-levels? + "SELECT /mob WHERE z % 2 == 0" + + Can you see where this is going? You can select objects with an arbitrary expression. + These expressions can also do variable access and proc calls (yes, both on-object and globals!) + Keep reading! + + Ok. What if you want to get every machine in the SSmachine process list? Looping through world is kinda + slow. + + "SELECT * IN SSmachines.machinery" + + Here "*" as type functions as a wildcard. + We know everything in the global SSmachines.machinery list is a machine. + + You can specify "IN " to return a list to operate on. + This can be any list that you can wizard together from global variables and global proc calls. + Every variable/proc name in the "IN" block is global. + It can also be a single object, in which case the object is wrapped in a list for you. + So yeah SDQL is unironically better than VV for complex single-object operations. + + You can of course combine these. + "SELECT * IN SSmachines.machinery WHERE z == 4" + "SELECT * IN SSmachines.machinery WHERE stat & 2" // (2 is NOPOWER, can't use defines from SDQL. Sorry!) + "SELECT * IN SSmachines.machinery WHERE stat & 2 && z == 4" + + The possibilities are endless (just don't crash the server, ok?). + + Oh it gets better. + + You can use "MAP " to run some code per object and use the result. For example: + + "SELECT /obj/machinery/power/smes MAP [charge / capacity * 100, RCon_tag, src]" + + This will give you a list of all the APCs, their charge AND RCon tag. Useful eh? + + [] being a list here. Yeah you can write out lists directly without > lol lists in VV. Color matrix + shenanigans inbound. + + After the "MAP" segment is executed, the rest of the query executes as if it's THAT object you just made + (here the list). + Yeah, by the way, you can chain these MAP / WHERE things FOREVER! + + "SELECT /mob WHERE client MAP client WHERE holder MAP holder" + + What if some dumbass admin spawned a bajillion spiders and you need to kill them all? + Oh yeah you'd rather not delete all the spiders in maintenace. Only that one room the spiders were + spawned in. + + "DELETE /mob/living/carbon/superior_animal/giant_spider WHERE loc.loc == marked" + + Here I used VV to mark the area they were in, and since loc.loc = area, voila. + Only the spiders in a specific area are gone. + + Or you know if you want to catch spiders that crawled into lockers too (how even?) + + "DELETE /mob/living/carbon/superior_animal/giant_spider WHERE global.get_area(src) == marked" + + What else can you do? + + Well suppose you'd rather gib those spiders instead of simply flat deleting them... + + "CALL gib() ON /mob/living/carbon/superior_animal/giant_spider WHERE global.get_area(src) == marked" + + Or you can have some fun.. + + "CALL forceMove(marked) ON /mob/living/carbon/superior_animal" + + You can also run multiple queries sequentially: + + "CALL forceMove(marked) ON /mob/living/carbon/superior_animal; CALL gib() ON + /mob/living/carbon/superior_animal" + + And finally, you can directly modify variables on objects. + + "UPDATE /mob WHERE client SET client.color = [0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]" + + Don't crash the server, OK? + + A quick recommendation: before you run something like a DELETE or another query.. Run it through SELECT + first. + You'd rather not gib every player on accident. + Or crash the server. + + By the way, queries are slow and take a while. Be patient. + They don't hang the entire server though. + + With great power comes great responsability. + + Here's a slightly more formal quick reference. + + The 4 queries you can do are: + + "SELECT " + "CALL ON " + "UPDATE SET var=,var2=" + "DELETE " + + "" in this context is " [IN ] [chain of MAP/WHERE modifiers]" + + "IN" (or "FROM", that works too but it's kinda weird to read), + is the list of objects to work on. This defaults to world if not provided. + But doing something like "IN living_mob_list" is quite handy and can optimize your query. + All names inside the IN block are global scope, so you can do living_mob_list (a global var) easily. + You can also run it on a single object. Because SDQL is that convenient even for single operations. + + filters out objects of, well, that type easily. "*" is a wildcard and just takes everything in + the source list. + + And then there's the MAP/WHERE chain. + These operate on each individual object being ran through the query. + They're both expressions like IN, but unlike it the expression is scoped *on the object*. + So if you do "WHERE z == 4", this does "src.z", effectively. + If you want to access global variables, you can do `global.living_mob_list`. + Same goes for procs. + + MAP "changes" the object into the result of the expression. + WHERE "drops" the object if the expression is falsey (0, null or "") + + What can you do inside expressions? + + * Proc calls + * Variable reads + * Literals (numbers, strings, type paths, etc...) + * \ref referencing: {0x30000cc} grabs the object with \ref [0x30000cc] + * Lists: [a, b, c] or [a: b, c: d] + * Math and stuff. + * A few special variables: src (the object currently scoped on), usr (your mob), + marked (your marked datum), global(global scope) + + TG ADDITIONS START: + Add USING keyword to the front of the query to use options system + The defaults aren't necessarily implemented, as there is no need to. + Available options: (D) means default + PROCCALL = (D)ASYNC, BLOCKING + SELECT = FORCE_NULLS, (D)SKIP_NULLS + PRIORITY = HIGH, (D) NORMAL + AUTOGC = (D) AUTOGC, KEEP_ALIVE + + Example: USING PROCCALL = BLOCKING, SELECT = FORCE_NULLS, PRIORITY = HIGH SELECT /mob FROM world WHERE z == 1 */ + +#define SDQL2_STATE_ERROR 0 +#define SDQL2_STATE_IDLE 1 +#define SDQL2_STATE_PRESEARCH 2 +#define SDQL2_STATE_SEARCHING 3 +#define SDQL2_STATE_EXECUTING 4 +#define SDQL2_STATE_SWITCHING 5 +#define SDQL2_STATE_HALTING 6 + +#define SDQL2_VALID_OPTION_TYPES list("proccall", "select", "priority", "autogc") +#define SDQL2_VALID_OPTION_VALUES list("async", "blocking", "force_nulls", "skip_nulls", "high", "normal", "keep_alive") + +#define SDQL2_OPTION_SELECT_OUTPUT_SKIP_NULLS (1<<0) +#define SDQL2_OPTION_BLOCKING_CALLS (1<<1) +#define SDQL2_OPTION_HIGH_PRIORITY (1<<2) //High priority SDQL query, allow using almost all of the tick. +#define SDQL2_OPTION_DO_NOT_AUTOGC (1<<3) + +#define SDQL2_OPTIONS_DEFAULT (SDQL2_OPTION_SELECT_OUTPUT_SKIP_NULLS) + +#define SDQL2_IS_RUNNING (state == SDQL2_STATE_EXECUTING || state == SDQL2_STATE_SEARCHING || state == SDQL2_STATE_SWITCHING || state == SDQL2_STATE_PRESEARCH) +#define SDQL2_HALT_CHECK if(!SDQL2_IS_RUNNING) {state = SDQL2_STATE_HALTING; return FALSE;}; + +#define SDQL2_TICK_CHECK ((options & SDQL2_OPTION_HIGH_PRIORITY)? CHECK_TICK_HIGH_PRIORITY : CHECK_TICK) + +#define SDQL2_STAGE_SWITCH_CHECK if(state != SDQL2_STATE_SWITCHING){\ + if(state == SDQL2_STATE_HALTING){\ + state = SDQL2_STATE_IDLE;\ + return FALSE}\ + state = SDQL2_STATE_ERROR;\ + CRASH("SDQL2 fatal error");}; + /client/proc/SDQL2_query(query_text as message) set category = "Debug" if(!check_rights(R_DEBUG)) //Shouldn't happen... but just to be safe. @@ -25,139 +197,694 @@ log_admin("Non-admin [key_name(usr)] attempted to execute a SDQL query!") return FALSE var/list/results = world.SDQL2_query(query_text, key_name_admin(usr), "[key_name(usr)]") - for(var/I in 1 to 3) - to_chat(usr, results[I]) + if(length(results) == 3) + for(var/I in 1 to 3) + to_chat(usr, results[I]) SSblackbox.record_feedback("nested tally", "SDQL query", 1, list(ckey, query_text)) /world/proc/SDQL2_query(query_text, log_entry1, log_entry2) - var/query_log = "executed SDQL query: \"[query_text]\"." + var/query_log = "executed SDQL query(s): \"[query_text]\"." message_admins("[log_entry1] [query_log]") query_log = "[log_entry2] [query_log]" log_game(query_log) NOTICE(query_log) + + var/start_time_total = REALTIMEOFDAY + + if(!length(query_text)) + return + var/list/query_list = SDQL2_tokenize(query_text) + if(!length(query_list)) + return + var/list/querys = SDQL_parse(query_list) + if(!length(querys)) + return + var/list/datum/SDQL2_query/running = list() + for(var/list/query_tree in querys) + var/datum/SDQL2_query/query = new /datum/SDQL2_query(query_tree) + if(QDELETED(query)) + continue + if(usr) + query.show_next_to_key = usr.ckey + running += query + var/msg = "Starting query #[query.id] - [query.get_query_text()]." + if(usr) + to_chat(usr, "[msg]") + log_admin(msg) + query.ARun() + var/finished = FALSE var/objs_all = 0 var/objs_eligible = 0 - var/start_time = REALTIMEOFDAY - - if(!query_text || length(query_text) < 1) - return - - - var/list/query_list = SDQL2_tokenize(query_text) - - if(!query_list || query_list.len < 1) - return - - var/list/querys = SDQL_parse(query_list) - - - if(!querys || querys.len < 1) - return - - var/list/refs = list() - var/where_used = FALSE - for(var/list/query_tree in querys) - var/list/from_objs = list() - var/list/select_types = list() - - switch(query_tree[1]) - if("explain") - SDQL_testout(query_tree["explain"]) - return - - if("call") - if("on" in query_tree) - select_types = query_tree["on"] + var/selectors_used = FALSE + var/list/combined_refs = list() + do + CHECK_TICK + finished = TRUE + for(var/i in running) + var/datum/SDQL2_query/query = i + if(QDELETED(query)) + running -= query + continue + else if(query.state != SDQL2_STATE_IDLE) + finished = FALSE + else if(query.state == SDQL2_STATE_ERROR) + if(usr) + to_chat(usr, "SDQL query [query.get_query_text()] errored. It will NOT be automatically garbage collected. Please remove manually.") + running -= query + else + if(query.finished) + objs_all += islist(query.obj_count_all)? length(query.obj_count_all) : query.obj_count_all + objs_eligible += islist(query.obj_count_eligible)? length(query.obj_count_eligible) : query.obj_count_eligible + selectors_used |= query.where_switched + combined_refs |= query.select_refs + running -= query + if(!CHECK_BITFIELD(query.options, SDQL2_OPTION_DO_NOT_AUTOGC)) + QDEL_IN(query, 50) else - return + if(usr) + to_chat(usr, "SDQL query [query.get_query_text()] was halted. It will NOT be automatically garbage collected. Please remove manually.") + running -= query + while(!finished) - if("select", "delete", "update") - select_types = query_tree[query_tree[1]] + var/end_time_total = REALTIMEOFDAY - start_time_total + return list("SDQL query combined results: [query_text]",\ + "SDQL query completed: [objs_all] objects selected by path, and [selectors_used ? objs_eligible : objs_all] objects executed on after WHERE filtering/MAPping if applicable.",\ + "SDQL combined querys took [DisplayTimeText(end_time_total)] to complete.") + combined_refs - from_objs = world.SDQL_from_objs(query_tree["from"]) +GLOBAL_LIST_INIT(sdql2_queries, GLOB.sdql2_queries || list()) +GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null, "VIEW VARIABLES (all)", null)) - var/list/objs = list() +/datum/SDQL2_query + var/list/query_tree + var/state = SDQL2_STATE_IDLE + var/options = SDQL2_OPTIONS_DEFAULT + var/superuser = FALSE //Run things like proccalls without using admin protections + var/allow_admin_interact = TRUE //Allow admins to do things to this excluding varedit these two vars + var/static/id_assign = 1 + var/id = 0 - for(var/type in select_types) - objs += SDQL_get_all(type, from_objs) - CHECK_TICK - objs_all = objs.len + var/qdel_on_finish = FALSE - if("where" in query_tree) - where_used = TRUE - var/objs_temp = objs - objs = list() - for(var/datum/d in objs_temp) - if(SDQL_expression(d, query_tree["where"])) - objs += d - objs_eligible++ - CHECK_TICK + //Last run + //General + var/finished = FALSE + var/start_time + var/end_time + var/where_switched = FALSE + var/show_next_to_key + //Select query only + var/list/select_refs + var/list/select_text + //Runtime tracked + //These three are weird. For best performance, they are only a number when they're not being changed by the SDQL searching/execution code. They only become numbers when they finish changing. + var/list/obj_count_all + var/list/obj_count_eligible + var/list/obj_count_finished - switch(query_tree[1]) - if("call") - for(var/datum/d in objs) - world.SDQL_var(d, query_tree["call"][1], source = d) - CHECK_TICK + //Statclick + var/obj/effect/statclick/SDQL2_delete/delete_click + var/obj/effect/statclick/SDQL2_action/action_click - if("delete") - for(var/datum/d in objs) - SDQL_qdel_datum(d) - CHECK_TICK +/datum/SDQL2_query/New(list/tree, SU = FALSE, admin_interact = TRUE, _options = SDQL2_OPTIONS_DEFAULT, finished_qdel = FALSE) + if(IsAdminAdvancedProcCall() || !LAZYLEN(tree)) + qdel(src) + return + LAZYADD(GLOB.sdql2_queries, src) + superuser = SU + allow_admin_interact = admin_interact + query_tree = tree + options = _options + id = id_assign++ + qdel_on_finish = finished_qdel - if("select") - var/text = "" - for(var/datum/t in objs) - text += SDQL_gen_vv_href(t) - refs[REF(t)] = TRUE - CHECK_TICK - usr << browse(text, "window=SDQL-result") +/datum/SDQL2_query/Destroy() + state = SDQL2_STATE_HALTING + query_tree = null + obj_count_all = null + obj_count_eligible = null + obj_count_finished = null + select_text = null + select_refs = null + GLOB.sdql2_queries -= src + return ..() - if("update") - if("set" in query_tree) - var/list/set_list = query_tree["set"] - for(var/datum/d in objs) - SDQL_internal_vv(d, set_list) - CHECK_TICK +/datum/SDQL2_query/proc/get_query_text() + var/list/out = list() + recursive_list_print(out, query_tree) + return out.Join() - var/end_time = REALTIMEOFDAY - end_time -= start_time - return list("SDQL query results: [query_text]",\ - "SDQL query completed: [objs_all] objects selected by path, and [where_used ? objs_eligible : objs_all] objects executed on after WHERE filtering if applicable.",\ - "SDQL query took [DisplayTimeText(end_time)] to complete.") + refs +/proc/recursive_list_print(list/output = list(), list/input, datum/callback/datum_handler, datum/callback/atom_handler) + output += "\[ " + for(var/i in 1 to input.len) + var/final = i == input.len + var/key = input[i] -/proc/SDQL_qdel_datum(datum/d) - qdel(d) - -/proc/SDQL_gen_vv_href(t) - var/text = "" - text += "[REF(t)]" - if(istype(t, /atom)) - var/atom/a = t - var/turf/T = a.loc - var/turf/actual = get_turf(a) - if(istype(T)) - text += ": [t] at turf [T] [ADMIN_COORDJMP(T)]
" - else if(a.loc && istype(actual)) - text += ": [t] in [a.loc] at turf [actual] [ADMIN_COORDJMP(actual)]
" + //print the key + if(islist(key)) + recursive_list_print(output, key, datum_handler, atom_handler) + else if(is_proper_datum(key) && (datum_handler || (isatom(key) && atom_handler))) + if(isatom(key) && atom_handler) + output += atom_handler.Invoke(key) + else + output += datum_handler.Invoke(key) else - text += ": [t]
" - else - text += ": [t]
" - return text + output += "[key]" -/proc/SDQL_internal_vv(d, list/set_list) + //print the value + var/is_value = (!isnum(key) && !isnull(input[key])) + if(is_value) + var/value = input[key] + if(islist(value)) + recursive_list_print(output, value, datum_handler, atom_handler) + else if(is_proper_datum(value) && (datum_handler || (isatom(value) && atom_handler))) + if(isatom(value) && atom_handler) + output += atom_handler.Invoke(value) + else + output += datum_handler.Invoke(value) + else + output += " = [value]" + + if(!final) + output += " , " + + output += " \]" + +/datum/SDQL2_query/proc/text_state() + switch(state) + if(SDQL2_STATE_ERROR) + return "###ERROR" + if(SDQL2_STATE_IDLE) + return "####IDLE" + if(SDQL2_STATE_PRESEARCH) + return "PRESEARCH" + if(SDQL2_STATE_SEARCHING) + return "SEARCHING" + if(SDQL2_STATE_EXECUTING) + return "EXECUTING" + if(SDQL2_STATE_SWITCHING) + return "SWITCHING" + if(SDQL2_STATE_HALTING) + return "##HALTING" + +/datum/SDQL2_query/proc/generate_stat() + if(!allow_admin_interact) + return + if(!delete_click) + delete_click = new(null, "INITIALIZING", src) + if(!action_click) + action_click = new(null, "INITIALIZNG", src) + stat("[id] ", delete_click.update("DELETE QUERY | STATE : [text_state()] | ALL/ELIG/FIN \ + [islist(obj_count_all)? length(obj_count_all) : (isnull(obj_count_all)? "0" : obj_count_all)]/\ + [islist(obj_count_eligible)? length(obj_count_eligible) : (isnull(obj_count_eligible)? "0" : obj_count_eligible)]/\ + [islist(obj_count_finished)? length(obj_count_finished) : (isnull(obj_count_finished)? "0" : obj_count_finished)] - [get_query_text()]")) + stat(" ", action_click.update("[SDQL2_IS_RUNNING? "HALT" : "RUN"]")) + +/datum/SDQL2_query/proc/delete_click() + admin_del(usr) + +/datum/SDQL2_query/proc/action_click() + if(SDQL2_IS_RUNNING) + admin_halt(usr) + else + admin_run(usr) + +/datum/SDQL2_query/proc/admin_halt(user = usr) + if(!SDQL2_IS_RUNNING) + return + var/msg = "[key_name(user)] has halted query #[id]" + message_admins(msg) + log_admin(msg) + state = SDQL2_STATE_HALTING + +/datum/SDQL2_query/proc/admin_run(mob/user = usr) + if(SDQL2_IS_RUNNING) + return + var/msg = "[key_name(user)] has (re)started query #[id]" + message_admins(msg) + log_admin(msg) + show_next_to_key = user.ckey + ARun() + +/datum/SDQL2_query/proc/admin_del(user = usr) + var/msg = "[key_name(user)] has stopped + deleted query #[id]" + message_admins(msg) + log_admin(msg) + qdel(src) + +/datum/SDQL2_query/proc/set_option(name, value) + switch(name) + if("select") + switch(value) + if("force_nulls") + DISABLE_BITFIELD(options, SDQL2_OPTION_SELECT_OUTPUT_SKIP_NULLS) + if("proccall") + switch(value) + if("blocking") + ENABLE_BITFIELD(options, SDQL2_OPTION_BLOCKING_CALLS) + if("priority") + switch(value) + if("high") + ENABLE_BITFIELD(options, SDQL2_OPTION_HIGH_PRIORITY) + if("autogc") + switch(value) + if("keep_alive") + ENABLE_BITFIELD(options, SDQL2_OPTION_DO_NOT_AUTOGC) + +/datum/SDQL2_query/proc/ARun() + INVOKE_ASYNC(src, .proc/Run) + +/datum/SDQL2_query/proc/Run() + if(SDQL2_IS_RUNNING) + return FALSE + if(query_tree["options"]) + for(var/name in query_tree["options"]) + var/value = query_tree["options"][name] + set_option(name, value) + select_refs = list() + select_text = null + obj_count_all = 0 + obj_count_eligible = 0 + obj_count_finished = 0 + start_time = REALTIMEOFDAY + + state = SDQL2_STATE_PRESEARCH + var/list/search_tree = PreSearch() + SDQL2_STAGE_SWITCH_CHECK + + state = SDQL2_STATE_SEARCHING + var/list/found = Search(search_tree) + SDQL2_STAGE_SWITCH_CHECK + + state = SDQL2_STATE_EXECUTING + Execute(found) + SDQL2_STAGE_SWITCH_CHECK + + end_time = REALTIMEOFDAY + state = SDQL2_STATE_IDLE + finished = TRUE + . = TRUE + if(show_next_to_key) + var/client/C = GLOB.directory[show_next_to_key] + if(C) + var/mob/showmob = C.mob + to_chat(showmob, "SDQL query results: [get_query_text()]
\ + SDQL query completed: [islist(obj_count_all)? length(obj_count_all) : obj_count_all] objects selected by path, and \ + [where_switched? "[islist(obj_count_eligible)? length(obj_count_eligible) : obj_count_eligible] objects executed on after WHERE keyword selection." : ""]
\ + SDQL query took [DisplayTimeText(end_time - start_time)] to complete.
") + if(length(select_text)) + var/text = islist(select_text)? select_text.Join() : select_text + var/static/result_offset = 0 + showmob << browse(text, "window=SDQL-result-[result_offset++]") + show_next_to_key = null + if(qdel_on_finish) + qdel(src) + +/datum/SDQL2_query/proc/PreSearch() + SDQL2_HALT_CHECK + switch(query_tree[1]) + if("explain") + SDQL_testout(query_tree["explain"]) + state = SDQL2_STATE_HALTING + return + if("call") + . = query_tree["on"] + if("select", "delete", "update") + . = query_tree[query_tree[1]] + state = SDQL2_STATE_SWITCHING + +/datum/SDQL2_query/proc/Search(list/tree) + SDQL2_HALT_CHECK + var/type = tree[1] + var/list/from = tree[2] + var/list/objs = SDQL_from_objs(from) + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + objs = SDQL_get_all(type, objs) + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + + // 1 and 2 are type and FROM. + var/i = 3 + while (i <= tree.len) + var/key = tree[i++] + var/list/expression = tree[i++] + switch (key) + if ("map") + for(var/j = 1 to objs.len) + var/x = objs[j] + objs[j] = SDQL_expression(x, expression) + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + + if ("where") + where_switched = TRUE + var/list/out = list() + obj_count_eligible = out + for(var/x in objs) + if(SDQL_expression(x, expression)) + out += x + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + objs = out + if(islist(obj_count_eligible)) + obj_count_eligible = objs.len + else + obj_count_eligible = obj_count_all + . = objs + state = SDQL2_STATE_SWITCHING + +/datum/SDQL2_query/proc/SDQL_from_objs(list/tree) + if(IsAdminAdvancedProcCall()) + if("world" in tree) + var/text = "[key_name(usr)] attempted to grab world with a procedure call to a SDQL datum." + message_admins(text) + log_admin(text) + return + if("world" in tree) + return world + return SDQL_expression(world, tree) + +/datum/SDQL2_query/proc/SDQL_get_all(type, location) + var/list/out = list() + obj_count_all = out + +// If only a single object got returned, wrap it into a list so the for loops run on it. + if(!islist(location) && location != world) + location = list(location) + + if(type == "*") + for(var/i in location) + var/datum/d = i + if(d.can_vv_get() || superuser) + out += d + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + return out + if(istext(type)) + type = text2path(type) + var/typecache = typecacheof(type) + + if(ispath(type, /mob)) + for(var/mob/d in location) + if(typecache[d.type] && (d.can_vv_get() || superuser)) + out += d + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + + else if(ispath(type, /turf)) + for(var/turf/d in location) + if(typecache[d.type] && (d.can_vv_get() || superuser)) + out += d + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + + else if(ispath(type, /obj)) + for(var/obj/d in location) + if(typecache[d.type] && (d.can_vv_get() || superuser)) + out += d + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + + else if(ispath(type, /area)) + for(var/area/d in location) + if(typecache[d.type] && (d.can_vv_get() || superuser)) + out += d + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + + else if(ispath(type, /atom)) + for(var/atom/d in location) + if(typecache[d.type] && (d.can_vv_get() || superuser)) + out += d + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + + else if(ispath(type, /datum)) + if(location == world) //snowflake for byond shortcut + for(var/datum/d) //stupid byond trick to have it not return atoms to make this less laggy + if(typecache[d.type] && (d.can_vv_get() || superuser)) + out += d + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + else + for(var/datum/d in location) + if(typecache[d.type] && (d.can_vv_get() || superuser)) + out += d + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + obj_count_all = out.len + return out + +/datum/SDQL2_query/proc/Execute(list/found) + SDQL2_HALT_CHECK + select_refs = list() + select_text = list() + switch(query_tree[1]) + if("call") + for(var/i in found) + if(!is_proper_datum(i)) + continue + world.SDQL_var(i, query_tree["call"][1], null, i, superuser, src) + obj_count_finished++ + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + + if("delete") + for(var/datum/d in found) + SDQL_qdel_datum(d) + obj_count_finished++ + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + + if("select") + var/list/text_list = list() + var/print_nulls = !(options & SDQL2_OPTION_SELECT_OUTPUT_SKIP_NULLS) + obj_count_finished = select_refs + for(var/i in found) + SDQL_print(i, text_list, print_nulls) + select_refs[REF(i)] = TRUE + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + select_text = text_list + + if("update") + if("set" in query_tree) + var/list/set_list = query_tree["set"] + for(var/d in found) + if(!is_proper_datum(d)) + continue + SDQL_internal_vv(d, set_list) + obj_count_finished++ + SDQL2_TICK_CHECK + SDQL2_HALT_CHECK + if(islist(obj_count_finished)) + obj_count_finished = obj_count_finished.len + state = SDQL2_STATE_SWITCHING + +/datum/SDQL2_query/proc/SDQL_print(object, list/text_list, print_nulls = TRUE) + if(is_proper_datum(object)) + text_list += "[REF(object)] : [object]" + if(istype(object, /atom)) + var/atom/A = object + var/turf/T = A.loc + var/area/a + if(istype(T)) + text_list += " at [T] [ADMIN_COORDJMP(T)]" + a = T.loc + else + var/turf/final = get_turf(T) //Recursive, hopefully? + if(istype(final)) + text_list += " at [final] [ADMIN_COORDJMP(final)]" + a = final.loc + else + text_list += " at nonexistant location" + if(a) + text_list += " in area [a]" + if(T.loc != a) + text_list += " inside [T]" + text_list += "
" + else if(islist(object)) + var/list/L = object + var/first = TRUE + text_list += "\[" + for (var/x in L) + if (!first) + text_list += ", " + first = FALSE + SDQL_print(x, text_list) + if (!isnull(x) && !isnum(x) && L[x] != null) + text_list += " -> " + SDQL_print(L[L[x]]) + text_list += "]
" + else + if(isnull(object)) + if(print_nulls) + text_list += "NULL
" + else + text_list += "[object]
" + +/datum/SDQL2_query/CanProcCall() + if(!allow_admin_interact) + return FALSE + return ..() + +/datum/SDQL2_query/vv_edit_var(var_name, var_value) + if(!allow_admin_interact) + return FALSE + if(var_name == NAMEOF(src, superuser) || var_name == NAMEOF(src, allow_admin_interact) || var_name == NAMEOF(src, query_tree)) + return FALSE + return ..() + +/datum/SDQL2_query/proc/SDQL_internal_vv(d, list/set_list) for(var/list/sets in set_list) var/datum/temp = d var/i = 0 for(var/v in sets) if(++i == sets.len) - temp.vv_edit_var(v, SDQL_expression(d, set_list[sets])) + if(superuser) + if(temp.vars.Find(v)) + temp.vars[v] = SDQL_expression(d, set_list[sets]) + else + temp.vv_edit_var(v, SDQL_expression(d, set_list[sets])) break - if(temp.vars.Find(v) && (istype(temp.vars[v], /datum))) + if(temp.vars.Find(v) && (istype(temp.vars[v], /datum) || istype(temp.vars[v], /client))) temp = temp.vars[v] else break +/datum/SDQL2_query/proc/SDQL_function_blocking(datum/object, procname, list/arguments, source) + var/list/new_args = list() + for(var/arg in arguments) + new_args[++new_args.len] = SDQL_expression(source, arg) + if(object == GLOB) // Global proc. + procname = "/proc/[procname]" + return superuser? (call(procname)(new_args)) : (WrapAdminProcCall(GLOBAL_PROC, procname, new_args)) + return superuser? (call(object, procname)(new_args)) : (WrapAdminProcCall(object, procname, new_args)) + +/datum/SDQL2_query/proc/SDQL_function_async(datum/object, procname, list/arguments, source) + set waitfor = FALSE + return SDQL_function_blocking(object, procname, arguments, source) + +/datum/SDQL2_query/proc/SDQL_expression(datum/object, list/expression, start = 1) + var/result = 0 + var/val + + for(var/i = start, i <= expression.len, i++) + var/op = "" + + if(i > start) + op = expression[i] + i++ + + var/list/ret = SDQL_value(object, expression, i) + val = ret["val"] + i = ret["i"] + + if(op != "") + switch(op) + if("+") + result = (result + val) + if("-") + result = (result - val) + if("*") + result = (result * val) + if("/") + result = (result / val) + if("&") + result = (result & val) + if("|") + result = (result | val) + if("^") + result = (result ^ val) + if("%") + result = (result % val) + if("=", "==") + result = (result == val) + if("!=", "<>") + result = (result != val) + if("<") + result = (result < val) + if("<=") + result = (result <= val) + if(">") + result = (result > val) + if(">=") + result = (result >= val) + if("and", "&&") + result = (result && val) + if("or", "||") + result = (result || val) + else + to_chat(usr, "SDQL2: Unknown op [op]") + result = null + else + result = val + + return result + +/datum/SDQL2_query/proc/SDQL_value(datum/object, list/expression, start = 1) + var/i = start + var/val = null + + if(i > expression.len) + return list("val" = null, "i" = i) + + if(istype(expression[i], /list)) + val = SDQL_expression(object, expression[i]) + + else if(expression[i] == "TRUE") + val = TRUE + + else if(expression[i] == "FALSE") + val = FALSE + + else if(expression[i] == "!") + var/list/ret = SDQL_value(object, expression, i + 1) + val = !ret["val"] + i = ret["i"] + + else if(expression[i] == "~") + var/list/ret = SDQL_value(object, expression, i + 1) + val = ~ret["val"] + i = ret["i"] + + else if(expression[i] == "-") + var/list/ret = SDQL_value(object, expression, i + 1) + val = -ret["val"] + i = ret["i"] + + else if(expression[i] == "null") + val = null + + else if(isnum(expression[i])) + val = expression[i] + + else if(ispath(expression[i])) + val = expression[i] + + else if(copytext(expression[i], 1, 2) in list("'", "\"")) + val = copytext(expression[i], 2, length(expression[i])) + + else if(expression[i] == "\[") + var/list/expressions_list = expression[++i] + val = list() + for(var/list/expression_list in expressions_list) + var/result = SDQL_expression(object, expression_list) + var/assoc + if(expressions_list[expression_list] != null) + assoc = SDQL_expression(object, expressions_list[expression_list]) + if(assoc != null) + // Need to insert the key like this to prevent duplicate keys fucking up. + var/list/dummy = list() + dummy[result] = assoc + result = dummy + val += result + else + val = world.SDQL_var(object, expression, i, object, superuser, src) + i = expression.len + + return list("val" = val, "i" = i) + /proc/SDQL_parse(list/query_list) var/datum/SDQL_parser/parser = new() var/list/querys = list() @@ -193,8 +920,6 @@ qdel(parser) return querys - - /proc/SDQL_testout(list/query_tree, indent = 0) var/static/whitespace = "    " var/spaces = "" @@ -220,182 +945,19 @@ else to_chat(usr, "[spaces][whitespace][query_tree[item]]") - - -/world/proc/SDQL_from_objs(list/tree) - if("world" in tree) - return src - return SDQL_expression(src, tree) - -/proc/SDQL_get_all(type, location) - var/list/out = list() - -// If only a single object got returned, wrap it into a list so the for loops run on it. - if(!islist(location) && location != world) - location = list(location) - - type = text2path(type) - var/typecache = typecacheof(type) - - if(ispath(type, /mob)) - for(var/mob/d in location) - if(typecache[d.type] && d.can_vv_get()) - out += d - CHECK_TICK - - else if(ispath(type, /turf)) - for(var/turf/d in location) - if(typecache[d.type] && d.can_vv_get()) - out += d - CHECK_TICK - - else if(ispath(type, /obj)) - for(var/obj/d in location) - if(typecache[d.type] && d.can_vv_get()) - out += d - CHECK_TICK - - else if(ispath(type, /area)) - for(var/area/d in location) - if(typecache[d.type] && d.can_vv_get()) - out += d - CHECK_TICK - - else if(ispath(type, /atom)) - for(var/atom/d in location) - if(typecache[d.type] && d.can_vv_get()) - out += d - CHECK_TICK - else if(ispath(type, /datum)) - if(location == world) //snowflake for byond shortcut - for(var/datum/d) //stupid byond trick to have it not return atoms to make this less laggy - if(typecache[d.type] && d.can_vv_get()) - out += d - CHECK_TICK - else - for(var/datum/d in location) - if(typecache[d.type] && d.can_vv_get()) - out += d - CHECK_TICK - - return out - - -/proc/SDQL_expression(datum/object, list/expression, start = 1) - var/result = 0 - var/val - - for(var/i = start, i <= expression.len, i++) - var/op = "" - - if(i > start) - op = expression[i] - i++ - - var/list/ret = SDQL_value(object, expression, i) - val = ret["val"] - i = ret["i"] - - if(op != "") - switch(op) - if("+") - result = (result + val) - if("-") - result = (result - val) - if("*") - result = (result * val) - if("/") - result = (result / val) - if("&") - result = (result & val) - if("|") - result = (result | val) - if("^") - result = (result ^ val) - if("=", "==") - result = (result == val) - if("!=", "<>") - result = (result != val) - if("<") - result = (result < val) - if("<=") - result = (result <= val) - if(">") - result = (result > val) - if(">=") - result = (result >= val) - if("and", "&&") - result = (result && val) - if("or", "||") - result = (result || val) - else - to_chat(usr, "SDQL2: Unknown op [op]") - result = null - else - result = val - - return result - -/proc/SDQL_value(datum/object, list/expression, start = 1) - var/i = start - var/val = null - - if(i > expression.len) - return list("val" = null, "i" = i) - - if(istype(expression[i], /list)) - val = SDQL_expression(object, expression[i]) - - else if(expression[i] == "!") - var/list/ret = SDQL_value(object, expression, i + 1) - val = !ret["val"] - i = ret["i"] - - else if(expression[i] == "~") - var/list/ret = SDQL_value(object, expression, i + 1) - val = ~ret["val"] - i = ret["i"] - - else if(expression[i] == "-") - var/list/ret = SDQL_value(object, expression, i + 1) - val = -ret["val"] - i = ret["i"] - - else if(expression[i] == "null") - val = null - - else if(isnum(expression[i])) - val = expression[i] - - else if(copytext(expression[i], 1, 2) in list("'", "\"")) - val = copytext(expression[i], 2, length(expression[i])) - - else if(expression[i] == "\[") - var/list/expressions_list = expression[++i] - val = list() - for(var/list/expression_list in expressions_list) - var/result = SDQL_expression(object, expression_list) - var/assoc - if(expressions_list[expression_list] != null) - assoc = SDQL_expression(object, expressions_list[expression_list]) - if(assoc != null) - // Need to insert the key like this to prevent duplicate keys fucking up. - var/list/dummy = list() - dummy[result] = assoc - result = dummy - val += result - else - val = world.SDQL_var(object, expression, i, object) - i = expression.len - - return list("val" = val, "i" = i) - -/world/proc/SDQL_var(datum/object, list/expression, start = 1, source) +//Staying as a world proc as this is called too often for changes to offset the potential IsAdminAdvancedProcCall checking overhead. +/world/proc/SDQL_var(object, list/expression, start = 1, source, superuser, datum/SDQL2_query/query) var/v + var/static/list/exclude = list("usr", "src", "marked", "global") var/long = start < expression.len - if(object == world && long && expression[start + 1] == ".") - to_chat(usr, "Sorry, but world variables are not supported at the moment.") + var/datum/D + if(is_proper_datum(object)) + D = object + + if (object == world && (!long || expression[start + 1] == ".") && !(expression[start] in exclude)) + to_chat(usr, "World variables are not allowed to be accessed. Use global.") return null + else if(expression [start] == "{" && long) if(lowertext(copytext(expression[start + 1], 1, 3)) != "0x") to_chat(usr, "Invalid pointer syntax: [expression[start + 1]]") @@ -405,12 +967,13 @@ to_chat(usr, "Invalid pointer: [expression[start + 1]]") return null start++ - else if((!long || expression[start + 1] == ".") && (expression[start] in object.vars)) - if(object.can_vv_get(expression[start])) - v = object.vars[expression[start]] + long = start < expression.len + else if(D != null && (!long || expression[start + 1] == ".") && (expression[start] in D.vars)) + if(D.can_vv_get(expression[start]) || superuser) + v = D.vars[expression[start]] else v = "SECRET" - else if(long && expression[start + 1] == ":" && hascall(object, expression[start])) + else if(D != null && long && expression[start + 1] == ":" && hascall(D, expression[start])) v = expression[start] else if(!long || expression[start + 1] == ".") switch(expression[start]) @@ -427,38 +990,70 @@ v = world if("global") v = GLOB + if("MC") + v = Master + if("FS") + v = Failsafe + if("CFG") + v = config + //Subsystem switches + if("SSgarbage") + v = SSgarbage + if("SSmachines") + v = SSmachines + if("SSobj") + v = SSobj + if("SSresearch") + v = SSresearch + if("SSprojectiles") + v = SSprojectiles + if("SSfastprocess") + v = SSfastprocess + if("SSticker") + v = SSticker + if("SStimer") + v = SStimer + if("SSradiation") + v = SSradiation + if("SSnpcpool") + v = SSnpcpool + if("SSmobs") + v = SSmobs + if("SSmood") + v = SSmood + if("SSquirks") + v = SSquirks + if("SSwet_floors") + v = SSwet_floors + if("SSshuttle") + v = SSshuttle + if("SSmapping") + v = SSmapping + if("SSevents") + v = SSevents + //End else return null else if(object == GLOB) // Shitty ass hack kill me. v = expression[start] if(long) if(expression[start + 1] == ".") - return SDQL_var(v, expression[start + 2], source = source) + return SDQL_var(v, expression[start + 2], null, source, superuser, query) else if(expression[start + 1] == ":") - return SDQL_function(object, v, expression[start + 2], source) + return (query.options & SDQL2_OPTION_BLOCKING_CALLS)? query.SDQL_function_async(object, v, expression[start + 2], source) : query.SDQL_function_blocking(object, v, expression[start + 2], source) else if(expression[start + 1] == "\[" && islist(v)) var/list/L = v - var/index = SDQL_expression(source, expression[start + 2]) + var/index = query.SDQL_expression(source, expression[start + 2]) if(isnum(index) && (!ISINTEGER(index) || L.len < index)) to_chat(usr, "Invalid list index: [index]") return null return L[index] return v -/proc/SDQL_function(var/datum/object, var/procname, var/list/arguments, source) - set waitfor = FALSE - var/list/new_args = list() - for(var/arg in arguments) - new_args += SDQL_expression(source, arg) - if(object == GLOB) // Global proc. - procname = "/proc/[procname]" - return WrapAdminProcCall(GLOBAL_PROC, procname, new_args) - return WrapAdminProcCall(object, procname, new_args) - /proc/SDQL2_tokenize(query_text) var/list/whitespace = list(" ", "\n", "\t") - var/list/single = list("(", ")", ",", "+", "-", ".", ";", "{", "}", "\[", "]", ":") + var/list/single = list("(", ")", ",", "+", "-", ".", "\[", "]", "{", "}", ";", ":") var/list/multi = list( "=" = list("", "="), "<" = list("", "=", ">"), @@ -560,3 +1155,20 @@ if(word != "") query_list += word return query_list + +/proc/is_proper_datum(thing) + return istype(thing, /datum) || istype(thing, /client) + +/obj/effect/statclick/SDQL2_delete/Click() + var/datum/SDQL2_query/Q = target + Q.delete_click() + +/obj/effect/statclick/SDQL2_action/Click() + var/datum/SDQL2_query/Q = target + Q.action_click() + +/obj/effect/statclick/SDQL2_VV_all + name = "VIEW VARIABLES" + +/obj/effect/statclick/SDQL2_VV_all/Click() + usr.client.debug_variables(GLOB.sdql2_queries) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm index 1bd95bc239..272bf83ca4 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm @@ -7,36 +7,34 @@ // // query : select_query | delete_query | update_query | call_query | explain // explain : 'EXPLAIN' query +// select_query : 'SELECT' object_selectors +// delete_query : 'DELETE' object_selectors +// update_query : 'UPDATE' object_selectors 'SET' assignments +// call_query : 'CALL' variable 'ON' object_selectors // Note here: 'variable' does function calls. This simplifies parsing. // -// select_query : 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] -// delete_query : 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] -// update_query : 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression] -// call_query : 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]] +// select_item : '*' | object_type // -// select_list : select_item [',' select_list] -// select_item : '*' | select_function | object_type -// select_function : count_function -// count_function : 'COUNT' '(' '*' ')' | 'COUNT' '(' object_types ')' +// object_selectors : select_item [('FROM' | 'IN') from_item] [modifier_list] +// modifier_list : ('WHERE' bool_expression | 'MAP' expression) [modifier_list] // -// from_list : from_item [',' from_list] -// from_item : 'world' | object_type +// from_item : 'world' | expression // -// call_function : ['(' [arguments] ')'] +// call_function : '(' [arguments] ')' // arguments : expression [',' arguments] // -// object_type : | string +// object_type : // -// assignments : assignment, [',' assignments] +// assignments : assignment [',' assignments] // assignment : '=' expression -// variable : | '.' variable +// variable : | '.' variable | '[' ']' | '[' ']' '.' variable // // bool_expression : expression comparitor expression [bool_operator bool_expression] // expression : ( unary_expression | '(' expression ')' | value ) [binary_operator expression] // unary_expression : unary_operator ( unary_expression | value | '(' expression ')' ) // comparitor : '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' -// value : variable | string | number | 'null' +// value : variable | string | number | 'null' | object_type // unary_operator : '!' | '-' | '~' -// binary_operator : comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' +// binary_operator : comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' | '%' // bool_operator : 'AND' | '&&' | 'OR' | '||' // // string : ''' ''' | '"' '"' @@ -51,10 +49,9 @@ var/list/query var/list/tree - var/list/select_functions = list("count") var/list/boolean_operators = list("and", "or", "&&", "||") var/list/unary_operators = list("!", "-", "~") - var/list/binary_operators = list("+", "-", "/", "*", "&", "|", "^") + var/list/binary_operators = list("+", "-", "/", "*", "&", "|", "^", "%") var/list/comparitors = list("=", "==", "!=", "<>", "<", "<=", ">", ">=") /datum/SDQL_parser/New(query_list) @@ -62,12 +59,12 @@ /datum/SDQL_parser/proc/parse_error(error_message) error = 1 - to_chat(usr, "SQDL2 Parsing Error: [error_message]") + to_chat(usr, "SQDL2 Parsing Error: [error_message]") return query.len + 1 /datum/SDQL_parser/proc/parse() tree = list() - query(1, tree) + query_options(1, tree) if(error) return list() @@ -91,354 +88,547 @@ /datum/SDQL_parser/proc/tokenl(i) return lowertext(token(i)) +/datum/SDQL_parser/proc/query_options(i, list/node) + var/list/options = list() + if(tokenl(i) == "using") + i = option_assignments(i + 1, node, options) + query(i, node) + if(length(options)) + node["options"] = options + +//option_assignment: query_option '=' define +/datum/SDQL_parser/proc/option_assignment(i, list/node, list/assignment_list = list()) + var/type = tokenl(i) + if(!(type in SDQL2_VALID_OPTION_TYPES)) + parse_error("Invalid option type: [type]") + if(!(token(i + 1) == "=")) + parse_error("Invalid option assignment symbol: [token(i + 1)]") + var/val = tokenl(i + 2) + if(!(val in SDQL2_VALID_OPTION_VALUES)) + parse_error("Invalid optoin value: [val]") + assignment_list[type] = val + return (i + 3) + +//option_assignments: option_assignment, [',' option_assignments] +/datum/SDQL_parser/proc/option_assignments(i, list/node, list/store) + i = option_assignment(i, node, store) + + if(token(i) == ",") + i = option_assignments(i + 1, node, store) + + return i //query: select_query | delete_query | update_query /datum/SDQL_parser/proc/query(i, list/node) query_type = tokenl(i) + switch(query_type) if("select") select_query(i, node) + if("delete") delete_query(i, node) + if("update") update_query(i, node) + if("call") call_query(i, node) + if("explain") node += "explain" node["explain"] = list() query(i + 1, node["explain"]) -// select_query: 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] +// select_query: 'SELECT' object_selectors /datum/SDQL_parser/proc/select_query(i, list/node) var/list/select = list() - i = select_list(i + 1, select) - node += "select" + i = object_selectors(i + 1, select) + node["select"] = select - selectors(i, node) return i -//delete_query: 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] + +//delete_query: 'DELETE' object_selectors /datum/SDQL_parser/proc/delete_query(i, list/node) var/list/select = list() - i = select_list(i + 1, select) - node += "delete" + i = object_selectors(i + 1, select) + node["delete"] = select - selectors(i, node) + return i -//update_query: 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression] + +//update_query: 'UPDATE' object_selectors 'SET' assignments /datum/SDQL_parser/proc/update_query(i, list/node) var/list/select = list() - i = select_list(i + 1, select) - node += "update" + i = object_selectors(i + 1, select) + node["update"] = select + if(tokenl(i) != "set") i = parse_error("UPDATE has misplaced SET") + var/list/set_assignments = list() i = assignments(i + 1, set_assignments) - node += "set" + node["set"] = set_assignments - selectors(i, node) + return i -//call_query: 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]] + +//call_query: 'CALL' call_function ['ON' object_selectors] /datum/SDQL_parser/proc/call_query(i, list/node) var/list/func = list() i = variable(i + 1, func) // Yes technically does anything variable() matches but I don't care, if admins fuck up this badly then they shouldn't be allowed near SDQL. - node += "call" + node["call"] = func + if(tokenl(i) != "on") - return i + return parse_error("You need to specify what to call ON.") + var/list/select = list() - i = select_list(i + 1, select) - node += "on" + i = object_selectors(i + 1, select) + node["on"] = select - selectors(i, node) + return i -//select_list: select_item [',' select_list] +// object_selectors: select_item [('FROM' | 'IN') from_item] [modifier_list] +/datum/SDQL_parser/proc/object_selectors(i, list/node) + i = select_item(i, node) + + if (tokenl(i) == "from" || tokenl(i) == "in") + i++ + var/list/from = list() + i = from_item(i, from) + node[++node.len] = from + + else + node[++node.len] = list("world") + + i = modifier_list(i, node) + return i + +// modifier_list: ('WHERE' bool_expression | 'MAP' expression) [modifier_list] +/datum/SDQL_parser/proc/modifier_list(i, list/node) + while (TRUE) + if (tokenl(i) == "where") + i++ + node += "where" + var/list/expr = list() + i = bool_expression(i, expr) + node[++node.len] = expr + + else if (tokenl(i) == "map") + i++ + node += "map" + var/list/expr = list() + i = expression(i, expr) + node[++node.len] = expr + + else + return i + +//select_list:select_item [',' select_list] /datum/SDQL_parser/proc/select_list(i, list/node) i = select_item(i, node) + if(token(i) == ",") i = select_list(i + 1, node) + return i //assignments: assignment, [',' assignments] /datum/SDQL_parser/proc/assignments(i, list/node) i = assignment(i, node) + if(token(i) == ",") i = assignments(i + 1, node) + return i + //select_item: '*' | select_function | object_type /datum/SDQL_parser/proc/select_item(i, list/node) - if(token(i) == "*") + if (token(i) == "*") node += "*" i++ - else if(tokenl(i) in select_functions) - i = select_function(i, node) - else + + else if (copytext(token(i), 1, 2) == "/") i = object_type(i, node) + + else + i = parse_error("Expected '*' or type path for select item") + return i // Standardized method for handling the IN/FROM and WHERE options. /datum/SDQL_parser/proc/selectors(i, list/node) while (token(i)) var/tok = tokenl(i) - if(tok in list("from", "in")) + if (tok in list("from", "in")) var/list/from = list() i = from_item(i + 1, from) + node["from"] = from continue - if(tok == "where") + + if (tok == "where") var/list/where = list() i = bool_expression(i + 1, where) + node["where"] = where continue + parse_error("Expected either FROM, IN or WHERE token, found [token(i)] instead.") return i + 1 - if(!node.Find("from")) + + if (!node.Find("from")) node["from"] = list("world") + return i -//from_item: 'world' | object_type +//from_item: 'world' | expression /datum/SDQL_parser/proc/from_item(i, list/node) if(token(i) == "world") node += "world" i++ + else i = expression(i, node) + return i + //bool_expression: expression [bool_operator bool_expression] /datum/SDQL_parser/proc/bool_expression(i, list/node) + var/list/bool = list() i = expression(i, bool) + node[++node.len] = bool + if(tokenl(i) in boolean_operators) i = bool_operator(i, node) i = bool_expression(i, node) + return i + //assignment: '=' expression /datum/SDQL_parser/proc/assignment(var/i, var/list/node, var/list/assignment_list = list()) assignment_list += token(i) + if(token(i + 1) == ".") i = assignment(i + 2, node, assignment_list) + else if(token(i + 1) == "=") var/exp_list = list() node[assignment_list] = exp_list + i = expression(i + 2, exp_list) + else parse_error("Assignment expected, but no = found") + return i -//variable: | '.' variable + +//variable: | '.' variable | '[' ']' | '[' ']' '.' variable /datum/SDQL_parser/proc/variable(i, list/node) var/list/L = list(token(i)) node[++node.len] = L + if(token(i) == "{") - L += token(i+1) + L += token(i + 1) i += 2 + if(token(i) != "}") parse_error("Missing } at end of pointer.") + if(token(i + 1) == ".") L += "." i = variable(i + 2, L) - else if(token(i + 1) == "(") // OH BOY PROC + + else if (token(i + 1) == "(") // OH BOY PROC var/list/arguments = list() i = call_function(i, null, arguments) L += ":" L[++L.len] = arguments - else if(token(i + 1) == "\[") + + else if (token(i + 1) == "\[") var/list/expression = list() i = expression(i + 2, expression) if (token(i) != "]") parse_error("Missing ] at the end of list access.") + L += "\[" L[++L.len] = expression i++ + else i++ + return i + +//object_type: +/datum/SDQL_parser/proc/object_type(i, list/node) + + if (copytext(token(i), 1, 2) != "/") + return parse_error("Expected type, but it didn't begin with /") + + var/path = text2path(token(i)) + if (path == null) + return parse_error("Nonexistant type path: [token(i)]") + + node += path + + return i + 1 + + +//comparitor: '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' +/datum/SDQL_parser/proc/comparitor(i, list/node) + + if(token(i) in list("=", "==", "!=", "<>", "<", "<=", ">", ">=")) + node += token(i) + + else + parse_error("Unknown comparitor [token(i)]") + + return i + 1 + + +//bool_operator: 'AND' | '&&' | 'OR' | '||' +/datum/SDQL_parser/proc/bool_operator(i, list/node) + + if(tokenl(i) in list("and", "or", "&&", "||")) + node += token(i) + + else + parse_error("Unknown comparitor [token(i)]") + + return i + 1 + + +//string: ''' ''' | '"' '"' +/datum/SDQL_parser/proc/string(i, list/node) + + if(copytext(token(i), 1, 2) in list("'", "\"")) + node += token(i) + + else + parse_error("Expected string but found '[token(i)]'") + + return i + 1 + //array: '[' expression, expression, ... ']' -/datum/SDQL_parser/proc/array(i, list/node) +/datum/SDQL_parser/proc/array(var/i, var/list/node) + // Arrays get turned into this: list("[", list(exp_1a = exp_1b, ...), ...), "[" is to mark the next node as an array. if(copytext(token(i), 1, 2) != "\[") parse_error("Expected an array but found '[token(i)]'") return i + 1 - node += token(i) + + node += token(i) // Add the "[" + var/list/expression_list = list() + i++ if(token(i) != "]") var/list/temp_expression_list = list() var/tok do tok = token(i) - if(tok == "," || tok == ":") - if(temp_expression_list == null) + if (tok == "," || tok == ":") + if (temp_expression_list == null) parse_error("Found ',' or ':' without expression in an array.") return i + 1 + expression_list[++expression_list.len] = temp_expression_list temp_expression_list = null - if(tok == ":") + if (tok == ":") temp_expression_list = list() i = expression(i + 1, temp_expression_list) expression_list[expression_list[expression_list.len]] = temp_expression_list temp_expression_list = null tok = token(i) - if(tok != ",") - if(tok == "]") + if (tok != ",") + if (tok == "]") break + parse_error("Expected ',' or ']' after array assoc value, but found '[token(i)]'") return i + + i++ continue + temp_expression_list = list() i = expression(i, temp_expression_list) + + // Ok, what the fuck BYOND? + // Not having these lines here causes the parser to die + // on an error saying that list/token() doesn't exist as a proc. + // These lines prevent that. + // I assume the compiler/VM is shitting itself and swapping out some variables internally? + // While throwing in debug logging it disappeared + // And these 3 lines prevent it from happening while being quiet. + // So.. it works. + // Don't touch it. + var/whatthefuck = i + whatthefuck = src.type + whatthefuck = whatthefuck + while(token(i) && token(i) != "]") - if(temp_expression_list) + + if (temp_expression_list) expression_list[++expression_list.len] = temp_expression_list + node[++node.len] = expression_list - return i + 1 -//object_type: | string -/datum/SDQL_parser/proc/object_type(i, list/node) - if(copytext(token(i), 1, 2) == "/") - node += token(i) - else - i = string(i, node) - return i + 1 - -//comparitor: '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' -/datum/SDQL_parser/proc/comparitor(i, list/node) - if(token(i) in list("=", "==", "!=", "<>", "<", "<=", ">", ">=")) - node += token(i) - else - parse_error("Unknown comparitor [token(i)]") - return i + 1 - -//bool_operator: 'AND' | '&&' | 'OR' | '||' -/datum/SDQL_parser/proc/bool_operator(i, list/node) - if(tokenl(i) in list("and", "or", "&&", "||")) - node += token(i) - else - parse_error("Unknown comparitor [token(i)]") - return i + 1 - -//string: ''' ''' | '"' '"' -/datum/SDQL_parser/proc/string(i, list/node) - if(copytext(token(i), 1, 2) in list("'", "\"")) - node += token(i) - else - parse_error("Expected string but found '[token(i)]'") return i + 1 //call_function: ['(' [arguments] ')'] /datum/SDQL_parser/proc/call_function(i, list/node, list/arguments) if(length(tokenl(i))) var/procname = "" - if(token(i) == "global" && token(i+1) == ".") + if(tokenl(i) == "global" && token(i + 1) == ".") // Global proc. i += 2 procname = "global." node += procname + token(i++) if(token(i) != "(") parse_error("Expected ( but found '[token(i)]'") + else if(token(i + 1) != ")") - var/list/expression_list_temp = list() + var/list/temp_expression_list = list() do - i = expression(i + 1, expression_list_temp) + i = expression(i + 1, temp_expression_list) if(token(i) == ",") - arguments[++arguments.len] = expression_list_temp - expression_list_temp = list() + arguments[++arguments.len] = temp_expression_list + temp_expression_list = list() continue + while(token(i) && token(i) != ")") - arguments[++arguments.len] = expression_list_temp + + arguments[++arguments.len] = temp_expression_list // The code this is copy pasted from won't be executed when it's the last param, this fixes that. else i++ else parse_error("Expected a function but found nothing") return i + 1 -//select_function: count_function -/datum/SDQL_parser/proc/select_function(i, list/node) - parse_error("Sorry, function calls aren't available yet") - return i //expression: ( unary_expression | '(' expression ')' | value ) [binary_operator expression] /datum/SDQL_parser/proc/expression(i, list/node) + if(token(i) in unary_operators) i = unary_expression(i, node) + else if(token(i) == "(") var/list/expr = list() + i = expression(i + 1, expr) + if(token(i) != ")") parse_error("Missing ) at end of expression.") + else i++ + node[++node.len] = expr + else i = value(i, node) + if(token(i) in binary_operators) i = binary_operator(i, node) i = expression(i, node) + else if(token(i) in comparitors) i = binary_operator(i, node) + var/list/rhs = list() i = expression(i, rhs) + node[++node.len] = rhs + + return i + //unary_expression: unary_operator ( unary_expression | value | '(' expression ')' ) /datum/SDQL_parser/proc/unary_expression(i, list/node) + if(token(i) in unary_operators) var/list/unary_exp = list() + unary_exp += token(i) i++ + if(token(i) in unary_operators) i = unary_expression(i, unary_exp) + else if(token(i) == "(") var/list/expr = list() + i = expression(i + 1, expr) + if(token(i) != ")") parse_error("Missing ) at end of expression.") + else i++ + unary_exp[++unary_exp.len] = expr + else i = value(i, unary_exp) + node[++node.len] = unary_exp + + else parse_error("Expected unary operator but found '[token(i)]'") + return i -//binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' + +//binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' | '%' /datum/SDQL_parser/proc/binary_operator(i, list/node) + if(token(i) in (binary_operators + comparitors)) node += token(i) + else parse_error("Unknown binary operator [token(i)]") + return i + 1 -//value: variable | string | number | 'null' + +//value: variable | string | number | 'null' | object_type /datum/SDQL_parser/proc/value(i, list/node) if(token(i) == "null") node += "null" i++ - else if(lowertext(copytext(token(i),1,3)) == "0x" && isnum(hex2num(copytext(token(i),3)))) - node += hex2num(copytext(token(i),3)) + + else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3)))) + node += hex2num(copytext(token(i), 3)) i++ + else if(isnum(text2num(token(i)))) node += text2num(token(i)) i++ + else if(copytext(token(i), 1, 2) in list("'", "\"")) i = string(i, node) + else if(copytext(token(i), 1, 2) == "\[") // Start a list. i = array(i, node) + else if(copytext(token(i), 1, 2) == "/") + i = object_type(i, node) else i = variable(i, node) - return i -/*EXPLAIN SELECT * WHERE 42 = 6 * 9 OR val = - 5 == 7*/ + return i diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm index 56faa1f6c4..a984e40fee 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm @@ -48,6 +48,12 @@ /proc/_image(icon, loc, icon_state, layer, dir) return image(icon, loc, icon_state, layer, dir) +/proc/_istype(object, type) + return istype(object, type) + +/proc/_ispath(path, type) + return ispath(path, type) + /proc/_length(E) return length(E) @@ -208,4 +214,3 @@ /proc/_step_away(ref, trg, max) step_away(ref, trg, max) - diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index 97cc991523..72da825e0c 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -4,10 +4,12 @@ if(!check_rights(R_SOUNDS)) return - var/freq = 1 var/vol = input(usr, "What volume would you like the sound to play at?",, 100) as null|num if(!vol) return + var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num + if(!freq) + freq = 1 vol = CLAMP(vol, 1, 100) var/sound/admin_sound = new() @@ -96,13 +98,17 @@ if (data["webpage_url"]) webpage_url = "[title]" + var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num + if(!freq) + freq = 1 + pitch = freq + var/res = alert(usr, "Show the title of and link to this song to the players?\n[title]",, "No", "Yes", "Cancel") switch(res) if("Yes") to_chat(world, "An admin played: [webpage_url]") if("Cancel") return - SSblackbox.record_feedback("nested tally", "played_url", 1, list("[ckey]", "[web_sound_input]")) log_admin("[key_name(src)] played web sound: [web_sound_input]") message_admins("[key_name(src)] played web sound: [web_sound_input]") diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index b227e6cce1..808c48e002 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -845,7 +845,7 @@ Traitors and the like can also be revived with the previous role mostly intact. if(!check_rights(R_ADMIN)) return - var/level = input("Select security level to change to","Set Security Level") as null|anything in list("green","blue","red","delta") + var/level = input("Select security level to change to","Set Security Level") as null|anything in list("green","blue","amber","red","delta") if(level) set_security_level(level) diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm index ad83d5f4d2..41f501e346 100644 --- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm +++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm @@ -194,7 +194,8 @@ else L.visible_message("[L]'s eyes blaze with brilliant light!", \ "Your vision suddenly screams with white-hot light!") - L.Knockdown(15) + L.Knockdown(160) + L.adjustStaminaLoss(140) // now kindle works pretty much like bloodcult stun knockdown and stamcrit wise L.apply_status_effect(STATUS_EFFECT_KINDLE) L.flash_act(1, 1) if(iscultist(L)) diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm index e78a6e4623..6415d9f91a 100644 --- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm +++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm @@ -71,7 +71,7 @@ desc = "Charges your slab with divine energy, allowing you to overwhelm a target with Ratvar's light." invocations = list("Divinity, show them your light!") whispered = TRUE - channel_time = 30 + channel_time = 20 // I think making kindle channel a third of the time less is a good make up for the fact that it silences people for such a little amount of time. power_cost = 125 usage_tip = "The light can be used from up to two tiles away. Damage taken will GREATLY REDUCE the stun's duration." tier = SCRIPTURE_DRIVER @@ -112,21 +112,21 @@ quickbind_desc = "Applies handcuffs to a struck target." -//Vanguard: Provides twenty seconds of stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker. +//Vanguard: Provides twenty seconds of greatly increased stamina and stun immunity. At the end of the twenty seconds, 25% of all stuns absorbed are applied to the invoker. /datum/clockwork_scripture/vanguard descname = "Self Stun Immunity" name = "Vanguard" - desc = "Provides twenty seconds of stun immunity. At the end of the twenty seconds, the invoker is knocked down for the equivalent of 25% of all stuns they absorbed. \ + desc = "Provides twenty seconds of greatly increased stamina and stun immunity. At the end of the twenty seconds, the invoker is knocked down for the equivalent of 25% of all stuns they absorbed. \ Excessive absorption will cause unconsciousness." invocations = list("Shield me...", "...from darkness!") channel_time = 30 - power_cost = 25 + power_cost = 75 usage_tip = "You cannot reactivate Vanguard while still shielded by it." tier = SCRIPTURE_DRIVER primary_component = VANGUARD_COGWHEEL sort_priority = 6 quickbind = TRUE - quickbind_desc = "Allows you to temporarily absorb stuns. All stuns absorbed will affect you when disabled." + quickbind_desc = "Allows you to temporarily have quickly regenerating stamina and absorb stuns. All stuns absorbed will affect you when disabled." /datum/clockwork_scripture/vanguard/check_special_requirements() if(!GLOB.ratvar_awakens && islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 5e3c0aa872..c582d0f8f2 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -508,7 +508,9 @@ if(SEC_LEVEL_GREEN) set_coefficient = 2 if(SEC_LEVEL_BLUE) - set_coefficient = 1 + set_coefficient = 1.2 + if(SEC_LEVEL_AMBER) + set_coefficient = 0.8 else set_coefficient = 0.5 var/surplus = timer - (SSshuttle.emergencyCallTime * set_coefficient) diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index e365f09b55..ade5458765 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -588,12 +588,18 @@ This is here to make the tiles around the station mininuke change when it's arme var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control if(istype(loneop)) loneop.weight += 1 + if(loneop.weight % 5 == 0) + message_admins("[src] is stationary in [ADMIN_VERBOSEJMP(newturf)]. The weight of Lone Operative is now [loneop.weight].") + log_game("[src] is stationary for too long in [loc_name(newturf)], and has increased the weight of the Lone Operative event to [loneop.weight].") else lastlocation = newturf last_disk_move = world.time var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control if(istype(loneop) && prob(loneop.weight)) loneop.weight = max(loneop.weight - 1, 0) + if(loneop.weight % 5 == 0) + message_admins("[src] is on the move (currently in [ADMIN_VERBOSEJMP(newturf)]). The weight of Lone Operative is now [loneop.weight].") + log_game("[src] being on the move has reduced the weight of the Lone Operative event to [loneop.weight].") /obj/item/disk/nuclear/examine(mob/user) . = ..() diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index 6fac9730f3..e6cae518b6 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -60,50 +60,13 @@ owner.current.forceMove(pick(GLOB.wizardstart)) /datum/antagonist/wizard/proc/create_objectives() - switch(rand(1,100)) - if(1 to 30) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = owner - kill_objective.find_target() - objectives += kill_objective + var/datum/objective/new_objective = new("Cause as much creative mayhem as you can aboard the station! The more outlandish your methods of achieving this, the better! Make sure there's a decent amount of crew alive to tell of your tale.") + new_objective.owner = owner + objectives += new_objective - if (!(locate(/datum/objective/escape) in owner.objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = owner - objectives += escape_objective - - if(31 to 60) - var/datum/objective/steal/steal_objective = new - steal_objective.owner = owner - steal_objective.find_target() - objectives += steal_objective - - if (!(locate(/datum/objective/escape) in owner.objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = owner - objectives += escape_objective - - if(61 to 85) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = owner - kill_objective.find_target() - objectives += kill_objective - - var/datum/objective/steal/steal_objective = new - steal_objective.owner = owner - steal_objective.find_target() - objectives += steal_objective - - if (!(locate(/datum/objective/survive) in owner.objectives)) - var/datum/objective/survive/survive_objective = new - survive_objective.owner = owner - objectives += survive_objective - - else - if (!(locate(/datum/objective/hijack) in owner.objectives)) - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = owner - objectives += hijack_objective + var/datum/objective/escape/escape_objective = new + escape_objective.owner = owner + objectives += escape_objective for(var/datum/objective/O in objectives) owner.objectives += O diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index b653c3de7f..ad83ed8c13 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -125,7 +125,9 @@ to_chat(M, "[user] blinds you with the flash!") else to_chat(M, "You are blinded by [src]!") - M.Knockdown(rand(80,120)) + var/toblur = 20 - M.eye_blurry + if(toblur > 0) + M.blur_eyes(toblur) else if(user) visible_message("[user] fails to blind [M] with the flash!") to_chat(user, "You fail to blind [M] with the flash!") @@ -141,7 +143,7 @@ if(!try_use_flash(user)) return FALSE if(iscarbon(M)) - flash_carbon(M, user, 5, 1) + flash_carbon(M, user, 20, 1) return TRUE else if(issilicon(M)) var/mob/living/silicon/robot/R = M diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm index ebca252167..bf5d8efb13 100644 --- a/code/modules/atmospherics/environmental/LINDA_fire.dm +++ b/code/modules/atmospherics/environmental/LINDA_fire.dm @@ -20,8 +20,8 @@ if(active_hotspot) if(soh) if((tox > 0.5 || trit > 0.5) && oxy > 0.5) - if(active_hotspot.temperature < exposed_temperature) - active_hotspot.temperature = exposed_temperature + if(active_hotspot.temperature < exposed_temperature*50) + active_hotspot.temperature = exposed_temperature*50 if(active_hotspot.volume < exposed_volume) active_hotspot.volume = exposed_volume return 1 @@ -36,7 +36,7 @@ return 0 active_hotspot = new /obj/effect/hotspot(src) - active_hotspot.temperature = exposed_temperature + active_hotspot.temperature = exposed_temperature*50 active_hotspot.volume = exposed_volume*25 active_hotspot.just_spawned = (current_cycle < SSair.times_fired) @@ -47,6 +47,7 @@ heating.temperature = exposed_temperature heating.react() assume_air(heating) + air_update_turf() return igniting //This is the icon for fire on turfs, also helps for nurturing small fires until they are full tile diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index bcb3752cbf..0a7b76cc79 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -650,7 +650,7 @@ if(0) add_overlay(AALARM_OVERLAY_GREEN) overlay_state = AALARM_OVERLAY_GREEN - light_color = LIGHT_COLOR_BLUEGREEN + light_color = LIGHT_COLOR_PALEBLUE set_light(brightness_on) if(1) add_overlay(AALARM_OVERLAY_WARN) diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm index 16ecae7a5f..7cb771737e 100644 --- a/code/modules/awaymissions/mission_code/snowdin.dm +++ b/code/modules/awaymissions/mission_code/snowdin.dm @@ -10,6 +10,10 @@ name = "Snowdin Tundra Plains" icon_state = "awaycontent25" +/area/awaymission/snowdin/outside/vip + name = "Snowdin Tundra Plains" + icon_state = "awaycontent25" + /area/awaymission/snowdin/post name = "Snowdin Outpost" icon_state = "awaycontent2" @@ -116,7 +120,7 @@ name = "Snowdin Main Base" icon_state = "awaycontent16" dynamic_lighting = DYNAMIC_LIGHTING_ENABLED - requires_power = TRUE + requires_power = FALSE /area/awaymission/snowdin/dungeon1 name = "Snowdin Depths" diff --git a/code/modules/cargo/exports/manifest.dm b/code/modules/cargo/exports/manifest.dm index d59ef1093f..763ca70dfe 100644 --- a/code/modules/cargo/exports/manifest.dm +++ b/code/modules/cargo/exports/manifest.dm @@ -76,3 +76,17 @@ /datum/export/manifest_correct_denied/get_cost(obj/O) var/obj/item/paper/fluff/jobs/cargo/manifest/M = O return ..() - M.order_cost + +// Paper work done correctly + +/datum/export/paperwork_correct + cost = 50 + unit_name = "correct paperwork" + export_types = list(/obj/item/paper/fluff/jobs/cargo/manifest/paperwork_correct) + +// Paper work not done retruned + +/datum/export/paperwork_incorrect + cost = -500 // Failed to meet NT standers + unit_name = "returned incorrect paperwork" + export_types = list(/obj/item/paper/fluff/jobs/cargo/manifest/paperwork) diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm index cef8685027..1f0d7d29b3 100644 --- a/code/modules/cargo/order.dm +++ b/code/modules/cargo/order.dm @@ -95,3 +95,14 @@ while(--lost >= 0) qdel(pick(C.contents)) return C + +//Paperwork for NT +/obj/item/paper/fluff/jobs/cargo/manifest/paperwork + name = "Incomplete Paperwork" + desc = "These should've been filled out four months ago! Unfinished grant papers issued by Nanotrasen's finance department. Complete this page for additional funding." + icon = 'icons/obj/bureaucracy.dmi' + +/obj/item/paper/fluff/jobs/cargo/manifest/paperwork_correct + name = "Finished Paperwork" + desc = "A neat stack of filled-out forms, in triplicate and signed. Is there anything more satisfying? Make sure they get stamped." + icon = 'icons/obj/bureaucracy.dmi' diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 1bf41e3d25..42b3509872 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -81,10 +81,19 @@ crate_name = "emergency crate" crate_type = /obj/structure/closet/crate/internals +/datum/supply_pack/emergency/rcds + name = "Emergency RCDs" + desc = "Bombs going off on station? SME blown and now you need to fix the hole it left behind? Well this crate has a pare of Rcds to be able to easily fix up any problem you may have!" + cost = 1500 + contains = list(/obj/item/construction/rcd, + /obj/item/construction/rcd) + crate_name = "emergency rcds" + crate_type = /obj/structure/closet/crate/internals + /datum/supply_pack/emergency/soft_suit name = "Emergency Space Suit " desc = "Is there bombs going off left and right? Is there meteors shooting around the station? Well we have two fragile space suit for emergencys as well as air and masks." - cost = 1000 + cost = 1000 contains = list(/obj/item/tank/internals/air, /obj/item/tank/internals/air, /obj/item/clothing/mask/gas, @@ -256,6 +265,26 @@ crate_name = "weed control crate" crate_type = /obj/structure/closet/crate/secure/hydroponics +/datum/supply_pack/medical/anitvirus + name = "Virus Containment Crate" + desc = "Viro let out a death plague Mk II again? Someone didnt wash there hands? Old plagues born anew? Well this crate is for you! Hope you cure it before it brakes out of the station... This crate needs medical access to open and has two bio suits, a box of needles and beakers, five spaceacillin needles, and a medibot." + cost = 3000 + access = ACCESS_MEDICAL + contains = list(/mob/living/simple_animal/bot/medbot, + /obj/item/clothing/head/bio_hood, + /obj/item/clothing/head/bio_hood, + /obj/item/clothing/suit/bio_suit, + /obj/item/clothing/suit/bio_suit, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/reagent_containers/syringe/antiviral, + /obj/item/storage/box/syringes, + /obj/item/storage/box/beakers) + crate_name = "virus containment unit crate" + crate_type = /obj/structure/closet/crate/secure/plasma + ////////////////////////////////////////////////////////////////////////////// //////////////////////////// Security //////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -386,6 +415,29 @@ /obj/item/melee/baton/loaded) crate_name = "stun baton crate" +/datum/supply_pack/security/russianclothing + name = "Russian Surplus Clothing" + desc = "An old russian crate full of surplus armor that they used to use! Has two sets of bulletproff armor, a few union suits and some warm hats!" + hidden = TRUE + contraband = TRUE + cost = 5000 // Its basicly sec suits, good boots/gloves + contains = list(/obj/item/clothing/suit/security/officer/russian, + /obj/item/clothing/suit/security/officer/russian, + /obj/item/clothing/shoes/combat, + /obj/item/clothing/shoes/combat, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/head/ushanka, + /obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/suit/armor/bulletproof, + /obj/item/clothing/head/helmet/alt, + /obj/item/clothing/head/helmet/alt, + /obj/item/clothing/gloves/combat, + /obj/item/clothing/gloves/combat, + /obj/item/clothing/mask/gas, + /obj/item/clothing/mask/gas) + crate_name = "surplus russian clothing" + crate_type = /obj/structure/closet/crate/internals + /datum/supply_pack/security/taser name = "Taser Crate" desc = "From the depths of stunbased combat, this order rises above, supreme. Contains three hybrid tasers, capable of firing both electrodes and disabling shots. Requires Security access to open." @@ -666,6 +718,15 @@ /obj/item/clothing/suit/space/hardsuit/engine) crate_name = "engineering hardsuit" +/datum/supply_pack/engineering/industrialrcd + name = "Industrial RCD" + desc = "A industrial RCD in case the station has gone through more then one meteor storm and the CE needs to bring out the somthing a bit more reliable. Dose not contain spare ammo for the industrial RCD or any other RCD modles." + cost = 4500 + access = ACCESS_CE + contains = list(/obj/item/construction/rcd/industrial) + crate_name = "industrial rcd" + crate_type = /obj/structure/closet/crate/secure/engineering + /datum/supply_pack/engineering/powergamermitts name = "Insulated Gloves Crate" desc = "The backbone of modern society. Barely ever ordered for actual engineering. Contains three insulated gloves." @@ -1011,6 +1072,28 @@ contains = list(/obj/item/stack/sheet/mineral/wood/fifty) crate_name = "wood planks crate" +/datum/supply_pack/materials/rcdammo + name = "Spare RDC ammo" + desc = "This crate contains sixteen RCD ammo packs, to help with any holes or projects people mite be working on." + cost = 3750 + contains = list(/obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo, + /obj/item/rcd_ammo) + crate_name = "rcd ammo" + /datum/supply_pack/materials/bz name = "BZ Canister Crate" desc = "Contains a canister of BZ. Requires Toxins access to open." @@ -1153,6 +1236,24 @@ /obj/item/storage/firstaid/regular) crate_name = "first aid kit crate" +/datum/supply_pack/medical/iv_drip + name = "IV Drip Crate" + desc = "Contains a single IV drip stand for intravenous delivery." + cost = 700 + contains = list(/obj/machinery/iv_drip) + crate_name = "iv drip crate" + +/datum/supply_pack/science/adv_surgery_tools + name = "Med-Co Advanced surgery tools" + desc = "A full set of Med-Co advanced surgery tools, this crate also comes with a spay of synth flesh as well as a can of . Requires Surgery access to open." + cost = 5000 + access = ACCESS_SURGERY + contains = list(/obj/item/storage/belt/medical/surgery_belt_adv, + /obj/item/reagent_containers/medspray/synthflesh, + /obj/item/reagent_containers/medspray/sterilizine) + crate_name = "medco newest surgery tools" + crate_type = /obj/structure/closet/crate/medical + /datum/supply_pack/medical/medicalhardsuit name = "Medical Hardsuit" desc = "Got people being spaced left and right? Hole in the same room as the dead body of Hos or cap? Fear not, now you can buy one medical hardsuit with a mask and air tank to save your fellow crewmembers." @@ -1162,13 +1263,6 @@ /obj/item/clothing/suit/space/hardsuit/medical) crate_name = "medical hardsuit" -/datum/supply_pack/medical/iv_drip - name = "IV Drip Crate" - desc = "Contains a single IV drip for administering blood to patients." - cost = 700 - contains = list(/obj/machinery/iv_drip) - crate_name = "iv drip crate" - /datum/supply_pack/medical/supplies name = "Medical Supplies Crate" desc = "Contains seven beakers, syringes, and bodybags. Three morphine bottles, four insulin pills. Two charcoal bottles, epinephrine bottles, antitoxin bottles, and large beakers. Finally, a single roll of medical gauze, as well as a bottle of stimulant pills for long, hard work days. German doctor not included." @@ -1280,6 +1374,7 @@ crate_type = /obj/structure/closet/crate/secure/plasma dangerous = TRUE + ////////////////////////////////////////////////////////////////////////////// //////////////////////////// Science ///////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -1395,6 +1490,19 @@ /datum/supply_pack/service group = "Service" + +/datum/supply_pack/service/advlighting + name = "Advanced Lighting crate" + desc = "Thanks to advanced lighting tech we here at the Lamp Factory have be able to produce more lamps and lamp items! This crate has three lamps, a box of lights and a state of the art rapid-light-device!" + cost = 2500 //Fair + contains = list(/obj/item/construction/rld, + /obj/item/flashlight/lamp, + /obj/item/flashlight/lamp, + /obj/item/flashlight/lamp/green, + /obj/item/storage/box/lights/mixed) + crate_name = "advanced lighting crate" + crate_type = /obj/structure/closet/crate/secure + /datum/supply_pack/service/cargo_supples name = "Cargo Supplies Crate" desc = "Sold everything that wasn't bolted down? You can get right back to work with this crate containing stamps, an export scanner, destination tagger, hand labeler and some package wrapping." @@ -1453,6 +1561,20 @@ crate_name = "janitor backpack crate" crate_type = /obj/structure/closet/crate/secure +/datum/supply_pack/service/janitor/janpremium + name = "Janitor Premium Supplies" + desc = "Do to the union for better supplies, we have desided to make a deal for you, In this crate you can get a brand new chem, Drying Angent this stuff is the work of slimes or magic! This crate also contains a rag to test out the Drying Angent magic, three wet floor signs, and some spare bottles of ammonia." + cost = 3000 + access = ACCESS_JANITOR + contains = list(/obj/item/caution, + /obj/item/caution, + /obj/item/caution, + /obj/item/reagent_containers/glass/rag, + /obj/item/reagent_containers/glass/bottle/ammonia, + /obj/item/reagent_containers/glass/bottle/ammonia, + /obj/item/reagent_containers/spray/drying_agent) + crate_name = "janitor backpack crate" + /datum/supply_pack/service/mule name = "MULEbot Crate" desc = "Pink-haired Quartermaster not doing her job? Replace her with this tireless worker, today!" @@ -1606,7 +1728,7 @@ name = "Kitchen Cutlery Deluxe Set" desc = "Need to slice and dice away those ''Tomatos'' well we got what you need! From a nice set of knifes, forks, plates, glasses, and a whetstone for when you got some grizzle that is a bit harder to slice then normal." cost = 10000 - contraband = TRUE + contraband = TRUE contains = list(/obj/item/sharpener, /obj/item/kitchen/fork, /obj/item/kitchen/fork, @@ -1663,6 +1785,22 @@ access = ACCESS_THEATRE crate_type = /obj/structure/closet/crate/secure +/datum/supply_pack/organic/hunting + name = "Huntting gear" + desc = "Even in space, we can fine prey to hunt, this crate contains everthing a fine hunter needs to have a sporting time. This crate needs armory access to open. A true huntter only needs a fine bottle of cognac, a nice coat, some good o' cigars, and of cource a huntting shotgun. " + cost = 3500 + contraband = TRUE + contains = list(/obj/item/clothing/head/flatcap, + /obj/item/clothing/suit/hooded/wintercoat/captain, + /obj/item/reagent_containers/food/drinks/bottle/cognac, + /obj/item/storage/fancy/cigarettes/cigars/havana, + /obj/item/clothing/gloves/color/white, + /obj/item/clothing/under/rank/curator, + /obj/item/gun/ballistic/shotgun/lethal) + access = ACCESS_ARMORY + crate_name = "sporting crate" + crate_type = /obj/structure/closet/crate/secure // Would have liked a wooden crate but access >:( + /datum/supply_pack/organic/hydroponics name = "Hydroponics Crate" desc = "Supplies for growing a great garden! Contains two bottles of ammonia, two Plant-B-Gone spray bottles, a hatchet, cultivator, plant analyzer, as well as a pair of leather gloves and a botanist's apron." @@ -2106,8 +2244,7 @@ /datum/supply_pack/costumes_toys/randomised/toys name = "Toy Crate" desc = "Who cares about pride and accomplishment? Skip the gaming and get straight to the sweet rewards with this product! Contains five random toys. Warranty void if used to prank research directors." - cost = 5000 // or play the arcade machines ya lazy bum - // TODID make this actually just use the arcade machine loot list + cost = 1500 // or play the arcade machines ya lazy bum num_contained = 5 contains = list(/obj/item/storage/box/snappops, /obj/item/toy/talking/AI, @@ -2161,6 +2298,77 @@ crate_name = "toy crate" crate_type = /obj/structure/closet/crate/wooden +/datum/supply_pack/costumes_toys/randomised/plush + name = "Plush Crate" + desc = "Plush tide station wide. Contains 5 random plushies for you to love. Warranty void if your love violates the terms of use." + cost = 1500 // or play the arcade machines ya lazy bum + num_contained = 5 + contains = list(/obj/item/toy/plush/lizardplushie, + /obj/item/toy/plush/lizardplushie/durgit, + /obj/item/toy/plush/lizardplushie/rio, + /obj/item/toy/plush/lizardplushie/urinsu, + /obj/item/toy/plush/lizardplushie/arfrehn, + /obj/item/toy/plush/lizardplushie/soars, + /obj/item/toy/plush/lizardplushie/ghostie, + /obj/item/toy/plush/lizardplushie/amber, + /obj/item/toy/plush/lizardplushie/cyan, + /obj/item/toy/plush/lizardplushie/meena, + /obj/item/toy/plush/lizardplushie/stalks, + /obj/item/toy/plush/lizardplushie/kobold, + /obj/item/toy/plush/lizardplushie/gorgi, + /obj/item/toy/plush/lizardplushie/almaz, + /obj/item/toy/plush/snakeplushie/sasha, + /obj/item/toy/plush/snakeplushie/shay, + /obj/item/toy/plush/snakeplushie/vulken, + /obj/item/toy/plush/mothplushie, + /obj/item/toy/plush/mothplushie/bumble, + /obj/item/toy/plush/mothplushie/nameko, + /obj/item/toy/plush/mothplushie/suru, + /obj/item/toy/plush/xeno, + /obj/item/toy/plush/lampplushie, + /obj/item/toy/plush/borgplushie, + /obj/item/toy/plush/borgplushie/medihound, + /obj/item/toy/plush/borgplushie/scrubpuppy, + /obj/item/toy/plush/borgplushie/seeking, + /obj/item/toy/plush/borgplushie/neeb, + /obj/item/toy/plush/bird, + /obj/item/toy/plush/bird/esela, + /obj/item/toy/plush/bird/jahonna, + /obj/item/toy/plush/bird/krick, + /obj/item/toy/plush/bird/birddi, + /obj/item/toy/plush/bird/jewel, + /obj/item/toy/plush/mammal, + /obj/item/toy/plush/mammal/dubious, + /obj/item/toy/plush/mammal/gladwyn, + /obj/item/toy/plush/mammal/gavin, + /obj/item/toy/plush/mammal/blep, + /obj/item/toy/plush/mammal/circe, + /obj/item/toy/plush/mammal/pavel, + /obj/item/toy/plush/mammal/oten, + /obj/item/toy/plush/mammal/ray, + /obj/item/toy/plush/mammal/dawud, + /obj/item/toy/plush/mammal/edgar, + /obj/item/toy/plush/mammal/frank, + /obj/item/toy/plush/mammal/poojawa, + /obj/item/toy/plush/mammal/hazel, + /obj/item/toy/plush/mammal/jermaine, + /obj/item/toy/plush/mammal/gunther, + /obj/item/toy/plush/mammal/fox, + /obj/item/toy/plush/mammal/zed, + /obj/item/toy/plush/mammal/dog, + /obj/item/toy/plush/mammal/dog/frost, + /obj/item/toy/plush/mammal/dog/atticus, + /obj/item/toy/plush/mammal/dog/fletch, + /obj/item/toy/plush/mammal/dog/vincent, + /obj/item/toy/plush/mammal/dog/zigfried, + /obj/item/toy/plush/mammal/dog/nikolai, + /obj/item/toy/plush/catgirl, + /obj/item/toy/plush/catgirl/skylar, + /obj/item/toy/plush/catgirl/mikeel, + /obj/item/toy/plush/catgirl/robin) + crate_name = "plushie crate" + crate_type = /obj/structure/closet/crate/wooden + /datum/supply_pack/costumes_toys/wizard name = "Wizard Costume Crate" desc = "Pretend to join the Wizard Federation with this full wizard outfit! Nanotrasen would like to remind its employees that actually joining the Wizard Federation is subject to termination of job and life." @@ -2404,7 +2612,7 @@ crate_type = /obj/structure/closet/crate /datum/supply_pack/misc/lewdkeg - name = "Lewd Deluxe Keg" + name = "Lewd Deluxe Keg" desc = "That other stuff not getting you ready? Well I have a Chemslut making tons of the good stuff." cost = 7000 //It can be a weapon contraband = TRUE @@ -2412,6 +2620,27 @@ crate_name = "deluxe keg" crate_type = /obj/structure/closet/crate +/datum/supply_pack/misc/paper_work + name = "Freelance Paper work" + desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up. + cost = 400 // Net of 0 credits + contains = list(/obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork, + /obj/item/pen/fountain, + /obj/item/pen/fountain, + /obj/item/pen/fountain, + /obj/item/pen/fountain, + /obj/item/pen/fountain) + crate_name = "Paperwork" + /datum/supply_pack/misc/toner name = "Toner Crate" desc = "Spent too much ink printing butt pictures? Fret not, with these six toner refills, you'll be printing butts 'till the cows come home!'" diff --git a/code/modules/client/verbs/aooc.dm b/code/modules/client/verbs/aooc.dm index 90c0dc5a55..893501a852 100644 --- a/code/modules/client/verbs/aooc.dm +++ b/code/modules/client/verbs/aooc.dm @@ -61,7 +61,7 @@ antaglisting |= M.current.client for(var/mob/M in GLOB.player_list) - if(M.client && (M.stat == DEAD || M.client.holder)) + if(M.client && (M.stat == DEAD || M.client.holder) && !istype(M, /mob/dead/new_player)) antaglisting |= M.client for(var/client/C in antaglisting) diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index a5465354ac..7f7b3ae0ed 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -67,6 +67,11 @@ user.visible_message("[user] is putting \the [src] to [user.p_their()] eyes and overloading the brightness! It looks like [user.p_theyre()] trying to commit suicide!") return BRUTELOSS +/obj/item/clothing/glasses/meson/prescription + name = "prescription optical meson scanner" + desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting conditions. This one has prescription lens fitted in." + vision_correction = 1 + /obj/item/clothing/glasses/meson/night name = "night vision meson scanner" desc = "An optical meson scanner fitted with an amplified visible light spectrum overlay, providing greater visual clarity in darkness." @@ -159,6 +164,7 @@ attack_verb = list("sliced") hitsound = 'sound/weapons/bladeslice.ogg' sharpness = IS_SHARP + vision_correction = 1 glass_colour_type = /datum/client_colour/glass_colour/lightgreen /obj/item/clothing/glasses/regular diff --git a/code/modules/clothing/glasses/engine_goggles.dm b/code/modules/clothing/glasses/engine_goggles.dm index 336881106e..47706a3e1e 100644 --- a/code/modules/clothing/glasses/engine_goggles.dm +++ b/code/modules/clothing/glasses/engine_goggles.dm @@ -21,6 +21,11 @@ var/mode = MODE_NONE var/range = 1 +/obj/item/clothing/glasses/meson/engine/prescription + name = "prescription engineering scanner goggles" + desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, the T-ray Scanner mode lets you see underfloor objects such as cables and pipes, and the Radiation Scanner mode let's you see objects contaminated by radiation. Each lens has been replaced with a corrective lens." + vision_correction = 1 + /obj/item/clothing/glasses/meson/engine/Initialize() . = ..() START_PROCESSING(SSobj, src) @@ -137,6 +142,11 @@ modes = list(MODE_NONE = MODE_TRAY, MODE_TRAY = MODE_NONE) +/obj/item/clothing/glasses/meson/engine/tray/prescription + name = "prescription optical t-ray scanner" + desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, the T-ray Scanner mode lets you see underfloor objects such as cables and pipes, and the Radiation Scanner mode let's you see objects contaminated by radiation. This one has a lens that help correct eye sight." + vision_correction = 1 + /obj/item/clothing/glasses/meson/engine/shuttle name = "shuttle region scanner" icon_state = "trayson-shuttle" diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index 19bcf470bd..a87e95e28c 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -37,6 +37,14 @@ hud_type = DATA_HUD_MEDICAL_ADVANCED glass_colour_type = /datum/client_colour/glass_colour/lightblue +/obj/item/clothing/glasses/hud/health/prescription + name = "prescription health scanner HUD" + desc = "A heads-up display, made with a prescription lens, that scans the humans in view and provides accurate data about their health status." + icon_state = "healthhud" + hud_type = DATA_HUD_MEDICAL_ADVANCED + vision_correction = 1 + glass_colour_type = /datum/client_colour/glass_colour/lightblue + /obj/item/clothing/glasses/hud/health/night name = "night vision health scanner HUD" desc = "An advanced medical head-up display that allows doctors to find patients in complete darkness." @@ -62,6 +70,14 @@ hud_type = DATA_HUD_DIAGNOSTIC_BASIC glass_colour_type = /datum/client_colour/glass_colour/lightorange +/obj/item/clothing/glasses/hud/diagnostic/prescription + name = "prescription diagnostic HUD" + desc = "A heads-up display capable of analyzing the integrity and status of robotics and exosuits. This one has a prescription lens." + icon_state = "diagnostichud" + hud_type = DATA_HUD_DIAGNOSTIC_BASIC + vision_correction = 1 + glass_colour_type = /datum/client_colour/glass_colour/lightorange + /obj/item/clothing/glasses/hud/diagnostic/night name = "night vision diagnostic HUD" desc = "A robotics diagnostic HUD fitted with a light amplifier." @@ -78,6 +94,14 @@ hud_type = DATA_HUD_SECURITY_ADVANCED glass_colour_type = /datum/client_colour/glass_colour/red +/obj/item/clothing/glasses/hud/security/prescription + name = "prescription security HUD" + desc = "A heads-up display that scans the humans in view and provides accurate data about their ID status and security records. This one has a prescription lens so you can see the banana peal that slipped you." + icon_state = "securityhud" + hud_type = DATA_HUD_SECURITY_ADVANCED + vision_correction = 1 + glass_colour_type = /datum/client_colour/glass_colour/red + /obj/item/clothing/glasses/hud/security/chameleon name = "chameleon security HUD" desc = "A stolen security HUD integrated with Syndicate chameleon technology. Provides flash protection." diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm index 89f114f7e5..cd8efd74bf 100644 --- a/code/modules/clothing/spacesuits/miscellaneous.dm +++ b/code/modules/clothing/spacesuits/miscellaneous.dm @@ -168,6 +168,7 @@ Contains: strip_delay = 130 item_flags = NODROP brightness_on = 7 + resistance_flags = ACID_PROOF /obj/item/clothing/suit/space/hardsuit/ert name = "emergency response team suit" @@ -179,6 +180,7 @@ Contains: armor = list("melee" = 65, "bullet" = 50, "laser" = 50, "energy" = 50, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 80) slowdown = 0 strip_delay = 130 + resistance_flags = ACID_PROOF //ERT Security /obj/item/clothing/head/helmet/space/hardsuit/ert/sec diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm index cbc8f33e3a..6d9a02e05a 100644 --- a/code/modules/clothing/suits/bio.dm +++ b/code/modules/clothing/suits/bio.dm @@ -5,7 +5,7 @@ desc = "A hood that protects the head and face from biological contaminants." permeability_coefficient = 0.01 clothing_flags = THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT - armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 80, "fire" = 30, "acid" = 100) + armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 60, "fire" = 30, "acid" = 100) flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDEFACE resistance_flags = ACID_PROOF flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH @@ -22,7 +22,7 @@ body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS slowdown = 1 allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/pen, /obj/item/flashlight/pen, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/hypospray) - armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 80, "fire" = 30, "acid" = 100) + armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 60, "fire" = 30, "acid" = 100) flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAUR strip_delay = 70 equip_delay_other = 70 diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm index 2516d446d6..5b2291e59c 100644 --- a/code/modules/clothing/suits/reactive_armour.dm +++ b/code/modules/clothing/suits/reactive_armour.dm @@ -37,6 +37,7 @@ actions_types = list(/datum/action/item_action/toggle) resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF hit_reaction_chance = 50 // Only on the chest yet blocks all attacks? + rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE /obj/item/clothing/suit/armor/reactive/attack_self(mob/user) active = !(active) @@ -64,8 +65,9 @@ /obj/item/clothing/suit/armor/reactive/teleport name = "reactive teleport armor" desc = "Someone separated our Research Director from his own head!" - var/tele_range = 6 - var/rad_amount= 15 + var/tele_range = 8 + var/rad_amount = 60 + var/rad_amount_before = 120 reactivearmor_cooldown_duration = 100 /obj/item/clothing/suit/armor/reactive/teleport/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) @@ -79,6 +81,7 @@ owner.visible_message("The reactive teleport system flings [H] clear of [attack_text], shutting itself off in the process!") playsound(get_turf(owner),'sound/magic/blink.ogg', 100, 1) var/list/turfs = new/list() + var/turf/old = get_turf(src) for(var/turf/T in orange(tele_range, H)) if(T.density) continue @@ -93,7 +96,8 @@ if(!isturf(picked)) return H.forceMove(picked) - H.rad_act(rad_amount) + radiation_pulse(old, rad_amount_before) + radiation_pulse(src, rad_amount) reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration return 1 return 0 @@ -157,6 +161,8 @@ var/tesla_power = 25000 var/tesla_range = 20 var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE + var/legacy = FALSE + var/legacy_dmg = 30 /obj/item/clothing/suit/armor/reactive/tesla/dropped(mob/user) ..() @@ -179,7 +185,15 @@ owner.visible_message("The tesla capacitors on [owner]'s reactive tesla armor are still recharging! The armor merely emits some sparks.") return owner.visible_message("[src] blocks [attack_text], sending out arcs of lightning!") - tesla_zap(owner, tesla_range, tesla_power, tesla_flags) + if(!legacy) + tesla_zap(owner, tesla_range, tesla_power, tesla_flags) + else + for(var/mob/living/M in view(7, owner)) + if(M == owner) + continue + owner.Beam(M,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5) + M.adjustFireLoss(legacy_dmg) + playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1) reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration return TRUE diff --git a/code/modules/clothing/under/vg_under.dm b/code/modules/clothing/under/vg_under.dm index 64bf75d5ac..f416f2ecc5 100644 --- a/code/modules/clothing/under/vg_under.dm +++ b/code/modules/clothing/under/vg_under.dm @@ -1,3 +1,6 @@ +// Fixed to work with Citadel code. Apparently none of them had NO_MUTANTRACE flags. +// I was pissy when I realised how to fix this because it's so fucking easy and nobody apparently had done it. + /obj/item/clothing/under/stripper_pink name = "pink stripper outfit" icon_state = "stripper_p" @@ -6,7 +9,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/stripper_green name = "green stripper outfit" @@ -16,8 +19,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/wedding/bride_orange name = "orange wedding dress" @@ -28,7 +30,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/wedding/bride_purple name = "purple wedding dress" @@ -39,7 +41,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/wedding/bride_blue name = "blue wedding dress" @@ -50,7 +52,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/wedding/bride_red name = "red wedding dress" @@ -61,7 +63,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/wedding/bride_white name = "white wedding dress" @@ -72,7 +74,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/mankini name = "pink mankini" @@ -82,6 +84,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' + mutantrace_variation = NO_MUTANTRACE_VARIATION /* /obj/item/clothing/under/psysuit @@ -126,7 +129,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/russobluecamooutfit name = "russian blue camo" @@ -137,7 +140,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/stilsuit name = "stillsuit" @@ -148,7 +151,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/aviatoruniform name = "aviator uniform" @@ -159,7 +162,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/bikersuit name = "biker's outfit" @@ -169,7 +172,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/jacketsuit name = "richard's outfit" @@ -180,7 +183,7 @@ can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION obj/item/clothing/under/mega name = "\improper DRN-001 suit" @@ -191,7 +194,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/proto name = "The Prototype Suit" @@ -202,7 +205,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/megax name = "\improper Maverick Hunter regalia" @@ -213,7 +216,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/joe name = "The Sniper Suit" @@ -224,7 +227,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/roll name = "\improper DRN-002 Dress" @@ -235,7 +238,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/gokugidown name = "turtle hermit undershirt" @@ -246,7 +249,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/gokugi name = "turtle hermit outfit" @@ -257,7 +260,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/doomguy name = "\improper Doomguy's pants" @@ -268,7 +271,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/vault13 name = "vault 13 Jumpsuit" @@ -279,7 +282,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/vault name = "vault jumpsuit" @@ -290,7 +293,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/clownpiece name = "Clownpiece's Pierrot suit" @@ -301,7 +304,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/cia name = "casual IAA outfit" @@ -312,7 +315,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/greaser name = "greaser outfit" @@ -322,7 +325,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/greaser/New() var/greaser_colour = "default" @@ -341,6 +344,8 @@ obj/item/clothing/under/mega item_color = "greaser_[greaser_colour]" can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' + mutantrace_variation = NO_MUTANTRACE_VARIATION + /obj/item/clothing/under/wintercasualwear name = "winter casualwear" @@ -351,8 +356,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/casualwear name = "spring casualwear" @@ -363,7 +367,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/keyholesweater name = "keyhole sweater" @@ -374,7 +378,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/casualhoodie name = "casual hoodie" @@ -385,8 +389,7 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' - - + mutantrace_variation = NO_MUTANTRACE_VARIATION /obj/item/clothing/under/casualhoodie/skirt icon_state = "hoodieskirt" @@ -394,6 +397,8 @@ obj/item/clothing/under/mega item_color = "hoodieskirt" can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' + mutantrace_variation = NO_MUTANTRACE_VARIATION + /* /obj/item/clothing/under/mummy_rags name = "mummy rags" @@ -427,3 +432,5 @@ obj/item/clothing/under/mega can_adjust = 0 icon = 'modular_citadel/icons/obj/clothing/vg_clothes.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi' + mutantrace_variation = NO_MUTANTRACE_VARIATION + diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 586819ed8f..750b172286 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -694,10 +694,18 @@ /obj/item/reagent_containers/food/snacks/grown/potato = 1) category = CAT_MISC +/datum/crafting_recipe/paperwork + name = "Filed Paper Work" + result = /obj/item/paper/fluff/jobs/cargo/manifest/paperwork_correct + time = 90 //Takes time for people to file and complete paper work! + reqs = list(/obj/item/pen = 1, + /obj/item/paper/fluff/jobs/cargo/manifest/paperwork = 2) + category = CAT_MISC + /datum/crafting_recipe/ghettojetpack name = "Improvised Jetpack" result = /obj/item/tank/jetpack/improvised time = 30 reqs = list(/obj/item/tank/internals/oxygen/red = 2, /obj/item/extinguisher = 1, /obj/item/pipe = 3, /obj/item/stack/cable_coil = 30)//red oxygen tank so it looks right category = CAT_MISC - tools = list(TOOL_WRENCH, TOOL_WELDER, TOOL_WIRECUTTER) \ No newline at end of file + tools = list(TOOL_WRENCH, TOOL_WELDER, TOOL_WIRECUTTER) diff --git a/code/modules/events/brand_intelligence.dm b/code/modules/events/brand_intelligence.dm index e33cfbd25d..a838b62e0d 100644 --- a/code/modules/events/brand_intelligence.dm +++ b/code/modules/events/brand_intelligence.dm @@ -18,7 +18,14 @@ "Your money can buy happiness!", \ "Engage direct marketing!", \ "Advertising is legalized lying! But don't let that put you off our great deals!", \ - "You don't want to buy anything? Yeah, well, I didn't want to buy your mom either.") + "You don't want to buy anything? Yeah, well, I didn't want to buy your mom either.", + "Gamers, rise up!", + "Ok, now, this is epic.", + "HUMAN FUNNY.", + "But I'm already tracer!", + "How do I vore people?", + "ERP?", + "Not epic bros...") /datum/round_event/brand_intelligence/announce(fake) diff --git a/code/modules/events/devil.dm b/code/modules/events/devil.dm index 3760cbe05d..7d6e0bd441 100644 --- a/code/modules/events/devil.dm +++ b/code/modules/events/devil.dm @@ -39,6 +39,7 @@ var/datum/job/jobdatum = SSjob.GetJob("Assistant") devil.job = jobdatum.title jobdatum.equip(devil) + success_spawn = TRUE return SUCCESSFUL_SPAWN diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index ba57643339..3ae71f99d8 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -12,7 +12,7 @@ var/removeDontImproveChance = 10 //chance the randomly created law replaces a random law instead of simply being added var/shuffleLawsChance = 10 //chance the AI's laws are shuffled afterwards var/botEmagChance = 10 - var/announceEvent = ION_RANDOM // -1 means don't announce, 0 means have it randomly announce, 1 means + var/announceEvent = ION_RANDOM // -1 means don't announce, 0 means have it randomly announce, 1 means it is announced var/ionMessage = null var/ionAnnounceChance = 33 announceWhen = 1 @@ -30,7 +30,7 @@ /datum/round_event/ion_storm/start() - //AI laws + //Generate AI law change for(var/mob/living/silicon/ai/M in GLOB.alive_mob_list) M.laws_sanity_check() if(M.stat != DEAD && M.see_in_dark != 0) @@ -53,6 +53,31 @@ log_game("Ion storm changed laws of [key_name(M)] to [english_list(M.laws.get_law_list(TRUE, TRUE))]") M.post_lawchange() + //Generate Cyborg law change + for(var/mob/living/silicon/robot/M in GLOB.alive_mob_list) + M.laws_sanity_check() + if(M.stat != DEAD && M.see_in_dark != 0) + if(prob(replaceLawsetChance)) + M.laws.pick_weighted_lawset() + + if(prob(removeRandomLawChance)) + M.remove_law(rand(1, M.laws.get_law_amount(list(LAW_INHERENT, LAW_SUPPLIED)))) + + var/message = ionMessage || generate_ion_law() + if(message) + if(prob(removeDontImproveChance)) + M.replace_random_law(message, list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION)) + else + M.add_ion_law(message) + + if(prob(shuffleLawsChance)) + M.shuffle_laws(list(LAW_INHERENT, LAW_SUPPLIED, LAW_ION)) + + log_game("Ion storm changed laws of [key_name(M)] to [english_list(M.laws.get_law_list(TRUE, TRUE))]") + M.post_lawchange() + + + //Chance to emag a Bot if(botEmagChance) for(var/mob/living/simple_animal/bot/bot in GLOB.alive_mob_list) if(prob(botEmagChance)) diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm index 160304b1c3..3945a12a40 100644 --- a/code/modules/events/vent_clog.dm +++ b/code/modules/events/vent_clog.dm @@ -79,12 +79,28 @@ typepath = /datum/round_event/vent_clog/beer max_occurrences = 0 +/datum/round_event/vent_clog/beer + reagentsAmount = 100 + /datum/round_event_control/vent_clog/plasma_decon name = "Plasma decontamination" typepath = /datum/round_event/vent_clog/plasma_decon max_occurrences = 0 -/datum/round_event/vent_clog/beer +/datum/round_event_control/vent_clog/female + name = "FemCum stationwide" + typepath = /datum/round_event/vent_clog/female + max_occurrences = 0 + +/datum/round_event/vent_clog/female + reagentsAmount = 100 + +/datum/round_event_control/vent_clog/male + name = "Semen stationwide" + typepath = /datum/round_event/vent_clog/male + max_occurrences = 0 + +/datum/round_event/vent_clog/male reagentsAmount = 100 /datum/round_event/vent_clog/beer/announce() @@ -102,6 +118,30 @@ foam.start() CHECK_TICK +/datum/round_event/vent_clog/male/start() + for(var/obj/machinery/atmospherics/components/unary/vent in vents) + if(vent && vent.loc) + var/datum/reagents/R = new/datum/reagents(1000) + R.my_atom = vent + R.add_reagent("semen", reagentsAmount) + + var/datum/effect_system/foam_spread/foam = new + foam.set_up(200, get_turf(vent), R) + foam.start() + CHECK_TICK + +/datum/round_event/vent_clog/female/start() + for(var/obj/machinery/atmospherics/components/unary/vent in vents) + if(vent && vent.loc) + var/datum/reagents/R = new/datum/reagents(1000) + R.my_atom = vent + R.add_reagent("femcum", reagentsAmount) + + var/datum/effect_system/foam_spread/foam = new + foam.set_up(200, get_turf(vent), R) + foam.start() + CHECK_TICK + /datum/round_event/vent_clog/plasma_decon/announce() priority_announce("We are deploying an experimental plasma decontamination system. Please stand away from the vents and do not breathe the smoke that comes out.", "Central Command Update") diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index 9256f5bdd1..6594146e81 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -120,6 +120,12 @@ I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) B.icon = I B.name = "broken [name]" + if(ranged) + var/matrix/M = matrix(B.transform) + M.Turn(rand(-170, 170)) + B.transform = M + B.pixel_x = rand(-12, 12) + B.pixel_y = rand(-12, 12) if(prob(33)) new/obj/item/shard(drop_location()) playsound(src, "shatter", 70, 1) @@ -296,6 +302,12 @@ B.force = 0 B.throwforce = 0 B.desc = "A carton with the bottom half burst open. Might give you a papercut." + if(ranged) + var/matrix/M = matrix(B.transform) + M.Turn(rand(-170, 170)) + B.transform = M + B.pixel_x = rand(-12, 12) + B.pixel_y = rand(-12, 12) transfer_fingerprints_to(B) qdel(src) diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm index 3bc7443a9b..46e637e640 100644 --- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm +++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm @@ -23,6 +23,12 @@ var/obj/item/broken_bottle/B = new (loc) if(!ranged) thrower.put_in_hands(B) + else + var/matrix/M = matrix(B.transform) + M.Turn(rand(-170, 170)) + B.transform = M + B.pixel_x = rand(-12, 12) + B.pixel_y = rand(-12, 12) B.icon_state = icon_state var/icon/I = new('icons/obj/drinks.dmi', src.icon_state) diff --git a/code/modules/food_and_drinks/food/snacks_bread.dm b/code/modules/food_and_drinks/food/snacks_bread.dm index 0638bfad25..0f11fc8ed2 100644 --- a/code/modules/food_and_drinks/food/snacks_bread.dm +++ b/code/modules/food_and_drinks/food/snacks_bread.dm @@ -185,6 +185,17 @@ icon_state = "" bitesize = 2 +GLOBAL_VAR_INIT(frying_hardmode, TRUE) +GLOBAL_VAR_INIT(frying_bad_chem_add_volume, TRUE) +GLOBAL_LIST_INIT(frying_bad_chems, list( +"bad_food" = 10, +"clf3" = 2, +"aranesp" = 2, +"blackpowder" = 10, +"phlogiston" = 3, +"cyanide" = 3, +)) + /obj/item/reagent_containers/food/snacks/deepfryholder/Initialize(mapload, obj/item/fried) . = ..() name = fried.name //We'll determine the other stuff when it's actually removed @@ -210,6 +221,13 @@ else fried.forceMove(src) trash = fried + if(!istype(fried, /obj/item/reagent_containers/food) && GLOB.frying_hardmode && GLOB.frying_bad_chems.len) + var/R = rand(1, GLOB.frying_bad_chems.len) + var/bad_chem = GLOB.frying_bad_chems[R] + var/bad_chem_amount = GLOB.frying_bad_chems[bad_chem] + if(GLOB.frying_bad_chem_add_volume) + reagents.maximum_volume += bad_chem_amount + reagents.add_reagent(bad_chem, bad_chem_amount) /obj/item/reagent_containers/food/snacks/deepfryholder/Destroy() if(trash) diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm index a2f5b06042..af7a8c06f4 100644 --- a/code/modules/food_and_drinks/food/snacks_other.dm +++ b/code/modules/food_and_drinks/food/snacks_other.dm @@ -563,9 +563,9 @@ /obj/item/reagent_containers/food/snacks/tinychocolate name = "chocolate" - desc = "A tiny and sweet chocolate." + desc = "A tiny and sweet chocolate. Has a 'strawberry' filling!" icon_state = "tiny_chocolate" - list_reagents = list("nutriment" = 1, "sugar" = 1, "cocoa" = 1) + list_reagents = list("nutriment" = 1, "sugar" = 1, "cocoa" = 1, "aphro" = 1) filling_color = "#A0522D" tastes = list("chocolate" = 1) - foodtype = JUNKFOOD | SUGAR \ No newline at end of file + foodtype = JUNKFOOD | SUGAR diff --git a/code/modules/food_and_drinks/food/snacks_pizza.dm b/code/modules/food_and_drinks/food/snacks_pizza.dm index a6b026ac30..5bf5abacb0 100644 --- a/code/modules/food_and_drinks/food/snacks_pizza.dm +++ b/code/modules/food_and_drinks/food/snacks_pizza.dm @@ -149,16 +149,16 @@ icon_state = "pineapplepizza" slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/pineapple bonus_reagents = list("nutriment" = 6, "vitamin" = 6) - tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "pineapple" = 2, "ham" = 2) - foodtype = GRAIN | VEGETABLES | DAIRY | MEAT | FRUIT | PINEAPPLE + tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "pineapple" = 6, "ham" = 2) + foodtype = PINEAPPLE //Over powering tast of gods fruit /obj/item/reagent_containers/food/snacks/pizzaslice/pineapple name = "\improper Hawaiian pizza slice" desc = "A slice of delicious controversy." icon_state = "pineapplepizzaslice" filling_color = "#FF4500" - tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "pineapple" = 2, "ham" = 2) - foodtype = GRAIN | VEGETABLES | DAIRY | MEAT | FRUIT | PINEAPPLE + tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "pineapple" = 6, "ham" = 2) + foodtype = PINEAPPLE //Over powering tast of gods fruit /obj/item/reagent_containers/food/snacks/pizza/arnold name = "\improper Arnold pizza" diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 3592f5a437..02106e808c 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -1,6 +1,5 @@ ////////////////////////////////////////// COCKTAILS ////////////////////////////////////// - /datum/chemical_reaction/goldschlager name = "Goldschlager" id = "goldschlager" @@ -676,7 +675,6 @@ results = list("fernet_cola" = 2) required_reagents = list("fernet" = 1, "cola" = 1) - /datum/chemical_reaction/fanciulli name = "Fanciulli" id = "fanciulli" @@ -688,3 +686,9 @@ id = "branca_menta" results = list("branca_menta" = 3) required_reagents = list("fernet" = 1, "creme_de_menthe" = 1, "ice" = 1) + +/datum/chemical_reaction/pwrgame + name = "Power Gamer" + id = "pwr_game" + results = list("pwr_game" = 5) + required_reagents = list("sodawater" = 1, "blackcrayonpowder" = 1, "sodiumchloride" = 1) diff --git a/code/modules/holodeck/turfs.dm b/code/modules/holodeck/turfs.dm index 2a36983561..a4c89b8874 100644 --- a/code/modules/holodeck/turfs.dm +++ b/code/modules/holodeck/turfs.dm @@ -122,7 +122,7 @@ /turf/open/floor/holofloor/wood icon_state = "wood" tiled_dirt = FALSE - + /turf/open/floor/holofloor/snow gender = PLURAL name = "snow" @@ -133,6 +133,15 @@ bullet_sizzle = TRUE bullet_bounce_sound = null tiled_dirt = FALSE + baseturfs = /turf/open/floor/holofloor/snow + +/turf/open/floor/holofloor/snow/attack_hand(mob/living/user) + . = ..() + if(.) + return + user.visible_message("[user] scroops up some snow from [src].", "You scoop up some snow from [src].") + var/obj/item/toy/snowball/S = new(get_turf(src)) + user.put_in_hands(S) /turf/open/floor/holofloor/snow/cold initial_gas_mix = "nob=7500;TEMP=2.7" @@ -143,3 +152,22 @@ icon = 'icons/turf/floors.dmi' icon_state = "asteroid" tiled_dirt = FALSE + +/turf/open/floor/holofloor/ice + name = "ice sheet" + desc = "A sheet of solid ice. Looks slippery." + icon = 'icons/turf/floors/ice_turf.dmi' + icon_state = "unsmooth" + baseturfs = /turf/open/floor/holofloor/ice + slowdown = 1 + footstep = FOOTSTEP_FLOOR + +/turf/open/floor/holofloor/ice/smooth + icon_state = "smooth" + smooth = SMOOTH_MORE | SMOOTH_BORDER + canSmoothWith = list(/turf/open/floor/plating/ice/smooth, /turf/open/floor/plating/ice, /turf/open/floor/holofloor/ice) + baseturfs = /turf/open/floor/holofloor/ice/smooth + +/turf/open/floor/holofloor/ice/Initialize() + . = ..() + MakeSlippery(TURF_WET_PERMAFROST, INFINITY, 0, INFINITY, TRUE) diff --git a/code/modules/hydroponics/grown/tomato.dm b/code/modules/hydroponics/grown/tomato.dm index 5a44cb78f8..d07f5d4d08 100644 --- a/code/modules/hydroponics/grown/tomato.dm +++ b/code/modules/hydroponics/grown/tomato.dm @@ -136,7 +136,7 @@ spawn(30) if(!QDELETED(src)) - investigate_log(INVESTIGATE_BOTANY, "[key_name(user)] released a killer tomato at [COORD(src)]") + investigate_log("[key_name(user)] released a killer tomato at [COORD(src)]", INVESTIGATE_BOTANY) var/mob/living/simple_animal/hostile/killertomato/K = new /mob/living/simple_animal/hostile/killertomato(get_turf(src.loc)) K.maxHealth += round(seed.endurance / 3) K.melee_damage_lower += round(seed.potency / 10) diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm index e3ca576944..1ea0068a1a 100644 --- a/code/modules/hydroponics/hydroitemdefines.dm +++ b/code/modules/hydroponics/hydroitemdefines.dm @@ -24,10 +24,7 @@ lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi' volume = 100 - -/obj/item/reagent_containers/spray/weedspray/Initialize() - . = ..() - reagents.add_reagent("weedkiller", 100) + list_reagents = list("weedkiller" = 100) /obj/item/reagent_containers/spray/weedspray/suicide_act(mob/user) user.visible_message("[user] is huffing [src]! It looks like [user.p_theyre()] trying to commit suicide!") @@ -42,10 +39,7 @@ lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi' volume = 100 - -/obj/item/reagent_containers/spray/pestspray/Initialize() - . = ..() - reagents.add_reagent("pestkiller", 100) + list_reagents = list("pestkiller" = 100) /obj/item/reagent_containers/spray/pestspray/suicide_act(mob/user) user.visible_message("[user] is huffing [src]! It looks like [user.p_theyre()] trying to commit suicide!") @@ -157,71 +151,45 @@ /obj/item/reagent_containers/glass/bottle/nutrient name = "bottle of nutrient" - icon = 'icons/obj/chemical.dmi' volume = 50 - w_class = WEIGHT_CLASS_TINY amount_per_transfer_from_this = 10 possible_transfer_amounts = list(1,2,5,10,15,25,50) /obj/item/reagent_containers/glass/bottle/nutrient/Initialize() . = ..() - src.pixel_x = rand(-5, 5) - src.pixel_y = rand(-5, 5) + pixel_x = rand(-5, 5) + pixel_y = rand(-5, 5) /obj/item/reagent_containers/glass/bottle/nutrient/ez name = "bottle of E-Z-Nutrient" desc = "Contains a fertilizer that causes mild mutations with each harvest." - icon = 'icons/obj/chemical.dmi' - -/obj/item/reagent_containers/glass/bottle/nutrient/ez/Initialize() - . = ..() - reagents.add_reagent("eznutriment", 50) + list_reagents = list("eznutriment" = 50) /obj/item/reagent_containers/glass/bottle/nutrient/l4z name = "bottle of Left 4 Zed" desc = "Contains a fertilizer that limits plant yields to no more than one and causes significant mutations in plants." - icon = 'icons/obj/chemical.dmi' - -/obj/item/reagent_containers/glass/bottle/nutrient/l4z/Initialize() - . = ..() - reagents.add_reagent("left4zednutriment", 50) + list_reagents = list("left4zednutriment" = 50) /obj/item/reagent_containers/glass/bottle/nutrient/rh name = "bottle of Robust Harvest" desc = "Contains a fertilizer that increases the yield of a plant by 30% while causing no mutations." - icon = 'icons/obj/chemical.dmi' - -/obj/item/reagent_containers/glass/bottle/nutrient/rh/Initialize() - . = ..() - reagents.add_reagent("robustharvestnutriment", 50) + list_reagents = list("robustharvestnutriment" = 50) /obj/item/reagent_containers/glass/bottle/nutrient/empty name = "bottle" - icon = 'icons/obj/chemical.dmi' /obj/item/reagent_containers/glass/bottle/killer - name = "bottle" - icon = 'icons/obj/chemical.dmi' volume = 50 - w_class = WEIGHT_CLASS_TINY amount_per_transfer_from_this = 10 possible_transfer_amounts = list(1,2,5,10,15,25,50) /obj/item/reagent_containers/glass/bottle/killer/weedkiller name = "bottle of weed killer" desc = "Contains a herbicide." - icon = 'icons/obj/chemical.dmi' - -/obj/item/reagent_containers/glass/bottle/killer/weedkiller/Initialize() - . = ..() - reagents.add_reagent("weedkiller", 50) + list_reagents = list("weedkiller" = 50) /obj/item/reagent_containers/glass/bottle/killer/pestkiller name = "bottle of pest spray" desc = "Contains a pesticide." - icon = 'icons/obj/chemical.dmi' - -/obj/item/reagent_containers/glass/bottle/killer/pestkiller/Initialize() - . = ..() - reagents.add_reagent("pestkiller", 50) + list_reagents = list("pestkiller" = 50) \ No newline at end of file diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/job.dm index 16e1ccdfb7..0e1daff5e0 100644 --- a/code/modules/jobs/job_types/job.dm +++ b/code/modules/jobs/job_types/job.dm @@ -127,6 +127,8 @@ return 0 if(!CONFIG_GET(flag/use_age_restriction_for_jobs)) return 0 + if(C.prefs.db_flags & DB_FLAG_EXEMPT) + return 0 if(!isnum(C.player_age)) return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced if(!isnum(minimal_player_age)) diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index ca1fd7f9bb..1e77a907c6 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -19,22 +19,24 @@ new /datum/data/mining_equipment("Soap", /obj/item/soap/nanotrasen, 200), new /datum/data/mining_equipment("Laser Pointer", /obj/item/laser_pointer, 300), new /datum/data/mining_equipment("Alien Toy", /obj/item/clothing/mask/facehugger/toy, 300), - new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 400), new /datum/data/mining_equipment("Fulton Beacon", /obj/item/fulton_core, 400), new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 400), new /datum/data/mining_equipment("GAR Meson Scanners", /obj/item/clothing/glasses/meson/gar, 500), new /datum/data/mining_equipment("Explorer's Webbing", /obj/item/storage/belt/mining, 500), new /datum/data/mining_equipment("Point Transfer Card", /obj/item/card/mining_point_card, 500), - new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 500), + new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 600), new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600), + new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750), + new /datum/data/mining_equipment("Stabilizing Serum", /obj/item/hivelordstabilizer, 750), new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750), new /datum/data/mining_equipment("Kinetic Crusher", /obj/item/twohanded/required/kinetic_crusher, 750), new /datum/data/mining_equipment("Kinetic Accelerator", /obj/item/gun/energy/kinetic_accelerator, 750), new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 800), new /datum/data/mining_equipment("Burn First-Aid Kit", /obj/item/storage/firstaid/fire, 800), - new /datum/data/mining_equipment("First-Aid Kit", /obj/item/storage/firstaid/regular, 800), + new /datum/data/mining_equipment("First-Aid Kit", /obj/item/storage/firstaid/regular, 800), new /datum/data/mining_equipment("Advanced Scanner", /obj/item/t_scanner/adv_mining_scanner, 800), new /datum/data/mining_equipment("Resonator", /obj/item/resonator, 800), + new /datum/data/mining_equipment("Mini Extinguisher", /obj/item/extinguisher/mini, 1000), new /datum/data/mining_equipment("Fulton Pack", /obj/item/extraction_pack, 1000), new /datum/data/mining_equipment("Lazarus Injector", /obj/item/lazarus_injector, 1000), new /datum/data/mining_equipment("Silver Pickaxe", /obj/item/pickaxe/silver, 1000), @@ -315,4 +317,4 @@ new /obj/item/clothing/mask/gas/seva(drop_location) SSblackbox.record_feedback("tally", "suit_voucher_redeemed", 1, selection) - qdel(voucher) \ No newline at end of file + qdel(voucher) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 746b87e434..84be6438c0 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -33,7 +33,8 @@ return /mob/dead/new_player/proc/new_player_panel() - var/output = "

Setup Character

" + var/output = "

Welcome, [client ? client.prefs.real_name : "Unknown User"]

" + output += "

Setup Character

" if(SSticker.current_state <= GAME_STATE_PREGAME) switch(ready) @@ -441,58 +442,87 @@ var/available_job_count = 0 for(var/datum/job/job in SSjob.occupations) if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE) - available_job_count++; + available_job_count++ for(var/spawner in GLOB.mob_spawners) available_job_count++ + break - for(var/datum/job/prioritized_job in SSjob.prioritized_jobs) - if(prioritized_job.current_positions >= prioritized_job.total_positions) - SSjob.prioritized_jobs -= prioritized_job + if(!available_job_count) + dat += "
There are currently no open positions!
" - if(length(SSjob.prioritized_jobs)) - dat += "
The station has flagged these jobs as high priority:
" - var/amt = length(SSjob.prioritized_jobs) - var/amt_count - for(var/datum/job/a in SSjob.prioritized_jobs) - amt_count++ - if(amt_count != amt) // checks for the last job added. - dat += " [a.title], " - else - dat += " [a.title].
" + else + dat += "
Choose from the following open positions:

" + var/list/categorizedJobs = list( + "Command" = list(jobs = list(), titles = GLOB.command_positions, color = "#aac1ee"), + "Engineering" = list(jobs = list(), titles = GLOB.engineering_positions, color = "#ffd699"), + "Supply" = list(jobs = list(), titles = GLOB.supply_positions, color = "#ead4ae"), + "Miscellaneous" = list(jobs = list(), titles = list(), color = "#ffffff", colBreak = TRUE), + "Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff"), + "Synthetic" = list(jobs = list(), titles = GLOB.nonhuman_positions, color = "#ccffcc"), + "Service" = list(jobs = list(), titles = GLOB.civilian_positions, color = "#cccccc"), + "Medical" = list(jobs = list(), titles = GLOB.medical_positions, color = "#99ffe6", colBreak = TRUE), + "Science" = list(jobs = list(), titles = GLOB.science_positions, color = "#e6b3e6"), + "Security" = list(jobs = list(), titles = GLOB.security_positions, color = "#ff9999"), + ) + for(var/spawner in GLOB.mob_spawners) + categorizedJobs["Ghost Role"]["jobs"] += spawner - dat += "
Choose from the following open positions:

" - dat += "(G) - Ghost Role
" - dat += "
" - var/job_count = 0 - for(var/datum/job/job in SSjob.occupations) - if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE) - job_count++; - if (job_count > round(available_job_count / 2)) - dat += "
" - var/position_class = "otherPosition" - if (job.title in GLOB.command_positions) - position_class = "commandPosition" - dat += "[job.title] ([job.current_positions])
" - if(!job_count) //if there's nowhere to go, overflow opens up. for(var/datum/job/job in SSjob.occupations) - if(job.title != SSjob.overflow_role) + if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE) + var/categorized = FALSE + for(var/jobcat in categorizedJobs) + var/list/jobs = categorizedJobs[jobcat]["jobs"] + if(job.title in categorizedJobs[jobcat]["titles"]) + categorized = TRUE + if(jobcat == "Command") + + if(job.title == "Captain") // Put captain at top of command jobs + jobs.Insert(1, job) + else + jobs += job + else // Put heads at top of non-command jobs + if(job.title in GLOB.command_positions) + jobs.Insert(1, job) + else + jobs += job + if(!categorized) + categorizedJobs["Miscellaneous"]["jobs"] += job + + + dat += "
" + for(var/jobcat in categorizedJobs) + if(categorizedJobs[jobcat]["colBreak"]) + dat += "" + if(!length(categorizedJobs[jobcat]["jobs"])) continue - dat += "[job.title] ([job.current_positions])
" - break - for(var/spawner in GLOB.mob_spawners) - job_count++ - if(job_count > round(available_job_count / 2)) - dat += "[spawner] (G)
" - dat += "" + var/color = categorizedJobs[jobcat]["color"] + dat += "
" + dat += "[jobcat]" + for(var/datum/job/job in categorizedJobs[jobcat]["jobs"]) + var/position_class = "otherPosition" + if(job.title in GLOB.command_positions) + position_class = "commandPosition" + if(job in SSjob.prioritized_jobs) + dat += "[job.title] ([job.current_positions])" + else + dat += "[job.title] ([job.current_positions])" + categorizedJobs[jobcat]["jobs"] -= job + + for(var/spawner in categorizedJobs[jobcat]["jobs"]) + dat += "[spawner]" + + dat += "

" + dat += "
" + dat += "" // Removing the old window method but leaving it here for reference //src << browse(dat, "window=latechoices;size=300x640;can_close=1") // Added the new browser window method - var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 440, 500) + var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 680, 580) popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css') popup.set_content(dat) - popup.open(0) // 0 is passed to open so that it doesn't use the onclose() proc + popup.open(FALSE) // FALSE is passed to open so that it doesn't use the onclose() proc /mob/dead/new_player/proc/create_character(transfer_after) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index a6d6a7c7b6..c2518bfc9b 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -188,6 +188,7 @@ update_inv_hands() I.pixel_x = initial(I.pixel_x) I.pixel_y = initial(I.pixel_y) + I.transform = initial(I.transform) return hand_index || TRUE return FALSE diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm index e8a15d70ae..76b416772e 100644 --- a/code/modules/mob/living/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -15,7 +15,6 @@ OB.brainmob = src forceMove(OB) - /mob/living/brain/proc/create_dna() stored_dna = new /datum/dna/stored(src) if(!stored_dna.species) @@ -28,6 +27,7 @@ death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA if(mind) //You aren't allowed to return to brains that don't exist mind.current = null + mind.active = FALSE //No one's using it anymore. ghostize() //Ghostize checks for key so nothing else is necessary. container = null return ..() diff --git a/code/modules/mob/living/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm index 90d20bc236..9e0bb0428b 100644 --- a/code/modules/mob/living/brain/posibrain.dm +++ b/code/modules/mob/living/brain/posibrain.dm @@ -36,7 +36,7 @@ GLOBAL_VAR(posibrain_notify_cooldown) /obj/item/mmi/posibrain/proc/ping_ghosts(msg, newlymade) if(newlymade || GLOB.posibrain_notify_cooldown <= world.time) - notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/effects/ghost2.ogg':null, enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_POSIBRAIN) + notify_ghosts("[name] [msg] in [get_area(src)]!", ghost_sound = !newlymade ? 'sound/misc/server-ready.ogg':null, enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_POSIBRAIN) if(!newlymade) GLOB.posibrain_notify_cooldown = world.time + askDelay diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 7bc0e281c5..ea13255dfe 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -188,6 +188,8 @@ if(thrown_thing) visible_message("[src] has thrown [thrown_thing].") src.log_message("has thrown [thrown_thing]", LOG_ATTACK) + do_attack_animation(target, no_effect = 1) + playsound(loc, 'sound/weapons/punchmiss.ogg', 50, 1, -1) newtonian_move(get_dir(target, src)) thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src) diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 36d26f0faa..c42bd82797 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -88,6 +88,9 @@ if(digitalcamo) msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly unsimian manner.\n" + + if(combatmode) + msg += "[t_He] [t_is] visibly tense[resting ? "." : ", and [t_is] standing in combative stance."]\n" GET_COMPONENT_FROM(mood, /datum/component/mood, src) if(mood) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 548381ba8a..8c8c8e2d0c 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -264,6 +264,8 @@ if(pocket_item) if(pocket_item == (pocket_id == SLOT_R_STORE ? r_store : l_store)) //item still in the pocket we search dropItemToGround(pocket_item) + if(!put_in_hands(pocket_item)) + pocket_item.forceMove(drop_location()) else if(place_item) if(place_item.mob_can_equip(src, usr, pocket_id, FALSE, TRUE)) @@ -599,11 +601,7 @@ //Check for dresscode violations if(istype(head, /obj/item/clothing/head/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/syndi) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi)) - threatcount += 6 //fuk u antags <3 - - //Check for nonhuman scum - if(dna && dna.species.id && dna.species.id != "human") - threatcount += 1 + threatcount += 4 //fuk u antags <3 //no you //mindshield implants imply trustworthyness if(has_trait(TRAIT_MINDSHIELD)) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 4185f8f3aa..ce906565d2 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -273,7 +273,7 @@ else playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) if(!lying) //CITADEL EDIT - Knockdown(100, override_duration = 30, override_stam = 25) + Knockdown(100, TRUE, FALSE, 30, 25) else Knockdown(100) log_combat(M, src, "tackled") diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 617e62773d..e3164e0dcb 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -92,3 +92,5 @@ limbs_id = "lizard" species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE) inherent_traits = list(TRAIT_NOGUNS,TRAIT_NOBREATH) + burnmod = 0.9 + brutemod = 0.9 \ No newline at end of file diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 0c50b7ef60..c32b6ace78 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -700,9 +700,13 @@ var/list/L = where if(what == who.get_item_for_held_index(L[2])) if(who.dropItemToGround(what)) + if(!put_in_hands(what)) + what.forceMove(drop_location()) log_combat(src, who, "stripped [what] off") if(what == who.get_item_by_slot(where)) if(who.dropItemToGround(what)) + if(!put_in_hands(what)) + what.forceMove(drop_location()) log_combat(src, who, "stripped [what] off") // The src mob is trying to place an item on someone diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm index 41644ec234..be9b435a18 100644 --- a/code/modules/mob/living/simple_animal/hostile/carp.dm +++ b/code/modules/mob/living/simple_animal/hostile/carp.dm @@ -93,8 +93,15 @@ desc = "A failed Syndicate experiment in weaponized space carp technology, it now serves as a lovable mascot." gender = FEMALE speak_emote = list("squeaks") + maxHealth = 90 + health = 90 gold_core_spawnable = NO_SPAWN faction = list(ROLE_SYNDICATE) AIStatus = AI_OFF + harm_intent_damage = 12 + obj_damage = 70 + melee_damage_lower = 15 + melee_damage_upper = 18 + #undef REGENERATION_DELAY diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index c60dae6a35..45745bd84e 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -44,6 +44,7 @@ Difficulty: Hard ranged_cooldown_time = 10 ranged = 1 pixel_x = -32 + gender = MALE del_on_death = 1 crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher) loot = list(/obj/structure/closet/crate/necropolis/bubblegum) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index a563aef86a..79215ff5f5 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -564,7 +564,12 @@ GLOB.cameranet.stat_entry() if(statpanel("Tickets")) GLOB.ahelp_tickets.stat_entry() - + if(length(GLOB.sdql2_queries)) + if(statpanel("SDQL2")) + stat("Access Global SDQL2 List", GLOB.sdql2_vv_statobj) + for(var/i in GLOB.sdql2_queries) + var/datum/SDQL2_query/Q = i + Q.generate_stat() if(listed_turf && client) if(!TurfAdjacent(listed_turf)) listed_turf = null diff --git a/code/modules/ninja/ninja_event.dm b/code/modules/ninja/ninja_event.dm index 9fd8e4baf2..ccd9b765c1 100644 --- a/code/modules/ninja/ninja_event.dm +++ b/code/modules/ninja/ninja_event.dm @@ -33,7 +33,6 @@ Contents: control.occurrences-- return ..() - /datum/round_event/ghost_role/ninja/spawn_role() //selecting a spawn_loc if(!spawn_loc) @@ -74,6 +73,7 @@ Contents: spawned_mobs += Ninja message_admins("[ADMIN_LOOKUPFLW(Ninja)] has been made into a ninja by an event.") log_game("[key_name(Ninja)] was spawned as a ninja by an event.") + success_spawn = TRUE return SUCCESSFUL_SPAWN @@ -86,4 +86,4 @@ Contents: A.real_name = "[pick(GLOB.ninja_titles)] [pick(GLOB.ninja_names)]" A.copy_to(new_ninja) new_ninja.dna.update_dna_identity() - return new_ninja \ No newline at end of file + return new_ninja diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm index f3f960c0ee..8e121dc809 100644 --- a/code/modules/power/generator.dm +++ b/code/modules/power/generator.dm @@ -65,7 +65,7 @@ if(delta_temperature > 0 && cold_air_heat_capacity > 0 && hot_air_heat_capacity > 0) - var/efficiency = 0.65 + var/efficiency = 0.45 var/energy_transfer = delta_temperature*hot_air_heat_capacity*cold_air_heat_capacity/(hot_air_heat_capacity+cold_air_heat_capacity) diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm index 33ebefbf4c..2265f806a5 100644 --- a/code/modules/power/tesla/coil.dm +++ b/code/modules/power/tesla/coil.dm @@ -94,7 +94,7 @@ var/power = (powernet.avail/2) add_load(power) playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5) - tesla_zap(src, 10, power/(coeff/2)) + tesla_zap(src, 10, power/(coeff/2), TESLA_FUSION_FLAGS) tesla_buckle_check(power/(coeff/2)) // Tesla R&D researcher @@ -174,4 +174,4 @@ flick("grounding_rodhit", src) tesla_buckle_check(power) else - ..() \ No newline at end of file + ..() diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm index e16b9bb9b5..87fdbc65b0 100644 --- a/code/modules/projectiles/ammunition/_ammunition.dm +++ b/code/modules/projectiles/ammunition/_ammunition.dm @@ -73,6 +73,11 @@ /obj/item/ammo_casing/proc/bounce_away(still_warm = FALSE, bounce_delay = 3) update_icon() SpinAnimation(10, 1) + var/matrix/M = matrix(transform) + M.Turn(rand(-170,170)) + transform = M + pixel_x = rand(-12, 12) + pixel_y = rand(-12, 12) var/turf/T = get_turf(src) if(still_warm && T && T.bullet_sizzle) addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, src, 'sound/items/welder.ogg', 20, 1), bounce_delay) //If the turf is made of water and the shell casing is still hot, make a sizzling sound when it's ejected. diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm index 39cf924169..d57edf154d 100644 --- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm +++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm @@ -115,7 +115,7 @@ /obj/item/ammo_casing/shotgun/dart/noreact name = "cryostasis shotgun dart" - desc = "A dart for use in shotguns, using similar technology as cryostatis beakers to keep internal reagents from reacting. Can be injected with up to 10 units of any chemical." + desc = "A dart for use in shotguns. Uses technology similar to cryostasis beakers to keep internal reagents from reacting. Can be injected with up to 10 units of any chemical." icon_state = "cnrshell" reagent_amount = 10 reagent_react = FALSE diff --git a/code/modules/projectiles/boxes_magazines/external/shotgun.dm b/code/modules/projectiles/boxes_magazines/external/shotgun.dm index bb04446129..1fa3db28b5 100644 --- a/code/modules/projectiles/boxes_magazines/external/shotgun.dm +++ b/code/modules/projectiles/boxes_magazines/external/shotgun.dm @@ -34,3 +34,8 @@ name = "shotgun magazine (12g meteor slugs)" icon_state = "m12gbc" ammo_type = /obj/item/ammo_casing/shotgun/meteorslug + +/obj/item/ammo_box/magazine/m12g/scatter + name = "shotgun magazine (12g scatter laser shot slugs)" + icon_state = "m12gb" + ammo_type = /obj/item/ammo_casing/shotgun/laserslug diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 54ca03f872..83ce525ac8 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -43,7 +43,7 @@ pump(user) recentpump = world.time + 10 if(istype(user))//CIT CHANGE - makes pumping shotguns cost a lil bit of stamina. - user.adjustStaminaLossBuffered(5) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added + user.adjustStaminaLossBuffered(2) //CIT CHANGE - DITTO. make this scale inversely to the strength stat when stats/skills are added return /obj/item/gun/ballistic/shotgun/blow_up(mob/user) @@ -206,7 +206,7 @@ desc = "A compact version of the semi automatic combat shotgun. For close encounters." icon_state = "cshotgunc" mag_type = /obj/item/ammo_box/magazine/internal/shot/com/compact - w_class = WEIGHT_CLASS_BULKY + w_class = WEIGHT_CLASS_NORMAL //Dual Feed Shotgun diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index ad2949892e..fba355d738 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -50,7 +50,7 @@ damage = 50 damage_type = BRUTE flag = "bomb" - range = 5 + range = 4 log_override = TRUE /obj/item/gun/energy/kinetic_accelerator/premiumka/update_icon() diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 457ec78e9b..c8c4a73b3b 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -88,8 +88,12 @@ do_sparks(1, TRUE, src) ..() -// Mech Scattershot +// Mech Scattershots /obj/item/projectile/bullet/scattershot damage = 20 stamina = 65 + +/obj/item/projectile/bullet/seed + damage = 4 + stamina = 1 diff --git a/code/modules/projectiles/projectile/special/neurotoxin.dm b/code/modules/projectiles/projectile/special/neurotoxin.dm index def7ea187e..baf1495abb 100644 --- a/code/modules/projectiles/projectile/special/neurotoxin.dm +++ b/code/modules/projectiles/projectile/special/neurotoxin.dm @@ -10,5 +10,5 @@ nodamage = TRUE else if(isliving(target)) var/mob/living/L = target - L.Knockdown(100, override_duration = 30, override_stam = 25) + L.Knockdown(100, TRUE, FALSE, 30, 25) return ..() diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index f9dbd1928b..6e4d5e5a7d 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1398,15 +1398,15 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/eggnog name = "Eggnog" id = "eggnog" - description = "For enjoying the most wonderful time of the year." + description = "The traditional way to get absolutely hammered at a Christmas party." color = "#fcfdc6" // rgb: 252, 253, 198 nutriment_factor = 2 * REAGENTS_METABOLISM boozepwr = 1 quality = DRINK_VERYGOOD taste_description = "custard and alcohol" - glass_icon_state = "glass_yellow" + glass_icon_state = "nog3" glass_name = "eggnog" - glass_desc = "For enjoying the most wonderful time of the year." + glass_desc = "The traditional way to get absolutely hammered at a Christmas party." /datum/reagent/consumable/ethanol/narsour diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 685b37564a..52b212f8c5 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -112,7 +112,7 @@ /datum/reagent/consumable/cooking_oil/reaction_obj(obj/O, reac_volume) if(holder && holder.chem_temp >= fry_temperature) - if(isitem(O) && !istype(O, /obj/item/reagent_containers/food/snacks/deepfryholder)) + if(isitem(O) && !istype(O, /obj/item/reagent_containers/food/snacks/deepfryholder) && !(O.resistance_flags & (FIRE_PROOF|INDESTRUCTIBLE))) O.loc.visible_message("[O] rapidly fries as it's splashed with hot oil! Somehow.") var/obj/item/reagent_containers/food/snacks/deepfryholder/F = new(O.drop_location(), O) F.fry(volume) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 671e62a9e6..4e278d2ede 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -546,19 +546,14 @@ overdose_threshold = 45 addiction_threshold = 30 -/datum/reagent/medicine/ephedrine/on_mob_add(mob/living/L) - ..() - L.add_trait(TRAIT_GOTTAGOFAST, id) - -/datum/reagent/medicine/ephedrine/on_mob_delete(mob/living/L) - L.remove_trait(TRAIT_GOTTAGOFAST, id) - ..() - /datum/reagent/medicine/ephedrine/on_mob_life(mob/living/carbon/M) M.AdjustStun(-20, 0) M.AdjustKnockdown(-20, 0) M.AdjustUnconscious(-20, 0) - M.adjustStaminaLoss(-1*REM, 0) + M.adjustStaminaLoss(-4.5*REM, 0) + M.Jitter(10) + if(prob(50)) + M.confused = max(M.confused, 1) ..() return TRUE diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 53bc7e2c17..a7e4e0f590 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1280,6 +1280,7 @@ reagent_state = SOLID color = "#FFFFFF" // rgb: 207, 54, 0 taste_description = "the back of class" + no_mob_color = TRUE /datum/reagent/colorful_reagent/crayonpowder/New() description = "\an [colorname] powder made by grinding down crayons, good for colouring chemical reagents." @@ -1481,14 +1482,16 @@ color = "#C8A5DC" var/list/random_color_list = list("#00aedb","#a200ff","#f47835","#d41243","#d11141","#00b159","#00aedb","#f37735","#ffc425","#008744","#0057e7","#d62d20","#ffa700") taste_description = "rainbows" - + var/no_mob_color = FALSE /datum/reagent/colorful_reagent/on_mob_life(mob/living/carbon/M) - M.add_atom_colour(pick(random_color_list), WASHABLE_COLOUR_PRIORITY) + if(!no_mob_color) + M.add_atom_colour(pick(random_color_list), WASHABLE_COLOUR_PRIORITY) ..() /datum/reagent/colorful_reagent/reaction_mob(mob/living/M, reac_volume) - M.add_atom_colour(pick(random_color_list), WASHABLE_COLOUR_PRIORITY) + if(!no_mob_color) + M.add_atom_colour(pick(random_color_list), WASHABLE_COLOUR_PRIORITY) ..() /datum/reagent/colorful_reagent/reaction_obj(obj/O, reac_volume) diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index f2e9baeba4..e1f4e3dd36 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -592,3 +592,24 @@ id = "pax" results = list("pax" = 3) required_reagents = list("mindbreaker" = 1, "synaptizine" = 1, "water" = 1) + +/datum/chemical_reaction/cat + name = "felined mutation toxic" + id = "cats" + results = list("felinidmutationtoxin" = 1) + required_reagents = list("mindbreaker" = 1, "ammonia" = 1, "water" = 1, "aphro" = 10, "stablemutationtoxin" = 1) // Maybe aphro+ if it becomes a shitty meme + required_temp = 450 + +/datum/chemical_reaction/moff + name = "moth mutation toxic" + id = "moffs" + results = list("mothmutationtoxin" = 1) + required_reagents = list("liquid_dark_matter" = 2, "ammonia" = 5, "lithium" = 1, "stablemutationtoxin" = 1) + required_temp = 320 + +/datum/chemical_reaction/notlight //Harder to make do to it being a hard race to play + name = "shadow muatatuin toxic" + id = "notlight" + results = list("shadowmutationtoxin" = 1) + required_reagents = list("liquid_dark_matter" = 5, "synaptizine" = 10, "oculine" = 10, "stablemutationtoxin" = 1) + required_temp = 600 diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 85868f1895..955b519e6a 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -103,6 +103,7 @@ else if(bartender_check(target) && thrown) visible_message("[src] lands onto the [target.name] without spilling a single drop.") + transform = initial(transform) return else diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index b88f680dbb..f59f00a4b8 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -168,6 +168,13 @@ amount_per_transfer_from_this = 1 list_reagents = list("unstablemutationtoxin" = 1) +/obj/item/reagent_containers/hypospray/medipen/firelocker + name = "fire treatment medipen" + desc = "A medipen that has been fulled with burn healing chemicals for personnel without advanced medical knowledge." + volume = 15 + amount_per_transfer_from_this = 15 + list_reagents = list("oxandrolone" = 5, "kelotane" = 10) + /obj/item/reagent_containers/hypospray/combat/heresypurge name = "holy water autoinjector" desc = "A modified air-needle autoinjector for use in combat situations. Prefilled with 5 doses of a holy water mixture." diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 8941724274..b5d00d2ba4 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -81,66 +81,77 @@ icon_state = "pill5" list_reagents = list("toxin" = 50) roundstart = 1 + /obj/item/reagent_containers/pill/cyanide name = "cyanide pill" desc = "Don't swallow this." icon_state = "pill5" list_reagents = list("cyanide" = 50) roundstart = 1 + /obj/item/reagent_containers/pill/adminordrazine name = "adminordrazine pill" desc = "It's magic. We don't have to explain it." icon_state = "pill16" list_reagents = list("adminordrazine" = 50) roundstart = 1 + /obj/item/reagent_containers/pill/morphine name = "morphine pill" desc = "Commonly used to treat insomnia." icon_state = "pill8" list_reagents = list("morphine" = 30) roundstart = 1 + /obj/item/reagent_containers/pill/stimulant name = "stimulant pill" desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!" icon_state = "pill19" list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30) roundstart = 1 + /obj/item/reagent_containers/pill/salbutamol name = "salbutamol pill" desc = "Used to treat oxygen deprivation." icon_state = "pill16" list_reagents = list("salbutamol" = 30) roundstart = 1 + /obj/item/reagent_containers/pill/charcoal name = "charcoal pill" desc = "Neutralizes many common toxins." icon_state = "pill17" list_reagents = list("charcoal" = 10) roundstart = 1 + /obj/item/reagent_containers/pill/epinephrine name = "epinephrine pill" desc = "Used to stabilize patients." icon_state = "pill5" list_reagents = list("epinephrine" = 15) roundstart = 1 + /obj/item/reagent_containers/pill/mannitol name = "mannitol pill" desc = "Used to treat brain damage." icon_state = "pill17" list_reagents = list("mannitol" = 50) roundstart = 1 + /obj/item/reagent_containers/pill/mutadone name = "mutadone pill" desc = "Used to treat genetic damage." icon_state = "pill20" list_reagents = list("mutadone" = 50) roundstart = 1 + /obj/item/reagent_containers/pill/salicyclic name = "salicylic acid pill" desc = "Used to dull pain." icon_state = "pill9" list_reagents = list("sal_acid" = 24) roundstart = 1 + /obj/item/reagent_containers/pill/oxandrolone name = "oxandrolone pill" desc = "Used to stimulate burn healing." @@ -154,6 +165,13 @@ icon_state = "pill18" list_reagents = list("insulin" = 50) roundstart = 1 + +/obj/item/reagent_containers/pill/antirad + name = "potassium iodide pill" + desc = "Used to treat radition used to counter radiation poisoning." + icon_state = "pill18" + list_reagents = list("potass_iodide" = 50) + roundstart = 1 ///////////////////////////////////////// this pill is used only in a legion mob drop /obj/item/reagent_containers/pill/shadowtoxin name = "black pill" diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index e3576b3625..a51134f84d 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -166,6 +166,15 @@ user.visible_message("[user] decided life was worth living.") return +//Drying Agent +/obj/item/reagent_containers/spray/drying_agent + name = "drying agent spray" + desc = "A spray bottle for drying agent." + volume = 100 + list_reagents = list("drying_agent" = 100) + amount_per_transfer_from_this = 2 + stream_amount = 5 + //spray tan /obj/item/reagent_containers/spray/spraytan name = "spray tan" diff --git a/code/modules/recycling/disposal/pipe.dm b/code/modules/recycling/disposal/pipe.dm index 6c269e44be..aed2310a7f 100644 --- a/code/modules/recycling/disposal/pipe.dm +++ b/code/modules/recycling/disposal/pipe.dm @@ -1,5 +1,7 @@ // Disposal pipes +#define IFFY 2 + /obj/structure/disposalpipe name = "disposal pipe" desc = "An underfloor disposal pipe." @@ -16,6 +18,7 @@ var/dpdir = NONE // bitmask of pipe directions var/initialize_dirs = NONE // bitflags of pipe directions added on init, see \code\_DEFINES\pipe_construction.dm var/flip_type // If set, the pipe is flippable and becomes this type when flipped + var/canclank = FALSE // Determines if the pipe will cause a clank sound when holders pass by it. use the IFFY define for weird-ass edge cases like the segment subtype var/obj/structure/disposalconstruct/stored @@ -75,6 +78,8 @@ H.merge(H2) H.forceMove(P) + if(P.canclank == TRUE || (P.canclank == IFFY && P.dpdir != 3 && P.dpdir != 12)) + playsound(P, H.hasmob ? "clang" : "clangsmall", H.hasmob ? 50 : 25, 1) return P else // if wasn't a pipe, then they're now in our turf H.forceMove(get_turf(src)) @@ -184,6 +189,7 @@ /obj/structure/disposalpipe/segment icon_state = "pipe" initialize_dirs = DISP_DIR_FLIP + canclank = IFFY // A three-way junction with dir being the dominant direction @@ -191,6 +197,7 @@ icon_state = "pipe-j1" initialize_dirs = DISP_DIR_RIGHT | DISP_DIR_FLIP flip_type = /obj/structure/disposalpipe/junction/flip + canclank = TRUE // next direction to move // if coming in from secondary dirs, then next is primary dir @@ -229,6 +236,7 @@ //a trunk joining to a disposal bin or outlet on the same turf /obj/structure/disposalpipe/trunk icon_state = "pipe-t" + canclank = TRUE var/obj/linked // the linked obj/machinery/disposal or obj/disposaloutlet /obj/structure/disposalpipe/trunk/Initialize() @@ -299,3 +307,5 @@ /obj/structure/disposalpipe/broken/deconstruct() qdel(src) + +#undef IFFY diff --git a/code/modules/recycling/disposal/pipe_sorting.dm b/code/modules/recycling/disposal/pipe_sorting.dm index 5e26e9b767..d85c4bca78 100644 --- a/code/modules/recycling/disposal/pipe_sorting.dm +++ b/code/modules/recycling/disposal/pipe_sorting.dm @@ -5,6 +5,7 @@ desc = "An underfloor disposal pipe with a sorting mechanism." icon_state = "pipe-j1s" initialize_dirs = DISP_DIR_RIGHT | DISP_DIR_FLIP + canclank = TRUE /obj/structure/disposalpipe/sorting/nextdir(obj/structure/disposalholder/H) var/sortdir = dpdir & ~(dir | turn(dir, 180)) diff --git a/code/modules/research/designs/electronics_designs.dm b/code/modules/research/designs/electronics_designs.dm index e9db641811..552976824d 100644 --- a/code/modules/research/designs/electronics_designs.dm +++ b/code/modules/research/designs/electronics_designs.dm @@ -118,3 +118,16 @@ build_path = /obj/item/disk/integrated_circuit/upgrade/clone category = list("Electronics") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE + +//CIT ADDITIONS +/datum/design/drone_shell + name = "Drone Shell" + desc = "A shell of a maintenance drone, an expendable robot built to perform station repairs." + id = "drone_shell" + build_type = MECHFAB | PROTOLATHE + materials = list(MAT_METAL = 800, MAT_GLASS = 350) + construction_time = 150 + build_path = /obj/item/drone_shell + category = list("Misc") + departmental_flags = DEPARTMENTAL_FLAG_SCIENCE + diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm index cee0dc7413..3ee7d344dc 100644 --- a/code/modules/research/designs/mecha_designs.dm +++ b/code/modules/research/designs/mecha_designs.dm @@ -147,6 +147,16 @@ construction_time = 100 category = list("Exosuit Equipment") +/datum/design/mech_seedscatter + name = "Exosuit Weapon (Melon Seed \"Scattershot\")" + desc = "Allows for the construction of Melon Seed Scattershot." + id = "mech_seedscatter" + build_type = MECHFAB + build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/seedscatter + materials = list(MAT_METAL=10000, MAT_GLASS = 10000) + construction_time = 70 + category = list("Exosuit Equipment") + /datum/design/mech_carbine name = "Exosuit Weapon (FNX-99 \"Hades\" Carbine)" desc = "Allows for the construction of FNX-99 \"Hades\" Carbine." diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index b7da52468b..ca3f2b420b 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -44,6 +44,16 @@ category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +/datum/design/medicalkit + name = "Empty Medkit" + desc = "A plastic medical kit for storging medical items." + id = "medicalkit" + build_type = PROTOLATHE + materials = list(MAT_PLASTIC = 5000) + build_path = /obj/item/storage/firstaid //So we dont spawn medical items in it + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + /datum/design/xlarge_beaker name = "X-large Beaker" id = "xlarge_beaker" @@ -526,6 +536,80 @@ category = list("Medical Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +///////////////////// +//Adv Surgery Tools// +///////////////////// + +/datum/design/drapes + name = "Plastic Drapes" + desc = "A large surgery drape made of plastic." + id = "drapes" + build_type = PROTOLATHE + materials = list(MAT_PLASTIC = 2500) + build_path = /obj/item/surgical_drapes + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/retractor_adv + name = "Advanced Retractor" + desc = "A high-class, premium retractor, featuring precision crafted, silver-plated hook-ends and an electrum handle." + id = "retractor_adv" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1500, MAT_GOLD = 1000) + build_path = /obj/item/retractor/adv + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/hemostat_adv + name = "Advanced Hemostat" + desc = "An exceptionally fine pair of arterial forceps. These appear to be plated in electrum and feel soft to the touch." + id = "hemostat_adv" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1000, MAT_GOLD = 1500) + build_path = /obj/item/hemostat/adv + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/cautery_adv + name = "Electrocautery" //This is based on real-life science. + desc = "A high-tech unipolar Electrocauter. This tiny device contains an extremely powerful microbattery that uses arcs of electricity to painlessly sear wounds shut. It seems to recharge with the user's body-heat. Wow!" + id = "cautery_adv" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 1000, MAT_GOLD = 1500) + build_path = /obj/item/cautery/adv + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/surgicaldrill_adv + name = "Surgical Autodrill" + desc = "With a diamond tip and built-in depth and safety sensors, this drill alerts the user before overpenetrating a patient's skull or tooth. There also appears to be a disable switch." + id = "surgicaldrill_adv" + build_type = PROTOLATHE + materials = list(MAT_METAL = 2500, MAT_GLASS = 2500, MAT_SILVER = 6000, MAT_GOLD = 5500, MAT_DIAMOND = 3500) + build_path = /obj/item/surgicaldrill/adv + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/scalpel_adv + name = "Precision Scalpel" + desc = "A perfectly balanced electrum scalpel with a silicon-coated edge to eliminate wear and tear." + id = "scalpel_adv" + build_type = PROTOLATHE + materials = list(MAT_METAL = 1500, MAT_GLASS = 1500, MAT_SILVER = 4000, MAT_GOLD = 2500) + build_path = /obj/item/scalpel/adv + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + +/datum/design/circular_saw_adv + name = "Diamond-Grit Circular Saw" + desc = "For those Assistants with REALLY thick skulls." + id = "circular_saw_adv" + build_type = PROTOLATHE + materials = list(MAT_METAL = 7500, MAT_GLASS = 6000, MAT_SILVER = 6500, MAT_GOLD = 7500, MAT_DIAMOND = 4500) + build_path = /obj/item/circular_saw/adv + category = list("Medical Designs") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE + ///////////////////// ///Surgery Designs/// ///////////////////// diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm index 0ac01aec38..d567334998 100644 --- a/code/modules/research/designs/misc_designs.dm +++ b/code/modules/research/designs/misc_designs.dm @@ -13,6 +13,16 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL +/datum/design/health_hud_prescription + name = "Prescription Health Scanner HUD" + desc = "A heads-up display that scans the humans in view and provides accurate data about their health status. This one has a prescription lens." + id = "health_hud_prescription" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 350) + build_path = /obj/item/clothing/glasses/hud/health/prescription + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + /datum/design/health_hud_night name = "Night Vision Health Scanner HUD" desc = "An advanced medical head-up display that allows doctors to find patients in complete darkness." @@ -33,6 +43,17 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_SECURITY +/datum/design/security_hud_prescription + name = "Prescription Security HUD" + desc = "A heads-up display that scans the humans in view and provides accurate data about their ID status. This one has a prescription lens." + id = "security_hud_prescription" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 350) + build_path = /obj/item/clothing/glasses/hud/security/prescription + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + + /datum/design/security_hud_night name = "Night Vision Security HUD" desc = "A heads-up display which provides id data and vision in complete darkness." @@ -53,6 +74,16 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE +/datum/design/diagnostic_hud_prescription + name = "Prescription Diagnostic HUD" + desc = "A HUD used to analyze and determine faults within robotic machinery. This one has a prescription lens." + id = "diagnostic_hud_prescription" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_GOLD = 350) + build_path = /obj/item/clothing/glasses/hud/diagnostic/prescription + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_SCIENCE + /datum/design/diagnostic_hud_night name = "Night Vision Diagnostic HUD" desc = "Upgraded version of the diagnostic HUD designed to function during a power failure." @@ -107,6 +138,16 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_ENGINEERING +/datum/design/mesons_prescription + name = "Prescription Optical Meson Scanners" + desc = "Used by engineering and mining staff to see basic structural and terrain layouts through walls, regardless of lighting condition. Prescription lens has been added into this design." + id = "mesons_prescription" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 350) + build_path = /obj/item/clothing/glasses/meson/prescription + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_ENGINEERING + /datum/design/engine_goggles name = "Engineering Scanner Goggles" desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, regardless of lighting condition. The T-ray Scanner mode lets you see underfloor objects such as cables and pipes." @@ -117,6 +158,16 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING +/datum/design/engine_goggles_prescription + name = "Prescription Engineering Scanner Goggles" + desc = "Goggles used by engineers. The Meson Scanner mode lets you see basic structural and terrain layouts through walls, regardless of lighting condition. The T-ray Scanner mode lets you see underfloor objects such as cables and pipes. Prescription lens has been added into this design." + id = "engine_goggles_prescription" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_PLASMA = 100, MAT_SILVER = 350) + build_path = /obj/item/clothing/glasses/meson/engine/prescription + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + /datum/design/tray_goggles name = "Optical T-Ray Scanners" desc = "Used by engineering staff to see underfloor objects such as cables and pipes." @@ -127,6 +178,16 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING +/datum/design/tray_goggles_prescription + name = "Prescription Optical T-Ray Scanners" + desc = "Used by engineering staff to see underfloor objects such as cables and pipes. Prescription lens has been added into this design." + id = "tray_goggles_prescription" + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 150) + build_path = /obj/item/clothing/glasses/meson/engine/tray/prescription + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + /datum/design/nvgmesons name = "Night Vision Optical Meson Scanners" desc = "Prototype meson scanners fitted with an extra sensor which amplifies the visible light spectrum and overlays it to the UHD display." @@ -187,86 +248,6 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE -/datum/design/handdrill - name = "Hand Drill" - desc = "A small electric hand drill with an interchangeable screwdriver and bolt bit" - id = "handdrill" - build_type = PROTOLATHE - materials = list(MAT_METAL = 3500, MAT_SILVER = 1500, MAT_TITANIUM = 2500) - build_path = /obj/item/screwdriver/power - category = list("Equipment") - departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - -/datum/design/jawsoflife - name = "Jaws of Life" - desc = "A small, compact Jaws of Life with an interchangeable pry jaws and cutting jaws" - id = "jawsoflife" // added one more requirment since the Jaws of Life are a bit OP - build_path = /obj/item/crowbar/power - build_type = PROTOLATHE - materials = list(MAT_METAL = 4500, MAT_SILVER = 2500, MAT_TITANIUM = 3500) - category = list("Equipment") - departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - -/datum/design/alienwrench - name = "Alien Wrench" - desc = "An advanced wrench obtained through Abductor technology." - id = "alien_wrench" - build_path = /obj/item/wrench/abductor - build_type = PROTOLATHE - materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) - category = list("Equipment") - departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - -/datum/design/alienwirecutters - name = "Alien Wirecutters" - desc = "Advanced wirecutters obtained through Abductor technology." - id = "alien_wirecutters" - build_path = /obj/item/wirecutters/abductor - build_type = PROTOLATHE - materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) - category = list("Equipment") - departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - -/datum/design/alienscrewdriver - name = "Alien Screwdriver" - desc = "An advanced screwdriver obtained through Abductor technology." - id = "alien_screwdriver" - build_path = /obj/item/screwdriver/abductor - build_type = PROTOLATHE - materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) - category = list("Equipment") - departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - -/datum/design/aliencrowbar - name = "Alien Crowbar" - desc = "An advanced crowbar obtained through Abductor technology." - id = "alien_crowbar" - build_path = /obj/item/crowbar/abductor - build_type = PROTOLATHE - materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) - category = list("Equipment") - departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - -/datum/design/alienwelder - name = "Alien Welding Tool" - desc = "An advanced welding tool obtained through Abductor technology." - id = "alien_welder" - build_path = /obj/item/weldingtool/abductor - build_type = PROTOLATHE - materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) - category = list("Equipment") - departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - -/datum/design/alienmultitool - name = "Alien Multitool" - desc = "An advanced multitool obtained through Abductor technology." - id = "alien_multitool" - build_path = /obj/item/multitool/abductor - build_type = PROTOLATHE - materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) - category = list("Equipment") - departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING - /datum/design/diskplantgene name = "Plant Data Disk" desc = "A disk for storing plant genetic data." @@ -385,6 +366,86 @@ category = list("Equipment") departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING +/datum/design/handdrill + name = "Hand Drill" + desc = "A small electric hand drill with an interchangeable screwdriver and bolt bit" + id = "handdrill" + build_type = PROTOLATHE + materials = list(MAT_METAL = 3500, MAT_SILVER = 1500, MAT_TITANIUM = 2500) + build_path = /obj/item/screwdriver/power + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/jawsoflife + name = "Jaws of Life" + desc = "A small, compact Jaws of Life with an interchangeable pry jaws and cutting jaws" + id = "jawsoflife" // added one more requirment since the Jaws of Life are a bit OP + build_path = /obj/item/crowbar/power + build_type = PROTOLATHE + materials = list(MAT_METAL = 4500, MAT_SILVER = 2500, MAT_TITANIUM = 3500) + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/alienwrench + name = "Alien Wrench" + desc = "An advanced wrench obtained through Abductor technology." + id = "alien_wrench" + build_path = /obj/item/wrench/abductor + build_type = PROTOLATHE + materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/alienwirecutters + name = "Alien Wirecutters" + desc = "Advanced wirecutters obtained through Abductor technology." + id = "alien_wirecutters" + build_path = /obj/item/wirecutters/abductor + build_type = PROTOLATHE + materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/alienscrewdriver + name = "Alien Screwdriver" + desc = "An advanced screwdriver obtained through Abductor technology." + id = "alien_screwdriver" + build_path = /obj/item/screwdriver/abductor + build_type = PROTOLATHE + materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/aliencrowbar + name = "Alien Crowbar" + desc = "An advanced crowbar obtained through Abductor technology." + id = "alien_crowbar" + build_path = /obj/item/crowbar/abductor + build_type = PROTOLATHE + materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 1000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/alienwelder + name = "Alien Welding Tool" + desc = "An advanced welding tool obtained through Abductor technology." + id = "alien_welder" + build_path = /obj/item/weldingtool/abductor + build_type = PROTOLATHE + materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/alienmultitool + name = "Alien Multitool" + desc = "An advanced multitool obtained through Abductor technology." + id = "alien_multitool" + build_path = /obj/item/multitool/abductor + build_type = PROTOLATHE + materials = list(MAT_METAL = 5000, MAT_SILVER = 2500, MAT_PLASMA = 5000, MAT_TITANIUM = 2000, MAT_DIAMOND = 2000) + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + /datum/design/anomaly_neutralizer name = "Anomaly Neutralizer" desc = "An advanced tool capable of instantly neutralizing anomalies, designed to capture the fleeting aberrations created by the engine." diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index bf503c2653..2402967ff3 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -294,7 +294,7 @@ departmental_flags = DEPARTMENTAL_FLAG_SECURITY /datum/design/cryostatis_shotgun_dart - name = "Cryostatis Shotgun Dart" + name = "Cryostasis Shotgun Dart" desc = "A shotgun dart designed with similar internals to that of a cryostatis beaker, allowing reagents to not react when inside." id = "shotgundartcryostatis" build_type = PROTOLATHE diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 826f8d05b8..e7bbd468dc 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -43,13 +43,24 @@ description = "Various tools fit for basic mech units" design_ids = list("mech_drill", "mech_mscanner", "mech_extinguisher", "mech_cable_layer") + +/datum/techweb_node/surplus_lims + id = "surplus_lims" + display_name = "Basic Prosthetics" + description = "Basic fragile lims for the impaired." + starting_node = TRUE + prereq_ids = list("biotech") + design_ids = list("basic_l_arm", "basic_r_arm", "basic_r_leg", "basic_l_leg") + export_price = 5000 + + /////////////////////////Biotech///////////////////////// /datum/techweb_node/biotech id = "biotech" display_name = "Biological Technology" description = "What makes us tick." //the MC, silly! prereq_ids = list("base") - design_ids = list("chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag") + design_ids = list("medicalkit", "chem_heater", "chem_master", "chem_dispenser", "sleeper", "vr_sleeper", "pandemic", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "blood_bag") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 @@ -71,21 +82,21 @@ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 -/datum/techweb_node/surplus_lims - id = "surplus_lims" - display_name = "Basic Prosthetics" - description = "Basic fragile lims for the impaired." - prereq_ids = list("biotech") - design_ids = list("basic_l_arm", "basic_r_arm", "basic_r_leg", "basic_l_leg") - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) // You can knock them off with a glass shard... - export_price = 5000 - /datum/techweb_node/advance_lims id = "advance_lims" display_name = "Upgraded Prosthetics" description = "Reinforced prosthetics for the impaired." prereq_ids = list("adv_biotech", "surplus_lims") design_ids = list("adv_l_arm", "adv_r_arm", "adv_r_leg", "adv_l_leg") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1250) + export_price = 5000 + +/datum/techweb_node/advance_surgerytools + id = "advance_surgerytools" + display_name = "Advanced Surgery Tools" + description = "Refined and improved redesigns for the run-of-the-mill medical utensils." + prereq_ids = list("adv_biotech", "adv_surgery") + design_ids = list("drapes", "retractor_adv", "hemostat_adv", "cautery_adv", "surgicaldrill_adv", "scalpel_adv", "circular_saw_adv") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 @@ -152,7 +163,7 @@ display_name = "Advanced Engineering" description = "Pushing the boundaries of physics, one chainsaw-fist at a time." prereq_ids = list("engineering", "emp_basic") - design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask") + design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask", "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000) export_price = 5000 @@ -254,7 +265,7 @@ display_name = "Basic Robotics Research" description = "Programmable machines that make our lives lazier." prereq_ids = list("base") - design_ids = list("paicard") + design_ids = list("paicard", "drone_shell") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000) export_price = 5000 @@ -415,7 +426,7 @@ display_name = "Integrated HUDs" description = "The usefulness of computerized records, projected straight onto your eyepiece!" prereq_ids = list("comp_recordkeeping", "emp_basic") - design_ids = list("health_hud", "security_hud", "diagnostic_hud", "scigoggles") + design_ids = list("health_hud", "security_hud", "diagnostic_hud", "scigoggles", "health_hud_prescription", "security_hud_prescription", "diagnostic_hud_prescription") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500) export_price = 5000 @@ -424,7 +435,7 @@ display_name = "Night Vision Technology" description = "Allows seeing in the dark without actual light!" prereq_ids = list("integrated_HUDs", "adv_engi", "emp_adv") - design_ids = list("health_hud_night", "security_hud_night", "diagnostic_hud_night", "night_visision_goggles", "night_visision_goggles_glasses", "nvgmesons") + design_ids = list("health_hud_night", "security_hud_night", "diagnostic_hud_night", "night_visision_goggles", "nvgmesons", "night_visision_goggles_glasses") research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) export_price = 5000 @@ -724,6 +735,15 @@ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) export_price = 5000 +/datum/techweb_node/mech_seedscatter + id = "mech_seedscatter" + display_name = "Exosuit Weapon (Melon Seed \"Scattershot\")" + description = "An advanced piece of mech weaponry" + prereq_ids = list("ballistic_weapons") + design_ids = list("mech_seedscatter") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + export_price = 5000 + /datum/techweb_node/mech_carbine id = "mech_carbine" display_name = "Exosuit Weapon (FNX-99 \"Hades\" Carbine)" diff --git a/code/modules/security_levels/security_levels.dm b/code/modules/security_levels/security_levels.dm index 7e45854628..70b06e6438 100644 --- a/code/modules/security_levels/security_levels.dm +++ b/code/modules/security_levels/security_levels.dm @@ -1,6 +1,7 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) //SEC_LEVEL_GREEN = code green //SEC_LEVEL_BLUE = code blue +//SEC_LEVEL_AMBER = code amber //SEC_LEVEL_RED = code red //SEC_LEVEL_DELTA = code delta @@ -12,6 +13,8 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) level = SEC_LEVEL_GREEN if("blue") level = SEC_LEVEL_BLUE + if("amber") + level = SEC_LEVEL_AMBER if("red") level = SEC_LEVEL_RED if("delta") @@ -25,8 +28,10 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) if(GLOB.security_level >= SEC_LEVEL_RED) SSshuttle.emergency.modTimer(4) + else if(GLOB.security_level == SEC_LEVEL_AMBER) + SSshuttle.emergency.modTimer(2.5) else - SSshuttle.emergency.modTimer(2) + SSshuttle.emergency.modTimer(1.66) GLOB.security_level = SEC_LEVEL_GREEN for(var/obj/machinery/firealarm/FA in GLOB.machines) if(is_station_level(FA.z)) @@ -35,24 +40,46 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) if(GLOB.security_level < SEC_LEVEL_BLUE) minor_announce(CONFIG_GET(string/alert_blue_upto), "Attention! Security level elevated to blue:",1) if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - SSshuttle.emergency.modTimer(0.5) + SSshuttle.emergency.modTimer(0.6) else minor_announce(CONFIG_GET(string/alert_blue_downto), "Attention! Security level lowered to blue:") if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - SSshuttle.emergency.modTimer(2) + if(GLOB.security_level >= SEC_LEVEL_RED) + SSshuttle.emergency.modTimer(2.4) + else + SSshuttle.emergency.modTimer(1.5) GLOB.security_level = SEC_LEVEL_BLUE sound_to_playing_players('sound/misc/voybluealert.ogg') // Citadel change - Makes alerts play a sound for(var/obj/machinery/firealarm/FA in GLOB.machines) if(is_station_level(FA.z)) FA.update_icon() + if(SEC_LEVEL_AMBER) + if(GLOB.security_level < SEC_LEVEL_AMBER) + minor_announce(CONFIG_GET(string/alert_amber_upto), "Attention! Security level elevated to amber:",1) + if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) + if(GLOB.security_level == SEC_LEVEL_GREEN) + SSshuttle.emergency.modTimer(0.4) + else + SSshuttle.emergency.modTimer(0.66) + else + minor_announce(CONFIG_GET(string/alert_amber_downto), "Attention! Security level lowered to amber:") + if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) + SSshuttle.emergency.modTimer(1.6) + GLOB.security_level = SEC_LEVEL_AMBER + sound_to_playing_players('sound/effects/alert.ogg') // Citadel change - Makes alerts play a sound + for(var/obj/machinery/firealarm/FA in GLOB.machines) + if(is_station_level(FA.z)) + FA.update_icon() if(SEC_LEVEL_RED) if(GLOB.security_level < SEC_LEVEL_RED) minor_announce(CONFIG_GET(string/alert_red_upto), "Attention! Code red!",1) if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) if(GLOB.security_level == SEC_LEVEL_GREEN) SSshuttle.emergency.modTimer(0.25) + else if(GLOB.security_level == SEC_LEVEL_BLUE) + SSshuttle.emergency.modTimer(0.416) else - SSshuttle.emergency.modTimer(0.5) + SSshuttle.emergency.modTimer(0.625) else minor_announce(CONFIG_GET(string/alert_red_downto), "Attention! Code red!") GLOB.security_level = SEC_LEVEL_RED @@ -66,10 +93,12 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) if(SEC_LEVEL_DELTA) minor_announce(CONFIG_GET(string/alert_delta), "Attention! Delta security level reached!",1) if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) - if(GLOB.security_level == SEC_LEVEL_GREEN) + if(GLOB.security_level < SEC_LEVEL_BLUE) SSshuttle.emergency.modTimer(0.25) else if(GLOB.security_level == SEC_LEVEL_BLUE) - SSshuttle.emergency.modTimer(0.5) + SSshuttle.emergency.modTimer(0.416) + else + SSshuttle.emergency.modTimer(0.625) GLOB.security_level = SEC_LEVEL_DELTA sound_to_playing_players('sound/misc/deltakalaxon.ogg') // Citadel change - Makes alerts play a sound for(var/obj/machinery/firealarm/FA in GLOB.machines) @@ -93,6 +122,8 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) return "green" if(SEC_LEVEL_BLUE) return "blue" + if(SEC_LEVEL_AMBER) + return "amber" if(SEC_LEVEL_RED) return "red" if(SEC_LEVEL_DELTA) @@ -104,6 +135,8 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) return "green" if(SEC_LEVEL_BLUE) return "blue" + if(SEC_LEVEL_AMBER) + return "amber" if(SEC_LEVEL_RED) return "red" if(SEC_LEVEL_DELTA) @@ -115,6 +148,8 @@ GLOBAL_VAR_INIT(security_level, SEC_LEVEL_GREEN) return SEC_LEVEL_GREEN if("blue") return SEC_LEVEL_BLUE + if("amber") + return SEC_LEVEL_AMBER if("red") return SEC_LEVEL_RED if("delta") diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index cbc6810143..9af4194049 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -206,7 +206,9 @@ if(SEC_LEVEL_GREEN) set_coefficient = 2 if(SEC_LEVEL_BLUE) - set_coefficient = 1 + set_coefficient = 1.2 + if(SEC_LEVEL_AMBER) + set_coefficient = 0.8 else set_coefficient = 0.5 var/call_time = SSshuttle.emergencyCallTime * set_coefficient * engine_coeff diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index 1841ac52b5..8d0547d2c5 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -295,6 +295,7 @@ var/datum/species/S = H.dna.species species_id = S.limbs_id + should_draw_citadel = S.should_draw_citadel // Citadel Addition species_flags_list = H.dna.species.species_traits if(S.use_skintones) @@ -396,7 +397,7 @@ limb.icon_state = "[species_id]_[body_zone]" // Citadel Start - if(should_draw_citadel) + if(should_draw_citadel && !use_digitigrade) limb.icon = 'modular_citadel/icons/mob/mutant_bodyparts.dmi' if(should_draw_gender) limb.icon_state = "[species_id]_[body_zone]_[icon_gender]" diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 9f71f58ff8..6ec1ea12d9 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -15,7 +15,7 @@ var/safe_co2_min = 0 var/safe_co2_max = 10 // Yes it's an arbitrary value who cares? var/safe_toxins_min = 0 - var/safe_toxins_max = 0.05 + var/safe_toxins_max = MOLES_GAS_VISIBLE var/SA_para_min = 1 //Sleeping agent var/SA_sleep_min = 5 //Sleeping agent var/BZ_trip_balls_min = 1 //BZ gas @@ -324,7 +324,7 @@ // Clear out moods when no miasma at all else SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "smell") - + handle_breath_temperature(breath, H) breath.garbage_collect() return TRUE diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index bbbe8c584d..55ead3b5b4 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -251,8 +251,10 @@ var/static/regex/clap_words = regex("clap|applaud") var/static/regex/honk_words = regex("ho+nk") //hooooooonk var/static/regex/multispin_words = regex("like a record baby|right round") - var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt") //CITADEL CHANGE + var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //CITADEL CHANGE var/static/regex/dab_words = regex("dab|mood") //CITADEL CHANGE + var/static/regex/snap_words = regex("snap") //CITADEL CHANGE + var/static/regex/bwoink_words = regex("what the fuck are you doing|bwoink|hey you got a moment?") //CITADEL CHANGE var/i = 0 //STUN @@ -582,6 +584,18 @@ for(var/V in listeners) var/mob/living/M = V M.say("*dab") + + //SNAP + else if((findtext(message, snap_words))) + cooldown = COOLDOWN_MEME + for(var/V in listeners) + var/mob/living/M = V + M.say("*snap") + + //BWOINK + else if((findtext(message, bwoink_words))) + cooldown = COOLDOWN_MEME + addtimer(CALLBACK(GLOBAL_PROC, .proc/playsound, get_turf(user), 'sound/effects/adminhelp.ogg', 300, 1), 25) //END CITADEL CHANGES else diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index aaf859ee52..517dfb412a 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -7,6 +7,15 @@ flags_1 = CONDUCT_1 w_class = WEIGHT_CLASS_TINY +/obj/item/retractor/adv + name = "Advanced Retractor" + desc = "A high-class, premium retractor, featuring precision crafted, silver-plated hook-ends and an electrum handle." + icon = 'icons/obj/surgery.dmi' + icon_state = "retractor" + materials = list(MAT_METAL=6000, MAT_GLASS=3000) + flags_1 = CONDUCT_1 + w_class = WEIGHT_CLASS_TINY + toolspeed = 0.65 /obj/item/retractor/augment name = "retractor" @@ -18,7 +27,6 @@ w_class = WEIGHT_CLASS_TINY toolspeed = 0.5 - /obj/item/hemostat name = "hemostat" desc = "You think you have seen this before." @@ -29,6 +37,16 @@ w_class = WEIGHT_CLASS_TINY attack_verb = list("attacked", "pinched") +/obj/item/hemostat/adv + name = "Advanced Hemostat" + desc = "An exceptionally fine pair of arterial forceps. These appear to be plated in electrum and feel soft to the touch." + icon = 'icons/obj/surgery.dmi' + icon_state = "hemostat" + materials = list(MAT_METAL=5000, MAT_GLASS=2500) + flags_1 = CONDUCT_1 + w_class = WEIGHT_CLASS_TINY + toolspeed = 0.65 + attack_verb = list("attacked", "pinched") /obj/item/hemostat/augment name = "hemostat" @@ -52,6 +70,16 @@ w_class = WEIGHT_CLASS_TINY attack_verb = list("burnt") +/obj/item/cautery/adv + name = "Electrocautery" + desc = "A high-tech unipolar Electrocauter. This tiny device contains an extremely powerful microbattery that uses arcs of electricity to painlessly sear wounds shut. It seems to recharge with the user's body-heat. Wow!" + icon = 'icons/obj/surgery.dmi' + icon_state = "cautery" + materials = list(MAT_METAL=2500, MAT_GLASS=750) + flags_1 = CONDUCT_1 + w_class = WEIGHT_CLASS_TINY + toolspeed = 0.5 + attack_verb = list("burnt") /obj/item/cautery/augment name = "cautery" @@ -79,6 +107,21 @@ w_class = WEIGHT_CLASS_NORMAL attack_verb = list("drilled") +/obj/item/surgicaldrill/adv + name = "Surgical Autodrill" + desc = "With a diamond tip and built-in depth and safety sensors, this drill alerts the user before overpenetrating a patient's skull or tooth. There also appears to be a disable switch." + icon = 'icons/obj/surgery.dmi' + icon_state = "drill" + lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi' + hitsound = 'sound/weapons/circsawhit.ogg' + materials = list(MAT_METAL=10000, MAT_GLASS=6000) + flags_1 = CONDUCT_1 + force = 13 //Damions are not ment for flesh cutting! + w_class = WEIGHT_CLASS_NORMAL + toolspeed = 0.65 + attack_verb = list("drilled") + sharpness = IS_SHARP_ACCURATE // Were making them use a damion for this... /obj/item/surgicaldrill/augment name = "surgical drill" @@ -116,6 +159,25 @@ . = ..() AddComponent(/datum/component/butchering, 80 * toolspeed, 100, 0) +/obj/item/scalpel/adv + name = "Precision Scalpel" + desc = "A perfectly balanced electrum scalpel with a silicon-coated edge to eliminate wear and tear." + icon = 'icons/obj/surgery.dmi' + icon_state = "scalpel" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + flags_1 = CONDUCT_1 + force = 8 + w_class = WEIGHT_CLASS_TINY + throwforce = 7 + throw_speed = 3 + throw_range = 6 + materials = list(MAT_METAL=4000, MAT_GLASS=1000) + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + toolspeed = 0.65 + hitsound = 'sound/weapons/bladeslice.ogg' + sharpness = IS_SHARP_ACCURATE + /obj/item/scalpel/augment name = "scalpel" desc = "Ultra-sharp blade attached directly to your bone for extra-accuracy." @@ -161,6 +223,26 @@ . = ..() AddComponent(/datum/component/butchering, 40 * toolspeed, 100, 5, 'sound/weapons/circsawhit.ogg') //saws are very accurate and fast at butchering +/obj/item/circular_saw/adv + name = "Diamond-Grit Circular Saw" + desc = "For those Assistants with REALLY thick skulls." + icon = 'icons/obj/surgery.dmi' + icon_state = "saw" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + hitsound = 'sound/weapons/circsawhit.ogg' + throwhitsound = 'sound/weapons/pierce.ogg' + flags_1 = CONDUCT_1 + force = 13 + w_class = WEIGHT_CLASS_NORMAL + throwforce = 6 + throw_speed = 1 + throw_range = 3 + materials = list(MAT_METAL=10000, MAT_GLASS=6000) + attack_verb = list("attacked", "slashed", "sawed", "cut") + toolspeed = 0.65 + sharpness = IS_SHARP + /obj/item/circular_saw/augment name = "circular saw" desc = "A small but very fast spinning saw. Edges dulled to prevent accidental cutting inside of the surgeon." diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 32eaf0cde9..05fdbadf87 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -506,6 +506,12 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/ammo_box/magazine/m12g/meteor include_modes = list(/datum/game_mode/nuclear) +/datum/uplink_item/ammo/shotgun/scatter + name = "12g Scatter Laser shot Slugs" + desc = "An alternative 8-round Scatter Laser Shot magazine for use in the Bulldog shotgun." + item = /obj/item/ammo_box/magazine/m12g/scatter + cost = 5 // most armor has less laser protection then bullet + /datum/uplink_item/ammo/shotgun/bag name = "12g Ammo Duffel Bag" desc = "A duffel bag filled with enough 12g ammo to supply an entire team, at a discounted price." @@ -982,6 +988,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/backpack/duffelbag/syndie/surgery cost = 3 +/datum/uplink_item/device_tools/surgerybag_adv + name = "Syndicate Surgery Duffel Bag" + desc = "The Syndicate surgery duffel bag is a toolkit containing all newest surgery tools, surgical drapes, \ + a Syndicate brand MMI, a straitjacket, a muzzle, and a full Syndicate Combat Medic Kit." + item = /obj/item/storage/backpack/duffelbag/syndie/surgery_adv + cost = 15 //Mite be to cheap + /datum/uplink_item/device_tools/military_belt name = "Chest Rig" desc = "A robust seven-slot set of webbing that is capable of holding all manner of tactical equipment." diff --git a/code/modules/vending/assist.dm b/code/modules/vending/assist.dm index de30109824..89c330789e 100644 --- a/code/modules/vending/assist.dm +++ b/code/modules/vending/assist.dm @@ -1,12 +1,19 @@ /obj/machinery/vending/assist - products = list(/obj/item/assembly/prox_sensor = 5, - /obj/item/assembly/igniter = 3, - /obj/item/assembly/signaler = 4, - /obj/item/wirecutters = 1, - /obj/item/cartridge/signal = 4) - contraband = list(/obj/item/assembly/timer = 2, - /obj/item/assembly/voice = 2, - /obj/item/assembly/health = 2) + products = list(/obj/item/assembly/prox_sensor = 7, + /obj/item/assembly/igniter = 6, + /obj/item/assembly/signaler = 6, + /obj/item/wirecutters = 3, + /obj/item/stock_parts/cell/crap = 6, + /obj/item/cartridge/signal = 6) + contraband = list(/obj/item/assembly/timer = 4, + /obj/item/assembly/voice = 4, + /obj/item/assembly/health = 4, + /obj/item/pressure_plate = 2, + /obj/item/multitool = 2, + /obj/item/stock_parts/cell/upgraded = 2) + premium = list(/obj/item/stock_parts/cell/upgraded/plus = 2, + /obj/item/flashlight/lantern = 2, + /obj/item/beacon = 2) product_ads = "Only the finest!;Have some tools.;The most robust equipment.;The finest gear in space!" armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) resistance_flags = FIRE_PROOF diff --git a/code/modules/vending/coffee.dm b/code/modules/vending/coffee.dm index 6ac9dd648d..c30c087d7b 100644 --- a/code/modules/vending/coffee.dm +++ b/code/modules/vending/coffee.dm @@ -8,6 +8,11 @@ /obj/item/reagent_containers/food/drinks/mug/tea = 25, /obj/item/reagent_containers/food/drinks/mug/coco = 25) contraband = list(/obj/item/reagent_containers/food/drinks/ice = 12) + premium = list(/obj/item/reagent_containers/food/snacks/chocolatebar = 3, + /obj/item/reagent_containers/food/condiment/milk = 2, + /obj/item/reagent_containers/food/drinks/bottle/cream = 2, + /obj/item/reagent_containers/food/condiment/sugar = 1) + refill_canister = /obj/item/vending_refill/coffee /obj/item/vending_refill/coffee diff --git a/code/modules/vending/engivend.dm b/code/modules/vending/engivend.dm index 0e64e0a367..9358d1652f 100644 --- a/code/modules/vending/engivend.dm +++ b/code/modules/vending/engivend.dm @@ -4,21 +4,28 @@ icon_state = "engivend" icon_deny = "engivend-deny" req_access = list(ACCESS_ENGINE_EQUIP) - products = list(/obj/item/clothing/glasses/meson/engine = 2, - /obj/item/clothing/glasses/welding = 3, - /obj/item/multitool = 4, + products = list(/obj/item/clothing/glasses/meson/engine = 5, + /obj/item/clothing/glasses/welding = 5, + /obj/item/multitool = 5, /obj/item/construction/rcd/loaded = 3, /obj/item/grenade/chem_grenade/smart_metal_foam = 10, - /obj/item/geiger_counter = 5, + /obj/item/geiger_counter = 6, /obj/item/stock_parts/cell/high = 10, - /obj/item/electronics/airlock = 10, + /obj/item/electronics/airlock = 10, /obj/item/electronics/apc = 10, /obj/item/electronics/airalarm = 10, /obj/item/electronics/firealarm = 10, - /obj/item/electronics/firelock = 10 + /obj/item/electronics/firelock = 10, + /obj/item/rcd_ammo = 3 ) - contraband = list(/obj/item/stock_parts/cell/potato = 3) + contraband = list(/obj/item/stock_parts/cell/potato = 3, + /obj/item/rcd_ammo = 2, + /obj/item/circuitboard/computer/slot_machine = 1, + /obj/item/tank/internals/emergency_oxygen/double = 3 + ) premium = list(/obj/item/storage/belt/utility = 3, - /obj/item/storage/box/smart_metal_foam = 1) + /obj/item/storage/box/smart_metal_foam = 3, + /obj/item/rcd_ammo/large = 5 + ) armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) resistance_flags = FIRE_PROOF diff --git a/code/modules/vending/medical_wall.dm b/code/modules/vending/medical_wall.dm index 84c4891589..018eb09d86 100644 --- a/code/modules/vending/medical_wall.dm +++ b/code/modules/vending/medical_wall.dm @@ -13,6 +13,7 @@ /obj/item/reagent_containers/medspray/sterilizine = 1) contraband = list(/obj/item/reagent_containers/pill/tox = 2, /obj/item/reagent_containers/pill/morphine = 2) + premium = list(/obj/item/reagent_containers/medspray/synthflesh = 2) armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) resistance_flags = FIRE_PROOF refill_canister = /obj/item/vending_refill/wallmed @@ -26,3 +27,4 @@ /obj/item/reagent_containers/pill/patch/styptic = 1, /obj/item/reagent_containers/pill/patch/silver_sulf = 1, /obj/item/reagent_containers/medspray/sterilizine = 1) + premium = list(/obj/item/reagent_containers/medspray/synthflesh = 2) diff --git a/code/modules/vending/snack.dm b/code/modules/vending/snack.dm index 69e510ad5a..19138bad32 100644 --- a/code/modules/vending/snack.dm +++ b/code/modules/vending/snack.dm @@ -12,6 +12,9 @@ /obj/item/reagent_containers/food/snacks/spacetwinkie = 6, /obj/item/reagent_containers/food/snacks/cheesiehonkers = 6) contraband = list(/obj/item/reagent_containers/food/snacks/syndicake = 6) + premium = list(/obj/item/storage/box/donkpockets = 1, + /obj/item/reagent_containers/food/snacks/poppypretzel = 3) + refill_canister = /obj/item/vending_refill/snack var/chef_compartment_access = "28" //ACCESS_KITCHEN diff --git a/code/modules/vending/youtool.dm b/code/modules/vending/youtool.dm index 495d60a461..ebaad4d715 100644 --- a/code/modules/vending/youtool.dm +++ b/code/modules/vending/youtool.dm @@ -3,19 +3,20 @@ desc = "Tools for tools." icon_state = "tool" icon_deny = "tool-deny" - products = list(/obj/item/stack/cable_coil/random = 10, - /obj/item/crowbar = 5, - /obj/item/weldingtool = 3, - /obj/item/wirecutters = 5, - /obj/item/wrench = 5, - /obj/item/analyzer = 5, - /obj/item/t_scanner = 5, - /obj/item/screwdriver = 5, - /obj/item/flashlight/glowstick = 3, - /obj/item/flashlight/glowstick/red = 3, - /obj/item/flashlight = 5) - contraband = list(/obj/item/weldingtool/hugetank = 2, - /obj/item/clothing/gloves/color/fyellow = 2) - premium = list(/obj/item/clothing/gloves/color/yellow = 1) + products = list(/obj/item/stack/cable_coil/random = 15, + /obj/item/crowbar = 10, + /obj/item/weldingtool = 6, + /obj/item/wirecutters = 10, + /obj/item/wrench = 10, + /obj/item/analyzer = 10, + /obj/item/t_scanner = 10, + /obj/item/screwdriver = 10, + /obj/item/flashlight/glowstick = 6, + /obj/item/flashlight/glowstick/red = 6, + /obj/item/flashlight = 7) + contraband = list(/obj/item/weldingtool/largetank = 4, + /obj/item/clothing/gloves/color/fyellow = 4) + premium = list(/obj/item/clothing/gloves/color/yellow = 2, + /obj/item/weldingtool/hugetank = 2) armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 70) resistance_flags = FIRE_PROOF diff --git a/config/config.txt b/config/config.txt index 33bff862d9..3bc9f873a9 100644 --- a/config/config.txt +++ b/config/config.txt @@ -16,6 +16,9 @@ $include antag_rep.txt ## Server name: This appears at the top of the screen in-game and in the BYOND hub. Uncomment and replace 'tgstation' with the name of your choice. # SERVERNAME tgstation +## Server tagline: This will appear right below the server's title. +# SERVERTAGLINE A generic TG-based server + ## Server SQL name: This is the name used to identify the server to the SQL DB, distinct from SERVERNAME as it must be at most 32 characters. # SERVERSQLNAME tgstation diff --git a/config/game_options.txt b/config/game_options.txt index bfc5ed5edb..6ff9182f0a 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -57,10 +57,12 @@ MULTIPLICATIVE_MOVESPEED /mob/living/simple_animal 1 ## ALERT LEVELS ### ALERT_GREEN All threats to the station have passed. Security may not have weapons visible, privacy laws are once again fully enforced. -ALERT_BLUE_UPTO The station has received reliable information about possible hostile activity on the station. Security staff may have weapons visible, random searches are permitted. -ALERT_BLUE_DOWNTO The immediate threat has passed. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still allowed. -ALERT_RED_UPTO There is an immediate serious threat to the station. Security may have weapons unholstered at all times. Random searches are allowed and advised. Additionally, access requirements on some doors have been lifted. -ALERT_RED_DOWNTO The station's destruction has been averted. There is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised. +ALERT_BLUE_UPTO The station has received reliable information about potential threats to the station. Security staff may have weapons visible, random searches are permitted. +ALERT_BLUE_DOWNTO Significant confirmed threats have been neutralized. Security may no longer have weapons drawn at all times, but may continue to have them visible. Random searches are still permitted. +ALERT_AMBER_UPTO There are signficant confirmed threats to the station. Security staff may have weapons unholstered at all times. Random searches are allowed and advised. +ALERT_AMBER_DOWNTO The immediate threat has passed. Security is no longer authorized to use lethal force, but may continue to have weapons drawn. Access requirements have been restored. +ALERT_RED_UPTO There is an immediate serious threat to the station. Security is now authorized to use lethal force. Additionally, access requirements on some machines have been lifted. +ALERT_RED_DOWNTO The station's destruction has been averted. There is still however an immediate serious threat to the station. Security is still authorized to use lethal force. ALERT_DELTA Destruction of the station is imminent. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill. diff --git a/html/changelogs/AutoChangeLog-pr-7860.yml b/html/changelogs/AutoChangeLog-pr-7860.yml new file mode 100644 index 0000000000..140f95aa40 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7860.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "The syndicate mask now works properly as intended." diff --git a/html/changelogs/AutoChangeLog-pr-7865.yml b/html/changelogs/AutoChangeLog-pr-7865.yml new file mode 100644 index 0000000000..a75282b293 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7865.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - balance: "Stamina is no longer affected by health at all." diff --git a/html/changelogs/AutoChangeLog-pr-7866.yml b/html/changelogs/AutoChangeLog-pr-7866.yml new file mode 100644 index 0000000000..17435075e0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7866.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "You can now right-click yourself in help intent in combat mode to instantly get up from resting. This will cost stamina equal to your entire stamina buffer. Manage your stamina well, and you'll be able to shrug off a single stray golden bolt" diff --git a/html/changelogs/AutoChangeLog-pr-7876.yml b/html/changelogs/AutoChangeLog-pr-7876.yml new file mode 100644 index 0000000000..649c0cc916 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7876.yml @@ -0,0 +1,4 @@ +author: "coiax" +delete-after: True +changes: + - admin: "When the nuclear disk stays stationary long enough to trigger an increase for the lone op event chance, admins will be notified every five increments." diff --git a/html/changelogs/AutoChangeLog-pr-7878.yml b/html/changelogs/AutoChangeLog-pr-7878.yml new file mode 100644 index 0000000000..6d10310d94 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7878.yml @@ -0,0 +1,4 @@ +author: "Tupinambis" +delete-after: True +changes: + - tweak: "Removed all living eggs from the xeno ruin because people self antag. Honk." diff --git a/html/changelogs/AutoChangeLog-pr-7908.yml b/html/changelogs/AutoChangeLog-pr-7908.yml new file mode 100644 index 0000000000..f6c1fda2ec --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7908.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "The new player panel now displays your currently selected character's name" diff --git a/html/changelogs/AutoChangeLog-pr-7911.yml b/html/changelogs/AutoChangeLog-pr-7911.yml new file mode 100644 index 0000000000..0d0d468aa8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7911.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - balance: "Flashes no longer knockdown. Instead, they deal eyeblur and have increased confusion" diff --git a/html/changelogs/AutoChangeLog-pr-7912.yml b/html/changelogs/AutoChangeLog-pr-7912.yml new file mode 100644 index 0000000000..834ad80091 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7912.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - server: "The server's tagline is now a config option. People can now stop confusing us with BR cit" diff --git a/html/changelogs/AutoChangeLog-pr-7914.yml b/html/changelogs/AutoChangeLog-pr-7914.yml new file mode 100644 index 0000000000..aac983d7ea --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7914.yml @@ -0,0 +1,4 @@ +author: "Ghom" +delete-after: True +changes: + - code_imp: "minor clean up on hydroponics reagent containers." diff --git a/html/changelogs/AutoChangeLog-pr-7916.yml b/html/changelogs/AutoChangeLog-pr-7916.yml new file mode 100644 index 0000000000..888f327f72 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7916.yml @@ -0,0 +1,4 @@ +author: "Skoglol" +delete-after: True +changes: + - rscadd: "You can now alt click storage (bags, boxes, etc) to open it." diff --git a/html/changelogs/AutoChangeLog-pr-7918.yml b/html/changelogs/AutoChangeLog-pr-7918.yml new file mode 100644 index 0000000000..b2340c2f67 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7918.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Attack animations will now rotate your character slightly, similar to Goon." diff --git a/html/changelogs/AutoChangeLog-pr-7919.yml b/html/changelogs/AutoChangeLog-pr-7919.yml new file mode 100644 index 0000000000..a62cc838c3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7919.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Throwing items will now perform the attack animation and play a sound" diff --git a/html/changelogs/AutoChangeLog-pr-7920.yml b/html/changelogs/AutoChangeLog-pr-7920.yml new file mode 100644 index 0000000000..08b0ec1f13 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7920.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "flashlights will now make sounds when toggled on/off" diff --git a/html/changelogs/AutoChangeLog-pr-7921.yml b/html/changelogs/AutoChangeLog-pr-7921.yml new file mode 100644 index 0000000000..66a245257f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7921.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Things in disposals will now emit sounds every single time they hit corners. This increases immersion." diff --git a/html/changelogs/AutoChangeLog-pr-7922.yml b/html/changelogs/AutoChangeLog-pr-7922.yml new file mode 100644 index 0000000000..08f06d7053 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7922.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - bugfix: "Air alarms now actually emit the proper light color when their status is okay." diff --git a/html/changelogs/AutoChangeLog-pr-7923.yml b/html/changelogs/AutoChangeLog-pr-7923.yml new file mode 100644 index 0000000000..5cf6527dad --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7923.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Backpacks and other storage items will now jiggle and squish when you interact with them, similar to the animations seen on Goon." diff --git a/html/changelogs/AutoChangeLog-pr-7930.yml b/html/changelogs/AutoChangeLog-pr-7930.yml new file mode 100644 index 0000000000..221a2af942 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7930.yml @@ -0,0 +1,4 @@ +author: "nicc" +delete-after: True +changes: + - balance: "teg less gay maybe" diff --git a/html/changelogs/AutoChangeLog-pr-7945.yml b/html/changelogs/AutoChangeLog-pr-7945.yml new file mode 100644 index 0000000000..edc2f96dc8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7945.yml @@ -0,0 +1,5 @@ +author: "Ghom" +delete-after: True +changes: + - bugfix: "fixes the perpetual lack of moisture that has affected genitalia descriptions since, like, forever." + - rscadd: "implements the arousal state for mammary glands." diff --git a/html/changelogs/AutoChangeLog-pr-7951.yml b/html/changelogs/AutoChangeLog-pr-7951.yml new file mode 100644 index 0000000000..e05a5a1911 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7951.yml @@ -0,0 +1,6 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixes many possible situations of null icons for cit races' bodyparts." + - imagedel: "Removes duplicate slimepeople' sprites." + - code_imp: "Purges that draw_citadel_parts()." diff --git a/html/changelogs/AutoChangeLog-pr-7954.yml b/html/changelogs/AutoChangeLog-pr-7954.yml new file mode 100644 index 0000000000..8a31b912ad --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7954.yml @@ -0,0 +1,6 @@ +author: "deathride58" +delete-after: True +changes: + - balance: "Mops no longer have a delay on their cleaning, making them an actually viable alternative to all of the janitor's other cleaning tools" + - balance: "To balance this, mops now take stamina to clean tiles. Standard mops take 5 stamina to use, while advanced mops take 2 stamina." + - tweak: "Oh and also mops make fancy new sounds and play animations when used now" diff --git a/html/changelogs/AutoChangeLog-pr-7964.yml b/html/changelogs/AutoChangeLog-pr-7964.yml new file mode 100644 index 0000000000..33cfaa453d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7964.yml @@ -0,0 +1,6 @@ +author: "CydiaButt13" +delete-after: True +changes: + - rscadd: "Lamp Plushie to loadout" + - imageadd: "added plushie_lamp to plush icons" + - code_imp: "added Lamp Plush to loadout and icons and items" diff --git a/html/changelogs/AutoChangeLog-pr-7973.yml b/html/changelogs/AutoChangeLog-pr-7973.yml new file mode 100644 index 0000000000..df9b9e2411 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7973.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - balance: "Pump-action shotguns now take 2 stamina per pump instead of 5 stamina per pump. This also applies to bolt-action rifles, as bolt racking counts as pumping." diff --git a/html/changelogs/AutoChangeLog-pr-7976.yml b/html/changelogs/AutoChangeLog-pr-7976.yml new file mode 100644 index 0000000000..4f334dc4ca --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7976.yml @@ -0,0 +1,7 @@ +author: "Tupinambis" +delete-after: True +changes: + - rscadd: "Adds a new security level between Blue and Red (Amber). The shuttle call time at this level is 8 minutes." + - tweak: "Blue security level now has a shuttle call time of 12 minutes." + - tweak: "The security level increase/decrease texts have been modified to accommodate the change." + - imageadd: "Adds a code Amber sprite for the fire alarms" diff --git a/html/changelogs/AutoChangeLog-pr-7977.yml b/html/changelogs/AutoChangeLog-pr-7977.yml new file mode 100644 index 0000000000..ca43ddbbf0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7977.yml @@ -0,0 +1,5 @@ +author: "Zargserg" +delete-after: True +changes: + - balance: "Lungs maximum toxin threshold is 0.5% of the atmosphere." + - bugfix: "Permanently contaminated atmosphere does not murder crew anymore." diff --git a/html/changelogs/AutoChangeLog-pr-7978.yml b/html/changelogs/AutoChangeLog-pr-7978.yml new file mode 100644 index 0000000000..b35ea975c3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7978.yml @@ -0,0 +1,4 @@ +author: "Poojawa" +delete-after: True +changes: + - rscadd: "Added the Yogs/Oracle ported latejoin menu" diff --git a/html/changelogs/AutoChangeLog-pr-7979.yml b/html/changelogs/AutoChangeLog-pr-7979.yml new file mode 100644 index 0000000000..ed06d73ac1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7979.yml @@ -0,0 +1,4 @@ +author: "Anonymous" +delete-after: True +changes: + - imageadd: "More crusader armor variants to pick from armament: Teutonic and Hospitaller." diff --git a/html/changelogs/AutoChangeLog-pr-7980.yml b/html/changelogs/AutoChangeLog-pr-7980.yml new file mode 100644 index 0000000000..a0b3b09fb5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7980.yml @@ -0,0 +1,4 @@ +author: "MediHound" +delete-after: True +changes: + - rscadd: "Made Cyborgs be affected by Ion Storm Law Changes like AIs" diff --git a/html/changelogs/AutoChangeLog-pr-7981.yml b/html/changelogs/AutoChangeLog-pr-7981.yml new file mode 100644 index 0000000000..e36dd711fa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7981.yml @@ -0,0 +1,5 @@ +author: "Tupinambis" +delete-after: True +changes: + - tweak: "Removed the plushes from the toy crate, giving them their own." + - tweak: "Plushes are now less likely to spawn out of arcades" diff --git a/html/changelogs/AutoChangeLog-pr-7982.yml b/html/changelogs/AutoChangeLog-pr-7982.yml new file mode 100644 index 0000000000..7255219c9e --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7982.yml @@ -0,0 +1,9 @@ +author: "Coolgat3 / Avunia" +delete-after: True +changes: + - rscadd: "Made kindle put the target into stamcrit, which makes it an actually working, useful stun." + - rscadd: "Added a stamina loss modifier to the vanguard spell which makes the user's stamina drain at a way slower rate. This doesn't make them immune to tasers, but it takes a few hits to actually get them to fall down." + - tweak: "Made it so that clock culties don't start with a chameleon suit. Instead they start with an engineer suit which is pretty much the same sprite and looks. If this is not perfect, then I am willing to make a slightly more brass-colored version of the engineer suit sprite and call it a ratvarian engineer jumpsuit." + - balance: "Increased the cost of vanguard, as it is now a spell that works somewhat like adrenals, minus the move speed, making your stamina drain really slow and making you unable to get knocked onto the ground by just a single taser shot." + - balance: "Lowered the charge time of kindle, reason being that you can usually have only one active spell on you, or two at max if you decide to run two slabs, but the fact that kindle silences people for such a small amount of time makes up for it, in my opinion." + - server: "Figured out that the consoles and their warp function actually work with the current code. The thing that makes them not work is when the gamemode is ran on debug mode, without the required players to actually support it. It also breaks the ark timer which is stuck on -1 seconds until activation. Whenever the gamemode starts properly, like any other gamemode, with player checks and all, everything seems to work just fine." diff --git a/html/changelogs/AutoChangeLog-pr-7983.yml b/html/changelogs/AutoChangeLog-pr-7983.yml new file mode 100644 index 0000000000..46e0a14f96 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7983.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - code_imp: "Fixes ISINRANGE_EX using the wrong relational operator." diff --git a/html/changelogs/AutoChangeLog-pr-7994.yml b/html/changelogs/AutoChangeLog-pr-7994.yml new file mode 100644 index 0000000000..703dcf31e1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7994.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - tweak: "Pickpocketing items will now place them in your hands if possible" diff --git a/html/changelogs/AutoChangeLog-pr-7995.yml b/html/changelogs/AutoChangeLog-pr-7995.yml new file mode 100644 index 0000000000..9d118ebbff --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7995.yml @@ -0,0 +1,5 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "Combat mode is now displayed in examine text" + - rscadd: "Combat mode now makes a visible message when enabled if you haven't touched your combat mode button in the last ten seconds. It's done this way to avoid chat spam from those who know how to pull off stam regen squeezing." diff --git a/html/changelogs/AutoChangeLog-pr-7996.yml b/html/changelogs/AutoChangeLog-pr-7996.yml new file mode 100644 index 0000000000..518feae251 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7996.yml @@ -0,0 +1,4 @@ +author: "deathride58" +delete-after: True +changes: + - balance: "All knockdown sources will now force people to be dismounted from ridden vehicles." diff --git a/html/changelogs/AutoChangeLog-pr-7997.yml b/html/changelogs/AutoChangeLog-pr-7997.yml new file mode 100644 index 0000000000..7b3db7fb44 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-7997.yml @@ -0,0 +1,9 @@ +author: "deathride58" +delete-after: True +changes: + - rscadd: "When an item is thrown, it will now be rotated and displaced." + - rscadd: "Shards of glass will now be rotated when spawned." + - rscadd: "Bullet casings will now be rotated when they're ejected from a gun." + - rscadd: "Bottles now have random rotations and pixel offsets when smashed via throwing." + - rscadd: "Picking up an item will now reset its rotation." + - rscadd: "Glasses thrown onto tables by bartenders will now have their rotation reset." diff --git a/icons/mob/custom_w.dmi b/icons/mob/custom_w.dmi index dc79247d48..1101f22d2e 100644 Binary files a/icons/mob/custom_w.dmi and b/icons/mob/custom_w.dmi differ diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 1d99a415df..03d6190507 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index f74ca2092d..904084adb5 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi index d336887e21..2ed1783941 100644 Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ diff --git a/icons/obj/2x2.dmi b/icons/obj/2x2.dmi index a72a86f3d8..c5b1df680a 100644 Binary files a/icons/obj/2x2.dmi and b/icons/obj/2x2.dmi differ diff --git a/icons/obj/chairs.dmi b/icons/obj/chairs.dmi index 96e4a4228e..3754ff052c 100644 Binary files a/icons/obj/chairs.dmi and b/icons/obj/chairs.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 73f3065b4f..34d8374a42 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index c3eb8b995c..51a5a4e358 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi index a64ba6468b..84155bfe43 100644 Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ diff --git a/icons/obj/custom.dmi b/icons/obj/custom.dmi index 197b870284..a05fbb72ab 100644 Binary files a/icons/obj/custom.dmi and b/icons/obj/custom.dmi differ diff --git a/icons/obj/doors/mineral_doors.dmi b/icons/obj/doors/mineral_doors.dmi index 7682252a6d..03fab197fe 100644 Binary files a/icons/obj/doors/mineral_doors.dmi and b/icons/obj/doors/mineral_doors.dmi differ diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi index e6e8ff9eb7..a32d0234d6 100644 Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ diff --git a/icons/obj/fluff.dmi b/icons/obj/fluff.dmi index b476d25228..72edaa0528 100644 Binary files a/icons/obj/fluff.dmi and b/icons/obj/fluff.dmi differ diff --git a/icons/obj/monitors.dmi b/icons/obj/monitors.dmi index f338ffcf3d..9880707010 100644 Binary files a/icons/obj/monitors.dmi and b/icons/obj/monitors.dmi differ diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi index 0bf89ab744..08b6faba9b 100644 Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index 518adfc766..2a56a03e66 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/modular_citadel/code/datums/components/phantomthief.dm b/modular_citadel/code/datums/components/phantomthief.dm index c09d17d930..d34e16f6e9 100644 --- a/modular_citadel/code/datums/components/phantomthief.dm +++ b/modular_citadel/code/datums/components/phantomthief.dm @@ -39,7 +39,7 @@ if(!istype(user)) return if(!combattoggle_redir) - combattoggle_redir = user.AddComponent(/datum/component/redirect,list(COMSIG_COMBAT_TOGGLED),CALLBACK(src,.proc/handlefilterstuff)) + combattoggle_redir = user.AddComponent(/datum/component/redirect, list(COMSIG_COMBAT_TOGGLED = CALLBACK(src, .proc/handlefilterstuff))) /datum/component/phantomthief/proc/OnDropped(mob/user) if(!istype(user)) diff --git a/modular_citadel/code/datums/components/souldeath.dm b/modular_citadel/code/datums/components/souldeath.dm new file mode 100644 index 0000000000..5beddf3529 --- /dev/null +++ b/modular_citadel/code/datums/components/souldeath.dm @@ -0,0 +1,35 @@ +/datum/component/souldeath + var/mob/living/wearer + var/equip_slot + var/signal = FALSE + +/datum/component/souldeath/Initialize() + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/equip) + RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/unequip) + +/datum/component/souldeath/proc/equip(datum/source, mob/living/equipper, slot) + if(!slot || equip_slot == slot) + wearer = equipper + RegisterSignal(wearer, COMSIG_MOB_DEATH, .proc/die, TRUE) + signal = TRUE + else + if(signal) + UnregisterSignal(wearer, COMSIG_MOB_DEATH) + signal = FALSE + return + +/datum/component/souldeath/proc/unequip() + UnregisterSignal(wearer, COMSIG_MOB_DEATH) + wearer = null + signal = FALSE + +/datum/component/souldeath/proc/die() + if(!wearer) + return //idfk + new/obj/effect/temp_visual/souldeath(wearer.loc, wearer) + playsound(wearer, 'modular_citadel/sound/misc/souldeath.ogg', 100, FALSE) + +/datum/component/souldeath/neck + equip_slot = SLOT_NECK diff --git a/modular_citadel/code/datums/status_effects/debuffs.dm b/modular_citadel/code/datums/status_effects/debuffs.dm index a57902d0cf..6dcfc84a87 100644 --- a/modular_citadel/code/datums/status_effects/debuffs.dm +++ b/modular_citadel/code/datums/status_effects/debuffs.dm @@ -1,5 +1,8 @@ /datum/status_effect/incapacitating/knockdown/on_creation(mob/living/new_owner, set_duration, updating_canmove, override_duration, override_stam) if(iscarbon(new_owner) && (isnum(set_duration) || isnum(override_duration))) + if(istype(new_owner.buckled, /obj/vehicle/ridden)) + var/obj/buckl = new_owner.buckled + buckl.unbuckle_mob(new_owner) new_owner.resting = TRUE new_owner.adjustStaminaLoss(isnull(override_stam)? set_duration*0.25 : override_stam) if(isnull(override_duration) && (set_duration > 80)) diff --git a/modular_citadel/code/game/objects/effects/temporary_visuals/souldeath.dm b/modular_citadel/code/game/objects/effects/temporary_visuals/souldeath.dm new file mode 100644 index 0000000000..1ebf6fb2a6 --- /dev/null +++ b/modular_citadel/code/game/objects/effects/temporary_visuals/souldeath.dm @@ -0,0 +1,5 @@ +/obj/effect/temp_visual/souldeath + name = "soul death" + icon = 'modular_citadel/icons/effects/souldeath.dmi' + icon_state = "souldeath" + duration = 30 \ No newline at end of file diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 7ef696ee91..63ed811666 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -90,6 +90,24 @@ /mob/living/proc/updatearousal() update_arousal_hud() +/mob/living/carbon/updatearousal() + . = ..() + for(var/obj/item/organ/genital/G in internal_organs) + if(istype(G)) + var/datum/sprite_accessory/S + switch(G.type) + if(/obj/item/organ/genital/penis) + S = GLOB.cock_shapes_list[G.shape] + if(/obj/item/organ/genital/vagina) + S = GLOB.vagina_shapes_list[G.shape] + if(/obj/item/organ/genital/breasts) + S = GLOB.breasts_shapes_list[G.shape] + if(S?.alt_aroused) + G.aroused_state = isPercentAroused(G.aroused_amount) + else + G.aroused_state = FALSE + G.update_appearance() + /mob/living/proc/update_arousal_hud() return 0 @@ -175,6 +193,7 @@ "You have relieved yourself.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) setArousalLoss(min_arousal) + adjustStaminaLoss(40) //Refractory periods /* switch(gender) if(MALE) @@ -215,6 +234,7 @@ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) + adjustStaminaLoss(40) //Refractory periods /mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes @@ -252,6 +272,7 @@ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) + adjustStaminaLoss(40) //Refractory periods /mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, mb_time = 30) //Used for climaxing with any living thing @@ -284,6 +305,7 @@ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) + adjustStaminaLoss(40) //Refractory periods else //knots and other non-spilling orgasms if(do_after(src, mb_time, target = src) && in_range(src, L)) fluid_source.trans_to(L, total_fluids) @@ -295,6 +317,7 @@ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) + adjustStaminaLoss(40) //Refractory periods /mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/G, obj/item/reagent_containers/container, mb_time = 30) //For beaker-filling, beware the bartender @@ -325,6 +348,7 @@ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(G.can_climax) setArousalLoss(min_arousal) + adjustStaminaLoss(40) //Refractory periods /mob/living/carbon/human/proc/pick_masturbate_genitals() var/obj/item/organ/genital/ret_organ diff --git a/modular_citadel/code/modules/arousal/organs/genitals.dm b/modular_citadel/code/modules/arousal/organs/genitals.dm index b43f17e58a..c10d444f07 100644 --- a/modular_citadel/code/modules/arousal/organs/genitals.dm +++ b/modular_citadel/code/modules/arousal/organs/genitals.dm @@ -311,10 +311,6 @@ if(!S || S.icon_state == "none") continue var/mutable_appearance/genital_overlay = mutable_appearance(S.icon, layer = -layer) - if(S.alt_aroused) - G.aroused_state = H.isPercentAroused(G.aroused_amount) - else - G.aroused_state = FALSE genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size]_[G.aroused_state]_[layertext]" if(S.center) diff --git a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm index 7c02b1c3a5..bcfa462789 100644 --- a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm +++ b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm @@ -100,6 +100,7 @@ /datum/sprite_accessory/breasts/pair icon_state = "pair" name = "Pair" + alt_aroused = TRUE //OVIPOSITORS BE HERE diff --git a/modular_citadel/code/modules/arousal/toys/dildos.dm b/modular_citadel/code/modules/arousal/toys/dildos.dm index 587702762c..4b0a7ad919 100644 --- a/modular_citadel/code/modules/arousal/toys/dildos.dm +++ b/modular_citadel/code/modules/arousal/toys/dildos.dm @@ -1,7 +1,7 @@ ////////// //DILDOS// ////////// -obj/item/dildo +/obj/item/dildo name = "dildo" desc = "Floppy!" icon = 'modular_citadel/icons/obj/genitals/dildo.dmi' @@ -18,9 +18,10 @@ obj/item/dildo var/random_color = TRUE var/random_size = FALSE var/random_shape = FALSE + var/is_knotted = FALSE //Lists moved to _cit_helpers.dm as globals so they're not instanced individually -obj/item/dildo/proc/update_appearance() +/obj/item/dildo/proc/update_appearance() icon_state = "[dildo_type]_[dildo_shape]_[dildo_size]" var/sizeword = "" switch(dildo_size) @@ -35,7 +36,7 @@ obj/item/dildo/proc/update_appearance() name = "[sizeword][dildo_shape] [can_customize ? "custom " : ""][dildo_type]" -obj/item/dildo/AltClick(mob/living/user) +/obj/item/dildo/AltClick(mob/living/user) if(QDELETED(src)) return if(!isliving(user)) @@ -46,7 +47,7 @@ obj/item/dildo/AltClick(mob/living/user) return customize(user) -obj/item/dildo/proc/customize(mob/living/user) +/obj/item/dildo/proc/customize(mob/living/user) if(!can_customize) return FALSE if(src && !user.incapacitated() && in_range(user,src)) @@ -75,7 +76,7 @@ obj/item/dildo/proc/customize(mob/living/user) update_appearance() return TRUE -obj/item/dildo/Initialize() +/obj/item/dildo/Initialize() . = ..() if(random_color == TRUE) var/randcolor = pick(GLOB.dildo_colors) @@ -91,38 +92,41 @@ obj/item/dildo/Initialize() pixel_y = rand(-7,7) pixel_x = rand(-7,7) -obj/item/dildo/examine(mob/user) +/obj/item/dildo/examine(mob/user) ..() if(can_customize) user << "Alt-Click \the [src.name] to customize it." -obj/item/dildo/random//totally random +/obj/item/dildo/random//totally random name = "random dildo"//this name will show up in vendors and shit so you know what you're vending(or don't, i guess :^)) random_color = TRUE random_shape = TRUE random_size = TRUE - -obj/item/dildo/knotted +/obj/item/dildo/knotted dildo_shape = "knotted" name = "knotted dildo" + attack_verb = list("penetrated", "knotted", "slapped", "inseminated") obj/item/dildo/human dildo_shape = "human" name = "human dildo" + attack_verb = list("penetrated", "slapped", "inseminated") obj/item/dildo/plain dildo_shape = "plain" name = "plain dildo" + attack_verb = list("penetrated", "slapped", "inseminated") obj/item/dildo/flared dildo_shape = "flared" name = "flared dildo" + attack_verb = list("penetrated", "slapped", "neighed", "gaped", "prolapsed", "inseminated") obj/item/dildo/flared/huge - name = "literal horse cock" - desc = "THIS THING IS HUGE!" - dildo_size = 4 + name = "literal horse cock" + desc = "THIS THING IS HUGE!" + dildo_size = 4 obj/item/dildo/custom name = "customizable dildo" @@ -131,3 +135,30 @@ obj/item/dildo/custom random_color = TRUE random_shape = TRUE random_size = TRUE + +// Suicide acts, by request + +/obj/item/dildo/proc/manual_suicide(mob/living/user) + user.visible_message("[user] finally finishes deepthroating the [src], and their life.") + user.adjustOxyLoss(200) + user.death(0) + +/obj/item/dildo/suicide_act(mob/living/user) +// is_knotted = ((src.dildo_shape == "knotted")?"They swallowed the knot":"Their face is turning blue") + if(do_after(user,17,target=src)) + user.visible_message("[user] tears-up and gags as they shove [src] down their throat! It looks like [user.p_theyre()] trying to commit suicide!") + playsound(loc, 'sound/weapons/gagging.ogg', 50, 1, -1) + user.Stun(150) + user.adjust_blurriness(8) + user.adjust_eye_damage(10) + return MANUAL_SUICIDE + +/obj/item/dildo/flared/huge/suicide_act(mob/living/user) + if(do_after(user,35,target=src)) + user.visible_message("[user] tears-up and gags as they try to deepthroat the [src]! WHY WOULD THEY DO THAT? It looks like [user.p_theyre()] trying to commit suicide!!") + playsound(loc, 'sound/weapons/gagging.ogg', 50, 2, -1) + user.Stun(300) + user.adjust_blurriness(8) + user.adjust_eye_damage(15) + return MANUAL_SUICIDE + diff --git a/modular_citadel/code/modules/cargo/packs.dm b/modular_citadel/code/modules/cargo/packs.dm index c03a049b60..6d39a51a76 100644 --- a/modular_citadel/code/modules/cargo/packs.dm +++ b/modular_citadel/code/modules/cargo/packs.dm @@ -23,6 +23,6 @@ /datum/supply_pack/misc/jukebox name = "Jukebox" - cost = 1000000 + cost = 35000 contains = list(/obj/machinery/jukebox) crate_name = "Jukebox" diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm index eda53c0afe..66245fbb8a 100644 --- a/modular_citadel/code/modules/client/loadout/__donator.dm +++ b/modular_citadel/code/modules/client/loadout/__donator.dm @@ -344,3 +344,27 @@ datum/gear/darksabresheath category = SLOT_WEAR_SUIT path = /obj/item/clothing/suit/hooded/ian_costume ckeywhitelist = list("cathodetherobot") + +/datum/gear/sharkcloth + name = "Leon's Skimpy Outfit" + category = SLOT_WEAR_SUIT + path = /obj/item/clothing/under/leoskimpy + ckeywhitelist = list("spectrosis") + +/datum/gear/mimemask + name = "Mime Mask" + category = SLOT_WEAR_MASK + path = /obj/item/clothing/mask/gas/mime + ckeywhitelist = list("pireamaineach") + +/datum/gear/mimeoveralls + name = "Mime's Overalls" + category = SLOT_WEAR_SUIT + path = /obj/item/clothing/under/mimeoveralls + ckeywhitelist = list("pireamaineach") + +/datum/gear/soulneck + name = "Soul Necklace" + category = SLOT_NECK + path = /obj/item/clothing/neck/undertale + ckeywhitelist = list("twilightic") \ No newline at end of file diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm index b3a59425a9..9f12dd8b03 100644 --- a/modular_citadel/code/modules/client/loadout/backpack.dm +++ b/modular_citadel/code/modules/client/loadout/backpack.dm @@ -18,6 +18,11 @@ category = SLOT_IN_BACKPACK path = /obj/item/toy/plush/slimeplushie +/datum/gear/plushlamp + name = "Lamp plushie" + category = SLOT_IN_BACKPACK + path = /obj/item/toy/plush/lampplushie + /datum/gear/tennis name = "Classic Tennis Ball" category = SLOT_IN_BACKPACK @@ -56,4 +61,14 @@ /datum/gear/dildo name = "Customizable dildo" category = SLOT_IN_BACKPACK - path = /obj/item/dildo/custom \ No newline at end of file + path = /obj/item/dildo/custom + +/datum/gear/paperbin + name = "Paper Bin" + category = SLOT_IN_BACKPACK + path = /obj/item/paper_bin + +/datum/gear/crayons + name = "Box of crayons" + category = SLOT_IN_BACKPACK + path = /obj/item/storage/crayons diff --git a/modular_citadel/code/modules/client/loadout/suit.dm b/modular_citadel/code/modules/client/loadout/suit.dm index 773366c81e..9d3a6b9a02 100644 --- a/modular_citadel/code/modules/client/loadout/suit.dm +++ b/modular_citadel/code/modules/client/loadout/suit.dm @@ -18,42 +18,6 @@ category = SLOT_WEAR_SUIT path = /obj/item/clothing/suit/hooded/cloak/david cost = 3 - -/datum/gear/creamsweater - name = "Cream Commando Sweater" - category = SLOT_WEAR_SUIT - path = /obj/item/clothing/under/bb_sweater - cost = 1 - -/datum/gear/blacksweater - name = "Black Commando Sweater" - category = SLOT_WEAR_SUIT - path = /obj/item/clothing/under/bb_sweater/black - cost = 1 - -/datum/gear/purpsweater - name = "Purple Commando Sweater" - category = SLOT_WEAR_SUIT - path = /obj/item/clothing/under/bb_sweater/purple - cost = 1 - -/datum/gear/greensweater - name = "Green Commando Sweater" - category = SLOT_WEAR_SUIT - path = /obj/item/clothing/under/bb_sweater/green - cost = 1 - -/datum/gear/redsweater - name = "Red Commando Sweater" - category = SLOT_WEAR_SUIT - path = /obj/item/clothing/under/bb_sweater/red - cost = 1 - -/datum/gear/bluesweater - name = "Navy Commando Sweater" - category = SLOT_WEAR_SUIT - path = /obj/item/clothing/under/bb_sweater/blue - cost = 1 /datum/gear/jacketbomber name = "Bomber jacket" diff --git a/modular_citadel/code/modules/client/loadout/uniform.dm b/modular_citadel/code/modules/client/loadout/uniform.dm index 7c592c60e1..e4e2f063d3 100644 --- a/modular_citadel/code/modules/client/loadout/uniform.dm +++ b/modular_citadel/code/modules/client/loadout/uniform.dm @@ -118,11 +118,43 @@ category = SLOT_W_UNIFORM path = /obj/item/clothing/under/pants/track +// Pantsless Sweaters + /datum/gear/turtleneck name = "Tactitool Turtleneck" category = SLOT_W_UNIFORM path = /obj/item/clothing/under/syndicate/cosmetic +/datum/gear/creamsweater + name = "Cream Commando Sweater" + category = SLOT_W_UNIFORM + path = /obj/item/clothing/under/bb_sweater + +/datum/gear/blacksweater + name = "Black Commando Sweater" + category = SLOT_W_UNIFORM + path = /obj/item/clothing/under/bb_sweater/black + +/datum/gear/purpsweater + name = "Purple Commando Sweater" + category = SLOT_W_UNIFORM + path = /obj/item/clothing/under/bb_sweater/purple + +/datum/gear/greensweater + name = "Green Commando Sweater" + category = SLOT_W_UNIFORM + path = /obj/item/clothing/under/bb_sweater/green + +/datum/gear/redsweater + name = "Red Commando Sweater" + category = SLOT_W_UNIFORM + path = /obj/item/clothing/under/bb_sweater/red + +/datum/gear/bluesweater + name = "Navy Commando Sweater" + category = SLOT_W_UNIFORM + path = /obj/item/clothing/under/bb_sweater/blue + /datum/gear/polykilt name = "Polychromic Kilt" category = SLOT_W_UNIFORM diff --git a/modular_citadel/code/modules/client/verbs/who.dm b/modular_citadel/code/modules/client/verbs/who.dm index 091dd7bf79..7640595e18 100644 --- a/modular_citadel/code/modules/client/verbs/who.dm +++ b/modular_citadel/code/modules/client/verbs/who.dm @@ -28,28 +28,37 @@ var/msg = "" var/list/Lines = list() + var/list/assembled = list() + var/admin_mode = check_rights_for(src, R_ADMIN) && isobserver(mob) + if(admin_mode) + log_admin("[key_name(usr)] checked advanced who in-round") if(length(GLOB.admins)) Lines += "Admins:" for(var/X in GLOB.admins) var/client/C = X if(C && C.holder && !C.holder.fakekey) - Lines += "\t [C.key][show_admin_info(C)] ([round(C.avgping, 1)]ms)" + assembled += "\t [C.key][admin_mode? "[show_admin_info(C)]":""] ([round(C.avgping, 1)]ms)" + Lines += sortList(assembled) + assembled.len = 0 if(length(GLOB.mentors)) Lines += "Mentors:" for(var/X in GLOB.mentors) var/client/C = X - if(C) - Lines += "\t [C.key][show_admin_info(C)] ([round(C.avgping, 1)]ms)" - + if(C && (!C.holder || (C.holder && !C.holder.fakekey))) //>using stuff this complex instead of just using if/else lmao + assembled += "\t [C.key][admin_mode? "[show_admin_info(C)]":""] ([round(C.avgping, 1)]ms)" + Lines += sortList(assembled) + assembled.len = 0 Lines += "Players:" for(var/X in sortList(GLOB.clients)) var/client/C = X - if(!C) continue + if(!C) + continue var/key = C.key if(C.holder && C.holder.fakekey) key = C.holder.fakekey - Lines += "\t [key][show_admin_info(C)] ([round(C.avgping, 1)]ms)" - + assembled += "\t [key][admin_mode? "[show_admin_info(C)]":""] ([round(C.avgping, 1)]ms)" + Lines += sortList(assembled) + for(var/line in Lines) msg += "[line]\n" @@ -60,9 +69,6 @@ if(!C) return "" - if(!check_rights_for(src, R_ADMIN)) - return "" - var/entry = "" if(C.holder && C.holder.fakekey) entry += " (as [C.holder.fakekey])" diff --git a/modular_citadel/code/modules/clothing/glasses/phantomthief.dm b/modular_citadel/code/modules/clothing/glasses/phantomthief.dm index e9d31f73d3..49eb089afa 100644 --- a/modular_citadel/code/modules/clothing/glasses/phantomthief.dm +++ b/modular_citadel/code/modules/clothing/glasses/phantomthief.dm @@ -36,7 +36,7 @@ if(!istype(user)) return if(!combattoggle_redir) - combattoggle_redir = user.AddComponent(/datum/component/redirect,list(COMSIG_COMBAT_TOGGLED),CALLBACK(src,.proc/injectadrenaline)) + combattoggle_redir = user.AddComponent(/datum/component/redirect, list(COMSIG_COMBAT_TOGGLED = CALLBACK(src, .proc/injectadrenaline))) /obj/item/clothing/glasses/phantomthief/syndicate/dropped(mob/user) . = ..() diff --git a/modular_citadel/code/modules/clothing/neck.dm b/modular_citadel/code/modules/clothing/neck.dm new file mode 100644 index 0000000000..8d7d4747b7 --- /dev/null +++ b/modular_citadel/code/modules/clothing/neck.dm @@ -0,0 +1,23 @@ +/datum/action/item_action/zanderlocket + name = "Activate the locket" + +/obj/item/clothing/neck/undertale + name = "Sylphaen Heart Locket" + desc = "A heart shaped locket...The name: 'Zander Sylphaen is inscribed on the front. Something about this necklace fills you with determination." + icon = 'modular_citadel/icons/obj/clothing/cit_neck.dmi' + item_state = "undertale" + icon_state = "undertale" + alternate_worn_icon = 'modular_citadel/icons/mob/clothing/necks.dmi' + resistance_flags = FIRE_PROOF + actions_types = list(/datum/action/item_action/zanderlocket) + var/toggled = FALSE + var/obj/effect/heart/heart + +/datum/action/item_action/zanderlocket/Trigger() + new/obj/effect/temp_visual/souldeath(owner.loc, owner) + playsound(owner, 'modular_citadel/sound/misc/souldeath.ogg', 100, FALSE) + + +/obj/item/clothing/neck/undertale/Initialize() + ..() + AddComponent(/datum/component/souldeath/neck) diff --git a/modular_citadel/code/modules/clothing/under/trek_under.dm b/modular_citadel/code/modules/clothing/under/trek_under.dm index 00f84b7583..ddcf0e6344 100644 --- a/modular_citadel/code/modules/clothing/under/trek_under.dm +++ b/modular_citadel/code/modules/clothing/under/trek_under.dm @@ -11,7 +11,7 @@ /obj/item/clothing/under/rank/trek name = "Section 31 Uniform" desc = "Oooh... right." - icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi' + icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi' item_state = "" can_adjust = FALSE //to prevent you from "wearing it casually" @@ -91,11 +91,12 @@ /obj/item/clothing/suit/storage/trek/ds9 name = "Padded Overcoat" desc = "The overcoat worn by all officers of the 2380s." - icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi' + icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi' icon_state = "trek_ds9_coat" alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi' item_state = "trek_ds9_coat" body_parts_covered = CHEST|GROIN|ARMS + mutantrace_variation = NO_MUTANTRACE_VARIATION permeability_coefficient = 0.50 allowed = list( /obj/item/flashlight, /obj/item/analyzer, @@ -136,10 +137,11 @@ name = "Federation Uniform Jacket (Red)" desc = "A uniform jacket from the United Federation. Starfleet still uses this uniform and there are variations of it. Set phasers to awesome." - icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi' + icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi' icon_state = "fedcoat" item_state = "fedcoat" + mutantrace_variation = NO_MUTANTRACE_VARIATION blood_overlay_type = "coat" body_parts_covered = CHEST|GROIN|ARMS @@ -204,7 +206,7 @@ /obj/item/clothing/suit/storage/fluff/modernfedcoat name = "Modern Federation Uniform Jacket" desc = "A modern uniform jacket from the United Federation. Their Starfleet had recently started using these uniforms. Wearing this makes you feel like a competant commander." - icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi' + icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi' alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi' icon_state = "fedmodern" item_state = "fedmodern" @@ -237,20 +239,20 @@ /obj/item/clothing/head/caphat/formal/fedcover name = "Federation Officer's Cap" desc = "An officer's cap that demands discipline from the one who wears it." - icon = 'modular_citadel/icons/mob/clothing/trek_item_icon.dmi' + icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi' icon_state = "fedcapofficer" alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi' - item_state = "fedcapofficer_mob" + item_state = "fedcapofficer" //Variants /obj/item/clothing/head/caphat/formal/fedcover/medsci icon_state = "fedcapsci" - item_state = "fedcapsci_mob" + item_state = "fedcapsci" /obj/item/clothing/head/caphat/formal/fedcover/eng icon_state = "fedcapeng" - item_state = "fedcapeng_mob" + item_state = "fedcapeng" /obj/item/clothing/head/caphat/formal/fedcover/sec icon_state = "fedcapsec" - item_state = "fedcapsec_mob" + item_state = "fedcapsec" diff --git a/modular_citadel/code/modules/custom_loadout/custom_items.dm b/modular_citadel/code/modules/custom_loadout/custom_items.dm index 8e26f8014f..5f0d8cfc00 100644 --- a/modular_citadel/code/modules/custom_loadout/custom_items.dm +++ b/modular_citadel/code/modules/custom_loadout/custom_items.dm @@ -420,3 +420,22 @@ item_state = "Divine_robes" icon_state = "Divine_robes" mutantrace_variation = NO_MUTANTRACE_VARIATION + +/obj/item/clothing/under/leoskimpy + name = "Leon's Skimpy Outfit" + icon = 'icons/obj/custom.dmi' + alternate_worn_icon = 'icons/mob/custom_w.dmi' + desc = "A rather skimpy outfit." + item_state = "shark_cloth" + icon_state = "shark_cloth" + mutantrace_variation = NO_MUTANTRACE_VARIATION + +/obj/item/clothing/under/mimeoveralls + name = "Mime's Overalls" + icon = 'icons/obj/custom.dmi' + alternate_worn_icon = 'icons/mob/custom_w.dmi' + desc = "A less-than-traditional mime's attire, completed by a set of dorky-looking overalls." + item_state = "moveralls" + icon_state = "moveralls" + mutantrace_variation = NO_MUTANTRACE_VARIATION + diff --git a/modular_citadel/code/modules/mob/cit_emotes.dm b/modular_citadel/code/modules/mob/cit_emotes.dm index c76b8f2c12..34c44be23f 100644 --- a/modular_citadel/code/modules/mob/cit_emotes.dm +++ b/modular_citadel/code/modules/mob/cit_emotes.dm @@ -194,4 +194,19 @@ user.apply_damage(20, BRUTE, def_zone) if(luck >= 95) user.adjustBrainLoss(100) - . = ..() \ No newline at end of file + . = ..() + + +/datum/emote/living/mothsqueak + key = "msqueak" + key_third_person = "lets out a tiny squeak" + message = "lets out a tiny squeak!" + emote_type = EMOTE_AUDIBLE + mob_type_allowed_typecache = list(/mob/living/carbon) + +/datum/emote/living/mothsqueak/run_emote(mob/living/user, params) + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'modular_citadel/sound/voice/mothsqueak.ogg', 50, 1, -1) + . = ..() diff --git a/modular_citadel/code/modules/mob/living/carbon/carbon.dm b/modular_citadel/code/modules/mob/living/carbon/carbon.dm index cf5ce03bc7..8d6b4576c9 100644 --- a/modular_citadel/code/modules/mob/living/carbon/carbon.dm +++ b/modular_citadel/code/modules/mob/living/carbon/carbon.dm @@ -3,6 +3,7 @@ var/lastmousedir var/wrongdirmovedelay var/lastdirchange + var/combatmessagecooldown /mob/living/carbon/CanPass(atom/movable/mover, turf/target) . = ..() @@ -27,6 +28,9 @@ if(hud_used && hud_used.static_inventory) for(var/obj/screen/combattoggle/selector in hud_used.static_inventory) selector.rebasetointerbay(src) + if(world.time >= combatmessagecooldown && combatmode) + visible_message("[src] [resting ? "tenses up" : "drops into a combative stance"].") + combatmessagecooldown = 10 SECONDS + world.time //This is set 100% of the time to make sure squeezing regen out of process cycles doesn't result in the combat mode message getting spammed SEND_SIGNAL(src, COMSIG_COMBAT_TOGGLED, src, combatmode) return TRUE diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species.dm b/modular_citadel/code/modules/mob/living/carbon/human/species.dm index 8d50bf16b0..1dd6276140 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/species.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/species.dm @@ -1,3 +1,6 @@ +/datum/species + var/should_draw_citadel = FALSE + /datum/species/proc/alt_spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style) if(!istype(M)) return TRUE @@ -13,11 +16,30 @@ H.visible_message("[M] attempted to touch [H]!") return TRUE switch(M.a_intent) - if("disarm") + if(INTENT_HELP) + if(M == H) + althelp(M, H, attacker_style) + return TRUE + return FALSE + if(INTENT_DISARM) altdisarm(M, H, attacker_style) return TRUE return FALSE +/datum/species/proc/althelp(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) + if(user == target && istype(user)) + if(user.getStaminaLoss() >= STAMINA_SOFTCRIT) + to_chat(user, "You're too exhausted for that.") + return + if(!user.resting) + to_chat(user, "You can only force yourself up if you're on the ground.") + return + user.visible_message("[user] forces [p_them()]self up to [p_their()] feet!", "You force yourself up to your feet!") + user.resting = 0 + user.update_canmove() + user.adjustStaminaLossBuffered(user.stambuffer) //Rewards good stamina management by making it easier to instantly get up from resting + playsound(user, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + /datum/species/proc/altdisarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(user.getStaminaLoss() >= STAMINA_SOFTCRIT) to_chat(user, "You're too exhausted.") @@ -59,17 +81,8 @@ //////////////////// -/obj/item/bodypart/var/should_draw_citadel = FALSE - -/mob/living/carbon/proc/draw_citadel_parts(undo = FALSE) - if(!undo) - for(var/O in bodyparts) - var/obj/item/bodypart/B = O - B.should_draw_citadel = TRUE - else - for(var/O in bodyparts) - var/obj/item/bodypart/B = O - B.should_draw_citadel = FALSE +/obj/item/bodypart + var/should_draw_citadel = FALSE /datum/species/proc/citadel_mutant_bodyparts(bodypart, mob/living/carbon/human/H) switch(bodypart) diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm index d7124d949c..16c5460174 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/furrypeople.dm @@ -2,6 +2,7 @@ name = "Mammal" id = "mammal" default_color = "4B4B4B" + should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) mutant_bodyparts = list("mam_tail", "mam_ears", "mam_body_markings", "snout", "taur", "legs") @@ -45,20 +46,13 @@ /datum/species/mammal/qualifies_for_rank(rank, list/features) return TRUE -/datum/species/mammal/on_species_gain(mob/living/carbon/human/C) - C.draw_citadel_parts() - . = ..() - -/datum/species/mammal/on_species_loss(mob/living/carbon/human/C) - C.draw_citadel_parts(TRUE) - . = ..() - //AVIAN// /datum/species/avian name = "Avian" id = "avian" say_mod = "chirps" default_color = "BCAC9B" + should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) mutant_bodyparts = list("snout", "wings", "taur", "mam_tail", "mam_body_markings", "taur") @@ -99,19 +93,12 @@ /datum/species/avian/qualifies_for_rank(rank, list/features) return TRUE -/datum/species/avian/on_species_gain(mob/living/carbon/human/C) - C.draw_citadel_parts() - . = ..() - -/datum/species/avian/on_species_loss(mob/living/carbon/human/C) - C.draw_citadel_parts(TRUE) - . = ..() - //AQUATIC// /datum/species/aquatic name = "Aquatic" id = "aquatic" default_color = "BCAC9B" + should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) mutant_bodyparts = list("mam_tail", "mam_body_markings", "mam_ears", "taur", "legs") @@ -153,19 +140,12 @@ /datum/species/aquatic/qualifies_for_rank(rank, list/features) return TRUE -/datum/species/aquatic/on_species_gain(mob/living/carbon/human/C) - C.draw_citadel_parts() - . = ..() - -/datum/species/aquatic/on_species_loss(mob/living/carbon/human/C) - C.draw_citadel_parts(TRUE) - . = ..() - //INSECT// /datum/species/insect name = "Insect" id = "insect" default_color = "BCAC9B" + should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,HAIR) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG) mutant_bodyparts = list("mam_body_markings", "mam_ears", "mam_tail", "taur", "moth_wings") @@ -206,14 +186,6 @@ /datum/species/insect/qualifies_for_rank(rank, list/features) return TRUE -/datum/species/insect/on_species_gain(mob/living/carbon/human/C) - C.draw_citadel_parts() - . = ..() - -/datum/species/insect/on_species_loss(mob/living/carbon/human/C) - C.draw_citadel_parts(TRUE) - . = ..() - //Alien// /datum/species/xeno // A cloning mistake, crossing human and xenomorph DNA @@ -221,6 +193,7 @@ id = "xeno" say_mod = "hisses" default_color = "00FF00" + should_draw_citadel = TRUE species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE) inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID) mutant_bodyparts = list("xenotail", "xenohead", "xenodorsal", "taur", "mam_body_markings") @@ -235,7 +208,6 @@ liked_food = MEAT /datum/species/xeno/on_species_gain(mob/living/carbon/human/C, datum/species/old_species) - C.draw_citadel_parts() if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Digitigrade Legs") species_traits += DIGITIGRADE if(DIGITIGRADE in species_traits) @@ -243,7 +215,6 @@ . = ..() /datum/species/xeno/on_species_loss(mob/living/carbon/human/C, datum/species/new_species) - C.draw_citadel_parts(TRUE) if(("legs" in C.dna.species.mutant_bodyparts) && C.dna.features["legs"] == "Normal Legs") species_traits -= DIGITIGRADE if(DIGITIGRADE in species_traits) diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm index 08d9d73f00..bbbe863ec2 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/ipc.dm @@ -3,6 +3,7 @@ id = "ipc" say_mod = "beeps" default_color = "00FF00" + should_draw_citadel = TRUE blacklisted = 0 sexes = 0 species_traits = list(MUTCOLORS,NOEYES,NOTRANSSTING) @@ -16,14 +17,12 @@ var/datum/action/innate/monitor_change/screen /datum/species/ipc/on_species_gain(mob/living/carbon/human/C) - C.draw_citadel_parts() if(isipcperson(C) && !screen) screen = new screen.Grant(C) ..() /datum/species/ipc/on_species_loss(mob/living/carbon/human/C) - C.draw_citadel_parts(TRUE) if(screen) screen.Remove(C) ..() diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 59c4bc5ef1..d188b43083 100644 --- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -6,6 +6,7 @@ /datum/species/jelly/roundstartslime name = "Slimeperson" id = "slimeperson" + limbs_id = "slime" default_color = "00FFFF" species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,NOBLOOD) inherent_traits = list(TRAIT_TOXINLOVER) @@ -19,14 +20,6 @@ heatmod = 1 burnmod = 1 -/datum/species/jelly/roundstartslime/on_species_gain(mob/living/carbon/human/C) - C.draw_citadel_parts() - . = ..() - -/datum/species/jelly/roundstartslime/on_species_loss(mob/living/carbon/human/C) - C.draw_citadel_parts(TRUE) - . = ..() - /datum/action/innate/slime_change name = "Alter Form" check_flags = AB_CHECK_CONSCIOUS diff --git a/modular_citadel/code/modules/mob/living/living.dm b/modular_citadel/code/modules/mob/living/living.dm index 955263b7af..b07b8ed64b 100644 --- a/modular_citadel/code/modules/mob/living/living.dm +++ b/modular_citadel/code/modules/mob/living/living.dm @@ -102,9 +102,9 @@ return FALSE /mob/living/carbon/update_stamina() - var/total_health = (min(health*2,100) - getStaminaLoss()) - if(getStaminaLoss()) - if(!recoveringstam && total_health <= STAMINA_CRIT_TRADITIONAL && !stat) + var/total_health = getStaminaLoss() + if(total_health) + if(!recoveringstam && total_health >= STAMINA_CRIT && !stat) to_chat(src, "You're too exhausted to keep going...") resting = TRUE if(combatmode) @@ -112,7 +112,7 @@ recoveringstam = TRUE filters += CIT_FILTER_STAMINACRIT update_canmove() - if(recoveringstam && total_health >= STAMINA_SOFTCRIT_TRADITIONAL) + if(recoveringstam && total_health <= STAMINA_SOFTCRIT) to_chat(src, "You don't feel nearly as exhausted anymore.") recoveringstam = FALSE filters -= CIT_FILTER_STAMINACRIT diff --git a/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm b/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm index 80e8234914..d2006cd12c 100644 --- a/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm +++ b/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm @@ -38,7 +38,7 @@ return to_chat(user, "You decide to wake up the banana spider...") awakening = 1 - + spawn(30) if(!QDELETED(src)) var/mob/living/simple_animal/banana_spider/S = new /mob/living/simple_animal/banana_spider(get_turf(src.loc)) @@ -55,7 +55,8 @@ icon_dead = "banana_peel" health = 1 maxHealth = 1 - turns_per_move = 5 + turns_per_move = 5 //this isn't player speed =| + speed = 2 //this is player speed loot = list(/obj/item/reagent_containers/food/snacks/deadbanana_spider) atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 270 @@ -67,7 +68,7 @@ response_harm = "splats" speak_emote = list("chitters") mouse_opacity = 2 - density = FALSE + density = TRUE ventcrawler = VENTCRAWLER_ALWAYS gold_core_spawnable = FRIENDLY_SPAWN verb_say = "chitters" @@ -75,19 +76,17 @@ verb_exclaim = "chitters loudly" verb_yell = "chitters loudly" var/squish_chance = 50 - del_on_death = 1 - + var/projectile_density = TRUE //griffons get shot + del_on_death = TRUE /mob/living/simple_animal/banana_spider/Initialize() . = ..() var/area/A = get_area(src) if(A) notify_ghosts("A banana spider has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE) - GLOB.poi_list |= src - /mob/living/simple_animal/banana_spider/attack_ghost(mob/user) - if(src.key) + if(key) //please stop using src. without a good reason. return if(CONFIG_GET(flag/use_age_restriction_for_jobs)) if(!isnum(user.client.player_age)) @@ -98,17 +97,19 @@ var/be_spider = alert("Become a banana spider? (Warning, You can no longer be cloned!)",,"Yes","No") if(be_spider == "No" || QDELETED(src) || !isobserver(user)) return - src.sentience_act() - src.key = user.key + sentience_act() + key = user.key density = TRUE /mob/living/simple_animal/banana_spider/ComponentInitialize() . = ..() - AddComponent(/datum/component/slippery, 80) + AddComponent(/datum/component/slippery, 40) - -/mob/living/simple_animal/banana_spider/Crossed(var/atom/movable/AM) +/mob/living/simple_animal/banana_spider/Crossed(atom/movable/AM) //no /var in proc headers . = ..() + if(istype(AM, /obj/item/projectile) && projectile_density) //forced projectile density + var/obj/item/projectile/P = AM + P.Bump(src) if(ismob(AM)) if(isliving(AM)) var/mob/living/A = AM @@ -147,4 +148,4 @@ /obj/item/reagent_containers/food/snacks/deadbanana_spider/Initialize() . = ..() - AddComponent(/datum/component/slippery, 80) + AddComponent(/datum/component/slippery, 20) diff --git a/modular_citadel/icons/effects/souldeath.dmi b/modular_citadel/icons/effects/souldeath.dmi new file mode 100644 index 0000000000..f225bd5321 Binary files /dev/null and b/modular_citadel/icons/effects/souldeath.dmi differ diff --git a/modular_citadel/icons/mob/clothing/necks.dmi b/modular_citadel/icons/mob/clothing/necks.dmi new file mode 100644 index 0000000000..65198bc64c Binary files /dev/null and b/modular_citadel/icons/mob/clothing/necks.dmi differ diff --git a/modular_citadel/icons/mob/clothing/trek_item_icon.dmi b/modular_citadel/icons/mob/clothing/trek_item_icon.dmi index 4ac77773a0..86afe16b03 100644 Binary files a/modular_citadel/icons/mob/clothing/trek_item_icon.dmi and b/modular_citadel/icons/mob/clothing/trek_item_icon.dmi differ diff --git a/modular_citadel/icons/mob/clothing/trek_mob_icon.dmi b/modular_citadel/icons/mob/clothing/trek_mob_icon.dmi index 9323ea9f3c..51daa8179f 100644 Binary files a/modular_citadel/icons/mob/clothing/trek_mob_icon.dmi and b/modular_citadel/icons/mob/clothing/trek_mob_icon.dmi differ diff --git a/modular_citadel/icons/mob/mutant_bodyparts.dmi b/modular_citadel/icons/mob/mutant_bodyparts.dmi index 8f3bfb3b87..7dcff09747 100644 Binary files a/modular_citadel/icons/mob/mutant_bodyparts.dmi and b/modular_citadel/icons/mob/mutant_bodyparts.dmi differ diff --git a/modular_citadel/icons/mob/suit_digi.dmi b/modular_citadel/icons/mob/suit_digi.dmi index 89284dbe52..95d03bb6d0 100644 Binary files a/modular_citadel/icons/mob/suit_digi.dmi and b/modular_citadel/icons/mob/suit_digi.dmi differ diff --git a/modular_citadel/icons/mob/uniform_digi.dmi b/modular_citadel/icons/mob/uniform_digi.dmi index 5d9f0ad235..c5ee6b1780 100644 Binary files a/modular_citadel/icons/mob/uniform_digi.dmi and b/modular_citadel/icons/mob/uniform_digi.dmi differ diff --git a/modular_citadel/icons/obj/clothing/cit_neck.dmi b/modular_citadel/icons/obj/clothing/cit_neck.dmi index ce115c2aa7..abccd4a115 100644 Binary files a/modular_citadel/icons/obj/clothing/cit_neck.dmi and b/modular_citadel/icons/obj/clothing/cit_neck.dmi differ diff --git a/modular_citadel/icons/obj/clothing/trek_item_icon.dmi b/modular_citadel/icons/obj/clothing/trek_item_icon.dmi new file mode 100644 index 0000000000..86afe16b03 Binary files /dev/null and b/modular_citadel/icons/obj/clothing/trek_item_icon.dmi differ diff --git a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi index d0597e1a38..2a7342553b 100644 Binary files a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi and b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi differ diff --git a/modular_citadel/sound/misc/souldeath.ogg b/modular_citadel/sound/misc/souldeath.ogg new file mode 100644 index 0000000000..98a19c0765 Binary files /dev/null and b/modular_citadel/sound/misc/souldeath.ogg differ diff --git a/modular_citadel/sound/voice/bark1.ogg b/modular_citadel/sound/voice/bark1.ogg new file mode 100644 index 0000000000..5d3853419f Binary files /dev/null and b/modular_citadel/sound/voice/bark1.ogg differ diff --git a/modular_citadel/sound/voice/bark2.ogg b/modular_citadel/sound/voice/bark2.ogg new file mode 100644 index 0000000000..dab73c4743 Binary files /dev/null and b/modular_citadel/sound/voice/bark2.ogg differ diff --git a/modular_citadel/sound/voice/mothsqueak.ogg b/modular_citadel/sound/voice/mothsqueak.ogg new file mode 100644 index 0000000000..c5ac979aed Binary files /dev/null and b/modular_citadel/sound/voice/mothsqueak.ogg differ diff --git a/modular_citadel/sound/voice/raptor_purr.ogg b/modular_citadel/sound/voice/raptor_purr.ogg new file mode 100644 index 0000000000..a1492718e5 Binary files /dev/null and b/modular_citadel/sound/voice/raptor_purr.ogg differ diff --git a/sound/effects/clang1.ogg b/sound/effects/clang1.ogg new file mode 100644 index 0000000000..eef118e4d4 Binary files /dev/null and b/sound/effects/clang1.ogg differ diff --git a/sound/effects/clang2.ogg b/sound/effects/clang2.ogg new file mode 100644 index 0000000000..175fe98fd1 Binary files /dev/null and b/sound/effects/clang2.ogg differ diff --git a/sound/effects/clangsmall1.ogg b/sound/effects/clangsmall1.ogg new file mode 100644 index 0000000000..7824db66cf Binary files /dev/null and b/sound/effects/clangsmall1.ogg differ diff --git a/sound/effects/clangsmall2.ogg b/sound/effects/clangsmall2.ogg new file mode 100644 index 0000000000..3211e66b75 Binary files /dev/null and b/sound/effects/clangsmall2.ogg differ diff --git a/sound/effects/slosh1.ogg b/sound/effects/slosh1.ogg new file mode 100644 index 0000000000..4da76aac49 Binary files /dev/null and b/sound/effects/slosh1.ogg differ diff --git a/sound/effects/slosh2.ogg b/sound/effects/slosh2.ogg new file mode 100644 index 0000000000..9df0243c4c Binary files /dev/null and b/sound/effects/slosh2.ogg differ diff --git a/sound/music/rocketridersprayer.ogg b/sound/music/rocketridersprayer.ogg new file mode 100644 index 0000000000..24d3beca3f Binary files /dev/null and b/sound/music/rocketridersprayer.ogg differ diff --git a/sound/weapons/gagging.ogg b/sound/weapons/gagging.ogg new file mode 100644 index 0000000000..0b0a3783f4 Binary files /dev/null and b/sound/weapons/gagging.ogg differ diff --git a/strings/names/clown.txt b/strings/names/clown.txt index 8eec0990d0..d8655d7cbf 100644 --- a/strings/names/clown.txt +++ b/strings/names/clown.txt @@ -1,12 +1,25 @@ +Alfie +Antsy Baby Cakes +Bam Bam +Beebee Bo Bo Sassy Bonker +Bonbon Bubble Buster Frown +Buttercup Button Candy Checkers +Clarabell +Clownsky +Clueless +Cluesky +Dazzle Dinky Doodle +Doodles +Duckie Flop O'Honker Freckle Giggles @@ -15,12 +28,18 @@ Goose McSunny Honkel the III Honker Honkerbelle +Knicknack +Jazzy Bella Jingle +Joy Jo Jo Bobo Bo Ladybug Honks +Lala Miss Stockings +Mittens Mr Shoe Patches +Pancake Pepinpop Pocket Razzle Dazzle @@ -33,5 +52,11 @@ Slippy Joe Sparkle Speckles Sprinkledinkle +Squigley +Tickle +Topcake Toodles Sharperton -Ziggy Yoyo \ No newline at end of file +Trixy +Witty +Ziggy Yoyo +Zippy diff --git a/strings/phobia.json b/strings/phobia.json index 3f56751333..e1ae1f4e13 100644 --- a/strings/phobia.json +++ b/strings/phobia.json @@ -257,6 +257,19 @@ "fowl" ], +"cats": [ + "mew", + "nya", + "moew", + "feline", + "cat", + "neko", + "viola", + "kitty", + "purr", + "headpat" + ], + "falling": [ "hold on", "hang in there", @@ -297,4 +310,4 @@ "ora", "~" ] -} \ No newline at end of file +} diff --git a/strings/round_start_sounds.txt b/strings/round_start_sounds.txt index 18fbb3f98f..a8409188fc 100644 --- a/strings/round_start_sounds.txt +++ b/strings/round_start_sounds.txt @@ -21,3 +21,4 @@ sound/music/indeep.ogg sound/music/goodbyemoonmen.ogg sound/music/flytothemoon_otomatone.ogg sound/music/milkyway.ogg +sound/music/rocketridersprayer.ogg diff --git a/strings/tips.txt b/strings/tips.txt index d389437158..9571527853 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -6,7 +6,7 @@ You can drag other players onto yourself to open the strip menu, letting you rem Clicking on a windoor rather then bumping into it will keep it open, you can click it again to close it. You can spray a fire extinguisher, throw items or fire a gun while floating through space to change your direction. Simply fire opposite to where you want to go. You can change the control scheme by pressing tab. One is WASD, the other is the arrow keys. Keep in mind that hotkeys are also changed with this. -All vending machines can be hacked to obtain some contraband items from them, and some can be fed with coins to gain access to premium items. +All vending machines can be hacked to obtain some contraband items from them, and many can be fed with coins to gain access to premium items. Firesuits and winter coats offer mild protection from the cold, allowing you to spend longer periods of time near breaches and space than if wearing nothing at all. Glass shards can be welded to make glass, and metal rods can be welded to make metal. Ores can be welded too, but this takes a lot of fuel. If you need to drag multiple people either to safety or to space, bring a locker or crate over and stuff them all in before hauling them off. @@ -18,13 +18,16 @@ You can recolor certain items like jumpsuits and gloves in washing machines by a Maintenance is full of equipment that is randomized every round. Look around and see if anything is worth using. Some roles cannot be antagonists by default, but antag selection is decided first. For instance, you can set Security Officer to High without affecting your chances of becoming an antag -- the game will just select a different role. There are many places around the station to hide contraband. A few for starters: linen boxes, toilet cisterns, body bags. Experiment to find more! -On some maps, you can use a machine in the vault to deposit space cash for cargo points or rob cargo blind. +On all maps, you can use a machine in the vault to deposit space cash for cargo points. Otherwise, use it to steal the station's cash and get out before the alarm goes off. As the Captain, you are one of the highest priority targets on the station. Everything from revolutions, to nuclear operatives, to traitors that need to rob you of your unique lasgun or your life are things to worry about. As the Captain, always take the nuclear disk and pinpointer with you every shift. It's a good idea to give one of these to another head you can trust with keeping it safe, such as the Head of Security. As the Captain, you have absolute access and control over the station, but this does not mean that being a horrible person won't result in mutiny and a ban. +As the Captain, you have a fancy pen that can be used as a holdout dagger or even as a scalpel in surgery! As the Captain, you can purchase a new emergency shuttle using a communications console. Some require credits, while others give you credits in exchange. Keep in mind that purchasing dangerous shuttles will incur the ire of your crew. As the Chief Medical Officer, your hypospray is like a refillable instant injection syringe that can hold 30 units as opposed to the standard 15. As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and geneticists during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting. +As a Medical Doctor, pester Research for improved surgical tools. They work faster, don't cost much and are typically more deadly. +As a Medical Doctor, your belt can hold a full set of surgical tools. Using sterilizine before each attempt during surgery will reduce your failure chance on tricky steps or when using less-than-optimal equipment. As a Medical Doctor, you can attempt to drain blood from a husk with a syringe to determine the cause. If you can extract blood, it was caused by extreme temperatures or lasers, if there is no blood to extract, you have confirmed the presence of changelings. As a Medical Doctor, while both heal toxin damage, the difference between charcoal and antitoxin is that charcoal will actively remove all other reagents from one's body, while antitoxin only removes various toxins - but can overdose. As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva. @@ -38,24 +41,27 @@ As a Chemist, there are dozens of chemicals that can heal, and even more that ca As a Chemist, some chemicals can only be synthesized by heating up the contents in the chemical heater. As a Chemist, you will be expected to supply crew with certain chemicals. For example, clonexadone and mannitol for the cryo tubes, unstable mutagen and saltpetre for botany as well as healing pills and patches for the front desk. As a Chemist, you can make 100u bottles from plastic sheets. The ChemMaster can produce infinite 30u glass bottles as well. -As a Geneticist, you can eject someone from cloning early by disabling power in genetics. Note that they will suffer more genetic damage and may lose vital organs from this. +As a Geneticist, you can eject someone from cloning early by clicking on the cloner pod with your ID. Note that they will suffer more genetic damage and may lose vital organs from this. As a Geneticist, becoming a hulk makes you capable of dealing high melee damage, stunlocking people, and punching through walls. However, you can't fire guns, will lose your hulk status if you take too much damage, and are not considered a human by the AI while you are a hulk. As the Virologist, your viruses can range from healing powers so great that you can heal out of critical status, or diseases so dangerous they can kill the entire crew with airborne spontaneous combustion. Experiment! As the Virologist, you only require small amounts of vaccine to heal a sick patient. Work with the Chemist to distribute your cures more efficiently. As the Research Director, you can take AIs out of their cores by loading them into an intelliCard, and then from there into an AI system integrity restorer computer to revive and/or repair them. As the Research Director, you can lock down cyborgs instead of blowing them up. Then you can have their laws reset or if that doesn't work, safely dismantled. +As the Research Director, you can upgrade your modular console with better computer parts to speed up its functions. This can be useful when using the AI system integrity restorer. As the Research Director, your console's NTnet monitoring tool can be used to retrieve airlock passkeys, provided that someone used a door remote. As a Scientist, you can use the mutation toxin obtained from green slimes to turn yourself into a jelly mutant. Each subspecies has unique features - for example telepathic powers, duplicating bodies or integrating slime extracts! As a Scientist, you can maximize the number of uses you get out of a slime by feeding it slime steroid, created from purple slimes, while alive. You can then apply extract enhancer, created from cerulean slimes, on each extract. -As a Scientist, you can disable anomalies by scanning them with an analyzer, then send a signal on the frequency it gives you with a remote signalling device. This will leave behind an anomaly core, which can be used to construct a Phazon mech! +As a Scientist, you can disable anomalies by scanning them with an analyzer, then send a signal on the frequency it gives you with a remote signalling device. This will leave behind an anomaly core, which can be used to construct a Phazon mech, or be used in the destructive analyzer for a 10,000 point bonus! As a Scientist, researchable stock parts can seriously improve the efficiency and speed of machines around the station. In some cases, it can even unlock new functions. As a Scientist, you can generate research points by letting the tachyon-doppler array record increasingly large explosions. As a Scientist, getting drunk just enough will speed up research. Skol! +As a Scientist, you can get points by placing slime cores into the deconstructive analyzer! This even works with crossbred slime cores. As a Roboticist, keep an ear out for anomaly announcements. If you get your hands on an anomaly core, you can build a Phazon mech! As a Roboticist, you can repair your cyborgs with a welding tool. If they have taken burn damage from lasers, you can remove their battery, expose the wiring with a screwdriver and replace their wires with a cable coil. As a Roboticist, you can reset a cyborg's module by cutting and mending the reset wire with a wire cutter. As a Roboticist, you can greatly help out Shaft Miners by building a Firefighter APLU equipped with a hydraulic clamp and plasma cutter. The mech is ash storm proof and can even walk across lava! As a Roboticist, you can augment people with cyborg limbs. Augmented limbs can easily be repaired with cables and welders. +As a Roboticist, you can use your printer that is linked to the ore silo to teleport mats into your work place! As the AI, you can click on people's names to look at them. This only works if there are cameras that can see them. As the AI, you can quickly open and close doors by holding shift while clicking them, bolt them when holding ctrl, and even shock them while holding alt. As the AI, you can take pictures with your camera and upload them to newscasters. @@ -65,8 +71,9 @@ As a Cyborg, you are impervious to fires and heat. If you are rogue, you can rel As a Cyborg, you are extremely vulnerable to EMPs as EMPs both stun you and damage you. The ion rifle in the armory or a traitor with an EMP kit can kill you in seconds. As a Service Cyborg, your spray can knocks people down. However, it is blocked by gas masks. As an Engineering Cyborg, you can attach air alarm/fire alarm/APC frames to walls by placing them on the floor and using a screwdriver on them. -As a Medical Cyborg, you can fully perform surgery and even augment people. +As a Medical Cyborg, you can fully perform surgery and even augment people. Best of all, they have a 0% failure chance. As a Janitor Cyborg, you are the bane of all slaughter demons and even Bubblegum himself. Cleaning up blood stains will severely gimp them. +As a Janitor Cyborg, you get a fancy bottle of drying agent! If you want to be nice, spray the janitor boots with them to magically upgrade them to absorbent galoshes. As the Chief Engineer, you can rename areas or create entirely new ones using your station blueprints. As the Chief Engineer, your hardsuit is significantly better than everybody else's. It has the best features of both engineering and atmospherics hardsuits - boasting nigh-invulnerability to radiation and all atmospheric conditions. As the Chief Engineer, you can spy on and even forge PDA communications with the message monitor console! The key is in your office. @@ -84,6 +91,7 @@ As an Engineer, you can use radiation collectors to generate research points. Lo As an Engineer, don't underestimate the humble P.A.C.M.A.N. generators. With upgraded parts, a couple units working in tandem are sufficient to take over for an exploded engine or shattered solars. As an Engineer, your departmental protolathe and circuit printer can manufacture the necessary circuit boards and components to build just about anything. Make extra medical machinery everywhere! Build a gibber for security! Set up an array of emitters pointing down the hall! The possibilities are endless! As an Engineer, you can pry open secure storage by disabling the engine room APC's main breaker. This is obviously a bad idea if the engine is running. +Don't forget that Cargo has access to a meteor defense satellite that can be ordered BEFORE meteors hit the station. Any idle Engineers should have this on their to-do list. As an Engineer, your RCD can be reloaded with mineral sheets instead of just compressed matter cartridges. As an Atmospheric Technician, you can unwrench a pipe regardless of the pressures of the gases inside, but if they're too high they can burst out and injure you! As an Atmospheric Technician, look into replacing your gas pumps with volumetric gas pumps, as those move air in flat numerical amounts, rather than percentages which leave trace gases. @@ -92,18 +100,31 @@ As an Atmospheric Technician, your backpack firefighter tank can launch resin. T As an Atmospheric Technician, your ATMOS holofan projector blocks gases while allowing objects to pass through. With it, you can quickly contain gas spills, fires and hull breaches. Or, use it to seal a plasmaman cloning room. As an Atmospheric Technician, burning a plasma/oxygen mix inside the incinerator will not only produce power, but also gases such as tritium and water vapor. As an Atmospheric Technician, you can change the layer of a pipe by clicking with it on a wrenched pipe or other atmos component of the desired layer. +As an Atmospheric Technician, you can take a few cans worth of N2/N2O and cool it down at local freezers. This is a good idea when dealing with (or preparing for) a supermatter meltdown. As the Head of Security, you are expected to coordinate your security force to handle any threat that comes to the station. Sometimes it means making use of the armory to handle a blob, sometimes it means being ruthless during a revolution or cult. As the Head of Security, you can call for executions or forced cyborgization, but may require the Captain's approval. As the Head of Security, don't let the power go to your head. You may have high access, great equipment, and a miniature army at your side, but being a terrible person without a good reason is grounds for banning. As the Warden, your duty is to be the watchdog of the brig and handler of prisoners when little is happening, and to hand out equipment and weapons to the security officers when a crisis strikes. As the Warden, keep a close eye on the armory at all times, as it is a favored strike point of nuclear operatives and cocky traitors. As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig or the gulag. Make sure to check on them once in a while! +As the Warden, never underestimate the power of tech slugs! Scattershot fires a cone of weaker lasers, Ion slugs fires EMPs that only effect the tiles they hit, and Pulse slugs fire a singular laser that can one-hit almost any wall! +As the Warden, you can use a surgical saw on riot shotguns to shorten the barrel, making them able to fit in your backpack. As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals. As the Warden, you can use handcuffs on orange prisoner shoes to turn them into cuffed shoes, forcing prisoners to walk and potentially thwarting an escape. +As the Warden, tracker implants can be used on sec officers. Doing this will let you track their corpse even without suits, though the implant will biodegrade after 5 minutes. +As the Warden, cryostasis shotgun darts hold 10u of chemicals that will not react untill it hits someone. +As the Warden, chemical implants can be loaded with a cocktail of healing or combat chems, perfect for the Hos or other sec officers to use. Be sure to keep a eye on them though, it will not auto inject! EMPs or starvation mite lead to the chemical implant to go off as well. +As the Warden, tracker implants can be used on sec officers. Doing this will let you be able to message them when telecoms are out, or when you suspect coms are compromised. This is also good against rogue AIs as the prisoner tracker doesn't leave logs or alarms for the AI. +As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time! +As a Security Officer, remember that your belt can hold more then one stun baton. +As a Security Officer, remember harm battoning someone in the head can deconvert them form a being a rev! This sadly doesn't work against the cult, nor does this protect them from getting reconverted. +As a Security Officer, remember that you can attach a sec-lite to your taser or your helmet! As a Security Officer, communicate and coordinate with your fellow officers using the security channel (:s) to avoid confusion. As a Security Officer, your sechuds or HUDsunglasses can not only see crewmates' job assignments and criminal status, but also if they are mindshield implanted. Use this to your advantage in a revolution to definitively tell who is on your side! As a Security Officer, mindshield implants can only prevent someone from being turned into a cultist: unlike revolutionaries, it will not de-cult them if they have already been converted. As a Security Officer, examining someone while wearing sechuds or HUDsunglasses will let you set their arrest level, which will cause Beepsky and other security bots to chase after them. +As a Security Officer, you can take out the power cell on your baton to replace it with a better or fully charged one. Just use a screwdriver on your baton to remove the old cell +As a Security Officer, you can place riot shotguns on your armor, this even works with winter sec coats! As the Detective, people leave fingerprints everywhere and on everything. With the exception of white latex, gloves will hide them. All is not lost, however, as gloves leave fibers specific to their kind such as black or nitrile, pointing to a general department. As the Detective, you can use your forensics scanner from a distance. As the Detective, your revolver can be loaded with .357 ammunition obtained from a hacked autolathe. Firing it has a decent chance to blow up your revolver. @@ -119,6 +140,8 @@ As the Clown, eating bananas heals you slightly. Honk! As the Clown, your Holy Grail is the mineral bananium, which can be given to the Roboticist to build you a fun and robust mech beloved by everyone. As the Clown, you can use your stamp on a sheet of cardboard as the first step of making a honkbot. Fun for the whole crew! As the Chaplain, your null rod has a lot of functions: it can convert water into holy water, which if spread on the ground prevents wizards from jaunting away, can destroy cultist runes by hitting them, and is a very powerful weapon to boot! +The Chaplain can bless any container with water by hitting it with their bible. Holy water has a myriad of uses against both cults and large amounts of it are a great contributor to success against them. +The Chaplain's holy weapon will kill clockwork marauders in two hits. As the Chaplain, your bible is also a container that can store small items. Depending on your god, your starting bible may come with a surprise! As the Chaplain, you are much more likely to get a response by praying to the gods than most people. To boost your chances, make altars with colorful crayon runes, lit candles, and wire art. As a Botanist, you can hack the MegaSeed Vendor to get access to more exotic seeds. These seeds can alternatively be ordered from cargo. @@ -129,15 +152,20 @@ As a Cook, you can load your food into snack vending machines. As a Cook, you can rename your custom made food with a pen. As a Cook, any food you make will be much healthier than the junk food found in vendors. Having the crew routinely eating from you will provide minor buffs. As a Cook, being in the kitchen will make you remember the basics of Close Quarters Cooking. It is highly effective at removing Assistants from your workplace. +As a Cook, your Kitchenmate can vend out trays that fit on your belt slot. These trays pick up 7 food items at a time and are a quick way to transport large meals. +As a Cook, the advanced roasting stick is used to cook food at a distance, and can be used on SME, singularity, and other objects that cook food normally. As the Bartender, the drinks you start with only give you the basics. If you want more advanced mixtures, look into working with chemistry, hydroponics, or even mining for things to grind up and throw in! As the Bartender, you can use a circular saw on your shotgun to make it easier to store. As a Janitor, if someone steals your janicart, you can instead use your space cleaner spray, grenades, water sprayer, exact bloody revenge or order another from Cargo. +As a Janitor, the trash bag can be used to hold more than trash. Tools, medical equipment, smuggled nuclear disks... You name it! As a Janitor, mousetraps can be used to create bombs or booby-trap containers. -As the Curator, you are not completely defenseless. Your whip easily disarms people, your laser pointer can blind humans and cyborgs, and you can hide items in wirecut books. +Beware the Curator, for they are not completely defenseless. The curator's whip always disarms people, their laser pointer can blind humans and cyborgs, and can hide items in wirecut books. As the Curator, be sure to keep the shelves stocked and the library clean for crew. As a Cargo Technician, you can hack MULEbots to make them faster, run over people in their way, and even let you ride them! As a Cargo Technician, you can order contraband items from the supply shuttle console by de-constructing it and using a multitool on the circuit board, the re-assembling it. As a Cargo Technician, you can earn more cargo points by shipping back crates from maintenance, liquid containers, plasma sheets, rare seeds from hydroponics, and more! +As a Cargo Technician, you get 400 points per packet! Stamp the manifest and sending back the crate will give you 200 points for the paperwork and 200 points for the crate! +As a Cargo Technician, paperwork is an alternative option to shipping off plasma sheets and other goods. Order Paperwork crates and go into the crafting menu to turn pens and undone paper work into completed grant paper work to get 50 points per sheet! As the Quartermaster, be sure to check the manifests on crates you receive to make sure all the info is correct. If there's a mistake, stamp the manifest DENIED and send it back in a crate with the items untouched for a refund! As the Quartermaster, you can construct an express supply console that instantly delivers crates by drop pod. The impact will cause a small explosion as well. As a Shaft Miner, the northern side of Lavaland has a lot more rare minerals than on the south. @@ -161,6 +189,9 @@ As a Monkey, you can still wear a few human items, such as backpacks, gas masks As the Malfunctioning AI, you can shunt to an APC if the situation gets bad. This disables your doomsday device if it is active. As the Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them. As the Malfunctioning AI, look into flooding the station with plasma fires to kill off large portions of the crew, letting you pick off the remaining few with space suits who escaped. +Xenomorphs? Science can craft deadly tech shells like pulse slugs and laser scatter shot that are highly effective against any alien threat. +When fighting aliens, it can be a good idea to turn off the gravity due to the alien's lack of zero-gravity control. +When fighting xenomorph aliens, consider a shield. Shields can block their pounces and be worn on the back, but beware of neurotoxin. As an Alien, your melee prowess is unmatched, but your ranged abilities are sorely lacking. Make use of corners to force a melee confrontation! As an Alien, you take double damage from all burn attacks, such as lasers, welding tools, and fires. Furthermore, fire can destroy your resin and eggs. Expose areas to space to starve away any flamethrower fires before they can do damage! As an Alien, resin floors not only regenerate your plasma supply, but also passively heal you. Fight on resin floors to gain a home turf advantage! @@ -180,6 +211,7 @@ As the Blob, talking will send a message to all other overminds and all Blobbern As a Blobbernaut, you can communicate with overminds and other Blobbernauts via :b. As a Blobbernaut, your HUD shows your health and the core health of the overmind that created you. As a Revolutionary, you cannot convert a head of staff or someone who has a mindshield implant, such as a security officer or those they implant. Implants can however be surgically removed, and do not carry over with cloning. Take control of medbay to keep control of conversions! +During a revolution, you cannot convert someone with brain damage, making an un-upgraded cloner a makeshift deconversion device. As a Revolutionary, cargo can be your best friend or your worst nightmare. In the best case scenario you will be able to order a limitless amount of guns and armor, in the worst case scenario security will take control and order a limitless number of mindshield implants to turn your fellow revolutionaries against you. As a Revolutionary, your main power comes from how quickly you spread. Convert people as fast as you can and overwhelm the heads of staff before security can arm up. As a Changeling, the Extract DNA sting counts for your genome absorb objective, but does not let you respec your powers. @@ -199,8 +231,6 @@ As a Servant, converting or sabotaging Science and Genetics can make defending t As a Servant, the Clockwork Armaments scripture allows you to summon armor and/or a weapon at will. Use it whenever you unlock it! You can deconvert Cultists of Nar-Sie and Servants of Ratvar by feeding them large amounts of holy water. Unlike revolutionaries, implanting them with mindshield implants won't do it! Tiles sprayed with holy water will permanently block Servants of Ratvar from teleporting onto them. -The Chaplain can bless any container with water by hitting it with their bible. Holy water has a myriad of uses against both cults and large amounts of it are a great contributor to success against them. -The Chaplain's holy weapon will kill clockwork marauders in two hits. As a Wizard, you can turn people to stone, then animate the resulting statue with a staff of animation to create an extremely powerful minion, for all of 5 minutes at least. As a Wizard, the fireball spell performs very poorly at close range, as it can easily catch you in the blast. It is best used as a form of artillery down long hallways. As a Wizard, summoning guns will turn a large portion of the crew against themselves, but will also give everyone anything from a pea shooter to a BFG 9000. Use at your own risk! @@ -217,17 +247,19 @@ As a Revenant, your Malfunction ability in general damages machinery and mechani As a Revenant, the illness inflicted on humans by Blight can be easily cured by lying down or with holy water, making it best used on targets that have no time to lie down, such as humans in combat. As a Swarmer, you can deconstruct more things than you think. Try deconstructing light switches, buttons, air alarms and more. Experiment! As a Swarmer, you can teleport fellow swarmers away if you think they are in danger. +As a Swarmer, you are weak to EMP and lasers. Upon death, you will drop a bluespace crystal. +As a Swarmer, use your ability to consume guns and other weapons to disarm the crew to keep your numbers high! As a Morph, you can talk while disguised, but your words have a chance of being slurred, giving you away! As a Drone, you can ping other drones to alert them of areas in the station in need of repair. +As a Drone, you can repair yourself by using a screwdriver on yourself and standing still! As a Ghost, you can see the inside of a container on the ground by clicking on it. As a Ghost, you can double click on just about anything to follow it. Or just warp around! As a Devil, you gain power for every three souls you control, however you also become more obvious. As a Devil, as long as you control at least one other soul, you will automatically resurrect, as long as a banishment ritual is not performed. At which time a Devil's nameth is spake on the tongue of man, the Devil may appeareth. -As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time! -As a Security Officer, remember that you can attach a sec-lite to your taser or your helmet! You can swap floor tiles by holding a crowbar in one hand and a stack of tiles in the other. When hacking doors, cutting and mending the "test light wire" will restore power to the door. When crafting most items, you can either manually combine parts or use the crafting menu. Suit storage units not only remove blood and dirt from clothing, but also radiation! Remote devices will work when used through cameras. For example: Bluespace RPEDs and door remotes. +Laser pointers can be upgraded by replacing its micro laser with a better one from RnD! Use a screwdriver on it to remove the old laser. Upgrading the laser pointer gives you better odds of stunning a cyborg, and even blinding people with sunglasses. diff --git a/tgstation.dme b/tgstation.dme index b17ba9363f..268d4f1ff9 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -2772,6 +2772,7 @@ #include "modular_citadel\code\datums\uplink_items_cit.dm" #include "modular_citadel\code\datums\components\material_container.dm" #include "modular_citadel\code\datums\components\phantomthief.dm" +#include "modular_citadel\code\datums\components\souldeath.dm" #include "modular_citadel\code\datums\mood_events\generic_negative_events.dm" #include "modular_citadel\code\datums\mood_events\generic_positive_events.dm" #include "modular_citadel\code\datums\mood_events\moodular.dm" @@ -2798,6 +2799,7 @@ #include "modular_citadel\code\game\objects\items.dm" #include "modular_citadel\code\game\objects\tools.dm" #include "modular_citadel\code\game\objects\effects\spawner\spawners.dm" +#include "modular_citadel\code\game\objects\effects\temporary_visuals\souldeath.dm" #include "modular_citadel\code\game\objects\effects\temporary_visuals\projectiles\impact.dm" #include "modular_citadel\code\game\objects\effects\temporary_visuals\projectiles\muzzle.dm" #include "modular_citadel\code\game\objects\effects\temporary_visuals\projectiles\tracer.dm" @@ -2870,6 +2872,7 @@ #include "modular_citadel\code\modules\client\loadout\uniform.dm" #include "modular_citadel\code\modules\client\verbs\who.dm" #include "modular_citadel\code\modules\clothing\clothing.dm" +#include "modular_citadel\code\modules\clothing\neck.dm" #include "modular_citadel\code\modules\clothing\glasses\phantomthief.dm" #include "modular_citadel\code\modules\clothing\head\head.dm" #include "modular_citadel\code\modules\clothing\spacesuits\cydonian_armor.dm"