diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm index e37bef86d4..faaa475894 100644 --- a/code/__defines/_planes+layers.dm +++ b/code/__defines/_planes+layers.dm @@ -76,8 +76,8 @@ What is the naming convention for planes or layers? #define ABOVE_JUNK_LAYER 3.1 // Things that want to be slightly above common objects #define DOOR_CLOSED_LAYER 3.1 // Doors when closed #define WINDOW_LAYER 3.2 // Windows - #define ABOVE_WINDOW_LAYER 3.25 //Above full tile windows so wall items are clickable #define ON_WINDOW_LAYER 3.3 // Ontop of a window + #define ABOVE_WINDOW_LAYER 3.4 //Above full tile windows so wall items are clickable // Mob planes #define MOB_PLANE -25 diff --git a/code/__defines/objects.dm b/code/__defines/objects.dm index 879bed2cd1..26ff77b4d8 100644 --- a/code/__defines/objects.dm +++ b/code/__defines/objects.dm @@ -1,6 +1,5 @@ /* * Defines used for miscellaneous objects. - * Currently only the home of the Multiool. */ // Multitool Mode Defines. @@ -8,3 +7,25 @@ #define MULTITOOL_MODE_STANDARD "Standard" #define MULTITOOL_MODE_INTCIRCUITS "Modular Wiring" #define MULTITOOL_MODE_DOORHACK "Advanced Jacking" + +// Identity system defines. +#define IDENTITY_UNKNOWN 0 // Nothing is known so far. +#define IDENTITY_PROPERTIES 1 // Basic function of the item, and amount of charges available if it uses them. +#define IDENTITY_QUALITY 2 // Blessed/Uncursed/Cursed status. Some things don't use this. +#define IDENTITY_FULL IDENTITY_PROPERTIES|IDENTITY_QUALITY // Know everything. + +#define IDENTITY_TYPE_NONE "generic" +#define IDENTITY_TYPE_TECH "technological" +#define IDENTITY_TYPE_CHEMICAL "chemical" + +// Roguelike object quality defines. Not used at the moment. +#define ROGUELIKE_ITEM_ARTIFACT 2 // Cannot degrade, very rare. +#define ROGUELIKE_ITEM_BLESSED 1 // Better than average and resists cursing. +#define ROGUELIKE_ITEM_UNCURSED 0 // Normal. +#define ROGUELIKE_ITEM_CURSED -1 // Does bad things, clothing cannot be taken off. + +// Consistant messages for certain events. +// Consistancy is import in order to avoid giving too much information away when using an +// unidentified object due to a typo or some other unique difference in message output. +#define ROGUELIKE_MESSAGE_NOTHING "Nothing happens." +#define ROGUELIKE_MESSAGE_UNKNOWN "Something happened, but you're not sure what." diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index b9a3cf0013..766d9cce75 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -52,6 +52,7 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G // Subsystem init_order, from highest priority to lowest priority // Subsystems shutdown in the reverse of the order they initialize in // The numbers just define the ordering, they are meaningless otherwise. +#define INIT_ORDER_MAPPING 17 #define INIT_ORDER_DECALS 16 #define INIT_ORDER_ATOMS 15 #define INIT_ORDER_MACHINES 10 diff --git a/code/_global_vars/misc.dm b/code/_global_vars/misc.dm index 504246e304..a2866a3b3e 100644 --- a/code/_global_vars/misc.dm +++ b/code/_global_vars/misc.dm @@ -1,4 +1,8 @@ -GLOBAL_LIST_EMPTY(all_observable_events) +GLOBAL_LIST_EMPTY(error_last_seen) +GLOBAL_LIST_EMPTY(error_cooldown) + +GLOBAL_DATUM_INIT(all_observable_events, /datum/all_observable_events, new) // This is a datum. It is not a list. +GLOBAL_DATUM_INIT(destroyed_event, /decl/observ/destroyed, new()) GLOBAL_VAR_INIT(timezoneOffset, 0) // The difference betwen midnight (of the host computer) and 0 world.ticks. diff --git a/code/controllers/Processes/alarm.dm b/code/controllers/Processes/alarm.dm index 47f311efea..3590149811 100644 --- a/code/controllers/Processes/alarm.dm +++ b/code/controllers/Processes/alarm.dm @@ -11,7 +11,7 @@ var/datum/controller/process/alarm/alarm_manager /datum/controller/process/alarm - var/list/datum/alarm/all_handlers + var/list/datum/alarm/all_handlers = list() /datum/controller/process/alarm/setup() name = "alarm" diff --git a/code/controllers/Processes/scheduler.dm b/code/controllers/Processes/scheduler.dm index a2a2f5f925..adf7db292c 100644 --- a/code/controllers/Processes/scheduler.dm +++ b/code/controllers/Processes/scheduler.dm @@ -40,7 +40,7 @@ // We are being killed. Least we can do is deregister all those events we registered /datum/controller/process/scheduler/onKill() for(var/st in scheduled_tasks) - destroyed_event.unregister(st, src) + GLOB.destroyed_event.unregister(st, src) /datum/controller/process/scheduler/statProcess() ..() @@ -130,7 +130,7 @@ /datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args) src.source = source - destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed) + GLOB.destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed) ..(trigger_time, procedure, arguments, task_after_process, task_after_process_args) /datum/scheduled_task/source/Destroy() diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index dcb52a8cb3..8c0b6fa5de 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -6,6 +6,7 @@ var/priority = FIRE_PRIORITY_DEFAULT //When mutiple subsystems need to run in the same tick, higher priority subsystems will run first and be given a higher share of the tick before MC_TICK_CHECK triggers a sleep var/flags = 0 //see MC.dm in __DEFINES Most flags must be set on world start to take full effect. (You can also restart the mc to force them to process again) + var/subsystem_initialized = FALSE //set to TRUE after it has been initialized, will obviously never be set if the subsystem doesn't initialize var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire //set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later @@ -154,6 +155,7 @@ //used to initialize the subsystem AFTER the map has loaded /datum/controller/subsystem/Initialize(start_timeofday) + subsystem_initialized = TRUE var/time = (REALTIMEOFDAY - start_timeofday) / 10 var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!" to_chat(world, "[msg]") diff --git a/code/controllers/subsystems/mapping.dm b/code/controllers/subsystems/mapping.dm new file mode 100644 index 0000000000..445a291628 --- /dev/null +++ b/code/controllers/subsystems/mapping.dm @@ -0,0 +1,29 @@ +// Handles map-related tasks, mostly here to ensure it does so after the MC initializes. +SUBSYSTEM_DEF(mapping) + name = "Mapping" + init_order = INIT_ORDER_MAPPING + flags = SS_NO_FIRE + + var/list/map_templates = list() + var/dmm_suite/maploader = null + +/datum/controller/subsystem/mapping/Initialize(timeofday) + if(subsystem_initialized) + return + maploader = new() + load_map_templates() + + if(config.generate_map) + // Map-gen is still very specific to the map, however putting it here should ensure it loads in the correct order. + if(using_map.perform_map_generation()) + using_map.refresh_mining_turfs() + + +/datum/controller/subsystem/mapping/proc/load_map_templates() + for(var/T in subtypesof(/datum/map_template)) + var/datum/map_template/template = T + if(!(initial(template.mappath))) // If it's missing the actual path its probably a base type or being used for inheritence. + continue + template = new T() + map_templates[template.name] = template + return TRUE diff --git a/code/datums/observation/_debug.dm b/code/datums/observation/_debug.dm index 2f882929cf..5b805aa930 100644 --- a/code/datums/observation/_debug.dm +++ b/code/datums/observation/_debug.dm @@ -1,7 +1,6 @@ /**************** * Debug Support * ****************/ -var/datum/all_observable_events/all_observable_events = new() /datum/all_observable_events var/list/events diff --git a/code/datums/observation/destroyed.dm b/code/datums/observation/destroyed.dm index 6a65300a25..ff8778645c 100644 --- a/code/datums/observation/destroyed.dm +++ b/code/datums/observation/destroyed.dm @@ -5,11 +5,10 @@ // // Arguments that the called proc should expect: // /datum/destroyed_instance: The instance that was destroyed. -var/decl/observ/destroyed/destroyed_event = new() /decl/observ/destroyed name = "Destroyed" /datum/Destroy() - destroyed_event.raise_event(src) + GLOB.destroyed_event.raise_event(src) . = ..() diff --git a/code/datums/observation/observation.dm b/code/datums/observation/observation.dm index 32a96871e6..db1f9e0d6e 100644 --- a/code/datums/observation/observation.dm +++ b/code/datums/observation/observation.dm @@ -63,7 +63,7 @@ var/list/global_listeners = list() // Associative list of instances that listen to all events of this type (as opposed to events belonging to a specific source) and the proc to call. /decl/observ/New() - all_observable_events.events += src + GLOB.all_observable_events.events += src . = ..() /decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call) diff --git a/code/datums/observation/~cleanup.dm b/code/datums/observation/~cleanup.dm index eb6ccceef8..3ffe4de89c 100644 --- a/code/datums/observation/~cleanup.dm +++ b/code/datums/observation/~cleanup.dm @@ -1,6 +1,6 @@ -var/list/global_listen_count = list() -var/list/event_sources_count = list() -var/list/event_listen_count = list() +GLOBAL_LIST_EMPTY(global_listen_count) +GLOBAL_LIST_EMPTY(event_sources_count) +GLOBAL_LIST_EMPTY(event_listen_count) /decl/observ/destroyed/raise_event() . = ..() @@ -8,39 +8,39 @@ var/list/event_listen_count = list() return var/source = args[1] - if(global_listen_count[source]) - cleanup_global_listener(source, global_listen_count[source]) - if(event_sources_count[source]) - cleanup_source_listeners(source, event_sources_count[source]) - if(event_listen_count[source]) - cleanup_event_listener(source, event_listen_count[source]) + if(GLOB.global_listen_count[source]) + cleanup_global_listener(source, GLOB.global_listen_count[source]) + if(GLOB.event_sources_count[source]) + cleanup_source_listeners(source, GLOB.event_sources_count[source]) + if(GLOB.event_listen_count[source]) + cleanup_event_listener(source, GLOB.event_listen_count[source]) /decl/observ/register(var/datum/event_source, var/datum/listener, var/proc_call) . = ..() if(.) - event_sources_count[event_source] += 1 - event_listen_count[listener] += 1 + GLOB.event_sources_count[event_source] += 1 + GLOB.event_listen_count[listener] += 1 /decl/observ/unregister(var/datum/event_source, var/datum/listener, var/proc_call) . = ..() if(.) - event_sources_count[event_source] -= 1 - event_listen_count[listener] -= 1 + GLOB.event_sources_count[event_source] -= 1 + GLOB.event_listen_count[listener] -= 1 /decl/observ/register_global(var/datum/listener, var/proc_call) . = ..() if(.) - global_listen_count[listener] += 1 + GLOB.global_listen_count[listener] += 1 /decl/observ/unregister_global(var/datum/listener, var/proc_call) . = ..() if(.) - global_listen_count[listener] -= 1 + GLOB.global_listen_count[listener] -= 1 /decl/observ/destroyed/proc/cleanup_global_listener(listener, listen_count) - global_listen_count -= listener - for(var/entry in all_observable_events.events) + GLOB.global_listen_count -= listener + for(var/entry in GLOB.all_observable_events.events) var/decl/observ/event = entry if(event.unregister_global(listener)) log_debug("[event] - [listener] was deleted while still registered to global events.") @@ -48,8 +48,8 @@ var/list/event_listen_count = list() return /decl/observ/destroyed/proc/cleanup_source_listeners(event_source, source_listener_count) - event_sources_count -= event_source - for(var/entry in all_observable_events.events) + GLOB.event_sources_count -= event_source + for(var/entry in GLOB.all_observable_events.events) var/decl/observ/event = entry var/proc_owners = event.event_sources[event_source] if(proc_owners) @@ -60,8 +60,8 @@ var/list/event_listen_count = list() return /decl/observ/destroyed/proc/cleanup_event_listener(listener, listener_count) - event_listen_count -= listener - for(var/entry in all_observable_events.events) + GLOB.event_listen_count -= listener + for(var/entry in GLOB.all_observable_events.events) var/decl/observ/event = entry for(var/event_source in event.event_sources) if(event.unregister(event_source, listener)) diff --git a/code/game/gamemodes/technomancer/devices/hypos.dm b/code/game/gamemodes/technomancer/devices/hypos.dm index f5174c45e3..002b3cfff0 100644 --- a/code/game/gamemodes/technomancer/devices/hypos.dm +++ b/code/game/gamemodes/technomancer/devices/hypos.dm @@ -1,16 +1,3 @@ -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector - name = "empty hypo" - desc = "A refined version of the standard autoinjector, allowing greater capacity." - icon_state = "autoinjector" - amount_per_transfer_from_this = 15 - volume = 15 - origin_tech = list(TECH_BIO = 4) - filled_reagents = list("inaprovaline" = 15) - -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/New() - ..() - - /datum/technomancer/consumable/hypo_brute name = "Trauma Hypo" desc = "A extended capacity hypo which can treat blunt trauma." @@ -59,50 +46,3 @@ desc = "A extended capacity hypo containing a dangerous cocktail of various combat stims." cost = 75 obj_path = /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat - - -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute - name = "trauma hypo" - desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to be used on victims of \ - moderate blunt trauma." - filled_reagents = list("bicaridine" = 15) - -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn - name = "burn hypo" - desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to be used on burn victims, \ - featuring an optimized chemical mixture to allow for rapid healing." - filled_reagents = list("kelotane" = 7.5, "dermaline" = 7.5) - -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin - name = "toxin hypo" - desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to counteract toxins." - filled_reagents = list("anti_toxin" = 15) - -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy - name = "oxy hypo" - desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to counteract oxygen \ - deprivation." - filled_reagents = list("dexalinp" = 10, "tricordrazine" = 5) - -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity - name = "purity hypo" - desc = "A refined version of the standard autoinjector, allowing greater capacity. This variant excels at \ - resolving viruses, infections, radiation, and genetic maladies." - filled_reagents = list("spaceacillin" = 9, "arithrazine" = 5, "ryetalyn" = 1) - -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain - name = "pain hypo" - desc = "A refined version of the standard autoinjector, allowing greater capacity. This one contains potent painkillers." - filled_reagents = list("tramadol" = 15) - -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ - name = "organ hypo" - desc = "A refined version of the standard autoinjector, allowing greater capacity. Organ damage is resolved by this variant." - filled_reagents = list("alkysine" = 1, "imidazoline" = 1, "peridaxon" = 13) - -/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat - name = "combat hypo" - desc = "A refined version of the standard autoinjector, allowing greater capacity. This is a more dangerous and potentially \ - addictive hypo compared to others, as it contains a potent cocktail of various chemicals to optimize the recipient's combat \ - ability." - filled_reagents = list("bicaridine" = 3, "kelotane" = 1.5, "dermaline" = 1.5, "oxycodone" = 3, "hyperzine" = 3, "tricordrazine" = 3) diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index c153e37190..7809014b8e 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -5,7 +5,6 @@ desc = "Used to view, edit and maintain medical records." icon_keyboard = "med_key" icon_screen = "medcomp" - density = 0 //Why does a laptop blocks peoples. light_color = "#315ab4" req_one_access = list(access_medical, access_forensics_lockers, access_robotics) circuit = /obj/item/weapon/circuitboard/med_data @@ -554,3 +553,4 @@ icon_state = "laptop" icon_keyboard = "laptop_key" icon_screen = "medlaptop" + density = 0 diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm index fb92e700ff..a374d48c8c 100644 --- a/code/game/machinery/computer/skills.dm +++ b/code/game/machinery/computer/skills.dm @@ -9,6 +9,7 @@ light_color = "#00b000" req_one_access = list(access_heads) circuit = /obj/item/weapon/circuitboard/skills + density = 0 var/obj/item/weapon/card/id/scan = null var/authenticated = null var/rank = null diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index 0a54b148d1..86b0bfa622 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/stationobjs.dmi' icon_state = "doorctrl0" power_channel = ENVIRON + layer = ABOVE_WINDOW_LAYER var/desiredstate = 0 var/exposedwires = 0 var/wires = 3 diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm index ab8819f8da..13cc48c4c5 100644 --- a/code/game/machinery/doors/blast_door.dm +++ b/code/game/machinery/doors/blast_door.dm @@ -23,7 +23,7 @@ var/icon_state_closed = null var/icon_state_closing = null - closed_layer = 3.3 // Above airlocks when closed + closed_layer = ON_WINDOW_LAYER // Above airlocks when closed var/id = 1.0 dir = 1 explosion_resistance = 25 diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm index 672b0a2c4e..480e613c27 100644 --- a/code/game/machinery/washing_machine.dm +++ b/code/game/machinery/washing_machine.dm @@ -50,6 +50,7 @@ else state = 5 update_icon() + playsound(src, 'sound/items/washingmachine.ogg', 50, 1, 1) sleep(200) for(var/atom/A in washing) A.clean_blood() diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 95f5e72faa..3b1584ca19 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -250,4 +250,4 @@ var/global/list/image/splatter_cache=list() /obj/effect/decal/cleanable/mucus/mapped/New() ..() virus2 |= new /datum/disease2/disease - virus2.makerandom() + virus2[1].makerandom() diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 97d352c3d7..8d4b4928ac 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -410,25 +410,28 @@ HALOGEN COUNTER - Radcount on mobs var/details = 0 var/recent_fail = 0 -/obj/item/device/reagent_scanner/afterattack(obj/O, mob/user as mob, proximity) +/obj/item/device/reagent_scanner/afterattack(obj/O, mob/living/user, proximity) if(!proximity || user.stat || !istype(O)) return - if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") - to_chat(user, "You don't have the dexterity to do this!") + if(!istype(user)) return if(!isnull(O.reagents)) + if(!(O.flags & OPENCONTAINER)) // The idea is that the scanner has to touch the reagents somehow. This is done to prevent cheesing unidentified autoinjectors. + to_chat(user, span("warning", "\The [O] is sealed, and cannot be scanned by \the [src] until unsealed.")) + return + var/dat = "" if(O.reagents.reagent_list.len > 0) var/one_percent = O.reagents.total_volume / 100 for (var/datum/reagent/R in O.reagents.reagent_list) - dat += "\n \t [R][details ? ": [R.volume / one_percent]%" : ""]" + dat += "\n \t " + span("notice", "[R][details ? ": [R.volume / one_percent]%" : ""]") if(dat) - to_chat(user, "Chemicals found: [dat]") + to_chat(user, span("notice", "Chemicals found: [dat]")) else - to_chat(user, "No active chemical agents found in [O].") + to_chat(user, span("notice", "No active chemical agents found in [O].")) else - to_chat(user, "No significant chemical agents found in [O].") + to_chat(user, span("notice", "No significant chemical agents found in [O].")) return diff --git a/code/game/objects/random/unidentified/medicine.dm b/code/game/objects/random/unidentified/medicine.dm new file mode 100644 index 0000000000..4cd2d5652c --- /dev/null +++ b/code/game/objects/random/unidentified/medicine.dm @@ -0,0 +1,149 @@ +/* +Semi-randomized loot for PoIs involving medicine. +Note that most of these include both 'good' and 'bad' results, with the bad results often being +much more likely to show up. This is done for several purposes; + + * A large influx of valuable medicine makes medical/SAR less needed for explorers, which is something we want to avoid. + * Blindly using autoinjectors should be risky, and to accomplish that, it needs to be more likely to get a bad effect. + * A large amount of bad loot helps make the good loot feel better to acquire. + +*/ + +// This one makes a purely random hypo. Not recommended for PoIs since it will produce nonsensical results for a PoI's theme. +// It's more of a thing to help pick specific hypos for the other lists. +/obj/random/unidentified_medicine + name = "unidentified medicine" + desc = "This will make a random hypo." + icon = 'icons/obj/syringe.dmi' + item_state = "hypo" + +/obj/random/unidentified_medicine/item_to_spawn() + return pick( + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/stimm/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/space_drugs/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/serotrotium/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cryptobiolin/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mindbreaker/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/psilocybin/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/impedrezene/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified, + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified) + +// Produces things you might find in an old medicine cabinet in a PoI. +// Old cabinets are typical of ruins and abandoned buildings in the plains, meaning they're usually easier to reach, and as such, inferior loot. +/obj/random/unidentified_medicine/old_medicine/item_to_spawn() + // 30 Good, 70 Bad. 30% to get something good. + // Poor odds, but these are fairly easy to reach as they're in abandoned areas. + return pick( + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified, + prob(65);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified) + +// Medicine belonging to a place still being occupied (or was recently), meaning the goods might still be fresh, and better. +/obj/random/unidentified_medicine/fresh_medicine/item_to_spawn() + // More likely to get something good, and a chance to get rare medicines. + // 75 Good, 25 Bad. 75% chance of getting something good. + // Good odds, but the contents aren't super great unless someone gets lucky. + return pick( + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified, + prob(25);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified) + +// For military PoIs like BSD. High odds of good loot since those PoIs are really hard. +/obj/random/unidentified_medicine/combat_medicine/item_to_spawn() + // More likely to get something good, and a chance to get rare medicines. + // 75 Good, 30 Bad, roughly 71.4% chance to get something good. + // Very high but very hard to reach and still has a chance of ending poorly if injecting blind. + return pick( + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified, + prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified, + prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified) + +// Hyposprays found inside various illicit places. +/obj/random/unidentified_medicine/drug_den/item_to_spawn() + // Combat stims are common, but so are nasty drugs. + // 65 Good, 160 Bad, roughly 28.8% to get something good. + // Poor odds, but there are a lot of these scattered in the drug dens and illegal chem labs. + return pick( + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified, + prob(40);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified, + prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/stimm/unidentified, + prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/space_drugs/unidentified, + prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/serotrotium/unidentified, + prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cryptobiolin/unidentified, + prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mindbreaker/unidentified, + prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/psilocybin/unidentified, + prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/impedrezene/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified) + +// Medicine made FOR SCIENCE. +/obj/random/unidentified_medicine/scientific/item_to_spawn() + // Potential for amazing loot, also potential for very nasty consequences if injecting blind. + // 45 Good, 45 Bad, 50% chance to get something good. + // Do you feel lucky? + return pick( + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified, + prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified, + prob(5);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified) + +// Nanomachines, son. Found in very advanced places such as the Crashed UFO. +/obj/random/unidentified_medicine/nanites/item_to_spawn() + // You better identify this if you value your life. + // 30 Good, 70 Bad. 30% of getting a good outcome. + return pick( + prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified, + prob(70);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified) + +// Found in virus-related areas like the Quarantined Shuttle. +/obj/random/unidentified_medicine/viral/item_to_spawn() + // Another one where's its important to identify the hypo. + // 30 Good, 70 Bad. 30% of getting a good outcome. + return pick( + prob(30);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified, + prob(40);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified, + prob(10);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified, + prob(20);/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified) \ No newline at end of file diff --git a/code/game/objects/structures/loot_piles.dm b/code/game/objects/structures/loot_piles.dm index 17d1ca4984..ea92ed27f1 100644 --- a/code/game/objects/structures/loot_piles.dm +++ b/code/game/objects/structures/loot_piles.dm @@ -911,4 +911,28 @@ Loot piles can be depleted, if loot_depleted is turned on. Note that players wh /obj/item/borg/upgrade/tasercooler, /obj/item/borg/upgrade/syndicate, /obj/item/borg/upgrade/vtec - ) \ No newline at end of file + ) + +// Contains old mediciation, most of it unidentified and has a good chance of being useless. +/obj/structure/loot_pile/surface/medicine_cabinet + name = "abandoned medicine cabinet" + desc = "An old cabinet, it might still have something of use inside." + icon_state = "medicine_cabinet" + density = FALSE + chance_uncommon = 0 + chance_rare = 0 + + common_loot = list( + /obj/random/unidentified_medicine/old_medicine + ) + +// Like the above but has way better odds, in exchange for being in a place still inhabited (or was recently). +/obj/structure/loot_pile/surface/medicine_cabinet/fresh + name = "medicine cabinet" + desc = "A cabinet designed to hold medicine, it might still have something of use inside." + icon_state = "medicine_cabinet" + density = FALSE + + common_loot = list( + /obj/random/unidentified_medicine/fresh_medicine + ) \ No newline at end of file diff --git a/code/modules/admin/verbs/map_template_loadverb.dm b/code/modules/admin/verbs/map_template_loadverb.dm index d0504e0223..85147c275b 100644 --- a/code/modules/admin/verbs/map_template_loadverb.dm +++ b/code/modules/admin/verbs/map_template_loadverb.dm @@ -5,10 +5,10 @@ var/datum/map_template/template - var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in map_templates + var/map = input(usr, "Choose a Map Template to place at your CURRENT LOCATION","Place Map Template") as null|anything in SSmapping.map_templates if(!map) return - template = map_templates[map] + template = SSmapping.map_templates[map] var/orientation = text2dir(input(usr, "Choose an orientation for this Map Template.", "Orientation") as null|anything in list("North", "South", "East", "West")) if(!orientation) @@ -41,10 +41,10 @@ var/datum/map_template/template - var/map = input(usr, "Choose a Map Template to place on a new Z-level.","Place Map Template") as null|anything in map_templates + var/map = input(usr, "Choose a Map Template to place on a new Z-level.","Place Map Template") as null|anything in SSmapping.map_templates if(!map) return - template = map_templates[map] + template = SSmapping.map_templates[map] var/orientation = text2dir(input(usr, "Choose an orientation for this Map Template.", "Orientation") as null|anything in list("North", "South", "East", "West")) if(!orientation) @@ -76,7 +76,7 @@ var/datum/map_template/M = new(map, "[map]") if(M.preload_size(map)) to_chat(usr, "Map template '[map]' ready to place ([M.width]x[M.height])") - map_templates[M.name] = M + SSmapping.map_templates[M.name] = M message_admins("[key_name_admin(usr)] has uploaded a map template ([map])") else to_chat(usr, "Map template '[map]' failed to load properly") diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm index e0bef9fd29..0470d85566 100644 --- a/code/modules/client/preference_setup/loadout/loadout_suit.dm +++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm @@ -244,42 +244,34 @@ datum/gear/suit/duster /datum/gear/suit/roles/poncho/cloak/cargo display_name = "cloak, cargo" path = /obj/item/clothing/accessory/poncho/roles/cloak/cargo - allowed_roles = list("Cargo Technician","Quartermaster") /datum/gear/suit/roles/poncho/cloak/mining display_name = "cloak, mining" path = /obj/item/clothing/accessory/poncho/roles/cloak/mining - allowed_roles = list("Quartermaster","Shaft Miner") /datum/gear/suit/roles/poncho/cloak/security display_name = "cloak, security" path = /obj/item/clothing/accessory/poncho/roles/cloak/security - allowed_roles = list("Head of Security","Detective","Warden","Security Officer") /datum/gear/suit/roles/poncho/cloak/service display_name = "cloak, service" path = /obj/item/clothing/accessory/poncho/roles/cloak/service - allowed_roles = list("Head of Personnel","Bartender","Botanist","Janitor","Chef","Librarian") /datum/gear/suit/roles/poncho/cloak/engineer display_name = "cloak, engineer" path = /obj/item/clothing/accessory/poncho/roles/cloak/engineer - allowed_roles = list("Chief Engineer","Station Engineer") /datum/gear/suit/roles/poncho/cloak/atmos display_name = "cloak, atmos" path = /obj/item/clothing/accessory/poncho/roles/cloak/atmos - allowed_roles = list("Chief Engineer","Atmospheric Technician") /datum/gear/suit/roles/poncho/cloak/research display_name = "cloak, science" path = /obj/item/clothing/accessory/poncho/roles/cloak/research - allowed_roles = list("Research Director","Scientist", "Roboticist", "Xenobiologist") /datum/gear/suit/roles/poncho/cloak/medical display_name = "cloak, medical" path = /obj/item/clothing/accessory/poncho/roles/cloak/medical - allowed_roles = list("Medical Doctor","Chief Medical Officer","Chemist","Paramedic","Geneticist", "Psychiatrist") /datum/gear/suit/unathi_robe display_name = "roughspun robe" @@ -499,4 +491,4 @@ datum/gear/suit/duster /datum/gear/suit/snowsuit/cargo display_name = "snowsuit, supply" path = /obj/item/clothing/suit/storage/snowsuit/cargo - allowed_roles = list("Quartermaster","Shaft Miner","Cargo Technician","Head of Personnel") \ No newline at end of file + allowed_roles = list("Quartermaster","Shaft Miner","Cargo Technician","Head of Personnel") diff --git a/code/modules/error_handler/error_handler.dm b/code/modules/error_handler/error_handler.dm index db3843a8c9..6aa9070c82 100644 --- a/code/modules/error_handler/error_handler.dm +++ b/code/modules/error_handler/error_handler.dm @@ -1,7 +1,5 @@ -var/list/error_last_seen = list() // error_cooldown items will either be positive (cooldown time) or negative (silenced error) // If negative, starts at -1, and goes down by 1 each time that error gets skipped -var/list/error_cooldown = list() var/total_runtimes = 0 var/total_runtimes_skipped = 0 // The ifdef needs to be down here, since the error viewer references total_runtimes @@ -10,18 +8,18 @@ var/total_runtimes_skipped = 0 if(!istype(e)) // Something threw an unusual exception log_error("\[[time_stamp()]] Uncaught exception: [e]") return ..() - if(!error_last_seen) // A runtime is occurring too early in start-up initialization + if(!GLOB.error_last_seen) // A runtime is occurring too early in start-up initialization return ..() total_runtimes++ var/erroruid = "[e.file][e.line]" - var/last_seen = error_last_seen[erroruid] - var/cooldown = error_cooldown[erroruid] || 0 + var/last_seen = GLOB.error_last_seen[erroruid] + var/cooldown = GLOB.error_cooldown[erroruid] || 0 if(last_seen == null) // A new error! - error_last_seen[erroruid] = world.time + GLOB.error_last_seen[erroruid] = world.time last_seen = world.time if(cooldown < 0) - error_cooldown[erroruid]-- // Used to keep track of skip count for this error + GLOB.error_cooldown[erroruid]-- // Used to keep track of skip count for this error total_runtimes_skipped++ return // Error is currently silenced, skip handling it @@ -36,13 +34,13 @@ var/total_runtimes_skipped = 0 spawn(0) usr = null sleep(ERROR_SILENCE_TIME) - var/skipcount = abs(error_cooldown[erroruid]) - 1 - error_cooldown[erroruid] = 0 + var/skipcount = abs(GLOB.error_cooldown[erroruid]) - 1 + GLOB.error_cooldown[erroruid] = 0 if(skipcount > 0) log_error("\[[time_stamp()]] Skipped [skipcount] runtimes in [e.file],[e.line].") error_cache.logError(e, skipCount = skipcount) - error_last_seen[erroruid] = world.time - error_cooldown[erroruid] = cooldown + GLOB.error_last_seen[erroruid] = world.time + GLOB.error_cooldown[erroruid] = cooldown // The detailed error info needs some tweaking to make it look nice var/list/srcinfo = null diff --git a/code/modules/holomap/station_holomap.dm b/code/modules/holomap/station_holomap.dm index bb10f0d339..d38875f220 100644 --- a/code/modules/holomap/station_holomap.dm +++ b/code/modules/holomap/station_holomap.dm @@ -125,7 +125,7 @@ watching_mob = user GLOB.moved_event.register(watching_mob, src, /obj/machinery/station_map/proc/checkPosition) GLOB.dir_set_event.register(watching_mob, src, /obj/machinery/station_map/proc/checkPosition) - destroyed_event.register(watching_mob, src, /obj/machinery/station_map/proc/stopWatching) + GLOB.destroyed_event.register(watching_mob, src, /obj/machinery/station_map/proc/stopWatching) update_use_power(2) if(bogus) @@ -154,7 +154,7 @@ M.client.images -= holomap_datum.station_map GLOB.moved_event.unregister(watching_mob, src) GLOB.dir_set_event.unregister(watching_mob, src) - destroyed_event.unregister(watching_mob, src) + GLOB.destroyed_event.unregister(watching_mob, src) watching_mob = null update_use_power(1) diff --git a/code/modules/identification/identification.dm b/code/modules/identification/identification.dm new file mode 100644 index 0000000000..568ad2103e --- /dev/null +++ b/code/modules/identification/identification.dm @@ -0,0 +1,127 @@ +// This is a datum attached to objects to make their 'identity' be unknown initially. +// The identitiy and properties of an unidentified object can be determined in-game through a specialized process or by potentially risky trial-and-error. +// This is very similar to a traditional roguelike's identification system, and as such will use certain terms from those to describe them. +// Despite this, unlike a roguelike, objects that do the same thing DO NOT have the same name/appearance/etc. + +/datum/identification + var/obj/holder = null // The thing the datum is 'attached' to. + // Holds the true information. + var/true_name = null // The real name of the object. It is copied automatically from holder, on the datum being instantiated. + var/true_desc = null // Ditto, for desc. + var/true_description_info = null // Ditto, for helpful examine panel entries. + var/true_description_fluff = null // Ditto, for lore. + var/true_description_antag = null // Ditto, for antag info (this probably won't get used). + var/identified = IDENTITY_UNKNOWN // Can be IDENTITY_UNKNOWN, IDENTITY_PROPERTIES, IDENTITY_QUALITY, or IDENTITY_FULL. + + // Holds what is displayed when not identified sufficently. + var/unidentified_name = null // The name given to the object when not identified. Generated by generate_unidentified_name() + var/unidentified_desc = "You're not too sure what this is." + var/unidentified_description_info = "This object is unidentified, and as such its properties are unknown. Using this object may be dangerous." + + // Lists of lists for generating names by combining one from each. + var/list/naming_lists = list() + + // What 'identification type' is needed to identify this. + var/identification_type = IDENTITY_TYPE_NONE + +/datum/identification/New(obj/new_holder) + ASSERT(new_holder) + holder = new_holder + record_true_identity() // Get all the identifying features from the holder. + update_name() // Then hide them for awhile if needed. + +/datum/identification/Destroy() + holder = null + return ..() + +// Records the object's inital identifiying features to the datum for future safekeeping. +/datum/identification/proc/record_true_identity() + true_name = holder.name + true_desc = holder.desc + true_description_info = holder.description_info + true_description_fluff = holder.description_fluff + true_description_antag = holder.description_antag + +// Formally identifies the holder. +/datum/identification/proc/identify(new_identity = IDENTITY_FULL, mob/user) + if(new_identity & identified) // Already done. + return + identified |= new_identity // Set the bitflag. + if(user) + switch(identified) + if(IDENTITY_QUALITY) + to_chat(user, "You've identified \the [holder]'s quality.") + if(IDENTITY_PROPERTIES) + to_chat(user, "You've identified \the [holder]'s functionality as a [true_name].") + if(IDENTITY_FULL) + to_chat(user, "You've identified \the [holder] as a [true_name], and its quality.") + update_name() + holder.update_icon() + +// Reverses identification for whatever reason. +/datum/identification/proc/unidentify(new_identity = IDENTITY_UNKNOWN, mob/user) + identified &= ~new_identity // Unset the bitflag. + update_name() + holder.update_icon() + if(user) + switch(identified) // Give a message based on what's left. + if(IDENTITY_QUALITY) + to_chat(user, span("warning", "You forgot what \the [holder] actually did...")) + if(IDENTITY_PROPERTIES) + to_chat(user, span("warning", "You forgot \the [holder]'s quality...")) + if(IDENTITY_UNKNOWN) + to_chat(user, span("warning", "You forgot everything about \the [holder].")) + +// Sets the holder's name to the real name if its properties are identified, or obscures it otherwise. +/datum/identification/proc/update_name() + if(identified & IDENTITY_PROPERTIES) + holder.name = true_name + holder.desc = true_desc + holder.description_info = true_description_info + holder.description_fluff = true_description_fluff + holder.description_antag = true_description_antag + return + + if(!unidentified_name) + unidentified_name = generate_unidentified_name() + + holder.name = unidentified_name + holder.desc = unidentified_desc + holder.description_info = unidentified_description_info + holder.description_fluff = null + holder.description_antag = null + +// Makes a name for an object that is not identified. It picks one string out of each list inside naming_list. +/datum/identification/proc/generate_unidentified_name() + if(!LAZYLEN(naming_lists)) + return "unidentified object" + + var/list/new_name = list() + for(var/i in naming_lists) + var/list/current_list = i + new_name += pick(current_list) + return new_name.Join(" ") + +// Used for tech-based objects. +// Unused for now pending Future Stuff(tm). +/datum/identification/mechanical + naming_lists = list( + list("unidentified", "unknown", "strange", "weird", "unfamiliar", "peculiar", "mysterious", "bizarre", "odd"), + list("device", "apparatus", "gadget", "mechanism", "appliance", "machine", "equipment", "invention", "contraption") + ) + identification_type = IDENTITY_TYPE_TECH + +// Used for unidentified hypos. +// Their contents can range from genuine medication, expired medicine, illicit drugs, toxins and poisons, and more. +// They are the analog for potions in a traditional roguelike. +/datum/identification/hypo + naming_lists = list( + list("unidentified", "unknown", "unmarked", "blank", "refilled", "custom", "modified", "questionable", "suspicious"), + list("hypospray", "autoinjector") + ) + unidentified_desc = "An autoinjector that does not give any indication towards what is inside. \ + The case is also sealed tight and the liquids contained cannot be removed except by injecting it into someone. \ + Do you feel lucky?" + unidentified_description_info = "A skilled chemist with a specialized machine can identify this autoinjector. \ + Blindly using the autoinjector is risky and can be dangerous." + identification_type = IDENTITY_TYPE_CHEMICAL diff --git a/code/modules/identification/item_procs.dm b/code/modules/identification/item_procs.dm new file mode 100644 index 0000000000..c2e5ddaed6 --- /dev/null +++ b/code/modules/identification/item_procs.dm @@ -0,0 +1,30 @@ +// This is on the base /item so badmins can play with it by calling hide_identity(). +/obj/item + var/datum/identification/identity = null + var/identity_type = /datum/identification + var/init_hide_identity = FALSE // Set to true to automatically obscure the object on initialization. + +/obj/item/Initialize() + if(init_hide_identity) + identity = new identity_type(src) + return ..() + +/obj/item/Destroy() + if(identity) + QDEL_NULL(identity) + return ..() + +/obj/item/proc/hide_identity() // Mostly for admins to make things secret. + if(!identity) + identity = new identity_type(src) + else + identity.unidentify() + +/obj/item/proc/identify(identity_type = IDENTITY_FULL, mob/user) + if(identity) + identity.identify(identity_type, user) + +/obj/item/proc/is_identified(identity_type = IDENTITY_FULL) + if(!identity) // No identification datum means nothing to hide. + return TRUE + return identity_type & identity.identified diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm index 344a7dc47e..7bb9b332d1 100644 --- a/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -188,14 +188,14 @@ // These procs do not relocate the grenade, that's the callers responsibility /obj/item/integrated_circuit/manipulation/grenade/proc/attach_grenade(var/obj/item/weapon/grenade/G) attached_grenade = G - destroyed_event.register(attached_grenade, src, /obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade) + GLOB.destroyed_event.register(attached_grenade, src, /obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade) size += G.w_class desc += " \An [attached_grenade] is attached to it!" /obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade() if(!attached_grenade) return - destroyed_event.unregister(attached_grenade, src, /obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade) + GLOB.destroyed_event.unregister(attached_grenade, src, /obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade) attached_grenade = null size = initial(size) desc = initial(desc) diff --git a/code/modules/integrated_electronics/subtypes/output.dm b/code/modules/integrated_electronics/subtypes/output.dm index 99a6c247a9..1026ba2633 100644 --- a/code/modules/integrated_electronics/subtypes/output.dm +++ b/code/modules/integrated_electronics/subtypes/output.dm @@ -300,7 +300,7 @@ text_output += "\an [name]" else text_output += "\an ["\improper[initial_name]"] labeled '[name]'" - text_output += " which is currently [get_pin_data(IC_INPUT, 1) ? "lit ¤" : "unlit."]" + text_output += " which is currently [get_pin_data(IC_INPUT, 1) ? "lit ¤" : "unlit."]" to_chat(user,jointext(text_output,null)) /obj/item/integrated_circuit/output/led/red @@ -462,8 +462,7 @@ /obj/item/integrated_circuit/output/holographic_projector/proc/destroy_hologram() - hologram.forceMove(src) - qdel(hologram) + QDEL_NULL(hologram) // holo_beam.End() // qdel_null(holo_beam) diff --git a/code/modules/maps/tg/map_template.dm b/code/modules/maps/tg/map_template.dm index d20daf1989..8a601163d0 100644 --- a/code/modules/maps/tg/map_template.dm +++ b/code/modules/maps/tg/map_template.dm @@ -1,15 +1,3 @@ -var/list/global/map_templates = list() - -// Called when the world starts, in world.dm -/proc/load_map_templates() - for(var/T in subtypesof(/datum/map_template)) - var/datum/map_template/template = T - if(!(initial(template.mappath))) // If it's missing the actual path its probably a base type or being used for inheritence. - continue - template = new T() - map_templates[template.name] = template - return TRUE - /datum/map_template var/name = "Default Template Name" var/desc = "Some text should go here. Maybe." @@ -27,8 +15,6 @@ var/list/global/map_templates = list() var/allow_duplicates = FALSE // If false, only one map template will be spawned by the game. Doesn't affect admins spawning then manually. var/discard_prob = 0 // If non-zero, there is a chance that the map seeding algorithm will skip this template when selecting potential templates to use. - var/static/dmm_suite/maploader = new - /datum/map_template/New(path = null, rename = null) if(path) mappath = path @@ -39,7 +25,7 @@ var/list/global/map_templates = list() name = rename /datum/map_template/proc/preload_size(path, orientation = SOUTH) - var/bounds = maploader.load_map(file(path), 1, 1, 1, cropMap=FALSE, measureOnly=TRUE, orientation=orientation) + var/bounds = SSmapping.maploader.load_map(file(path), 1, 1, 1, cropMap=FALSE, measureOnly=TRUE, orientation=orientation) if(bounds) width = bounds[MAP_MAXX] // Assumes all templates are rectangular, have a single Z level, and begin at 1,1,1 height = bounds[MAP_MAXY] @@ -91,7 +77,7 @@ var/list/global/map_templates = list() x = round((world.maxx - width)/2) y = round((world.maxy - height)/2) - var/list/bounds = maploader.load_map(file(mappath), x, y, no_changeturf = TRUE, orientation=orientation) + var/list/bounds = SSmapping.maploader.load_map(file(mappath), x, y, no_changeturf = TRUE, orientation=orientation) if(!bounds) return FALSE @@ -116,7 +102,7 @@ var/list/global/map_templates = list() if(annihilate) annihilate_bounds(old_T, centered, orientation) - var/list/bounds = maploader.load_map(file(mappath), T.x, T.y, T.z, cropMap=TRUE, orientation = orientation) + var/list/bounds = SSmapping.maploader.load_map(file(mappath), T.x, T.y, T.z, cropMap=TRUE, orientation = orientation) if(!bounds) return @@ -175,8 +161,8 @@ var/list/global/map_templates = list() var/list/priority_submaps = list() // Submaps that will always be placed. // Lets go find some submaps to make. - for(var/map in map_templates) - var/datum/map_template/MT = map_templates[map] + for(var/map in SSmapping.map_templates) + var/datum/map_template/MT = SSmapping.map_templates[map] if(!MT.allow_duplicates && MT.loaded > 0) // This probably won't be an issue but we might as well. continue if(!istype(MT, desired_map_template_type)) // Not the type wanted. diff --git a/code/modules/mob/_modifiers/modifiers_misc.dm b/code/modules/mob/_modifiers/modifiers_misc.dm index af5be943d1..1f21bb0c60 100644 --- a/code/modules/mob/_modifiers/modifiers_misc.dm +++ b/code/modules/mob/_modifiers/modifiers_misc.dm @@ -181,6 +181,23 @@ the artifact triggers the rage. accuracy_dispersion = 3 // Ditto. evasion = -45 // Too angry to dodge. +// Non-cult version of deep wounds. +// Surprisingly, more dangerous. +/datum/modifier/grievous_wounds + name = "grievous wounds" + desc = "Your wounds are not easily mended." + + on_created_text = "Your wounds pain you greatly." + on_expired_text = "The pain lulls." + + stacks = MODIFIER_STACK_EXTEND + + incoming_healing_percent = 0.50 // 50% less healing. + disable_duration_percent = 1.22 // 22% longer disables. + bleeding_rate_percent = 1.20 // 20% more bleeding. + + accuracy_dispersion = 2 // A combination of fear and immense pain or damage reults in a twitching firing arm. Flee. + diff --git a/code/modules/projectiles/effects.dm b/code/modules/projectiles/effects.dm index da21427eff..856633ccd3 100644 --- a/code/modules/projectiles/effects.dm +++ b/code/modules/projectiles/effects.dm @@ -288,4 +288,25 @@ icon_state = "impact_invert" light_range = 2 light_power = -2 - light_color = "#FFFFFF" \ No newline at end of file + light_color = "#FFFFFF" + +//---------------------------- +// Magnetohydronamic Howitzer +//---------------------------- +/obj/effect/projectile/tungsten/tracer + icon_state = "mhd_laser" + light_range = 4 + light_power = 3 + light_color = "#3300ff" + +/obj/effect/projectile/tungsten/muzzle + icon_state = "muzzle_mhd_laser" + light_range = 4 + light_power = 3 + light_color = "#3300ff" + +/obj/effect/projectile/tungsten/impact + icon_state = "impact_mhd_laser" + light_range = 4 + light_power = 3 + light_color = "#3300ff" \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 4d0f014c93..011469ae4e 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -8,6 +8,7 @@ var/obj/item/weapon/cell/power_supply //What type of power cell this uses var/charge_cost = 240 //How much energy is needed to fire. + var/accept_cell_type = /obj/item/weapon/cell/device var/cell_type = /obj/item/weapon/cell/device/weapon projectile_type = /obj/item/projectile/beam/practice @@ -89,13 +90,13 @@ if(self_recharge || battery_lock) user << "[src] does not have a battery port." return - if(istype(C, /obj/item/weapon/cell/device)) - var/obj/item/weapon/cell/device/P = C + if(istype(C, accept_cell_type)) + var/obj/item/weapon/cell/P = C if(power_supply) user << "[src] already has a power cell." else user.visible_message("[user] is reloading [src].", "You start to insert [P] into [src].") - if(do_after(user, 10)) + if(do_after(user, 5 * P.w_class)) user.remove_from_mob(P) power_supply = P P.loc = src @@ -175,6 +176,13 @@ icon_state = "[modifystate][ratio]" else icon_state = "[initial(icon_state)][ratio]" + + else if(power_supply) + if(modifystate) + icon_state = "[modifystate]" + else + icon_state = "[initial(icon_state)]" + if(!ignore_inhands) update_held_icon() /obj/item/weapon/gun/energy/proc/start_recharge() diff --git a/code/modules/projectiles/guns/energy/hooklauncher.dm b/code/modules/projectiles/guns/energy/hooklauncher.dm new file mode 100644 index 0000000000..dbb74c775a --- /dev/null +++ b/code/modules/projectiles/guns/energy/hooklauncher.dm @@ -0,0 +1,40 @@ +/* + * Contains weapons primarily using the 'grappling hook' projectiles. + */ + +/obj/item/weapon/gun/energy/hooklauncher + name = "gravity whip" + desc = "A large, strange gauntlet." + icon_state = "gravwhip" + item_state = "gravwhip" + fire_sound = 'sound/effects/zzzt.ogg' + fire_sound_text = "laser blast" + + fire_delay = 15 + charge_cost = 300 + + cell_type = /obj/item/weapon/cell/device/weapon + projectile_type = /obj/item/projectile/energy/hook + +// An easily concealable not-ripoff version. It would be silenced, if it didn't make it blatant you're the one using it. + +/obj/item/weapon/gun/energy/hooklauncher/ring + name = "ominous ring" + desc = "A small ring with strange symbols engraved upon it." + icon = 'icons/obj/clothing/rings.dmi' + icon_state = "seal-signet" + item_state = "concealed" + + w_class = ITEMSIZE_TINY + + cell_type = /obj/item/weapon/cell/device/weapon/recharge/alien + battery_lock = TRUE + charge_cost = 400 + charge_meter = FALSE + + projectile_type = /obj/item/projectile/energy/hook/ring + + firemodes = list( + list(mode_name="manipulate", fire_delay=15, projectile_type=/obj/item/projectile/energy/hook/ring, charge_cost = 400), + list(mode_name="battle", fire_delay=8, projectile_type=/obj/item/projectile/beam/xray, charge_cost = 260), + ) diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 5cfefc1bf5..3c83134126 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -151,6 +151,42 @@ toggle_scope(2.0) +/obj/item/weapon/gun/energy/monorifle + name = "antique mono-rifle" + desc = "An old laser rifle. This one can only fire once before requiring recharging." + description_fluff = "Modeled after ancient hunting rifles, this rifle was dubbed the 'Rainy Day Special' by some, due to its use as some barmens' fight-stopper of choice. One shot is all it takes, or so they say." + icon_state = "eshotgun" + item_state = "shotgun" + fire_sound = 'sound/weapons/gauss_shoot.ogg' + origin_tech = list(TECH_COMBAT = 6, TECH_MATERIAL = 4, TECH_POWER = 3) + projectile_type = /obj/item/projectile/beam/sniper + slot_flags = SLOT_BACK + charge_cost = 1300 + fire_delay = 20 + force = 8 + w_class = ITEMSIZE_LARGE + accuracy = 10 + scoped_accuracy = 15 + var/scope_multiplier = 1.5 + +/obj/item/weapon/gun/energy/monorifle/verb/sights() + set category = "Object" + set name = "Aim Down Sights" + set popup_menu = 1 + + toggle_scope(scope_multiplier) + +/obj/item/weapon/gun/energy/monorifle/combat + name = "combat mono-rifle" + desc = "A modernized version of the mono-rifle. This one can fire twice before requiring recharging." + description_fluff = "A modern design produced by a company once working from Saint Columbia, based on the antique mono-rifle 'Rainy Day Special' design." + icon_state = "ecshotgun" + item_state = "cshotgun" + charge_cost = 1000 + force = 12 + accuracy = 0 + scoped_accuracy = 20 + ////////Laser Tag//////////////////// /obj/item/weapon/gun/energy/lasertag diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 7bd20cdcef..51d4d6c2a1 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -186,6 +186,7 @@ obj/item/weapon/gun/energy/staff/focus desc = "A massive weapon designed to pressure the opposition by raining down a torrent of energy pellets." icon_state = "dakkalaser" item_state = "dakkalaser" + wielded_item_state = "dakkalaser-wielded" fire_sound = 'sound/weapons/Laser.ogg' w_class = ITEMSIZE_HUGE charge_cost = 24 // 100 shots, it's a spray and pray (to RNGesus) weapon. @@ -200,4 +201,94 @@ obj/item/weapon/gun/energy/staff/focus list(mode_name="single shot", burst = 1, burst_accuracy = list(75), dispersion = list(0), charge_cost = 24), list(mode_name="five shot burst", burst = 5, burst_accuracy = list(75,75,75,75,75), dispersion = list(1,1,1,1,1)), list(mode_name="ten shot burst", burst = 10, burst_accuracy = list(75,75,75,75,75,75,75,75,75,75), dispersion = list(2,2,2,2,2,2,2,2,2,2)), - ) \ No newline at end of file + ) + +/obj/item/weapon/gun/energy/maghowitzer + name = "portable MHD howitzer" + desc = "A massive weapon designed to destroy fortifications with a stream of molten tungsten." + description_fluff = "A weapon designed by joint cooperation of NanoTrasen, Hephaestus, and SCG scientists. Everything else is red tape and black highlighters." + description_info = "This weapon requires a wind-up period before being able to fire. Clicking on a target will create a beam between you and its turf, starting the timer. Upon completion, it will fire at the designated location." + icon_state = "mhdhowitzer" + item_state = "mhdhowitzer" + wielded_item_state = "mhdhowitzer-wielded" + fire_sound = 'sound/weapons/emitter2.ogg' + w_class = ITEMSIZE_HUGE + + charge_cost = 10000 // Uses large cells, can at max have 3 shots. + projectile_type = /obj/item/projectile/beam/tungsten + cell_type = /obj/item/weapon/cell/high + accept_cell_type = /obj/item/weapon/cell + + accuracy = 75 + charge_meter = 0 + one_handed_penalty = 30 + + var/power_cycle = FALSE + +/obj/item/weapon/gun/energy/maghowitzer/proc/pick_random_target(var/turf/T) + var/foundmob = FALSE + var/foundmobs = list() + for(var/mob/living/L in T.contents) + foundmob = TRUE + foundmobs += L + if(foundmob) + var/return_target = pick(foundmobs) + return return_target + return FALSE + +/obj/item/weapon/gun/energy/maghowitzer/attack(atom/A, mob/living/user, def_zone) + if(power_cycle) + to_chat(user, "\The [src] is already powering up!") + return 0 + var/turf/target_turf = get_turf(A) + var/beameffect = user.Beam(target_turf,icon_state="sat_beam",icon='icons/effects/beam.dmi',time=31, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=3) + if(beameffect) + user.visible_message("[user] aims \the [src] at \the [A].") + if(power_supply && power_supply.charge >= charge_cost) //Do a delay for pointblanking too. + power_cycle = TRUE + if(do_after(user, 30)) + if(A.loc == target_turf) + ..(A, user, def_zone) + else + var/rand_target = pick_random_target(target_turf) + if(rand_target) + ..(rand_target, user, def_zone) + else + ..(target_turf, user, def_zone) + else + if(beameffect) + qdel(beameffect) + power_cycle = FALSE + else + ..(A, user, def_zone) //If it can't fire, just bash with no delay. + +/obj/item/weapon/gun/energy/maghowitzer/afterattack(atom/A, mob/living/user, adjacent, params) + if(power_cycle) + to_chat(user, "\The [src] is already powering up!") + return 0 + + var/turf/target_turf = get_turf(A) + + var/beameffect = user.Beam(target_turf,icon_state="sat_beam",icon='icons/effects/beam.dmi',time=31, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=3) + + if(beameffect) + user.visible_message("[user] aims \the [src] at \the [A].") + + if(!power_cycle) + power_cycle = TRUE + if(do_after(user, 30)) + if(A.loc == target_turf) + ..(A, user, adjacent, params) + else + var/rand_target = pick_random_target(target_turf) + if(rand_target) + ..(rand_target, user, adjacent, params) + else + ..(target_turf, user, adjacent, params) + else + if(beameffect) + qdel(beameffect) + handle_click_empty(user) + power_cycle = FALSE + else + to_chat(user, "\The [src] is already powering up!") diff --git a/code/modules/projectiles/guns/magnetic/bore.dm b/code/modules/projectiles/guns/magnetic/bore.dm new file mode 100644 index 0000000000..e27fdc38d6 --- /dev/null +++ b/code/modules/projectiles/guns/magnetic/bore.dm @@ -0,0 +1,141 @@ +/obj/item/weapon/gun/magnetic/matfed + name = "portable phoron bore" + desc = "A large man-portable tunnel bore, using phorogenic plasma blasts. Point away from user." + description_fluff = "An aging Grayson Manufactories mining tool used for rapidly digging through rock. Mass production was discontinued when many of the devices were stolen and used to break into a high security facility by Boiling Point drones." + description_antag = "This device is exceptional at breaking down walls, though it is incredibly loud when doing so." + description_info = "The projectile of this tool will travel six tiles before dissipating, excavating mineral walls as it does so. It can be reloaded with phoron sheets." + + icon_state = "bore" + item_state = "bore" + wielded_item_state = "bore-wielded" + one_handed_penalty = 5 + + projectile_type = /obj/item/projectile/bullet/magnetic/bore + + gun_unreliable = 0 + + power_cost = 750 + load_type = /obj/item/stack/material + var/mat_storage = 0 // How much material is stored inside? Input in multiples of 2000 as per auto/protolathe. + var/max_mat_storage = 8000 // How much material can be stored inside? + var/mat_cost = 500 // How much material is used per-shot? + var/ammo_material = MAT_PHORON + var/loading = FALSE + +/obj/item/weapon/gun/magnetic/matfed/examine(mob/user) + . = ..() + show_ammo(user) + +/obj/item/weapon/gun/magnetic/matfed/update_icon() + var/list/overlays_to_add = list() + if(removable_components) + if(cell) + overlays_to_add += image(icon, "[icon_state]_cell") + if(capacitor) + overlays_to_add += image(icon, "[icon_state]_capacitor") + if(!cell || !capacitor) + overlays_to_add += image(icon, "[icon_state]_red") + else if(capacitor.charge < power_cost) + overlays_to_add += image(icon, "[icon_state]_amber") + else + overlays_to_add += image(icon, "[icon_state]_green") + if(mat_storage) + overlays_to_add += image(icon, "[icon_state]_loaded") + + overlays = overlays_to_add + ..() +/obj/item/weapon/gun/magnetic/matfed/attack_hand(var/mob/user) // It doesn't keep a loaded item inside. + if(user.get_inactive_hand() == src) + var/obj/item/removing + + if(cell && removable_components) + removing = cell + cell = null + + if(removing) + removing.forceMove(get_turf(src)) + user.put_in_hands(removing) + user.visible_message("\The [user] removes \the [removing] from \the [src].") + playsound(loc, 'sound/machines/click.ogg', 10, 1) + update_icon() + return + . = ..() + +/obj/item/weapon/gun/magnetic/matfed/check_ammo() + if(mat_storage - mat_cost >= 0) + return TRUE + return FALSE + +/obj/item/weapon/gun/magnetic/matfed/use_ammo() + mat_storage -= mat_cost + +/obj/item/weapon/gun/magnetic/matfed/show_ammo(var/mob/user) + if(mat_storage) + to_chat(user, "It has [mat_storage] out of [max_mat_storage] units of [ammo_material] loaded.") + +/obj/item/weapon/gun/magnetic/matfed/attackby(var/obj/item/thing, var/mob/user) + if(removable_components) + if(istype(thing, /obj/item/weapon/cell)) + if(cell) + to_chat(user, "\The [src] already has \a [cell] installed.") + return + cell = thing + user.drop_from_inventory(cell) + cell.forceMove(src) + playsound(loc, 'sound/machines/click.ogg', 10, 1) + user.visible_message("\The [user] slots \the [cell] into \the [src].") + update_icon() + return + + if(thing.is_screwdriver()) + if(!capacitor) + to_chat(user, "\The [src] has no capacitor installed.") + return + capacitor.forceMove(get_turf(src)) + user.put_in_hands(capacitor) + user.visible_message("\The [user] unscrews \the [capacitor] from \the [src].") + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + capacitor = null + update_icon() + return + + if(istype(thing, /obj/item/weapon/stock_parts/capacitor)) + if(capacitor) + to_chat(user, "\The [src] already has \a [capacitor] installed.") + return + capacitor = thing + user.drop_from_inventory(capacitor) + capacitor.forceMove(src) + playsound(loc, 'sound/machines/click.ogg', 10, 1) + power_per_tick = (power_cost*0.15) * capacitor.rating + user.visible_message("\The [user] slots \the [capacitor] into \the [src].") + update_icon() + return + + if(istype(thing, load_type)) + loading = TRUE + var/obj/item/stack/material/M = thing + + if(!M.material || M.material.name != ammo_material) + return + + if(mat_storage + 2000 > max_mat_storage) + to_chat(user, "\The [src] cannot hold more [ammo_material].") + return + + var/can_hold_val = 0 + while(can_hold_val < round(max_mat_storage / 2000)) + if(mat_storage + 2000 <= max_mat_storage && do_after(user,1.5 SECONDS)) + can_hold_val ++ + mat_storage += 2000 + playsound(loc, 'sound/effects/phasein.ogg', 15, 1) + else + loading = FALSE + break + M.use(can_hold_val) + + user.visible_message("\The [user] loads \the [src] with \the [M].") + playsound(loc, 'sound/weapons/flipblade.ogg', 50, 1) + update_icon() + return + . = ..() diff --git a/code/modules/projectiles/projectile/hook.dm b/code/modules/projectiles/projectile/hook.dm new file mode 100644 index 0000000000..ef8e9bc7c6 --- /dev/null +++ b/code/modules/projectiles/projectile/hook.dm @@ -0,0 +1,192 @@ +/* + * File containing special 'hook' projectiles. Function is dictated by the launcher's intent. + */ + +/obj/item/projectile/energy/hook + name = "graviton sphere" + icon_state = "bluespace" + + var/beam_state = "b_beam" + + damage = 5 + step_delay = 2 + damage_type = BURN + check_armour = "energy" + armor_penetration = 15 + + var/impact_sound = 'sound/effects/uncloak.ogg' + var/crack_sound = 'sound/effects/teleport.ogg' + + var/target_distance = null // Shamelessly stolen from arcing projectiles. + var/my_tracking_beam = null // Beam made by the launcher. Tracked here to destroy it in time with the impact. + var/launcher_intent = null // Stores the launcher's intent. + + var/disarm_chance = 60 // Chance for a successful disarm hit. The inverse is a throw away from the firer. + + var/list/help_messages = list("slaps", "pokes", "nudges", "bumps", "pinches") + var/done_mob_unique = FALSE // Has the projectile already done something to a mob? + +/obj/item/projectile/energy/hook/launch(atom/target, target_zone, x_offset=0, y_offset=0, angle_offset=0) + var/expected_distance = get_dist(target, loc) + kill_count = expected_distance // So the hook hits the ground if no mob is hit. + target_distance = expected_distance + if(firer) // Needed to ensure later checks in impact and on hit function. + launcher_intent = firer.a_intent + firer.Beam(src,icon_state=beam_state,icon='icons/effects/beam.dmi',time=60, maxdistance=10,beam_type=/obj/effect/ebeam,beam_sleep_time=1) + + if(launcher_intent) + switch(launcher_intent) + if(I_HURT) + check_armour = "bullet" + damage *= 3 + sharp = 1 + agony = 20 + if(I_GRAB) + check_armour = "melee" + damage_type = HALLOSS + if(I_DISARM) + check_armour = "melee" + if(prob(30)) // A chance for a successful hit to either knock someone down, or cause minor disorientation. + weaken = 1 + else + stun = 2 + eyeblur = 3 + if(I_HELP) + silenced = 1 + damage_type = HALLOSS + + ..() // Does the regular launching stuff. + +/obj/item/projectile/energy/hook/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null) + if(..()) + perform_intent_unique(target) + +/obj/item/projectile/energy/hook/on_impact(var/atom/A) + perform_intent_unique(get_turf(A)) + +/obj/item/projectile/energy/hook/proc/ranged_disarm(var/mob/living/carbon/human/H) + if(istype(H)) + var/list/holding = list(H.get_active_hand() = 60, H.get_inactive_hand() = 40) + + for(var/obj/item/weapon/gun/W in holding) // Guns are complex devices, both of a mechanical and electronic nature. A weird gravity ball or other type of object trying to pull or grab it is likely not safe. + if(W && prob(holding[W])) + var/list/turfs = list() + for(var/turf/T in view()) + turfs += T + if(turfs.len) + var/turf/target = pick(turfs) + visible_message("[H]'s [W] goes off due to \the [src]!") + return W.afterattack(target,H) + + if(!(H.species.flags & NO_SLIP) && prob(50)) + var/armor_check = H.run_armor_check(def_zone, "melee") + H.apply_effect(3, WEAKEN, armor_check) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + if(armor_check < 60) + visible_message("\The [src] has pushed [H]!") + else + visible_message("\The [src] attempted to push [H]!") + return + + else + if(H.break_all_grabs(firer)) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return + + for(var/obj/item/I in holding) + if(I) + H.drop_from_inventory(I) + visible_message("\The [src] has disarmed [H]!") + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + return + + +/obj/item/projectile/energy/hook/proc/perform_intent_unique(atom/target) + playsound(src.loc, impact_sound, 40, 1) + var/success = FALSE + if(istype(target,/turf)) + if(launcher_intent) + if(launcher_intent != I_HELP && !done_mob_unique) + var/target_mob = pick(/mob/living in target.contents) + + if(!target_mob) + return + + if(Bump(target_mob, forced=1)) //If we hit a turf, try to force an interaction with a mob on the turf. + done_mob_unique = TRUE + success = TRUE + else if(firer) + var/obj/T + + if(original in target.contents && istype(original, /obj)) + T = original + + var/list/possible_targets = list() + for(var/obj/item/I in target.contents) + if(!I.anchored) + possible_targets += I + for(var/obj/structure/S in target.contents) + if(!S.anchored) + possible_targets += S + + if(!T) + if(!possible_targets || !possible_targets.len) + return + T = pick(possible_targets) + + spawn(2) + playsound(target, crack_sound, 40, 1) + visible_message("\The [T] is snatched by \the [src]!") + T.throw_at(get_turf(firer), 7, 1, src) + success = TRUE + else if(isliving(target) && !done_mob_unique) + var/mob/living/L = target + if(launcher_intent) + switch(launcher_intent) + if(I_HELP) + var/message = pick(help_messages) + if(message == "slaps") + spawn(1) + playsound(loc, 'sound/effects/snap.ogg', 50, 1) + visible_message("\The [src] [message] [target].") + done_mob_unique = TRUE + success = TRUE + if(I_HURT) + if(prob(10) && istype(L, /mob/living/carbon/human)) + to_chat(L, "\The [src] rips at your hands!") + ranged_disarm(L) + success = TRUE + done_mob_unique = TRUE + if(I_DISARM) + if(prob(disarm_chance) && istype(L, /mob/living/carbon/human)) + ranged_disarm(L) + else + L.visible_message("\The [src] sends \the [L] stumbling backwards.") + L.throw_at(get_turf(get_step(L,get_dir(firer,L))), 1, 1, src) + done_mob_unique = TRUE + success = TRUE + if(I_GRAB) + var/turf/STurf = get_turf(L) + spawn(2) + playsound(STurf, crack_sound, 60, 1) + L.visible_message("\The [src] rips [L] towards \the [firer]!") + L.throw_at(get_turf(get_step(firer,get_dir(firer,L))), 6, 1, src) + done_mob_unique = TRUE + success = TRUE + else if(istype(target, /obj/structure)) + var/obj/structure/S = target + if(!S.anchored) + S.throw_at(get_turf(get_step(firer,get_dir(firer,S))), 4, 1, src) + success = TRUE + qdel(my_tracking_beam) + return success + +/* + * Hook subtypes. + */ + +/obj/item/projectile/energy/hook/ring + name = "green orb" + icon_state = "green_laser" + beam_state = "n_beam" + damage = 3 diff --git a/code/modules/projectiles/projectile/magnetic.dm b/code/modules/projectiles/projectile/magnetic.dm index ed16ea208d..1d8182aaea 100644 --- a/code/modules/projectiles/projectile/magnetic.dm +++ b/code/modules/projectiles/projectile/magnetic.dm @@ -116,4 +116,29 @@ return ..(target, blocked, def_zone) /obj/item/projectile/bullet/magnetic/fuelrod/supermatter/check_penetrate() - return 1 \ No newline at end of file + return 1 + +/obj/item/projectile/bullet/magnetic/bore + name = "phorogenic blast" + icon_state = "purpleemitter" + damage = 20 + incendiary = 1 + armor_penetration = 20 + penetrating = 0 + check_armour = "melee" + irradiate = 20 + kill_count = 6 + +/obj/item/projectile/bullet/magnetic/bore/Bump(atom/A, forced=0) + if(istype(A, /turf/simulated/mineral)) + var/turf/simulated/mineral/MI = A + loc = get_turf(A) // Careful. + permutated.Add(A) + MI.GetDrilled(TRUE) + return 0 + else if(istype(A, /turf/simulated/wall) || istype(A, /turf/simulated/shuttle/wall)) // Cause a loud, but relatively minor explosion on the wall it hits. + explosion(A, -1, -1, 1, 3) + qdel(src) + return 1 + else + ..() diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index 2e27d125ef..b60c82e11d 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -257,3 +257,82 @@ visible_message("\The [src] splatters a layer of web on \the [target]!") new /obj/effect/spider/stickyweb(target.loc) ..() + +/obj/item/projectile/beam/tungsten + name = "core of molten tungsten" + icon_state = "energy" + fire_sound = 'sound/weapons/emitter2.ogg' + pass_flags = PASSTABLE | PASSGRILLE + damage = 70 + damage_type = BURN + check_armour = "laser" + light_range = 4 + light_power = 3 + light_color = "#3300ff" + + muzzle_type = /obj/effect/projectile/tungsten/muzzle + tracer_type = /obj/effect/projectile/tungsten/tracer + impact_type = /obj/effect/projectile/tungsten/impact + +/obj/item/projectile/beam/tungsten/on_hit(var/atom/target, var/blocked = 0) + if(isliving(target)) + var/mob/living/L = target + L.add_modifier(/datum/modifier/grievous_wounds, 30 SECONDS) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + + var/target_armor = H.getarmor(def_zone, check_armour) + var/obj/item/organ/external/target_limb = H.get_organ(def_zone) + + var/armor_special = 0 + + if(target_armor >= 60) + var/turf/T = get_step(H, pick(alldirs - src.dir)) + H.throw_at(T, 1, 1, src) + H.apply_damage(20, BURN, def_zone) + if(target_limb) + armor_special = 2 + target_limb.fracture() + + else if(target_armor >= 45) + H.apply_damage(15, BURN, def_zone) + if(target_limb) + armor_special = 1 + target_limb.dislocate() + + else if(target_armor >= 30) + H.apply_damage(10, BURN, def_zone) + if(prob(30) && target_limb) + armor_special = 1 + target_limb.dislocate() + + else if(target_armor >= 15) + H.apply_damage(5, BURN, def_zone) + if(prob(15) && target_limb) + armor_special = 1 + target_limb.dislocate() + + if(armor_special > 1) + target.visible_message("\The [src] slams into \the [target]'s [target_limb], reverberating loudly!") + + else if(armor_special) + target.visible_message("\The [src] slams into \the [target]'s [target_limb] with a low rumble!") + + ..() + +/obj/item/projectile/beam/tungsten/on_impact(var/atom/A) + if(istype(A,/turf/simulated/shuttle/wall) || istype(A,/turf/simulated/wall) || (istype(A,/turf/simulated/mineral) && A.density) || istype(A,/obj/mecha) || istype(A,/obj/machinery/door)) + var/blast_dir = src.dir + A.visible_message("\The [A] begins to glow!") + spawn(2 SECONDS) + var/blastloc = get_step(A, blast_dir) + if(blastloc) + explosion(blastloc, -1, -1, 2, 3) + ..() + +/obj/item/projectile/beam/tungsten/Bump(atom/A, forced=0) + if(istype(A, /obj/structure/window)) //It does not pass through windows. It pulverizes them. + var/obj/structure/window/W = A + W.shatter() + return 0 + ..() diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index e3fe4415b5..8bf4e4e910 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -32,7 +32,7 @@ /obj/machinery/chem_master/New() ..() - var/datum/reagents/R = new/datum/reagents(900) //Just a huge random number so the buffer should (probably) never dump your reagents. + var/datum/reagents/R = new/datum/reagents(900) //Just a huge random number so the buffer should (probably) never dump your reagents. reagents = R //There should be a nano ui thingy to warn of this. R.my_atom = src @@ -544,3 +544,65 @@ qdel(O) if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) break + + +/////////////// +/////////////// +// Detects reagents inside most containers, and acts as an infinite identification system for reagent-based unidentified objects. + +/obj/machinery/chemical_analyzer + name = "chem analyzer" + desc = "Used to precisely scan chemicals and other liquids inside various containers. \ + It may also identify the liquid contents of unknown objects." + description_info = "This machine will try to tell you what reagents are inside of something capable of holding reagents. \ + It is also used to 'identify' specific reagent-based objects with their properties obscured from inspection by normal means." + icon = 'icons/obj/chemical.dmi' + icon_state = "chem_analyzer" + density = TRUE + anchored = TRUE + use_power = TRUE + idle_power_usage = 20 + clicksound = "button" + var/analyzing = FALSE + +/obj/machinery/chemical_analyzer/update_icon() + icon_state = "chem_analyzer[analyzing ? "-working":""]" + +/obj/machinery/chemical_analyzer/attackby(obj/item/I, mob/living/user) + if(!istype(I)) + return ..() + + if(default_deconstruction_screwdriver(user, I)) + return + if(default_deconstruction_crowbar(user, I)) + return + + if(istype(I,/obj/item/weapon/reagent_containers)) + analyzing = TRUE + update_icon() + to_chat(user, span("notice", "Analyzing \the [I], please stand by...")) + + if(!do_after(user, 2 SECONDS, src)) + to_chat(user, span("warning", "Sample moved outside of scan range, please try again and remain still.")) + analyzing = FALSE + update_icon() + return + + // First, identify it if it isn't already. + if(!I.is_identified(IDENTITY_FULL)) + var/datum/identification/ID = I.identity + if(ID.identification_type == IDENTITY_TYPE_CHEMICAL) // This only solves chemical-based mysteries. + I.identify(IDENTITY_FULL, user) + + // Now tell us everything that is inside. + if(I.reagents && I.reagents.reagent_list.len) + to_chat(user, "
") // To add padding between regular chat and the output. + for(var/datum/reagent/R in I.reagents.reagent_list) + if(!R.name) + continue + to_chat(user, span("notice", "Contains [R.volume]u of [R.name].
[R.description]
")) + + to_chat(user, span("notice", "Scanning of \the [I] complete.")) + analyzing = FALSE + update_icon() + return \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm index ff753a5b37..954102b732 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm @@ -489,4 +489,21 @@ description = "A slurry of compounds that contains the basic requirements for life." taste_description = "salty meat" reagent_state = LIQUID - color = "#DF9FBF" \ No newline at end of file + color = "#DF9FBF" + +// The opposite to healing nanites, exists to make unidentified hypos implied to have nanites not be 100% safe. +/datum/reagent/defective_nanites + name = "Defective Nanites" + id = "defective_nanites" + description = "Miniature medical robots that are malfunctioning and cause bodily harm. Fortunately, they cannot self-replicate." + taste_description = "metal" + reagent_state = SOLID + color = "#333333" + metabolism = REM * 3 // Broken nanomachines go a bit slower. + scannable = 1 + +/datum/reagent/defective_nanites/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + M.take_organ_damage(2 * removed, 2 * removed) + M.adjustOxyLoss(4 * removed) + M.adjustToxLoss(2 * removed) + M.adjustCloneLoss(2 * removed) \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index 3f655d83de..1ec5e6e334 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -155,10 +155,26 @@ /datum/reagent/toxin/mold/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) ..() - M.adjustToxLoss(strength * removed) if(prob(5)) M.vomit() +/datum/reagent/toxin/expired_medicine + name = "Expired Medicine" + id = "expired_medicine" + description = "Some form of liquid medicine that is well beyond its shelf date. Administering it now would cause illness." + taste_description = "bitterness" + reagent_state = LIQUID + strength = 5 + +/datum/reagent/toxin/expired_medicine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + ..() + if(prob(5)) + M.vomit() + +/datum/reagent/toxin/expired_medicine/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + affect_blood(M, alien, removed * 0.66) + + /datum/reagent/toxin/stimm //Homemade Hyperzine name = "Stimm" id = "stimm" diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 3cfac06de1..efa9ff81c1 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -53,20 +53,29 @@ if(!do_after(user, 30, H)) return + do_injection(H, user) + return + +// This does the actual injection and transfer. +/obj/item/weapon/reagent_containers/hypospray/proc/do_injection(mob/living/carbon/human/H, mob/living/user) + if(!istype(H) || !istype(user)) + return FALSE + user.setClickCooldown(DEFAULT_QUICK_COOLDOWN) - to_chat(user, "You inject [M] with \the [src].") - to_chat(M, "You feel a tiny prick!") + to_chat(user, span("notice", "You inject \the [H] with \the [src].")) + to_chat(H, span("warning", "You feel a tiny prick!")) if(hyposound) - playsound(src, hyposound,25) + playsound(src, hyposound, 25) - if(M.reagents) + if(H.reagents) var/contained = reagentlist() - var/trans = reagents.trans_to_mob(M, amount_per_transfer_from_this, CHEM_BLOOD) - add_attack_logs(user,M,"Injected with [src.name] containing [contained], trasferred [trans] units") - to_chat(user, "[trans] units injected. [reagents.total_volume] units remaining in \the [src].") + var/trans = reagents.trans_to_mob(H, amount_per_transfer_from_this, CHEM_BLOOD) + add_attack_logs(user,H,"Injected with [src.name] containing [contained], trasferred [trans] units") + to_chat(user, span("notice", "[trans] units injected. [reagents.total_volume] units remaining in \the [src].")) + return TRUE + return FALSE - return //A vial-loaded hypospray. Cartridge-based! /obj/item/weapon/reagent_containers/hypospray/vial name = "hypospray mkII" @@ -143,12 +152,11 @@ flags &= ~OPENCONTAINER icon_state = "[initial(icon_state)]0" -/obj/item/weapon/reagent_containers/hypospray/autoinjector/attack(mob/M as mob, mob/user as mob) - ..() - if(reagents.total_volume <= 0) //Prevents autoinjectors to be refilled. +/obj/item/weapon/reagent_containers/hypospray/autoinjector/do_injection(mob/living/carbon/human/H, mob/living/user) + . = ..() + if(.) // Will occur if successfully injected. flags &= ~OPENCONTAINER - update_icon() - return + update_icon() /obj/item/weapon/reagent_containers/hypospray/autoinjector/update_icon() if(reagents.total_volume > 0) @@ -168,6 +176,63 @@ icon_state = "green" filled_reagents = list("anti_toxin" = 5) +// These have a 15u capacity, somewhat higher tech level, and generally more useful chems, but are otherwise the same as the regular autoinjectors. +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector + name = "empty hypo" + desc = "A refined version of the standard autoinjector, allowing greater capacity." + icon_state = "autoinjector" + amount_per_transfer_from_this = 15 + volume = 15 + origin_tech = list(TECH_BIO = 4) + filled_reagents = list("inaprovaline" = 15) + flags = 0 // Removed OPENCONTAINER so you can't extract things to cheese the identification system in unidentified versions. + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute + name = "trauma hypo" + desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to be used on victims of \ + moderate blunt trauma." + filled_reagents = list("bicaridine" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn + name = "burn hypo" + desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to be used on burn victims, \ + featuring an optimized chemical mixture to allow for rapid healing." + filled_reagents = list("kelotane" = 7.5, "dermaline" = 7.5) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin + name = "toxin hypo" + desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to counteract toxins." + filled_reagents = list("anti_toxin" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy + name = "oxy hypo" + desc = "A refined version of the standard autoinjector, allowing greater capacity. This one is made to counteract oxygen \ + deprivation." + filled_reagents = list("dexalinp" = 10, "tricordrazine" = 5) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity + name = "purity hypo" + desc = "A refined version of the standard autoinjector, allowing greater capacity. This variant excels at \ + resolving viruses, infections, radiation, and genetic maladies." + filled_reagents = list("spaceacillin" = 9, "arithrazine" = 5, "ryetalyn" = 1) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain + name = "pain hypo" + desc = "A refined version of the standard autoinjector, allowing greater capacity. This one contains potent painkillers." + filled_reagents = list("tramadol" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ + name = "organ hypo" + desc = "A refined version of the standard autoinjector, allowing greater capacity. Organ damage is resolved by this variant." + filled_reagents = list("alkysine" = 3, "imidazoline" = 2, "peridaxon" = 10) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat + name = "combat hypo" + desc = "A refined version of the standard autoinjector, allowing greater capacity. This is a more dangerous and potentially \ + addictive hypo compared to others, as it contains a potent cocktail of various chemicals to optimize the recipient's combat \ + ability." + filled_reagents = list("bicaridine" = 3, "kelotane" = 1.5, "dermaline" = 1.5, "oxycodone" = 3, "hyperzine" = 3, "tricordrazine" = 3) + /obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting name = "clotting agent" desc = "A refined version of the standard autoinjector, allowing greater capacity. This variant excels at treating bleeding wounds and internal bleeding." @@ -177,3 +242,109 @@ name = "bone repair injector" desc = "A refined version of the standard autoinjector, allowing greater capacity. This one excels at treating damage to bones." filled_reagents = list("inaprovaline" = 5, "osteodaxon" = 10) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/stimm + name = "stimm injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This one is filled with a home-made stimulant, with some serious side-effects." + filled_reagents = list("stimm" = 10) // More than 10u will OD. + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired + name = "expired injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This one has had its contents expire a long time ago, using it now will probably make someone sick, or worse." + filled_reagents = list("expired_medicine" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific + name = "soporific injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This one is sometimes used by orderlies, as it has soporifics, which make someone tired and fall asleep." + filled_reagents = list("stoxin" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide + name = "cyanide injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This one contains cyanide, a lethal poison. It being inside a medical autoinjector has certain unsettling implications." + filled_reagents = list("cyanide" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/serotrotium + name = "serotrotium injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This one is filled with serotrotium, which causes concentrated production of the serotonin neurotransmitter in humans." + filled_reagents = list("serotrotium" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/space_drugs + name = "illicit injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This one contains various illicit drugs, held inside a hypospray to make smuggling easier." + filled_reagents = list("space_drugs" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cryptobiolin + name = "cryptobiolin injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This one contains cryptobiolin, which causes confusion." + filled_reagents = list("cryptobiolin" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/impedrezene + name = "impedrezene injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This one has impedrezene inside, a narcotic that impairs higher brain functioning. \ + This autoinjector is almost certainly created illegitimately." + filled_reagents = list("impedrezene" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mindbreaker + name = "mindbreaker injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This one stores the dangerous hallucinogen called 'Mindbreaker', likely put in place \ + by illicit groups hoping to hide their product." + filled_reagents = list("mindbreaker" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/psilocybin + name = "psilocybin injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This has psilocybin inside, which is a strong psychotropic derived from certain species of mushroom. \ + This autoinjector likely was made by criminal elements to avoid detection from casual inspection." + filled_reagents = list("psilocybin" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen + name = "unstable mutagen injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This contains unstable mutagen, which makes using this a very bad idea. It will either \ + ruin your genetic health, turn you into a Five Points violation, or both!" + filled_reagents = list("mutagen" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/lexorin + name = "lexorin injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + This contains lexorin, a dangerous toxin that stops respiration, and has been \ + implicated in several high-profile assassinations in the past." + filled_reagents = list("lexorin" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites + name = "medical nanite injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + The injector stores a slurry of highly advanced and specialized nanomachines designed \ + to restore bodily health from within. The nanomachines are short-lived but degrade \ + harmlessly, and cannot self-replicate in order to remain Five Points compliant." + filled_reagents = list("healing_nanites" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites + name = "defective nanite injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + The injector stores a slurry of highly advanced and specialized nanomachines that \ + are unfortunately malfunctioning, making them unsafe to use inside of a living body. \ + Because of the Five Points, these nanites cannot self-replicate." + filled_reagents = list("defective_nanites" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated + name = "contaminated injector" + desc = "A refined version of the standard autoinjector, allowing greater capacity. \ + The hypospray contains a viral agent inside, as well as a liquid substance that encourages \ + the growth of the virus inside." + filled_reagents = list("virusfood" = 15) + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/do_injection(mob/living/carbon/human/H, mob/living/user) + . = ..() + if(.) // Will occur if successfully injected. + infect_mob_random_lesser(H) + add_attack_logs(user, H, "Infected \the [H] with \the [src], by \the [user].") \ No newline at end of file diff --git a/code/modules/reagents/reagent_containers/unidentified_hypospray.dm b/code/modules/reagents/reagent_containers/unidentified_hypospray.dm new file mode 100644 index 0000000000..518ed05111 --- /dev/null +++ b/code/modules/reagents/reagent_containers/unidentified_hypospray.dm @@ -0,0 +1,80 @@ +// Here are the paths for all hypos that start unidentified. +// Usually you want to use a random spawner instead of using them directly, unless you're spawning these live for adminbus purposes. + +/obj/item/weapon/reagent_containers/hypospray/autoinjector + identity_type = /datum/identification/hypo + +// The good. +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/brute/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/burn/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/toxin/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/oxy/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/purity/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/pain/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/organ/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/clotting/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/bonemed/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/combat/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/healing_nanites/unidentified + init_hide_identity = TRUE + +// The somewhat bad. +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/stimm/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/space_drugs/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/expired/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/serotrotium/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cryptobiolin/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mindbreaker/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/psilocybin/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/soporific/unidentified + init_hide_identity = TRUE + +// The very bad. +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/cyanide/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/impedrezene/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/mutagen/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/defective_nanites/unidentified + init_hide_identity = TRUE + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/biginjector/contaminated/unidentified + init_hide_identity = TRUE \ No newline at end of file diff --git a/code/world.dm b/code/world.dm index 13d79247aa..ab2ed63cd9 100644 --- a/code/world.dm +++ b/code/world.dm @@ -84,13 +84,6 @@ var/global/datum/global_init/init = new () // This is kinda important. Set up details of what the hell things are made of. populate_material_list() - // Loads all the pre-made submap templates. - load_map_templates() - - if(config.generate_map) - if(using_map.perform_map_generation()) - using_map.refresh_mining_turfs() - // Create frame types. populate_frame_types() diff --git a/icons/effects/projectiles.dmi b/icons/effects/projectiles.dmi index 2bf7813e05..1668359379 100644 Binary files a/icons/effects/projectiles.dmi and b/icons/effects/projectiles.dmi differ diff --git a/icons/mob/items/lefthand_guns.dmi b/icons/mob/items/lefthand_guns.dmi index 72e9c00465..c0431e2337 100644 Binary files a/icons/mob/items/lefthand_guns.dmi and b/icons/mob/items/lefthand_guns.dmi differ diff --git a/icons/mob/items/righthand_guns.dmi b/icons/mob/items/righthand_guns.dmi index f3f75a86ea..8047c95f71 100644 Binary files a/icons/mob/items/righthand_guns.dmi and b/icons/mob/items/righthand_guns.dmi differ diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi index 3bf2b9d660..1d4c723fca 100644 Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ diff --git a/icons/obj/gun.dmi b/icons/obj/gun.dmi index 1494841bea..80d58d104e 100644 Binary files a/icons/obj/gun.dmi and b/icons/obj/gun.dmi differ diff --git a/icons/obj/loot_piles.dmi b/icons/obj/loot_piles.dmi index d4722d995c..3d83d6612e 100644 Binary files a/icons/obj/loot_piles.dmi and b/icons/obj/loot_piles.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 731346ad0c..ca77d4d392 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/icons/obj/railgun.dmi b/icons/obj/railgun.dmi index 404aa1ea60..6f633db1e5 100644 Binary files a/icons/obj/railgun.dmi and b/icons/obj/railgun.dmi differ diff --git a/maps/southern_cross/southern_cross-1.dmm b/maps/southern_cross/southern_cross-1.dmm index 07f579d0a8..d7896355e3 100644 --- a/maps/southern_cross/southern_cross-1.dmm +++ b/maps/southern_cross/southern_cross-1.dmm @@ -6754,7 +6754,7 @@ "czT" = (/obj/effect/floor_decal/corner/paleblue{dir = 10},/obj/effect/floor_decal/corner/paleblue{dir = 5},/turf/simulated/floor/tiled/white,/area/medical/foyer) "czU" = (/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/paleblue/border{dir = 4},/turf/simulated/floor/tiled/white,/area/medical/foyer) "czV" = (/obj/structure/table/reinforced,/obj/machinery/door/firedoor/glass,/obj/machinery/door/window/westright{name = "Chemistry Desk"},/obj/machinery/door/window/eastright{name = "Chemistry Desk"; req_access = list(33)},/obj/machinery/door/blast/shutters{density = 0; dir = 8; icon_state = "shutter0"; id = "chemcounter"; name = "Pharmacy Counter Shutters"; opacity = 0},/turf/simulated/floor/tiled/white,/area/medical/chemistry) -"czW" = (/obj/item/weapon/stool/padded,/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/beige/border{dir = 8},/turf/simulated/floor/tiled/white,/area/medical/chemistry) +"czW" = (/obj/item/weapon/stool/padded,/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/beige/border{dir = 8},/obj/machinery/button/remote/blast_door{id = "chemcounter"; name = "Pharmacy Counter Lockdown Control"; pixel_x = -24; pixel_y = 24},/obj/machinery/button/remote/blast_door{id = "chemwindow"; name = "Pharmacy Windows Shutter Control"; pixel_x = -24; pixel_y = 32; pixel_z = 0},/turf/simulated/floor/tiled/white,/area/medical/chemistry) "czX" = (/turf/simulated/floor/tiled/white,/area/medical/chemistry) "czY" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/turf/simulated/floor/tiled/white,/area/medical/chemistry) "czZ" = (/obj/effect/floor_decal/steeldecal/steel_decals4,/obj/effect/floor_decal/steeldecal/steel_decals4{dir = 10},/turf/simulated/floor/tiled/white,/area/medical/chemistry) @@ -6846,11 +6846,11 @@ "cBH" = (/obj/structure/disposalpipe/junction{dir = 1; icon_state = "pipe-j2"},/turf/simulated/floor/tiled/white,/area/medical/foyer) "cBI" = (/obj/effect/floor_decal/corner/paleblue{dir = 6},/obj/effect/floor_decal/corner/paleblue{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/white,/area/medical/foyer) "cBJ" = (/obj/structure/bed/chair{dir = 8},/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/paleblue/border{dir = 4},/turf/simulated/floor/tiled/white,/area/medical/foyer) -"cBK" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/structure/table/glass,/obj/item/weapon/storage/box/syringes,/obj/item/weapon/tool/screwdriver,/obj/machinery/button/remote/blast_door{id = "chemwindow"; name = "Pharmacy Windows Shutter Control"; pixel_x = 6; pixel_y = -18; pixel_z = 0},/obj/machinery/button/remote/blast_door{id = "chemcounter"; name = "Pharmacy Counter Lockdown Control"; pixel_x = -6; pixel_y = -18},/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/beige/border{dir = 8},/turf/simulated/floor/tiled/white,/area/medical/chemistry) -"cBL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/medical/chemistry) +"cBK" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/turf/simulated/floor/tiled/white,/area/medical/chemistry) +"cBL" = (/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/beige/border{dir = 8},/obj/machinery/chemical_analyzer,/turf/simulated/floor/tiled/white,/area/medical/chemistry) "cBM" = (/obj/machinery/hologram/holopad,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/effect/floor_decal/industrial/outline/grey,/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled/white,/area/medical/chemistry) -"cBN" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/white,/area/medical/chemistry) -"cBO" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/machinery/newscaster{pixel_x = 30; pixel_y = 0},/obj/effect/floor_decal/borderfloorwhite/corner,/obj/effect/floor_decal/corner/beige/bordercorner,/turf/simulated/floor/tiled/white,/area/medical/chemistry) +"cBN" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled/white,/area/medical/chemistry) +"cBO" = (/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/obj/machinery/newscaster{pixel_x = 30; pixel_y = 0},/obj/effect/floor_decal/borderfloorwhite/corner,/obj/effect/floor_decal/corner/beige/bordercorner,/turf/simulated/floor/tiled/white,/area/medical/chemistry) "cBP" = (/obj/structure/bed/chair/wheelchair,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/effect/floor_decal/borderfloorwhite/corner{dir = 8},/obj/effect/floor_decal/corner/paleblue/bordercorner{dir = 8},/turf/simulated/floor/tiled/white,/area/medical/medbay_primary_storage) "cBQ" = (/obj/machinery/hologram/holopad,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/effect/floor_decal/industrial/outline/grey,/turf/simulated/floor/tiled/white,/area/medical/medbay_primary_storage) "cBR" = (/obj/machinery/firealarm{dir = 4; pixel_x = 24},/obj/machinery/camera/network/medbay{c_tag = "MED - Equipment Storage"; dir = 8},/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/paleblue/border{dir = 4},/turf/simulated/floor/tiled/white,/area/medical/medbay_primary_storage) @@ -6930,7 +6930,7 @@ "cDn" = (/obj/structure/bed/chair{dir = 8},/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/paleblue/border{dir = 4},/obj/effect/floor_decal/borderfloorwhite/corner2{dir = 5},/obj/effect/floor_decal/corner/paleblue/bordercorner2{dir = 5},/turf/simulated/floor/tiled/white,/area/medical/foyer) "cDo" = (/obj/structure/table/glass,/obj/item/weapon/packageWrap,/obj/item/weapon/hand_labeler,/obj/item/weapon/reagent_containers/spray/cleaner{desc = "Someone has crossed out the 'Space' from Space Cleaner and written in Chemistry. Scrawled on the back is, 'Okay, whoever filled this with polytrinic acid, it was only funny the first time. It was hard enough replacing the CMO's first cat!'"; name = "Chemistry Cleaner"},/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/beige/border{dir = 8},/turf/simulated/floor/tiled/white,/area/medical/chemistry) "cDp" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled/white,/area/medical/chemistry) -"cDq" = (/obj/structure/closet/secure_closet/chemical,/obj/item/weapon/storage/box/pillbottles,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 22},/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/beige/border{dir = 4},/turf/simulated/floor/tiled/white,/area/medical/chemistry) +"cDq" = (/obj/structure/closet/secure_closet/chemical,/obj/item/weapon/storage/box/pillbottles,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 22},/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/beige/border{dir = 4},/obj/item/weapon/storage/box/syringes,/obj/item/weapon/tool/screwdriver,/turf/simulated/floor/tiled/white,/area/medical/chemistry) "cDr" = (/obj/structure/bed/chair/wheelchair,/obj/item/device/radio/intercom/department/medbay{dir = 4; pixel_x = -21},/obj/effect/floor_decal/borderfloorwhite{dir = 8},/obj/effect/floor_decal/corner/paleblue/border{dir = 8},/turf/simulated/floor/tiled/white,/area/medical/medbay_primary_storage) "cDs" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled/white,/area/medical/medbay_primary_storage) "cDt" = (/obj/structure/table/standard,/obj/item/weapon/storage/toolbox/emergency,/obj/item/bodybag/cryobag,/obj/item/bodybag/cryobag,/obj/item/bodybag/cryobag,/obj/structure/extinguisher_cabinet{pixel_x = 25},/obj/structure/disposalpipe/segment,/obj/effect/floor_decal/borderfloorwhite{dir = 4},/obj/effect/floor_decal/corner/paleblue/border{dir = 4},/turf/simulated/floor/tiled/white,/area/medical/medbay_primary_storage) @@ -10949,7 +10949,7 @@ "ecC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/obj/machinery/meter,/obj/random/mob/mouse,/turf/simulated/floor/plating,/area/maintenance/thirddeck/foreport) "ecD" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/obj/machinery/meter,/obj/random/mob/mouse,/turf/simulated/floor/plating,/area/maintenance/thirddeck/forestarboard) "ecE" = (/obj/machinery/door/firedoor/border_only,/obj/effect/wingrille_spawn/reinforced,/obj/machinery/door/blast/shutters{density = 0; dir = 8; icon_state = "shutter0"; id = "heads_meeting"; name = "Meeting Room Window Shutters"; opacity = 0},/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/obj/structure/cable/green,/turf/simulated/floor/plating,/area/bridge/meeting_room) - + (1,1,1) = {" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -11345,7 +11345,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaabVvcczcdQcczcdQcczcdQcczcdQcczcdQcczbVycaJbTDcaKcuPcuQcuRcuScuQcuTcuUcpPcpPcpPcpPcpPcpPcpPcuXcuVctDcuWcuYcxbctDcvacvbcvccvcctIcvdctIcvecvfcvgcvhcvicvjcvkcvjcvlcvmcvncvocvpcvqcvrctOcvscvtcvucvvcoQdUSdUTdURdwUcvwcqocoVaaaaaactUcvxcvycvzcvAcvBbWzcDQcvDcqxcvEcvFcvGeckcvIcvJcsjcvKcvLcvMcvNcumcvOcvPcvQcvRcsAcvScvTcvUcgwaaaaaacpkcsDcuucvVcvWcvXcvYcvZcwacwbcwccwdcuycwecwfcwgcwhcwicwjcwkcwlcwmcwncwocwpcwqcwrcwscwtcwucwvcwwcwxcwycwzcwAcwBcwCcwDcwEcwFcwGcrmcwHcwIcwJcrqcrqcrqcwKcwLcwIcrvcaHcwMcwNcwOcaHccxcwPcaHcaHaafaafaafaadaXGaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaabMCcdRbMCcdRbMCcdRbMCcdRbMCcdRbMCcdRaadbYTcwQcwUcwScwTcxtcwScwTcwVcwWcwXcwYbTDcfRcrMcrNcrNcrNcwZctDcxacxccxdctDcvacxectHctHctIcxfcxgcxhcxicxjcxkcxlcxlcxlcxmcxncxocxpcxqcxrcxscFGcxucxvcxwcxxcvvcoQdwUdwUdwUdwUcoVcqocoVaaaaaactUcxycqrcxzcxAcxBbWzcxCcxDcqxcxEcxFcxGcsrcxHcxIcxJcvKcxKcxLcxMcxNcxOcxPcpdcvRcxQcxRcxScxTcgwaaaaaacpkcsDcuucxUcxVcxWcxXcxYcxZcyacybcyccuzcydcyecyfcygcyhcyicyjcykcylcymcyncyocypcyqcyrcyscyrcytcwwcyucyvcywcwAcyxcyycyzcwEcyAcyBcrmcrmcrmcrmcrmcrmcrmcrmcrmcpzcpzcaHcyCcaIcaHcaHcaHcaHcaHaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaadaaaaaaaaabKLbKMbKMbKMbKMbKMbKMbKMcyDbKMbKMbKMbVybXocyEcyFcyGcyHcyIcyJcyHcyKcyLcyLcyMbTDcfRcyNcmLcyOcyOcyPcyOctDcyRcyQctDctDcyTcyUcyVctIcyWcyXcyYcyZczaczbcxlcxlczcczdczeczfctOczgczhcziczjctOcoQcoQczkcoQcoQcqmcqmcqmcqmcoVcqoczlaaaaaacqpcsicqrczmcznczobWAbWAczpcqxcxEczqczrcsrcsjcvAcsjczscpdcztczuczvczwcpdcpdczxczyczzczAczBchZaaaaaaczCcsDcuuczDczEcxWczFczGcxZczHczIczJcuzczKcyeczLczMczNczOczPczQczRczSczTczUczVczWczXczYczXczZcAacAbcAccAdcwAcAecAfcAgcwEcAhcAicAjcAkcAlcAmcAncAocApcAqcArcAsbYScAtcAuaaaaaaaaaaaaaaaaafaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaabVvcczcdQcczcdQcczcdQcczcdQcczcdQcczbVyccBbTDbTDcAvcAwcAxbXpcAxcAycyLcyLcAzbTDcfRcyNcmLcyOcAAcABcACctDcAEcyScAFctDcAGcAHcAIctIcAJcAKcALcAMcANcAOcAPcAQcAQcARczecAScATcAUcAVcAWcAXctOcAYcAZcBacBbcBccqmcBdcqmcBecoVcqoczlaaaaaacqpcqpcBfcsjcuhcBgcBhbWAcBicqxcqxcqxcqxcBjcBkcBlcBkcBmcpdcpdcBncBocpdcpdcBpcBqcBrcjDcBschZchZaaaaaaczCcsDcuucuucBtcBucBvcBwcxZcBxcBycBzcuzcBAcBBcBCcBCcBDcBEcBFcBGcBHcBIcwocBJcypcBKcBLcBMcBNcBOcuGcBPcBQcBRcwAcBScBTcBUcwEcBVcBWcBXcBYcBYcAmcBZcCacCbcAmcAmcAsaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaagaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaabVvcczcdQcczcdQcczcdQcczcdQcczcdQcczbVyccBbTDbTDcAvcAwcAxbXpcAxcAycyLcyLcAzbTDcfRcyNcmLcyOcAAcABcACctDcAEcyScAFctDcAGcAHcAIctIcAJcAKcALcAMcANcAOcAPcAQcAQcARczecAScATcAUcAVcAWcAXctOcAYcAZcBacBbcBccqmcBdcqmcBecoVcqoczlaaaaaacqpcqpcBfcsjcuhcBgcBhbWAcBicqxcqxcqxcqxcBjcBkcBlcBkcBmcpdcpdcBncBocpdcpdcBpcBqcBrcjDcBschZchZaaaaaaczCcsDcuucuucBtcBucBvcBwcxZcBxcBycBzcuzcBAcBBcBCcBCcBDcBEcBFcBGcBHcBIcwocBJcypcBLcBNcBMcBKcBOcuGcBPcBQcBRcwAcBScBTcBUcwEcBVcBWcBXcBYcBYcAmcBZcCacCbcAmcAmcAsaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaagaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagaaaaaaaaabMCcdRbMCcdRbMCcdRbMCcdRbMCcdRbMCcdRaafaafaafbTEbTDbTDbTDbTDbTDbTDbTDbTDbTDbTDcfRcCccencyOcCdcABcCectDcCfcADcNpcCjcCkcClcCmctIcCncCocCpcCqctIcCrcCscCtcCtcCucCvcCwcxpcCxcCycxrcCzctOcAYcCAcCBcCCcBbcBbcqmcBdcqmcoVcqoczlaaaaaaaaactUcCDcCEcuhcCFcCGcCHcCIcCJdVzcCKcCLcCMcCNcskcCOcCMcCPcnDcCQcCRcCScCTcCUcCVcBrcCWcCXcgwaaaaaaaaaczCcsDcCYcuucCZcDacDbcDccxZcDdcDecDdcuzcDfcyecDgcDhcDicDjcDkcDlcwmcDmcwocDncypcDoczXcDpczXcDqcuGcDrcDscDtcwAcDucDvcDwcwEcDxcDycDzcDAcDBcDCcDDcDEcApcDFcDGcAsaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaaaaaacDHcDIcDJcDKcDLcDLcDMcDNcXVcCheclcPXcyOcDRcDScDTctDctDctDctDcDUcDVcDWcDUctIcDXctIcDYcDZctIcEacEbcEccEccEdcEecEactOcEfcEgcEhcEictOcEjcEjcEjcEkcEjcBbcBbcBbcqmcoVcqocoVaaaaaaaaactUctUcElcCEcuhcuhcEmcEncEocEocEpcEqcErcEscEtcEucErcEvcEwcExcExcEycEzcBrcBrcCWcEAcgwcgwaaaaaaaaacpkcsDcEBcuucuucECcEDcEEcxZcEFcEGcEHcuzcEIcEJcEKcELcEMcENcEOcEPcEQcERcEScETcuGcEUcEVcEWcEXcEYcuGcDOcFacFbcwAcFccFdcFecwEcFfcFgcFhcFicFjcAmcFkcFlcFmcAscAscAsaafaafaafabcaafaaaaaaaagaadaadaadaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadaadaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaaaaaacDHcFncFocFpcFqcDHcDHcDHcMXcEZcDPcFtcyOcyOcyOcyOcGTcFvcFwcFxcDUcFycFzcFAcFBcFCcFDcFEcFFctIcOlcFHcFIcFJcFKcFLcFMctOcxpcFNcxpcFOctOcFPcFQcFRcFScEjcoVcoVcFTcoVcoVcFUcoVaaaaaaaaaaaactUctUcElcCEcsjcFVcFWcFXcFYcsjcFZcGacGbcskcGccGacGdcjDcGecGfcGgcGhcjDcCWcEAcgwcgwaaaaaaaaaaaacpkcsDcGicGjcGkcGlcGmcGncGocGpcGqcGrcuzcGscuzcuzcGtcGucGtcuycuEcGvcuEcGwcuEcuGcwwcGxcGycwwcuGcuGcGzcGAcFrcwAcwEcGCcwEcwEcFfcFgcFhcGDcGEcAmcGFcGGcGHcAsaaaaaaaaaaaaaaaaadaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -11723,3 +11723,4 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa dUOaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa "} + diff --git a/maps/southern_cross/structures/closets/misc.dm b/maps/southern_cross/structures/closets/misc.dm index b687a2f196..4eae105184 100644 --- a/maps/southern_cross/structures/closets/misc.dm +++ b/maps/southern_cross/structures/closets/misc.dm @@ -24,7 +24,7 @@ return ..() /obj/structure/closet/secure_closet/guncabinet/phase - name = "phase pistol cabinet" + name = "explorer weapon cabinet" req_one_access = list(access_explorer,access_brig) starts_with = list( diff --git a/polaris.dme b/polaris.dme index 5c4fd1619a..ddfd3e37ba 100644 --- a/polaris.dme +++ b/polaris.dme @@ -198,6 +198,7 @@ #include "code\controllers\subsystems\inactivity.dm" #include "code\controllers\subsystems\lighting.dm" #include "code\controllers\subsystems\machines.dm" +#include "code\controllers\subsystems\mapping.dm" #include "code\controllers\subsystems\orbits.dm" #include "code\controllers\subsystems\overlays.dm" #include "code\controllers\subsystems\planets.dm" @@ -1068,6 +1069,7 @@ #include "code\game\objects\random\misc.dm" #include "code\game\objects\random\mob.dm" #include "code\game\objects\random\spacesuits.dm" +#include "code\game\objects\random\unidentified\medicine.dm" #include "code\game\objects\structures\barsign.dm" #include "code\game\objects\structures\bedsheet_bin.dm" #include "code\game\objects\structures\bonfire.dm" @@ -1671,6 +1673,8 @@ #include "code\modules\hydroponics\trays\tray_soil.dm" #include "code\modules\hydroponics\trays\tray_tools.dm" #include "code\modules\hydroponics\trays\tray_update_icons.dm" +#include "code\modules\identification\identification.dm" +#include "code\modules\identification\item_procs.dm" #include "code\modules\integrated_electronics\_defines.dm" #include "code\modules\integrated_electronics\core\assemblies.dm" #include "code\modules\integrated_electronics\core\detailer.dm" @@ -2260,6 +2264,7 @@ #include "code\modules\projectiles\guns\modular_guns.dm" #include "code\modules\projectiles\guns\projectile.dm" #include "code\modules\projectiles\guns\vox.dm" +#include "code\modules\projectiles\guns\energy\hooklauncher.dm" #include "code\modules\projectiles\guns\energy\laser.dm" #include "code\modules\projectiles\guns\energy\nuclear.dm" #include "code\modules\projectiles\guns\energy\phase.dm" @@ -2272,6 +2277,7 @@ #include "code\modules\projectiles\guns\launcher\pneumatic.dm" #include "code\modules\projectiles\guns\launcher\rocket.dm" #include "code\modules\projectiles\guns\launcher\syringe_gun.dm" +#include "code\modules\projectiles\guns\magnetic\bore.dm" #include "code\modules\projectiles\guns\magnetic\magnetic.dm" #include "code\modules\projectiles\guns\magnetic\magnetic_construction.dm" #include "code\modules\projectiles\guns\magnetic\magnetic_railgun.dm" @@ -2292,6 +2298,7 @@ #include "code\modules\projectiles\projectile\change.dm" #include "code\modules\projectiles\projectile\energy.dm" #include "code\modules\projectiles\projectile\force.dm" +#include "code\modules\projectiles\projectile\hook.dm" #include "code\modules\projectiles\projectile\magnetic.dm" #include "code\modules\projectiles\projectile\pellets.dm" #include "code\modules\projectiles\projectile\special.dm" @@ -2349,6 +2356,7 @@ #include "code\modules\reagents\reagent_containers\pill.dm" #include "code\modules\reagents\reagent_containers\spray.dm" #include "code\modules\reagents\reagent_containers\syringes.dm" +#include "code\modules\reagents\reagent_containers\unidentified_hypospray.dm" #include "code\modules\recycling\conveyor2.dm" #include "code\modules\recycling\disposal-construction.dm" #include "code\modules\recycling\disposal.dm" diff --git a/sound/items/washingmachine.ogg b/sound/items/washingmachine.ogg new file mode 100644 index 0000000000..b4745c0e67 Binary files /dev/null and b/sound/items/washingmachine.ogg differ diff --git a/tools/mapmerge/1prepare_map.sh b/tools/mapmerge/1prepare_map.sh new file mode 100755 index 0000000000..ee4fe2f5a5 --- /dev/null +++ b/tools/mapmerge/1prepare_map.sh @@ -0,0 +1,6 @@ +#!/bin/sh +cd ../../maps/southern_cross + +for f in *.dmm; +do cp $f $f.backup; +done diff --git a/tools/mapmerge/2clean_map.sh b/tools/mapmerge/2clean_map.sh new file mode 100755 index 0000000000..71c16f7999 --- /dev/null +++ b/tools/mapmerge/2clean_map.sh @@ -0,0 +1,4 @@ +#!/bin/sh +for f in ../../maps/southern_cross/*.dmm; +do java -jar MapPatcher.jar -clean $f.backup $f $f; +done