From baaced85c439b3f3f1e31683e9371ae1c7e86f22 Mon Sep 17 00:00:00 2001 From: CHOMPStation2StaffMirrorBot <94713762+CHOMPStation2StaffMirrorBot@users.noreply.github.com> Date: Thu, 29 May 2025 04:21:24 -0700 Subject: [PATCH] [MIRROR] Collector event machine (#10962) Co-authored-by: SatinIsle <98125273+SatinIsle@users.noreply.github.com> Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com> --- code/__defines/_reagents.dm | 2 + code/modules/admin/admin_verb_lists_vr.dm | 2 + .../collector_event/admin_commands.dm | 73 +++++ .../eventkit/collector_event/blockers.dm | 131 +++++++++ .../collector_event/event_collector.dm | 262 ++++++++++++++++++ .../nukies_maker/nukies_collector.dm | 47 ++++ code/modules/food/food/cans.dm | 14 + .../reagents/reagents/food_drinks_vr.dm | 26 ++ icons/obj/cooking_event.dmi | Bin 0 -> 2700 bytes icons/obj/general_collector.dmi | Bin 0 -> 827 bytes vorestation.dme | 6 +- 11 files changed, 562 insertions(+), 1 deletion(-) create mode 100644 code/modules/eventkit/collector_event/admin_commands.dm create mode 100644 code/modules/eventkit/collector_event/blockers.dm create mode 100644 code/modules/eventkit/collector_event/event_collector.dm create mode 100644 code/modules/eventkit/collector_event/nukies_maker/nukies_collector.dm create mode 100644 icons/obj/cooking_event.dmi create mode 100644 icons/obj/general_collector.dmi diff --git a/code/__defines/_reagents.dm b/code/__defines/_reagents.dm index 0f7373c7d9..48ed8b6bf7 100644 --- a/code/__defines/_reagents.dm +++ b/code/__defines/_reagents.dm @@ -573,6 +573,8 @@ #define REAGENT_ID_NUKIEMEGASHRINK "nukie_mega_shrink" #define REAGENT_NUKIEMEGAGROWTH "Nukie Mega Growth" #define REAGENT_ID_NUKIEMEGAGROWTH "nukie_mega_growth" +#define REAGENT_NUKIEONE "Nukie One" +#define REAGENT_ID_NUKIEONE "nukie_one" #define REAGENT_COATING "coating" #define REAGENT_ID_COATING "coating" #define REAGENT_BATTER "batter mix" diff --git a/code/modules/admin/admin_verb_lists_vr.dm b/code/modules/admin/admin_verb_lists_vr.dm index e0e2921e50..52e65c38b7 100644 --- a/code/modules/admin/admin_verb_lists_vr.dm +++ b/code/modules/admin/admin_verb_lists_vr.dm @@ -582,6 +582,8 @@ var/list/admin_verbs_event_manager = list( /client/proc/add_hidden_area, /client/proc/remove_hidden_area, /client/proc/hide_motion_tracker_feedback, + /client/proc/modify_event_collector, + /client/proc/induce_malfunction, /datum/admins/proc/quick_nif, //CHOMPStation Add, /datum/admins/proc/quick_authentic_nif, //CHOMPStation add /client/proc/reload_jobwhitelist, //ChompADD diff --git a/code/modules/eventkit/collector_event/admin_commands.dm b/code/modules/eventkit/collector_event/admin_commands.dm new file mode 100644 index 0000000000..a8918dac27 --- /dev/null +++ b/code/modules/eventkit/collector_event/admin_commands.dm @@ -0,0 +1,73 @@ +/* +Event Collector Admin Commands + +These need to be added to admin_verb_lists_vr.dm + +*/ +/client/proc/modify_event_collector(var/obj/structure/event_collector/target in GLOB.event_collectors) + set category = "Fun.Event Kit" + set desc="Configure Event Collector" + set name="Configure Collector" + + if(!check_rights(R_ADMIN)) + return + + var/msg = "---------------\n" + if(target?.active_recipe?.len > 0) + msg += " [target] has [target.active_recipe.len] left in its current recipe\n" + for(var/i in target.active_recipe) + msg += "* [i] \n" + + else + msg += "[target] has no more required items! \n" + + if(target.calls_remaining > 0) + msg += "[target] has [target.calls_remaining] progress to go! - unless stopped or slowed, this is about [(target.calls_remaining / 10 ) * 2] seconds! \n" + + var/blockers = target.get_blockers() + + if(blockers > 0) + msg += "[target] has [blockers] things blocking/slowing it down! Anything more than 10 means it's stopped!" + + to_chat(usr,msg) + + + var/list/options = list( + "Cancel", + "Start New Recipe", + "Clear Current Recipe", + "Force Clear Blockers" + ) + + var/option = tgui_input_list(usr, "What Would You Like To Do?", "Event Collector",options,"Cancel") + switch(option) + if("Cancel") + return + if("Start New Recipe") + target.pick_new_recipe() + if("Clear Current Recipe") + target.active_recipe = list() + target.awaiting_next_recipe = TRUE + target.calls_remaining = 0 + + if("Force Clear Blockers") + if(islist(GLOB.event_collector_blockers[target.blocker_channel])) + for(var/obj/structure/event_collector_blocker/tofix in GLOB.event_collector_blockers[target.blocker_channel]) + tofix.fix() + + if("Empty Stored Items") + target.empty_items() + +/client/proc/induce_malfunction(var/obj/structure/event_collector_blocker/target in GLOB.event_collector_blockers) + set category = "Fun.Event Kit" + set desc="Configure Collector Blocker" + set name="Toggle Malfunction State" + + if(!check_rights(R_ADMIN)) + return + + if(target.block_amount) + target.fix() + + else + target.induce_failure() diff --git a/code/modules/eventkit/collector_event/blockers.dm b/code/modules/eventkit/collector_event/blockers.dm new file mode 100644 index 0000000000..4d907732ae --- /dev/null +++ b/code/modules/eventkit/collector_event/blockers.dm @@ -0,0 +1,131 @@ +/obj/structure/event_collector_blocker + var/blocker_channel = "collector" + var/base_icon = "blocker" + + icon = 'icons/obj/general_collector.dmi' + icon_state = "blocker_on" + desc = "blocker? I barely know er" + var/tools_to_fix = FALSE + + //how much we're currently blocking + var/block_amount = 0 + + //how much we'll block when broken + var/default_block_amount = 100 + + //tool to what's fucked up + var/list/problem_descs = list( + TOOL_CROWBAR = "a panel is dislodged.", + TOOL_MULTITOOL = "a light next to a dataport is flashing some errors.", + TOOL_SCREWDRIVER = "there's some loose screws inside.", + TOOL_WIRECUTTER = "some loose wires are shorting things out.", + TOOL_WRENCH = "One of the supporting bolts are concerningly loose.", + TOOL_CABLE_COIL = "There's some wires that need replacement.", + TOOL_WELDER = "One of the brackets has a cracked weld." + ) + + //tool to how we unfuck it + var/list/fix_descs = list( + TOOL_CROWBAR = "you lodge the panel back in place.", + TOOL_MULTITOOL = "you reset the panel with the multitool.", + TOOL_SCREWDRIVER = "you tighten the loose screws.", + TOOL_WIRECUTTER = "you remove the excess wiring.", + TOOL_WRENCH = "you tighten up the supporting bolts.", + TOOL_CABLE_COIL = "you replace the worn wires.", + TOOL_WELDER = "you fix up the worn weld." + ) + + //what tools we need + var/list/active_repair_steps = list() + + +/obj/structure/event_collector_blocker/Initialize(mapload) + . = ..() + + GLOB.event_collector_blockers |= src + + if(GLOB.event_collector_associations == null) + GLOB.event_collector_associations = list() + + if(GLOB.event_collector_associations[blocker_channel] == null) + GLOB.event_collector_associations[blocker_channel] = list() + + GLOB.event_collector_associations[blocker_channel] |= src + +/obj/structure/event_collector_blocker/Destroy() + + GLOB.event_collector_blockers -= src + + if(GLOB.event_collector_associations[blocker_channel]) + GLOB.event_collector_associations[blocker_channel] -= src + . = ..() + + +/obj/structure/event_collector_blocker/update_icon() + . = ..() + icon_state = "[base_icon]_[block_amount ? "off" : "on"]" + +/obj/structure/event_collector_blocker/proc/induce_failure(var/intensity = -1) //progress to remove from the machine + if(intensity == -1) + intensity = default_block_amount + + block_amount = intensity + if(tools_to_fix) + active_repair_steps = list() + for(var/i in 1 to 4) + active_repair_steps += pick(list(TOOL_CROWBAR,TOOL_MULTITOOL,TOOL_SCREWDRIVER,TOOL_WRENCH,TOOL_CABLE_COIL,TOOL_WELDER)) //todo, make this a different list on the obj "Possible failures" or whatever. + update_icon(); + +/obj/structure/event_collector_blocker/proc/fix() + block_amount = 0 + active_repair_steps = list() + update_icon(); + +/obj/structure/event_collector_blocker/examine(mob/user, infix, suffix) + . = ..() + if(block_amount) + if(tools_to_fix) + if(active_repair_steps.len >= 1) + . += span_warning(problem_descs[active_repair_steps[active_repair_steps.len]]) + else + . += span_warning("It looks kinda messed up!") + else + . += span_warning("Looks like the breaker flipped!") + else + . += span_notice("Looks like it's functioning normally") + + +/obj/structure/event_collector_blocker/proc/get_repair_message(var/mob/user) + return "[user] repairs [src]" + +/obj/structure/event_collector_blocker/attack_hand(mob/user) + if(!tools_to_fix && block_amount > 0) + user.visible_message("[user] fixes [src] up!") //swap this with a message var, or just change it to be suitable + fix() + . = ..() + + +/obj/structure/event_collector_blocker/attackby(obj/item/O, mob/user) + . = ..() + if(tools_to_fix) + if(active_repair_steps.len >= 1) + if(O.has_tool_quality(active_repair_steps[active_repair_steps.len])) + if(do_after(user, 2 SECONDS)) + to_chat(usr,span_notice(fix_descs[active_repair_steps[active_repair_steps.len]])) + active_repair_steps.len = active_repair_steps.len - 1 + if(active_repair_steps.len == 0) + fix() + else + to_chat(user,"WRONG TOOL!") + +/obj/structure/event_collector_blocker/breaker //for these, if you change the base_icon you'll be good to go. ae, base_icon = breaker or circuit or whatever + name = "Breaker" + desc = "I barely know er!" + +/obj/structure/event_collector_blocker/breaker/get_repair_message(var/mob/user) + return "[user] flips [src]!" + +/obj/structure/event_collector_blocker/circuit_panel + name = "Circuit Panel" + desc = "Looks complicated!" + tools_to_fix = TRUE diff --git a/code/modules/eventkit/collector_event/event_collector.dm b/code/modules/eventkit/collector_event/event_collector.dm new file mode 100644 index 0000000000..ecadaa1ddb --- /dev/null +++ b/code/modules/eventkit/collector_event/event_collector.dm @@ -0,0 +1,262 @@ +GLOBAL_LIST_INIT(event_collector_associations,list()) +GLOBAL_LIST_INIT(event_collectors,list()) //for the verbs +GLOBAL_LIST_INIT(event_collector_blockers,list()) //ditto + + +/obj/structure/event_collector //set anchored, solid, etc to taste. + name = "event collector" + desc = "you really should set this up properly :(" + + icon = 'icons/obj/general_collector.dmi' + + var/blocker_channel = "collector" //used for list management - blockers that have the same key will add themselves as a disabler to every collector with the same key + + + var/recipe_size = 3 //how many ingredients do we pick out from the ingredients list for a "recipe"? + + var/blocker_insertion_impedement_threshold = -1 //if we have more blockers than this, we can't place item in :( + var/show_blocker_in_examine = TRUE + + + var/list/possible_ingredients = list( + /obj/item/trash, + /obj/item/toy/plushie/ipc, + /obj/item/toy/tennis + ) //list of items that can make up a recipe. + + var/no_dupes_in_recipe = FALSE //do we care about repeats? if so, set to true + var/need_recipe_in_order = FALSE //start from the first one! or ignore it and do whatever, man... + var/item_theft_mode = TRUE //if true, we store it in our contents for later use, otherwise, we just delete it. + + var/completion_time = 60 //how long to "complete" a recipe before starting the next one - this is in processing calls, 2 seconds if no time dialation + + var/step_insertion_time = 2 SECONDS //how long it takes to put an object into us! + var/list/step_insertion_verbs = list("inserts") //X inserts Item into [Src], picks from the list! Tosses, inserts, throws, etc + var/list/step_initiation_verbs = list("insert") //when we start it. X starts to insert Item into [src]. picks from list. put, insert, shove, etc + + var/automatic_recipe_restart = TRUE //do we start a new recipe as soon as the active one's done? if not, admin only! + + var/noisy_recipe_completion = TRUE //if true, alerts admins when a recipe is completed + var/noisy_step_completion = TRUE //if true, tells admins when a step is completed + + var/step_in_examine = TRUE //if true, simply tells the user what type of item they need next. note that we use typeof here, so a gold screwdriver counts as a screwdriver, but it'll just ask for a screwdriver + + var/animate_on_recipe_complete = TRUE //jiggle on complete? + var/animate_on_recipe_process = TRUE //jiggle with less intensity when working? + + var/sound_for_recipe_complete + + var/wait_between_items = 0 //How long must you wait before adding another item + var/next_item_added = 0 //world time when the next item can be added + + var/type_to_spawn_on_complete + + var/list/recipe_process_sounds = list('sound/effects/smoke.ogg', 'sound/effects/bubbles.ogg') + var/recipe_process_sound_chance = 50 //prob(50) per active process tick + + //internal stuff, don't touch this with subtypes. + var/calls_remaining + var/awaiting_next_recipe = FALSE //are we waiting for the timer to get negatives? + var/list/disabling_sources //what things are disabling us? + var/list/active_recipe //volatile, when given an item it removes it + var/current_step = 0 //current step for icon states + +/obj/structure/event_collector/Initialize(mapload) + . = ..() + GLOB.event_collectors |= src + +/obj/strucutre/event_collector/Destroy() + GLOB.event_collectors -= src + . = ..() + + +/obj/structure/event_collector/proc/get_blockers() + . = 0 + if(GLOB.event_collector_associations) + if(GLOB.event_collector_associations[blocker_channel]) + for(var/obj/structure/event_collector_blocker/blocker in GLOB.event_collector_associations[blocker_channel]) + . += blocker.block_amount + + +/obj/structure/event_collector/proc/jiggle_animation(var/intensity = 1) + var/matrix/secondary_effect = matrix() + var/matrix/effect = matrix() + effect.Turn(-5*intensity) + effect.Scale(1,1-intensity) + secondary_effect.Turn(5*intensity) + secondary_effect.Scale(1,1+intensity) + animate(src, transform = effect, time = 2) + animate(transform = secondary_effect, time = 2) + animate(transform = null, time = 2) + +/obj/structure/event_collector/proc/recipe_completed() + if(animate_on_recipe_complete) + jiggle_animation(0.2) + + if(automatic_recipe_restart) + pick_new_recipe() + + if(noisy_recipe_completion) + message_admins("\[EVENT\]: Event Collection object [src] has completed a recipe!") + + if(sound_for_recipe_complete) + playsound(src,sound_for_recipe_complete,75,1) + + if(type_to_spawn_on_complete) + new type_to_spawn_on_complete(get_turf(loc)) + + current_step = 0 + + update_icon() + +/obj/structure/event_collector/update_icon() + . = ..() //here more as a reminder than anything + + + +/obj/structure/event_collector/proc/recipe_failed() //called when reset by an admin assuming they want it to be + return + +/obj/structure/event_collector/proc/pick_new_recipe() + active_recipe = list() //clear it out + if(no_dupes_in_recipe) + var/list/destructive_clone = possible_ingredients.Copy() + for(var/i in 1 to recipe_size) + var/temp = pick(destructive_clone) + active_recipe += temp + destructive_clone -= temp + + else + for(var/i in 1 to recipe_size) + active_recipe += pick(possible_ingredients) + + if(noisy_step_completion) + var/next_item = "Nothing! The sequence is done!" + next_item = active_recipe[1] + message_admins("\[EVENT\] Event Collection object [src] has started a recipe! If it's in sequence, the next one is [next_item] ") + +/obj/structure/event_collector/process() + var/blockers = get_blockers() + if(awaiting_next_recipe && blockers < 10) + if( recipe_process_sounds && prob(recipe_process_sound_chance) ) + playsound(src,pick(recipe_process_sounds),25,TRUE) + + calls_remaining -= max(0, 10-blockers) //10's a multiplier in case we want to scale it based on how many blockers + if(calls_remaining <= 0) + awaiting_next_recipe = FALSE + recipe_completed() + if(animate_on_recipe_process) + jiggle_animation(0.1) + +/obj/structure/event_collector/Initialize(mapload) + . = ..() + START_PROCESSING(SSobj, src) + +/obj/structure/event_collector/Destroy() + STOP_PROCESSING(SSobj, src) + return ..() + + +/obj/structure/event_collector/examine(mob/user) + . = ..() + if(!active_recipe) return + + var/blocker_count = get_blockers() + + if(step_in_examine == TRUE) + if(active_recipe.len == 0) + . += span_notice("It doesn't seem to need anything at the moment!") + + else + if(need_recipe_in_order) + if(active_recipe.len > 0) + var/atom/firstitem = active_recipe[1] + . += span_notice("The next object in the sequence is a... [initial(firstitem.name)]") + else + . += span_notice("it doesn't seem to need anything at the moment!") + else + var/message = "It seems to need a " + for(var/i in 1 to active_recipe.len) + var/atom/x = active_recipe[i] + .+= span_notice(message + initial(x.name)) + message = pick("and a ", "a ", "with a ") + + if(show_blocker_in_examine) + if(blocker_count > 10) + . += span_danger("It's nonfunctional!") + else + if(blocker_count > 0) + . += span_warning("It's impeded!") + + //following's for debug, comment out if ur happy with it + //. += "There are uhhhh this many things blocking: [blocker_count]." + +/obj/structure/event_collector/attackby(obj/item/O, mob/user) + if(blocker_insertion_impedement_threshold > 0 && ( get_blockers() > blocker_insertion_impedement_threshold) ) + to_chat(usr,"It's fucked! Fix it first!") + return + + if(world.time < next_item_added) + to_chat(user,span_warning("It's not ready to take another item yet!")) + return + + if(active_recipe.len > 0) //do we have something active at all + var/stored_index = -1 //shortcut + if(need_recipe_in_order) //can we put this in? + if(!(istype(O,active_recipe[1]))) //if we need the recipe in order, check the first thing in the list + to_chat(user,span_warning("That's not the next object in the recipe!")) + return + else + stored_index = 1 + else + var/found = FALSE + for(var/ind in 1 to active_recipe.len) //isType != if(O.type in list) unfortunately + if(istype(O, active_recipe[ind])) + found = TRUE + stored_index = ind + break; + if(!found) + return; + + //put it in + user.visible_message("[user] begins to [pick(step_initiation_verbs)] \The [O] into \The [src]") + if(do_after(user, step_insertion_time, src)) //wait a second or two + user.visible_message("[user] [pick(step_insertion_verbs)] \The [O] into \The [src]!") + if(ishuman(user)) //should always be? + var/mob/living/carbon/human/h = user + h.drop_item() //drop held item. this is also what plays the item sound via association + if(noisy_step_completion) + var/next_item = "Nothing! The sequence is done!" + if(active_recipe.len > 1) + next_item = active_recipe[2] + message_admins("\[EVENT\] Event Collection object [src] has completed a step in its recipe with [O]! if it's in sequence, the next one is [next_item] ") + active_recipe -= active_recipe[stored_index] + if(item_theft_mode) + O.forceMove(src) //note that this does NOT delete anything! ever! or release it manually! entirely so admins can manually collect or do stuff later via moving/ejecting. + else + qdel(O) + + jiggle_animation(0.1) + if(active_recipe.len == 0) + start_recipe_process() + current_step += 1 + update_icon() + post_recipe_complete(user) + next_item_added = (world.time + wait_between_items) + else + user.visible_message("[user] gives up!") //shitty, change later + +/obj/structure/event_collector/proc/start_recipe_process() + awaiting_next_recipe = TRUE + calls_remaining = completion_time * 10 + message_admins("\[EVENT\] Event Collection object [src] has started processing its current recipe! ETA: [(calls_remaining/10) / 2] ish seconds.") + +/obj/structure/event_collector/proc/empty_items() //manual call only atm + for(var/atom/movable/to_move in contents) + to_move.forceMove(get_turf(src)) + +/obj/structure/event_collector/proc/post_object_insert(var/mob/user) + return + +/obj/structure/event_collector/proc/post_recipe_complete() + return diff --git a/code/modules/eventkit/collector_event/nukies_maker/nukies_collector.dm b/code/modules/eventkit/collector_event/nukies_maker/nukies_collector.dm new file mode 100644 index 0000000000..8ee65be388 --- /dev/null +++ b/code/modules/eventkit/collector_event/nukies_maker/nukies_collector.dm @@ -0,0 +1,47 @@ +/obj/structure/event_collector/nukies + name = "Experimental Nukies Mixer" + desc = "A machine rigged together from various bits and pieces, designed to mix some reagents into new Nukies." + icon = 'icons/obj/cooking_event.dmi' + icon_state = "equipment_empty" + + possible_ingredients = list( + /obj/item/collector_item/nukies_acid, + /obj/item/collector_item/nukies_formula, + /obj/item/collector_item/nukies_sludge + ) + + no_dupes_in_recipe = TRUE + automatic_recipe_restart = FALSE + step_in_examine = FALSE + wait_between_items = 1 MINUTE + need_recipe_in_order = TRUE + + type_to_spawn_on_complete = /obj/item/reagent_containers/food/drinks/cans/nukie_one + +/obj/structure/event_collector/update_icon() + . = ..() + if(!current_step) + icon_state = "equipment_empty" + else if(current_step <= 3) + icon_state = "equipment_[current_step]" + + +//simple obj defs here. overwrite or change as requested. + +/obj/item/collector_item + icon = 'icons/obj/cooking_event.dmi' + icon_state = "acid" + name = "Mewriatic Acid" + desc = "Not a typo or label misprint. There's an entire dissolved cat in here. Says so right on the ingredients label." + +/obj/item/collector_item/nukies_acid + +/obj/item/collector_item/nukies_formula + icon_state = "formula" + name = "Nukies Secret Formula" + desc = "A disgustingly thick bottle of... something. It smells bad, in a good way." + +/obj/item/collector_item/nukies_sludge + icon_state = "sludge" + name = "Sludge" + desc = "Eughghhgh. gross. Smells like gasoline and gamers." diff --git a/code/modules/food/food/cans.dm b/code/modules/food/food/cans.dm index 6120d90ed3..82b6f956a5 100644 --- a/code/modules/food/food/cans.dm +++ b/code/modules/food/food/cans.dm @@ -696,3 +696,17 @@ /obj/item/reagent_containers/food/drinks/cans/nukie_mega_grow/Initialize(mapload) . = ..() reagents.add_reagent(REAGENT_ID_NUKIEMEGAGROWTH, 60) + +////////////////////////Event Only Nukie////////////////////////////////// + +/obj/item/reagent_containers/food/drinks/cans/nukie_one + name = "\improper Nukies One" + desc = "The final. The ultimate nukeform. Power not meant to be supplied to mortal creatures. Legit." + icon_state = "nukie_one" + center_of_mass_x = 16 + center_of_mass_y = 8 + volume = 60 + +/obj/item/reagent_containers/food/drinks/cans/nukie_one/Initialize(mapload) + . = ..() + reagents.add_reagent(REAGENT_ID_NUKIEONE, 60) diff --git a/code/modules/reagents/reagents/food_drinks_vr.dm b/code/modules/reagents/reagents/food_drinks_vr.dm index 5b9b5310ae..7f5a505511 100644 --- a/code/modules/reagents/reagents/food_drinks_vr.dm +++ b/code/modules/reagents/reagents/food_drinks_vr.dm @@ -958,3 +958,29 @@ ..() var/new_size = clamp((M.size_multiplier + 0.01), RESIZE_MINIMUM_DORMS, RESIZE_MAXIMUM_DORMS) M.resize(new_size, uncapped = M.has_large_resize_bounds(), aura_animation = FALSE) + +/////////////////////////////Event only nukie////////////////////////////////////// + +/datum/reagent/drink/coffee/nukie/mega/one //Basically macrocillin but for ingesting + name = REAGENT_NUKIEONE + id = REAGENT_ID_NUKIEONE + color = "#90ed87" + taste_description = "everything" + overdose = 10 + adj_drowsy = -50 + adj_sleepy = -100 + +/datum/reagent/drink/coffee/nukie/mega/one/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + ..() + M.add_chemical_effect(CE_DARKSIGHT, 1) + M.add_chemical_effect(CE_SPEEDBOOST, 1) + M.heal_organ_damage(1.5 * removed, 1.5 * removed) + +/datum/reagent/drink/coffee/nukie/mega/one/overdose(var/mob/living/carbon/M, var/alien, var/removed) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + H.eye_blurry += 20 + H.adjustToxLoss(min(removed * overdose_mod * round(3 + 3 * volume / overdose), 1)) + H.adjustFireLoss(min(removed * overdose_mod * round(3 + 3 * volume / overdose), 1)) + H.adjustBruteLoss(min(removed * overdose_mod * round(3 + 3 * volume / overdose), 1)) + H.add_modifier(/datum/modifier/berserk, 2 SECONDS, suppress_failure = TRUE) diff --git a/icons/obj/cooking_event.dmi b/icons/obj/cooking_event.dmi new file mode 100644 index 0000000000000000000000000000000000000000..a44a2c2a49cf559690f89496e0c44844c847eedf GIT binary patch literal 2700 zcmb_eX*|^39{DJ`f<(5b#) zVKNBsKb8|SdtD<1X@#zNj>IW{RvMi`CRV803`$3UeiMRKir+eX0sx_0OEc4}k8^(K zBJLe>R?h}pmm4CSE=AsSK`}RDX)M4u}8KKL_pG(H`30k zYC<$yWlYtAW$6cg>9sn#zR)nYNQho5YAv;n{aoAbeMuOa6F%ZMl68}NQOP+|cTK&S zD%;K;3iq02zSIve=SGxdzZXiYuU8C%An!l4-xN=wUop0qTzs70RJd^sCrOi3!>h%6 zPz*mr|6Kq@)n!;ekIB3h@$Go8o|aqze{IZ(UcFvz+c#lCaXwz>G+HP^Df;X%QHaHu zZrG$Zvipm+Ejacme@=^bt>7`?il=Vk6q ztj_iK^Z<>5i~P^{xirzB@MQ7<=P>!dUSXzp+yDi-1r|zy3vV>@o-Lt{&g{LVhc}7lyOzO`{In%d}N& z7*$9Z^{wu^UWf~t5DymblZM97SLF$na-qyeQ9|L+<$*XV{XBzzm38J&lE5m;Ge^H1G>pOunE(__m%jD!FOe0uRj`byHp4Ci>U5OQ_%0)jJ9ESacx7<> zZ#-vz0l1|3z0x-{HBO<8G~eARp(MhbBEK6 z<~owqBegfIfo_3j8}&Cf8s8axsH@e+mVEXjvZ@wTTEmOxx&+qCqP&nW{M|=oUBVud z9oPDX2s*dBvKYsfGNbxw+el;p`8U3k7R+!M_Tmz-yfCF0!#GxX`fUe2d za^J{E!rTewZ76UibX}!t(RskJbmUvDk5{#1y&>oTQ{i>$#Gp;_&4m`9AL*VD?S|1| zo0tfVQ}`S1;NJfJTY-W5=c@)r8S*dy0)Zeu44e~_m62(TL6#LuJx-05J(cMmc?~#L z#a}Ck3vCl<#J_mw?D>s5*H1G!-GqJrV7KPUVS(GF)z5(C4%yA&l)1ItR2I zDaF0t+h%_`)yTigy9Vg^`I>(fG}`$}1t-3bj*fPEVtUu#|IS9J8&9dEBr&mrQ!*wX zSlQx4LmY<_Fj5AFU^X@${$62_u#zm)Le-*tmY{i#0K@*;jO~!*iMqPGaK{mS>$Hnt`Z)~6Ag^=a=Zx| zL+iBITXE%fMPRP{9EjJ-LQAK(@T$7GKm{+~>*6{5;edMu0`rS^lywTiGryc@v|RrdiLFXn_hK9MG7)?V!%ztwEi2Itl?1p;A)U!VRf6s7iDYi;WT0m0wTVz+ZZ#--n4HyY0S@4JwnK8;@69HZymzH#fE z0<}WjhqSw*KehH>6m#?+YB7~ljn2NC{)cMYMbpZ=$;|#+VW{W2suSWTkZqSevB4dxWY<;}=ZVlWmyF#{i3 z-8jW9l}Y)(Joq$JqJ?J<{9-&C)CB_o7GDbD-+@R}L<6gkWiu`?4Mj~YFzo+>#Y*uY Y=g|68xxwq|yzeDodEUyb^sEQ=p9OhJ_W%F@ literal 0 HcmV?d00001 diff --git a/icons/obj/general_collector.dmi b/icons/obj/general_collector.dmi new file mode 100644 index 0000000000000000000000000000000000000000..52ac3e35de1d945f310530e3629247566f175532 GIT binary patch literal 827 zcmV-B1H}A^P)fFDZ*Bkpc$`yKaB_9`^iy#0_2eo` zEh^5;&r`5fFwryM;w;ZhDainGjE%TBGg33tGfE(w;*!LYR3KAHiHkEOv#1!zH00t; zD@x2wg|OiYl5+Bsvr~)W^YgGP1sa@^nv+-w5;o8=#-cGT4ZBWrgid1}B*>+#;OgfB z_6-1gj5<^Lz?0wr00J9HL_t(&f$f*;a)Tfggaf&dhR{sj|7BYZ60RO)IhvWU{pDs2AJD~c1nwztjZ5=zI?w23RA!{hT*GtdLwuX z=({JK1|WV4FdcXc+>H?@V|7mh5I_DFxubM}w&sPsbsSpb+WKxvf?sP}_A;6ILF z0bzy(ZpLV(a{++wU9&%tB3xiR-~5)JalO9?V4EqJ0f^`L5d|Rr0)R`RFaYzDZ$S!h zj`Vnh0hmt%Ff096XitFLduUUD9r6$1CvXRVh-062*46dxV($N>&)xq?pSyUFK6n2o zeYD@hKHBf$^T!2-Um*P-IiI`#lRkI| zN&h3JAfD5f{h#!?`#gww1>caay43K=USN8k%04s|{Q-GR&j{{Ks{`peD zZvjB``{&pxSpnwzy#vVi`vw3+zju!y-|uk%x5MiCeLH~t#t>^Z4FIry-wdF(-!}n3 z`h5!ksNc5$fckv{fZeAcp7VA69tJ@BJq*zMeOK4_>JL}}TQ{S7?KS`a002ovPDHLk FV1jI(g@OP8 literal 0 HcmV?d00001 diff --git a/vorestation.dme b/vorestation.dme index eb8d86b49a..6f0fe4cded 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2622,6 +2622,10 @@ #include "code\modules\error_handler\error_viewer.dm" #include "code\modules\error_handler\~defines.dm" #include "code\modules\eventkit\event_machinery.dm" +#include "code\modules\eventkit\collector_event\admin_commands.dm" +#include "code\modules\eventkit\collector_event\blockers.dm" +#include "code\modules\eventkit\collector_event\event_collector.dm" +#include "code\modules\eventkit\collector_event\nukies_maker\nukies_collector.dm" #include "code\modules\eventkit\generic_objects\generic_item.dm" #include "code\modules\eventkit\generic_objects\generic_structure.dm" #include "code\modules\eventkit\gm_interfaces\fake_pda_conversations.dm" @@ -3531,6 +3535,7 @@ #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\broodmother_spawn.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\carrier.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\electric.dm" +#include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\event_spiders.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\frost.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\giant_spider_vr.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\hunter.dm" @@ -3543,7 +3548,6 @@ #include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\webslinger.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\hyena\hyena.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\armadillo_ch.dm" -#include "code\modules\mob\living\simple_mob\subtypes\animal\giant_spider\event_spiders.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\cockroach.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\crab.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\fish.dm"