diff --git a/code/__DEFINES/~monkestation/artifact.dm b/code/__DEFINES/~monkestation/artifact.dm index e4fcd4ff9c4f..8c5ed4744bfa 100644 --- a/code/__DEFINES/~monkestation/artifact.dm +++ b/code/__DEFINES/~monkestation/artifact.dm @@ -15,15 +15,19 @@ #define ARTIFACT_UNCOMMON 400 #define ARTIFACT_VERYUNCOMMON 300 #define ARTIFACT_RARE 250 -#define ARTIFACT_VERYRARE 140 +#define ARTIFACT_VERYRARE 125 -//cuts down on boiler plate code -#define ARTIFACT_SETUP(X,subsystem) ##X/Initialize(mapload, var/forced_origin = null){\ +//cuts down on boiler plate code, last 3 args can be null. +#define ARTIFACT_SETUP(X,subsystem,forced_origin,forced_effect,forced_size) ##X/Initialize(mapload){\ . = ..();\ START_PROCESSING(subsystem, src);\ if(assoc_comp) {\ - assoc_comp = AddComponent(assoc_comp, forced_origin);\ + assoc_comp = AddComponent(assoc_comp, forced_origin, forced_effect, forced_size);\ RegisterSignal(src, COMSIG_QDELETING, PROC_REF(on_delete));\ + if(isitem(src)) {\ + RegisterSignal(src,COMSIG_ITEM_POST_EQUIPPED,PROC_REF(on_artifact_touched));\ + RegisterSignal(src,COMSIG_MOB_ITEM_ATTACK,PROC_REF(on_artifact_attack));\ + }\ }\ } \ ##X/proc/on_delete(atom/source){\ @@ -33,17 +37,39 @@ ##X/process(){\ assoc_comp?.stimulate_from_turf_heat(get_turf(src));\ if(assoc_comp?.active) {\ - assoc_comp.effect_process();\ + for(var/datum/artifact_effect/eff in assoc_comp.artifact_effects) {\ + eff.effect_process();\ + }\ + }\ +} \ +##X/proc/on_artifact_touched(obj/item/the_item,mob/toucher,slot){ \ + SIGNAL_HANDLER; \ + if(assoc_comp) { \ + for(var/datum/artifact_effect/eff in assoc_comp.artifact_effects) {\ + eff.effect_touched(toucher);\ + }\ + }\ +}\ +##X/proc/on_artifact_attack(mob/target, mob/user, params){ \ + SIGNAL_HANDLER; \ + if(assoc_comp) { \ + for(var/datum/artifact_effect/eff in assoc_comp.artifact_effects) {\ + eff.effect_touched(target);\ + if(prob(10)){ \ + eff.effect_touched(user);\ + } \ + }\ }\ } \ ##X/rad_act(intensity){\ assoc_comp?.stimulate_from_rad_act(intensity)\ } -#define STIMULUS_CARBON_TOUCH (1<<0) -#define STIMULUS_SILICON_TOUCH (1<<1) -#define STIMULUS_FORCE (1<<2) -#define STIMULUS_HEAT (1<<3) -#define STIMULUS_SHOCK (1<<4) -#define STIMULUS_RADIATION (1<<5) -#define STIMULUS_DATA (1<<6) + +#define STIMULUS_CARBON_TOUCH (1<<1) +#define STIMULUS_SILICON_TOUCH (1<<2) +#define STIMULUS_FORCE (1<<3) +#define STIMULUS_HEAT (1<<4) +#define STIMULUS_SHOCK (1<<5) +#define STIMULUS_RADIATION (1<<6) +#define STIMULUS_DATA (1<<7) diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index bd68bed5b46c..a42422215636 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -677,11 +677,24 @@ design_ids = list( "anomaly_neutralizer", "reactive_armour", + //"artifact_heater", //MONKESTATION EDIT REMOVAL + //"artifact_xray", //MONKESTATION EDIT REMOVAL + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) +//MONKEYSTATION ADDITION START +/datum/techweb_node/artifact + id = "artifact_research" + display_name = "Artifact Research" + description = "Properly concuct research on the various artifacts found around." + prereq_ids = list("base") + design_ids = list( "artifact_heater", "artifact_xray", + "disk_artifact", + "artifact_wand" ) - research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000) - + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) +//MONKESTATION ADDITION END /datum/techweb_node/high_efficiency id = "high_efficiency" display_name = "High Efficiency Parts" diff --git a/icons/obj/machines/artifact_machines.dmi b/icons/obj/machines/artifact_machines.dmi index 004e7539d4e5..8cbd0b5ff0ba 100644 Binary files a/icons/obj/machines/artifact_machines.dmi and b/icons/obj/machines/artifact_machines.dmi differ diff --git a/monkestation/code/modules/art_sci_overrides/activators/_base.dm b/monkestation/code/modules/art_sci_overrides/activators/_base.dm index 57c25345fc73..34f1ecd81594 100644 --- a/monkestation/code/modules/art_sci_overrides/activators/_base.dm +++ b/monkestation/code/modules/art_sci_overrides/activators/_base.dm @@ -5,12 +5,16 @@ var/required_stimuli = NONE /// our baseline amount needed to even think about triggering (do this in setup otherwise its gonna be static) var/base_trigger_amount = 0 - ///the highest number our trigger can be + ///the highest number our trigger can be var/highest_trigger_amount = 0 ///the end goal of the amount we need set by setup below var/amount = 0 ///the hint we want to pass into the componenet for when we hit hint triggers - var/list/hint_texts = list("emits a faint noise..") + var/list/hint_texts = list("Emits a faint noise..") + ///what it says on inspect when discovered + var/discovered_text = "Activated by ... coderbus" + ///Research value when discovered + var/research_value = 0 /datum/artifact_activator/proc/setup(potency) amount = round(max(base_trigger_amount, base_trigger_amount + (highest_trigger_amount - base_trigger_amount) * (potency/100))) diff --git a/monkestation/code/modules/art_sci_overrides/activators/range.dm b/monkestation/code/modules/art_sci_overrides/activators/range.dm index dd946af80fbe..11a8c7237d48 100644 --- a/monkestation/code/modules/art_sci_overrides/activators/range.dm +++ b/monkestation/code/modules/art_sci_overrides/activators/range.dm @@ -3,7 +3,7 @@ /datum/artifact_activator/range name = "Generic Range Trigger" - //the upper range of the weapon basically between amount, and upper_range + var/upper_range = 0 ///Hint range goes like amount - hint_range to upper_range + hint_range var/hint_range = 0 @@ -12,40 +12,46 @@ /datum/artifact_activator/range/setup(potency) . = ..() - upper_range = amount + (hint_range * 2) /datum/artifact_activator/range/force name = "Physical Trauma" required_stimuli = STIMULUS_FORCE - highest_trigger_amount = 30 //any higher than this and its gonna be practically impossible to trigger + highest_trigger_amount = 10 //*meaty thwack* *both chuckle* hint_prob = 50 - hint_range = 10 - hint_texts = list("you almost want to start hitting things.", "a good whack might fix this.") + hint_range = 5 + hint_texts = list("You almost want to start hitting things.", "A good whack might fix this.") + discovered_text = "Activated by Kinetic Energy" + +/datum/artifact_activator/range/force/New() + base_trigger_amount = rand(2,highest_trigger_amount) /datum/artifact_activator/range/heat name = "Heat Sensisty" required_stimuli = STIMULUS_HEAT hint_range = 20 - highest_trigger_amount = 15000 - hint_texts = list("it feels like someone messed with the thermostat.", "it feels unpleasent being near") + highest_trigger_amount = 750 + hint_texts = list("It feels like someone messed with the thermostat.", "It feels unpleasent being near") + discovered_text = "Activated by Thermal Energy" /datum/artifact_activator/range/heat/New() - base_trigger_amount = rand(350, 1000) + base_trigger_amount = rand(350, highest_trigger_amount) /datum/artifact_activator/range/shock name = "Electrical Charged" required_stimuli = STIMULUS_SHOCK - highest_trigger_amount = 10000 // requires atleast t2 parts to trigger a max roll one + highest_trigger_amount = 1200 hint_range = 500 - hint_texts = list("you can feel the static in the air", "your hairs stand on their ends") + hint_texts = list("You can feel the static in the air", "Your hairs stand on their ends") + discovered_text = "Activated by Electrical Energy" /datum/artifact_activator/range/shock/New() - base_trigger_amount = rand(400, 1200) + base_trigger_amount = rand(400, highest_trigger_amount) /datum/artifact_activator/range/radiation name = "Radioactivity" required_stimuli = STIMULUS_RADIATION - highest_trigger_amount = 10 + highest_trigger_amount = 5 hint_range = 2 base_trigger_amount = 1 //x-ray machine goes from 1-10 - hint_texts = list("emits a hum that resembles the Super Matter", "you could swear you saw your bones for a second") + hint_texts = list("Emits a hum that resembles the Super Matter", "You could swear you saw your bones for a second") + discovered_text = "Activated by Radiation" diff --git a/monkestation/code/modules/art_sci_overrides/activators/touch.dm b/monkestation/code/modules/art_sci_overrides/activators/touch.dm index 4cdee177fd24..7d365b6f94b8 100644 --- a/monkestation/code/modules/art_sci_overrides/activators/touch.dm +++ b/monkestation/code/modules/art_sci_overrides/activators/touch.dm @@ -8,13 +8,16 @@ name = "Data" required_stimuli = STIMULUS_DATA hint_texts = list("It yearns for information") + discovered_text = "Activated by Information" /datum/artifact_activator/touch/carbon name = "Carbon Touch" required_stimuli = STIMULUS_CARBON_TOUCH hint_texts = list("You swear you hear the artifact saying it yearns for flesh.", "One touch couldn't hurt could it?") + discovered_text = "Activated by Organic Contact" /datum/artifact_activator/touch/silicon name = "Silicon Touch" required_stimuli = STIMULUS_SILICON_TOUCH hint_texts = list("It feels like it's malfunctioning") + discovered_text = "Activated by Silicon Contact" diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/_base_component.dm b/monkestation/code/modules/art_sci_overrides/artifact_components/_base_component.dm index 1e0520de7d1d..8ed960ebe0ea 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/_base_component.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_components/_base_component.dm @@ -1,13 +1,11 @@ #define BASE_MAX_ACTIVATORS 2 +#define BASE_MAX_EFFECTS 2 +#define STIMULI_CD_TIME 5 SECONDS /datum/component/artifact dupe_mode = COMPONENT_DUPE_UNIQUE - ///object related to this datum for spawning - var/obj/associated_object - ///actual specific object for this instance + //The object we are attached to var/obj/holder - ///list weight for picking this artifact datum (0 = never) - var/weight = 0 ///size class for visuals (ARTIFACT_SIZE_TINY,ARTIFACT_SIZE_SMALL,ARTIFACT_SIZE_LARGE) var/artifact_size = ARTIFACT_SIZE_LARGE ///type name for displaying on analysis forms @@ -21,7 +19,7 @@ ///activators that activate the artifact var/list/datum/artifact_activator/activators = list() var/max_activators = BASE_MAX_ACTIVATORS - ///Valid activators to pick + ///Valid activators to pick,mostly legacy code. var/list/valid_activators = list( /datum/artifact_activator/touch/carbon, /datum/artifact_activator/touch/silicon, @@ -32,71 +30,82 @@ /datum/artifact_activator/range/shock, /datum/artifact_activator/range/radiation, ) - ///valid list of faults with their weights [10 is base] - var/list/valid_faults = list( - /datum/artifact_fault/ignite = 10, - /datum/artifact_fault/warp = 10, - /datum/artifact_fault/reagent/poison = 10, - /datum/artifact_fault/death = 2, - /datum/artifact_fault/tesla_zap = 5, - /datum/artifact_fault/shrink = 10, - /datum/artifact_fault/explosion = 2, - ) - ///origin datum + ///this artifacts origin var/datum/artifact_origin/artifact_origin - ///origin datums to pick + ///Just any effect that is real and can be added to an artifact. Mostly legacy var/list/valid_origins = list( /datum/artifact_origin/narsie, /datum/artifact_origin/wizard, /datum/artifact_origin/silicon, /datum/artifact_origin/precursor, - /datum/artifact_origin/martian, + /datum/artifact_origin/martian ) var/activation_message var/activation_sound var/deactivation_message var/deactivation_sound - var/hint_text = "emits a faint noise.." - var/examine_hint var/mutable_appearance/act_effect - /// Potency in percentage, used for making more strong artifacts need more stimulus. (1% - 100%) 100 is strongest. - var/potency = 1 + ///Have we been xray scanned at least once? + var/researched = FALSE - ///structure description from x-ray machines - var/xray_result = "NONE" ///we store our analysis form var here var/obj/item/sticker/analysis_form/analysis var/mutable_appearance/extra_effect - ///the fault we picked from the listed ones + ///the fault we picked from the listed ones. Can be null! var/datum/artifact_fault/chosen_fault - ///the amount of freebies we get + ///the amount of times an artifact WONT do something bad, even though it should have var/freebies = 3 ///if we have a special examine IE borgers var/explict_examine + ///Fault = weight + var/static/list/datum/artifact_fault/fault_weight_list + + ///The activators we have discovered. + var/list/datum/artifact_activator/discovered_activators = list() + ///Have we discovered what the bad is? + var/fault_discovered = FALSE + ///A list of effects the artifact has + var/list/datum/artifact_effect/artifact_effects = list() + ///A list of effects that have been discovered + var/list/datum/artifact_effect/discovered_effects = list() + + COOLDOWN_DECLARE(reactivate_cooldown) -/datum/component/artifact/Initialize(forced_origin = null) - . = ..() +/datum/component/artifact/Initialize(forced_origin,forced_effect,forced_size) if(!isobj(parent)) return COMPONENT_INCOMPATIBLE holder = parent GLOB.running_artifact_list[holder] = src + if(forced_size != null) + artifact_size = forced_size + + if(!length(fault_weight_list)) + var/list/datum/artifact_fault/valid_faults_pre = typecacheof(/datum/artifact_fault,ignore_root_path = TRUE) + var/list/datum/artifact_fault/valid_faults = list() + for(var/datum/artifact_fault/fault as anything in valid_faults_pre) + valid_faults += fault + valid_faults[fault] = fault.weight + fault_weight_list = valid_faults if(forced_origin) valid_origins = list(forced_origin) - var/picked_origin = pick(valid_origins) + var/datum/artifact_origin/picked_origin = pick(valid_origins) artifact_origin = new picked_origin fake_name = "[pick(artifact_origin.name_vars["adjectives"])] [pick(isitem(holder) ? artifact_origin.name_vars["small-nouns"] : artifact_origin.name_vars["large-nouns"])]" - var/picked_fault = pick_weight(valid_faults) - chosen_fault = new picked_fault + if(prob(95)) + var/picked_fault = pick_weight(fault_weight_list) + chosen_fault = new picked_fault + chosen_fault.our_artifact = src + chosen_fault.on_added(src) generated_name = artifact_origin.generate_name() if(!generated_name) generated_name = "[pick(artifact_origin.name_vars["adjectives"])] [pick(isitem(holder) ? artifact_origin.name_vars["small-nouns"] : artifact_origin.name_vars["large-nouns"])]" holder.name = fake_name - holder.desc = "You have absolutely no clue what this thing is or how it got here." + holder.desc = "Some sort of artifact from a time long past." var/dat_icon switch(artifact_size) @@ -124,20 +133,35 @@ activation_sound = pick(artifact_origin.activation_sounds) if(LAZYLEN(artifact_origin.deactivation_sounds)) deactivation_sound = pick(artifact_origin.deactivation_sounds) - + setup() var/activator_amount = rand(1,max_activators) - while(activator_amount>0) + for(var/i in 1 to activator_amount) var/selection = pick(valid_activators) valid_activators -= selection - activators += new selection() - activator_amount-- - - ADD_TRAIT(holder, TRAIT_HIDDEN_EXPORT_VALUE, INNATE_TRAIT) - setup() - potency = clamp(potency, 0, 100) - for(var/datum/artifact_activator/activator in activators) + var/datum/artifact_activator/activator = new selection() + activators += activator + var/potency = rand(0,100) activator.setup(potency) - hint_text = activator.grab_hint() + if(forced_effect) + var/datum/artifact_effect/added_boogaloo = new forced_effect + artifact_effects += added_boogaloo + added_boogaloo.our_artifact = src + added_boogaloo.setup() + if(!length(GLOB.artifact_effect_rarity["all"])) + build_weighted_rarities() + var/list/datum/artifact_effect/dont_touch = GLOB.artifact_effect_rarity["all"] //Dont touch because below. + var/list/datum/artifact_effect/all_possible_effects = dont_touch.Copy() //If you touch it, it actually edits the list, we need a copy. We cant call copy directly because its not a static type list. + var/effects_amount = rand(1,BASE_MAX_EFFECTS) + + while(effects_amount > 0) + if(effects_amount <= 0) + logger.Log(LOG_CATEGORY_ARTIFACT, "[src] has ran out of possible artifact effects! It may not have any at all!") + break + var/datum/artifact_effect/effect = pick_weight(all_possible_effects) + all_possible_effects -= effect + if(try_add_effect(effect)) + effects_amount-- + /datum/component/artifact/RegisterWithParent() RegisterSignals(parent, list(COMSIG_ATOM_DESTRUCTION, COMSIG_QDELETING), PROC_REF(on_destroy)) @@ -168,10 +192,122 @@ COMSIG_ATOM_NO_LONGER_PULLED, COMSIG_ATOM_PULLED, )) +///This just clears all the effects,activators,and faults of the artifact, so we can add new ones with a proc. +/datum/component/artifact/proc/clear_out() + QDEL_LIST(activators) + QDEL_NULL(chosen_fault) + QDEL_LIST(artifact_effects) + fault_discovered = FALSE + discovered_effects = list() + return +///Adds an activator, returns TRUE/FALSE based on success. +/datum/component/artifact/proc/add_activator(datum/artifact_activator/new_activator,forced_potency = 0) + if(!new_activator) + return FALSE + if(length(activators) >= BASE_MAX_ACTIVATORS) + return FALSE + var/datum/artifact_activator/created + if(ispath(new_activator)) + created = new new_activator() + else + created = new new_activator.type + activators += created + if(forced_potency > 0 ) + created.setup(forced_potency) + else + created.setup(rand(1,100)) + return TRUE +///changes the fault of the artifact, returns TRUE/FALSE based on success. +/datum/component/artifact/proc/change_fault(datum/artifact_fault/new_fault) + if(new_fault) + return force_replace_fault(new_fault.type) + else + qdel(chosen_fault) + chosen_fault = new new_fault + return TRUE + +/* +* Long function, but basically: +* For given effect: +* If it has valid types, check to make sure its of the right type path. So you cant roll something that requires a structure on an item. +* If it has valid origins, and the artifact isnt that origin, return FALSE. +* If it has valid activators, and the artifact has none of them, return FALSE. +* If it has a valid size, and the artifact isnt that size, return FALSE. +* Then, if all is well, slam it on the artifact, call setup() on the effect, return TRUE +*/ +/datum/component/artifact/proc/try_add_effect(datum/artifact_effect/effect) + var/datum/artifact_effect/added + if(ispath(effect)) + added = new effect //We need it now, becasue for some reason we cant read the lists from just the raw datum. + else + added = new effect.type //Skip the checks, just add it. + artifact_effects += added + added.our_artifact = src + added.setup() + return TRUE + if(length(added.valid_type_paths)) + var/bad_path = FALSE + for(var/path in added.valid_type_paths) + if(!istype(holder,path)) + bad_path = TRUE + break + if(bad_path) + QDEL_NULL(added) + return FALSE + if(length(added.valid_origins)) + if(!(artifact_origin.type_name in added.valid_origins)) + QDEL_NULL(added) + return FALSE + if(length(added.valid_activators)) + var/good_activators = FALSE + for(var/datum/artifact_activator/activator as anything in activators) //Only need one to be correct. + if(activator.type in added.valid_activators) + good_activators = TRUE + break + if(!good_activators) + QDEL_NULL(added) + return FALSE + if(added.artifact_size) + if(artifact_size != added.artifact_size) + QDEL_NULL(added) + return FALSE + artifact_effects += added + added.our_artifact = src + added.setup() + return TRUE +///Kinda a legacy proc, but if you need something super special I guess. /datum/component/artifact/proc/setup() return +///Replaces the fault on the artifact with a new one. +/datum/component/artifact/proc/force_replace_fault(new_fault) + if(new_fault) + qdel(chosen_fault) + if(ispath(new_fault)) + chosen_fault = new new_fault + chosen_fault.our_artifact = src + chosen_fault.on_added(src) + else + chosen_fault = new_fault + chosen_fault.our_artifact = src + chosen_fault.on_added(src) + return TRUE + return FALSE + +///Adds a new artifact effect to the artifact. Ignores all normal checks. Admin Proc. Not called. +/datum/component/artifact/proc/force_add_effect(new_effect_path,effect_power = null) + if(new_effect_path && ispath(new_effect_path,/datum/artifact_effect)) + var/datum/artifact_effect/added_boogaloo = new new_effect_path + artifact_effects += added_boogaloo + added_boogaloo.our_artifact = src + if(effect_power) + added_boogaloo.potency = effect_power + added_boogaloo.setup() + return TRUE + return FALSE + +///Activates the artifact. /datum/component/artifact/proc/artifact_activate(silent) if(active) //dont activate activated objects return FALSE @@ -183,10 +319,12 @@ active = TRUE holder.add_overlay(act_effect) logger.Log(LOG_CATEGORY_ARTIFACT, "[parent] has been activated") - effect_activate(silent) + for(var/datum/artifact_effect/effect in artifact_effects) + effect.effect_activate(silent) return TRUE -/datum/component/artifact/proc/artifact_deactivate(silent) +///The opposite of activates the artifact +/datum/component/artifact/proc/artifact_deactivate(silent = FALSE) if(!active) return if(deactivation_sound && !silent) @@ -196,14 +334,22 @@ active = FALSE holder.cut_overlay(act_effect) logger.Log(LOG_CATEGORY_ARTIFACT, "[parent] has been deactivated") - effect_deactivate(silent) + for(var/datum/artifact_effect/effect in artifact_effects) + effect.effect_deactivate(silent) +/datum/component/artifact/effect_touched(mob/living/user) + for(var/datum/artifact_effect/effect in artifact_effects) + effect.effect_touched(user) + return + +///Called when the artifact gets something that may activate it. Skips re-activation of artifacts, but passes their triggers to faults. /datum/component/artifact/proc/process_stimuli(stimuli, stimuli_value, triggers_faults = TRUE) - if(!stimuli || active) // if called without a stimuli dont bother, if active we dont wanna reactivate + if(!stimuli) return var/checked_fault = FALSE + var/correct_trigger = FALSE for(var/datum/artifact_activator/listed_activator in activators) - if(!(listed_activator.required_stimuli & stimuli)) + if(!(listed_activator.required_stimuli & stimuli) && chosen_fault) if(!triggers_faults) continue if(freebies >= 1) @@ -219,17 +365,16 @@ holder.visible_message("[holder] [chosen_fault.visible_message]") continue checked_fault = TRUE - if(istype(listed_activator, /datum/artifact_activator/range)) - var/datum/artifact_activator/range/ranged_activator = listed_activator - //if we fail the range check check if we are in hint range to send out the hint - if(!ISINRANGE(stimuli_value, ranged_activator.amount, ranged_activator.upper_range)) - if(hint_text && !ISINRANGE(stimuli_value, ranged_activator.amount - ranged_activator.hint_range, ranged_activator.upper_range + ranged_activator.hint_range)) - continue - if(!prob(ranged_activator.hint_prob)) - continue - holder.visible_message(span_notice("[hint_text]")) + if((listed_activator.required_stimuli & stimuli) && istype(listed_activator, /datum/artifact_activator/range)) + if(stimuli_value < listed_activator.amount) continue + correct_trigger = TRUE + break + if(active || !correct_trigger) + return + if(COOLDOWN_FINISHED(src,reactivate_cooldown)) artifact_activate() + COOLDOWN_START(src,reactivate_cooldown,STIMULI_CD_TIME) /datum/component/artifact/proc/stimulate_from_turf_heat(turf/target) if(!QDELETED(target)) @@ -239,3 +384,5 @@ process_stimuli(STIMULUS_RADIATION, intensity) #undef BASE_MAX_ACTIVATORS +#undef BASE_MAX_EFFECTS +#undef STIMULI_CD_TIME diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/_base_component_signal_procs.dm b/monkestation/code/modules/art_sci_overrides/artifact_components/_base_component_signal_procs.dm index 03874852ae2a..9b89fd631f0f 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/_base_component_signal_procs.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_components/_base_component_signal_procs.dm @@ -4,15 +4,29 @@ if(!QDELETED(holder)) holder.loc.visible_message(span_warning("[holder] [artifact_origin.destroy_message]")) artifact_deactivate(TRUE) + for(var/datum/artifact_effect/effect in artifact_effects) + effect.on_destroy(source) if(!QDELETED(holder)) qdel(holder) /datum/component/artifact/proc/on_examine(atom/source, mob/user, list/examine_list) SIGNAL_HANDLER - if(examine_hint) - examine_list += examine_hint if(explict_examine) examine_list += explict_examine + for(var/datum/artifact_effect/effect in artifact_effects) + if(discovered_effects.Find(effect.type) && effect.examine_discovered) + examine_list += span_info(effect.examine_discovered) + else if (effect.examine_hint) + examine_list += span_info(effect.examine_hint) + + for(var/datum/artifact_activator/act in activators) + if(discovered_activators.Find(act.type) && act.discovered_text) + examine_list += span_info(act.discovered_text) + else if(length(act.hint_texts)) + examine_list += span_info(pick(act.hint_texts)) + + if(chosen_fault && chosen_fault.inspect_warning) + examine_list += span_warning(pick(chosen_fault.inspect_warning)) /datum/component/artifact/proc/on_sticker(atom/source, obj/item/sticker/sticker, mob/user) SIGNAL_HANDLER @@ -75,7 +89,8 @@ logger.Log(LOG_CATEGORY_ARTIFACT, "[user] has touched [parent]") if(active) - effect_touched(user) + for(var/datum/artifact_effect/effect in artifact_effects) + effect.effect_touched(user) return if(LAZYLEN(artifact_origin.touch_descriptors)) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), user, span_notice("[pick(artifact_origin.touch_descriptors)]")), 0.5 SECONDS) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/bomb.dm b/monkestation/code/modules/art_sci_overrides/artifact_components/bomb.dm deleted file mode 100644 index 476af7185a04..000000000000 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/bomb.dm +++ /dev/null @@ -1,152 +0,0 @@ -/datum/component/artifact/bomb - examine_hint = span_warning("It is covered in very conspicuous markings.") - valid_activators = list( - /datum/artifact_activator/range/force, - /datum/artifact_activator/range/heat, - /datum/artifact_activator/range/shock, - /datum/artifact_activator/range/radiation - ) - deactivation_message = "sputters a bit, and falls silent once more." - xray_result = "COMPLEX" - var/dud = FALSE - var/dud_message = "sputters, failing to activate! Its a dud!" - var/initial_warning = "begins overloading, rattling violenty!" - var/explode_delay = 1 MINUTES // also delayed by finale_delay for fluff - var/explode_cooldown_time = 1 MINUTES - var/finale_delay = 6 SECONDS //delay before we actually deliver the payload for fluff - var/final_message = "reaches a catastrophic overload, cracks forming at its surface!" - var/sound/active_alarm = 'sound/effects/alert.ogg' // plays every alarm_cooldown_time when active - var/alarm_cooldown_time = 3 SECONDS - var/sound/final_sound = 'sound/misc/bloblarm.ogg' - COOLDOWN_DECLARE(activation_cooldown) - COOLDOWN_DECLARE(alarm_cooldown) - var/timer_id - var/do_alert = FALSE //do we send an announcement on activation - -/datum/component/artifact/bomb/setup() - if(prob(20)) - dud = TRUE - -/datum/component/artifact/bomb/effect_activate() - if(!COOLDOWN_FINISHED(src,explode_cooldown_time)) - holder.visible_message(span_warning("[holder] [deactivation_message]")) //rekt - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/component/artifact, artifact_deactivate)), 1 SECONDS) - return - holder.visible_message(span_bolddanger("[holder] [initial_warning]")) - COOLDOWN_START(src,activation_cooldown,explode_cooldown_time) - timer_id = addtimer(CALLBACK(src, PROC_REF(finale)), explode_delay, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE) - if(do_alert && is_station_level(holder.z)) - priority_announce("A highly unstable object of type [type_name] has been activated at [get_area(holder)]. It has been marked on GPS, The crew is advised to get rid of it IMMEDIATELY.", null, SSstation.announcer.get_rand_report_sound(), has_important_message = TRUE) - holder.AddComponent(/datum/component/gps, "Unstable Object") - -/datum/component/artifact/bomb/effect_deactivate() - deltimer(timer_id) - -/datum/component/artifact/bomb/effect_process() - . = ..() - if(active && COOLDOWN_FINISHED(src,alarm_cooldown) && (COOLDOWN_TIMELEFT(src,alarm_cooldown) <= finale_delay)) - playsound(holder, active_alarm, 30, 1) - holder.Shake(duration = 1 SECONDS, shake_interval = 0.08 SECONDS) - COOLDOWN_START(src,alarm_cooldown, alarm_cooldown_time) - -/datum/component/artifact/bomb/proc/finale() - if(final_sound) - playsound(holder.loc, final_sound, 100, 1, -1) - if(finale_delay) - holder.visible_message(span_bolddanger("[holder] [final_message]")) - addtimer(CALLBACK(src, PROC_REF(payload)), finale_delay) - else - payload() - -/datum/component/artifact/bomb/on_destroy(/datum/source) - . = ..() - if(active) - payload() - deltimer(timer_id) - -/datum/component/artifact/bomb/proc/payload() - . = TRUE - if(dud || !active) - holder.visible_message(span_notice("[holder] [dud_message]")) - artifact_deactivate(TRUE) - return FALSE - -/// EXPLOSIVE BOMB - -/datum/component/artifact/bomb/explosive - associated_object = /obj/structure/artifact/bomb - type_name = "Bomb (explosive)" - weight = ARTIFACT_RARE - var/devast - var/heavy - var/light - -/datum/component/artifact/bomb/explosive/New() - . = ..() - devast = rand(1,3) - heavy = rand(2,4) - light = rand(3,10) - potency = (light + heavy + devast) * 2 - -/datum/component/artifact/bomb/explosive/payload() - if(!..()) - return FALSE - explosion(holder, devast,heavy,light,light*1.5) - on_destroy() - -/// DEVESTATING BOMB - -/datum/component/artifact/bomb/explosive/devastating - associated_object = /obj/structure/artifact/bomb/devastating - type_name = "Bomb (explosive, devastating)" - do_alert = TRUE - weight = ARTIFACT_VERYRARE - xray_result = "DENSE" - explode_delay = 2 MINUTES - -/datum/component/artifact/bomb/explosive/devastating/New() - ..() - devast = rand(3,7) - heavy = rand(7,12) - light = rand(10,25) - potency = (devast + heavy + light) * 2.25 // get real - -/// GAS BOMB - -/datum/component/artifact/bomb/gas - associated_object = /obj/structure/artifact/bomb/gas - type_name = "Bomb (gas)" - weight = ARTIFACT_RARE - xray_result = "POROUS" - initial_warning = "begins rattling violenty!" - final_message = "reaches a critical pressure, cracks forming at its surface!" - var/datum/gas/payload_gas - var/list/weighted_gas = list( - /datum/gas/plasma = 5, - /datum/gas/carbon_dioxide = 10, - /datum/gas/nitrous_oxide = 10, - /datum/gas/tritium = 5, - /datum/gas/hydrogen = 5, - /datum/gas/zauker = 2, - ) - -/datum/component/artifact/bomb/gas/setup() - . = ..() - payload_gas = pick_weight(weighted_gas) - -/datum/component/artifact/bomb/gas/payload() - if(!..()) - artifact_deactivate() - return FALSE - var/turf/open/O = get_turf(holder) - if(!isopenturf(O)) - artifact_deactivate() - return FALSE - var/datum/gas_mixture/merger = new - merger.assert_gas(payload_gas) - merger.assert_gas(/datum/gas/oxygen) - merger.gases[payload_gas][MOLES] = rand(150,2000) - merger.gases[/datum/gas/oxygen][MOLES] = 350 - merger.temperature = rand(200,3000) - O.assume_air(merger) - qdel(holder) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/bonk.dm b/monkestation/code/modules/art_sci_overrides/artifact_components/bonk.dm deleted file mode 100644 index 39b6136e894d..000000000000 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/bonk.dm +++ /dev/null @@ -1,38 +0,0 @@ -/datum/component/artifact/bonk - associated_object = /obj/structure/artifact/bonk - weight = ARTIFACT_UNCOMMON - type_name = "Slammer" - activation_message = "opens up!" - deactivation_message = "closes up." - valid_activators = list( - /datum/artifact_activator/touch/carbon, - /datum/artifact_activator/touch/silicon - ) - ///force of the hit - var/hit_power = 1 - COOLDOWN_DECLARE(bonk_cooldown) - -/datum/component/artifact/bonk/setup() - hit_power = rand(0,35) - potency += hit_power - -/datum/component/artifact/bonk/effect_touched(mob/living/user) - if(!COOLDOWN_FINISHED(src, bonk_cooldown)) - return - - if(iscarbon(user)) - var/mob/living/carbon/carbon = user - if(!carbon.get_bodypart(BODY_ZONE_HEAD)) - holder.say("My condolences to your missing head.") //they can speak uhh galactic common because alien tech idk - holder.visible_message(span_notice("[holder] shakes [user][p_s()] hands with an apparatus.")) - playsound(get_turf(holder), 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) - artifact_deactivate() - return - else - carbon.apply_damage(hit_power, BRUTE, BODY_ZONE_HEAD, carbon.run_armor_check(BODY_ZONE_HEAD, MELEE)) - holder.visible_message(span_danger("[holder] hits [carbon] over the head!")) - else - holder.visible_message(span_danger("[holder] slams [user]!")) - user.adjustBruteLoss(hit_power) - playsound(get_turf(holder), 'sound/misc/bonk.ogg', 80, FALSE) - COOLDOWN_START(src, bonk_cooldown, 1.5 SECONDS) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/cell.dm b/monkestation/code/modules/art_sci_overrides/artifact_components/cell.dm deleted file mode 100644 index 2c3ee53a1886..000000000000 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/cell.dm +++ /dev/null @@ -1,37 +0,0 @@ -/datum/component/artifact/cell - associated_object = /obj/item/stock_parts/cell/artifact - artifact_size = ARTIFACT_SIZE_TINY - type_name = "Power Cell" - weight = ARTIFACT_UNCOMMON - xray_result = "SEGMENTED" - valid_activators = list( - /datum/artifact_activator/range/heat, - /datum/artifact_activator/range/shock, - /datum/artifact_activator/range/radiation - ) - valid_faults = list( - /datum/artifact_fault/ignite = 10, - /datum/artifact_fault/warp = 10, - /datum/artifact_fault/reagent/poison = 10, - /datum/artifact_fault/death = 2, - /datum/artifact_fault/tesla_zap = 5, - /datum/artifact_fault/grow = 10, - /datum/artifact_fault/explosion = 2, - ) - -/datum/component/artifact/cell/setup() - var/obj/item/stock_parts/cell/artifact/cell = holder - cell.corrupted = prob(10) //trolled - cell.maxcharge = rand(5 KW, 500 MW) // the heavenly battery - cell.charge = cell.maxcharge / 2 - cell.chargerate = rand(5000, round(cell.maxcharge * 0.4)) - potency += cell.maxcharge / 900 - potency += cell.chargerate / 4000 - -/datum/component/artifact/cell/effect_activate() - var/obj/item/stock_parts/cell/artifact/cell = holder - cell.ratingdesc = TRUE - -/datum/component/artifact/cell/effect_deactivate() - var/obj/item/stock_parts/cell/artifact/cell = holder - cell.ratingdesc = FALSE diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/ghost_object.dm b/monkestation/code/modules/art_sci_overrides/artifact_components/ghost_object.dm new file mode 100644 index 000000000000..38c66f0e7863 --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_components/ghost_object.dm @@ -0,0 +1,118 @@ +///This is straight up an object version of the spirit plade one +/datum/component/ghost_object_control + var/attempting_awakening = FALSE + ///mob contained in the item,null untill controlled! + var/mob/living/basic/shade/bound_spirit + ///do we make a callback to retry untill someone posesses it? + var/repolling= FALSE + ///How often can this thing move in seconds + var/speed= 1.25 + COOLDOWN_DECLARE(move_cooldown) +/datum/component/ghost_object_control/Initialize(repoll = FALSE,move_speed = null) + if(!ismovable(parent)) //you may apply this to mobs, I take no responsibility for how that works out + return COMPONENT_INCOMPATIBLE + if(move_speed) + speed = move_speed + +/datum/component/ghost_object_control/Destroy(force, silent) + . = ..() + if(bound_spirit) + QDEL_NULL(bound_spirit) + +/datum/component/ghost_object_control/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_destroy)) + RegisterSignal(parent, COMSIG_ATOM_RELAYMOVE, TYPE_PROC_REF(/datum/component/ghost_object_control,move_host)) + //RegisterSignal(parent, COMSIG_RIDDEN_DRIVER_MOVE, TYPE_PROC_REF(/datum/component/ghost_object_control,move_host)) + +/datum/component/ghost_object_control/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE, COMSIG_QDELETING, COMSIG_ATOM_RELAYMOVE)) + +///Moves the object. Yippee! +/datum/component/ghost_object_control/proc/move_host(atom/movable/movable_parent,mob/buckled_mob,dir_to_move) + SIGNAL_HANDLER + + if(!COOLDOWN_FINISHED(src, move_cooldown)) + return COMSIG_BLOCK_RELAYMOVE + var/turf/next = get_step(movable_parent, dir_to_move) + var/turf/current = get_turf(movable_parent) + if(!istype(next) || !istype(current)) + return COMSIG_BLOCK_RELAYMOVE + if(next.density) + return COMSIG_BLOCK_RELAYMOVE + if(!isturf(movable_parent.loc)) + return COMSIG_BLOCK_RELAYMOVE + + step(movable_parent, dir_to_move) + var/last_move_diagonal = ((dir_to_move & (dir_to_move - 1)) && (movable_parent.loc == next)) + COOLDOWN_START(src, move_cooldown, ((last_move_diagonal ? 2 : 1) * speed) SECOND) + + if(QDELETED(src)) + return COMSIG_BLOCK_RELAYMOVE + return TRUE + +///signal fired on examining the parent +/datum/component/ghost_object_control/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + if(!bound_spirit) + return + examine_list += span_notice("[parent] is moving somehow?") + +///Call to poll for ghost role +/datum/component/ghost_object_control/proc/request_control(movement_speed) + if(attempting_awakening) + return + if(!(GLOB.ghost_role_flags & GHOSTROLE_STATION_SENTIENCE)) + return + + attempting_awakening = TRUE + + var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates( + "Do you want to play as [parent]?", + check_jobban = ROLE_SENTIENCE, + poll_time = 10 SECONDS, + ignore_category = POLL_IGNORE_SENTIENCE_POTION, + alert_pic = parent, + role_name_text = "[parent]", + ) + if(!LAZYLEN(candidates)) + if(repolling) + addtimer(CALLBACK(src,PROC_REF(request_control),2.5 MINUTE)) + attempting_awakening = FALSE + return + + var/mob/dead/observer/chosen_spirit = pick(candidates) + bound_spirit = new(parent) + bound_spirit.ckey = chosen_spirit.ckey + bound_spirit.fully_replace_character_name(null, "[parent]") + bound_spirit.status_flags |= GODMODE + bound_spirit.grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue + bound_spirit.update_atom_languages() + speed = movement_speed + + //Add new signals for parent and stop attempting to awaken + + // Now that all of the important things are in place for our spirit, it's time for them to choose their name. + var/valid_input_name = custom_name(bound_spirit) + if(valid_input_name) + bound_spirit.fully_replace_character_name(null, "[valid_input_name]") + + attempting_awakening = FALSE + +/** + * custom_name : Simply sends a tgui input text box to the blade asking what name they want to be called, and retries it if the input is invalid. + * + * Arguments: + * * awakener: user who interacted with the blade + */ +/datum/component/ghost_object_control/proc/custom_name(mob/subject) + var/chosen_name = sanitize_name(tgui_input_text(bound_spirit, "What are you named?", "Spectral Nomenclature", max_length = MAX_NAME_LEN)) + if(!chosen_name) // with the way that sanitize_name works, it'll actually send the error message to the awakener as well. + return custom_name(subject) //YOU WILL PICK A NAME. + return chosen_name + +///signal fired from parent being destroyed +/datum/component/ghost_object_control/proc/on_destroy(datum/source) + SIGNAL_HANDLER + to_chat(bound_spirit, span_userdanger("You were destroyed!")) + QDEL_NULL(bound_spirit) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/lamp.dm b/monkestation/code/modules/art_sci_overrides/artifact_components/lamp.dm deleted file mode 100644 index c62124f20c62..000000000000 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/lamp.dm +++ /dev/null @@ -1,34 +0,0 @@ - -/datum/component/artifact/lamp - associated_object = /obj/structure/artifact/lamp - weight = ARTIFACT_COMMON - type_name = "Lamp" - activation_message = "starts shining!" - deactivation_message = "stops shining." - -/datum/component/artifact/lamp/setup() - var/power - var/color = pick(COLOR_RED, COLOR_BLUE, COLOR_YELLOW, COLOR_GREEN, COLOR_PURPLE, COLOR_ORANGE) - var/range - switch(rand(1,100)) - if(1 to 75) - power = rand(2,5) - range = rand(2,5) - if(76 to 100) - range = rand(4,10) - power = rand(2,10) // the sun - - if(artifact_origin.type_name == ORIGIN_NARSIE && prob(40)) - color = COLOR_BLACK - holder.set_light_range_power_color(range, power, color) - potency += (range + power) * 2 - -/datum/component/artifact/lamp/effect_touched(mob/user) - holder.set_light_on(!holder.light_on) //toggle - to_chat(user, span_hear("[holder] clicks.")) - -/datum/component/artifact/lamp/effect_activate() - holder.set_light_on(TRUE) - -/datum/component/artifact/lamp/effect_deactivate() - holder.set_light_on(FALSE) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/repulsor.dm b/monkestation/code/modules/art_sci_overrides/artifact_components/repulsor.dm deleted file mode 100644 index 412b52123822..000000000000 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/repulsor.dm +++ /dev/null @@ -1,59 +0,0 @@ - -/datum/component/artifact/repulsor - associated_object = /obj/structure/artifact/repulsor - weight = ARTIFACT_COMMON - type_name = "Repulsor/Impulsor" - activation_message = "opens up, a weird aura starts emitting from it!" - deactivation_message = "closes up." - xray_result = "SEGMENTED" - var/attract = FALSE //if FALSE, repulse, otherwise, attract - var/strength - var/range - var/cooldown_time - COOLDOWN_DECLARE(cooldown) - -/datum/component/artifact/repulsor/setup() - attract = prob(40) - range = rand(1,3) - cooldown_time = rand(3,5) SECONDS - strength = rand(MOVE_FORCE_DEFAULT,MOVE_FORCE_OVERPOWERING) - potency += cooldown_time / 4 + strength / 3000 - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/component/artifact, artifact_deactivate)), round(20 * (potency * 10) SECONDS)) - -/datum/component/artifact/repulsor/effect_touched(mob/user) - if(!COOLDOWN_FINISHED(src,cooldown)) - return - pulse() - COOLDOWN_START(src,cooldown,cooldown_time) - -/datum/component/artifact/repulsor/effect_process() - . = ..() - if(prob(100 - potency)) - return - pulse() - -/datum/component/artifact/repulsor/RegisterWithParent() - . = ..() - RegisterSignal(parent, COMSIG_ATOM_HITBY, PROC_REF(pulse)) - -/datum/component/artifact/repulsor/UnregisterFromParent() - . = ..() - UnregisterSignal(parent, COMSIG_ATOM_HITBY) - -/datum/component/artifact/repulsor/proc/pulse(datum/source,atom/movable/thrown, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) - SIGNAL_HANDLER - if(!active) - return - holder.visible_message(span_warning("[holder] emits a pulse of energy, throwing things [attract ? "towards it!" : "away from it!"]")) - var/owner_turf = get_turf(holder) - if(isnull(thrown)) - for(var/atom/movable/throwee in oview(range,holder)) - if(throwee.anchored) - continue - if(attract) - throwee.safe_throw_at(holder, strength / 3000, 1, force = strength) - else - var/throwtarget = get_edge_target_turf(get_turf(throwee), get_dir(owner_turf, get_step_away(throwee, owner_turf))) - throwee.safe_throw_at(throwtarget, strength / 3000, 1, force = strength) - else if(throwingdatum?.thrower) - thrown.safe_throw_at(throwingdatum.thrower, get_dist(holder, throwingdatum.thrower), 1, force = strength) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/_artifact_effect.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/_artifact_effect.dm new file mode 100644 index 000000000000..cc94aacc97c6 --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/_artifact_effect.dm @@ -0,0 +1,69 @@ +/datum/artifact_effect + ///string added to artifact desc, if not discovered. + var/examine_hint + ///string added to artifact desc, if the effect has been discovered + var/examine_discovered + ///When you discover this, how many credits does it add to the sell price? + var/discovered_credits = CARGO_CRATE_VALUE*0.75 + ///how likely is it that this effect is added to an artifact? + var/weight = ARTIFACT_COMMON + ///if defined, artifact must be this size to roll + var/artifact_size + ///how strong is this effect,1-100 + var/potency + ///If the artifact doesnt have the right activator, cant be put on. If null, assume any. + var/list/valid_activators + ///If the artifact doesnt have this origin, cant be put on. If null, assume any. + var/list/valid_origins + ///sent on activation + var/activation_message + ///played on activation + var/activation_sound + ///sent on deactivation + var/deactivation_message + ///played on deactivation + var/deactivation_sound + ///list of paths the artifacts holder is allowed to be, if null, may be on any artifact datum holder. + var/list/valid_type_paths + ///Does this show up on the artifact fourm? + var/super_secret = FALSE + + ///Research value when discovered For reference,5000 is one node + var/research_value = 100 + ///The artifact we're on. + var/datum/component/artifact/our_artifact + ///Type of effect, shows up in Xray Machine + var/type_name = "Generic Artifact Effect" + +/datum/artifact_effect/New() + . = ..() + potency = rand(1,100) + + +///Called when the artifact has been created +/datum/artifact_effect/proc/setup() + return +///Called when the artifact has been activated +/datum/artifact_effect/proc/effect_activate(silent) + return +///Called when the artifact has been de-activated +/datum/artifact_effect/proc/effect_deactivate(silent) + return +///Called when the artifact has been touched by a living mob,does NOT call faults or activate artifact unless it has the correct touch component! +/datum/artifact_effect/proc/effect_touched(mob/living/user) + return +///Called on process() IF the artifact is active. +/datum/artifact_effect/proc/effect_process() + return +///Called when the artifact/effect is destroyed is destroyed +/datum/artifact_effect/proc/on_destroy(atom/source) + return +///Util, can be called to activate, then de-activate the artifact as a whole swiftly. Wont Re activate already active artifacts. +/datum/artifact_effect/proc/flick_active(silent) + if(!our_artifact.active) + our_artifact.artifact_activate(silent) + our_artifact.artifact_deactivate(silent) + return +///Util, can be called to swap the artifacts active status quickly. +/datum/artifact_effect/proc/toggle_active(silent) + our_artifact.active ? our_artifact.artifact_deactivate(silent) : our_artifact.artifact_activate(silent) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/bomb.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/bomb.dm new file mode 100644 index 000000000000..56ec1504836b --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/bomb.dm @@ -0,0 +1,155 @@ +/datum/artifact_effect/bomb + examine_hint = span_warning("It is covered in very conspicuous markings.") + valid_activators = list( + /datum/artifact_activator/range/force, + /datum/artifact_activator/range/heat, + /datum/artifact_activator/range/shock, + /datum/artifact_activator/range/radiation + ) + research_value = 1000 + + type_name = "Explosive Effect" + examine_discovered = span_warning("It appears to explode.") + + + var/dud = FALSE + var/dud_message = "sputters, failing to activate! Its a dud!" + var/initial_warning = "begins overloading, rattling violenty!" + var/explode_delay = 1 MINUTES // also delayed by finale_delay for fluff + var/explode_cooldown_time = 1 MINUTES + var/finale_delay = 6 SECONDS //delay before we actually deliver the payload for fluff + var/final_message = "reaches a catastrophic overload, cracks forming at its surface!" + var/sound/active_alarm = 'sound/effects/alert.ogg' // plays every alarm_cooldown_time when active + var/alarm_cooldown_time = 3 SECONDS + var/sound/final_sound = 'sound/misc/bloblarm.ogg' + COOLDOWN_DECLARE(activation_cooldown) + COOLDOWN_DECLARE(alarm_cooldown) + var/timer_id + var/do_alert = FALSE //do we send an announcement on activation + +/datum/artifact_effect/bomb/setup() + if(prob(20)) + dud = TRUE + +/datum/artifact_effect/bomb/effect_activate() + if(!our_artifact || !our_artifact.holder) + return + if(!COOLDOWN_FINISHED(src,activation_cooldown)) + our_artifact.holder.visible_message(span_warning("[our_artifact.holder] [deactivation_message]")) //rekt + addtimer(CALLBACK(src.our_artifact, TYPE_PROC_REF(/datum/component/artifact, artifact_deactivate)), 1 SECONDS) + return + our_artifact.holder.visible_message(span_bolddanger("[our_artifact.holder] [initial_warning]")) + COOLDOWN_START(src,activation_cooldown,explode_cooldown_time) + timer_id = addtimer(CALLBACK(src, PROC_REF(finale)), explode_delay, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE) + if(do_alert && is_station_level(our_artifact.holder.z)) + priority_announce("A highly unstable object has been activated at [get_area(our_artifact.holder)]. It has been marked on GPS, The crew is advised to get rid of it IMMEDIATELY.", null, SSstation.announcer.get_rand_report_sound(), has_important_message = TRUE) + our_artifact.holder.AddComponent(/datum/component/gps, "Unstable Object") + +/datum/artifact_effect/bomb/effect_deactivate() + deltimer(timer_id) + +/datum/artifact_effect/bomb/effect_process() + . = ..() + if(our_artifact.active && (COOLDOWN_FINISHED(src,alarm_cooldown) || (COOLDOWN_TIMELEFT(src,alarm_cooldown) <= finale_delay))) + playsound(our_artifact, active_alarm, 30, 1) + our_artifact.holder.Shake(duration = 1 SECONDS, shake_interval = 0.08 SECONDS) + COOLDOWN_START(src,alarm_cooldown, alarm_cooldown_time) + +/datum/artifact_effect/bomb/proc/finale() + if(final_sound) + playsound(our_artifact.holder.loc, final_sound, 100, 1, -1) + if(finale_delay) + our_artifact.holder.visible_message(span_bolddanger("[our_artifact.holder] [final_message]")) + addtimer(CALLBACK(src, PROC_REF(payload)), finale_delay) + else + payload() + +/datum/artifact_effect/bomb/on_destroy(datum/source) + . = ..() + if(our_artifact.active && source != src)//Prevents infinite bakoom. + payload() + deltimer(timer_id) + +/datum/artifact_effect/bomb/proc/payload() + . = TRUE + if(dud || !our_artifact.active) + our_artifact.holder.visible_message(span_notice("[our_artifact.holder] [dud_message]")) + our_artifact.artifact_deactivate(TRUE) + return FALSE + +/// EXPLOSIVE BOMB + +/datum/artifact_effect/bomb/explosive + type_name = "Bomb" + weight = ARTIFACT_RARE + var/devast + var/heavy + var/light + examine_discovered = span_danger("It appears to explode in a large radius!") + +/datum/artifact_effect/bomb/explosive/New() + . = ..() + devast = rand(1,3) + heavy = rand(2,4) + light = rand(3,10) + potency = (light + heavy + devast) * 2 + +/datum/artifact_effect/bomb/explosive/payload() + if(!..()) + return FALSE + explosion(our_artifact.holder, devast,heavy,light,light*1.5) + on_destroy(src) + +/// DEVESTATING BOMB + +/datum/artifact_effect/bomb/explosive/devastating + type_name = "Large Bomb" + do_alert = TRUE + weight = ARTIFACT_VERYRARE + explode_delay = 2 MINUTES + +/datum/artifact_effect/bomb/explosive/devastating/New() + ..() + devast = rand(2,4) + heavy = rand(4,6) + light = rand(6,16) + potency = (devast + heavy + light) * 2.25 // get real + +/// GAS BOMB + +/datum/artifact_effect/bomb/gas + type_name = "Atmospheric Bomb" + weight = ARTIFACT_RARE + examine_discovered = span_warning("It appears to explode, leaving gasses in its wake!") + initial_warning = "begins rattling violenty!" + final_message = "reaches a critical pressure, cracks forming at its surface!" + var/datum/gas/payload_gas + var/list/weighted_gas = list( + /datum/gas/plasma = 5, + /datum/gas/carbon_dioxide = 10, + /datum/gas/nitrous_oxide = 10, + /datum/gas/tritium = 5, + /datum/gas/hydrogen = 5, + /datum/gas/zauker = 2, + ) + +/datum/artifact_effect/bomb/gas/setup() + . = ..() + payload_gas = pick_weight(weighted_gas) + +/datum/artifact_effect/bomb/gas/payload() + if(!..()) + our_artifact.artifact_deactivate() + return FALSE + var/turf/open/O = get_turf(our_artifact.holder) + if(!isopenturf(O)) + our_artifact.artifact_deactivate() + return FALSE + var/datum/gas_mixture/merger = new + merger.assert_gas(payload_gas) + merger.assert_gas(/datum/gas/oxygen) + merger.gases[payload_gas][MOLES] = rand(150,2000) + merger.gases[/datum/gas/oxygen][MOLES] = 350 + merger.temperature = rand(200,3000) + O.assume_air(merger) + qdel(our_artifact) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/bonk.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/bonk.dm new file mode 100644 index 000000000000..b2fc28a51026 --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/bonk.dm @@ -0,0 +1,40 @@ +/datum/artifact_effect/bonk + weight = ARTIFACT_UNCOMMON + type_name = "Slammer Effect" + activation_message = "opens up!" + deactivation_message = "closes up." + valid_activators = list( + /datum/artifact_activator/touch/carbon, + /datum/artifact_activator/touch/silicon + ) + ///force of the hit + var/hit_power = 1 + artifact_size = ARTIFACT_SIZE_LARGE + COOLDOWN_DECLARE(bonk_cooldown) + research_value = 500 + examine_discovered = span_warning("It appears to bonk those with heads on said head.") + +/datum/artifact_effect/bonk/setup() + hit_power = rand(0,35) + potency += hit_power + +/datum/artifact_effect/bonk/effect_touched(mob/living/user) + if(!COOLDOWN_FINISHED(src, bonk_cooldown)) + return + + if(iscarbon(user)) + var/mob/living/carbon/carbon = user + if(!carbon.get_bodypart(BODY_ZONE_HEAD)) + our_artifact.holder.say("My condolences to your missing head.") //they can speak uhh galactic common because alien tech idk + our_artifact.holder.visible_message(span_notice("[our_artifact.holder] shakes [user][p_s()] hands with an apparatus.")) + playsound(get_turf(our_artifact.holder), 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1) + our_artifact.artifact_deactivate() + return + else + carbon.apply_damage(hit_power, BRUTE, BODY_ZONE_HEAD, carbon.run_armor_check(BODY_ZONE_HEAD, MELEE)) + our_artifact.holder.visible_message(span_danger("[our_artifact.holder] hits [carbon] over the head!")) + else + our_artifact.holder.visible_message(span_danger("[our_artifact.holder] slams [user]!")) + user.adjustBruteLoss(hit_power) + playsound(get_turf(our_artifact.holder), 'sound/misc/bonk.ogg', 80, FALSE) + COOLDOWN_START(src, bonk_cooldown, 1.5 SECONDS) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/borger.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/borger.dm similarity index 73% rename from monkestation/code/modules/art_sci_overrides/artifact_components/borger.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/borger.dm index e87a58fbe398..ef3e1ded89aa 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/borger.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/borger.dm @@ -1,14 +1,15 @@ -/datum/component/artifact/borger - associated_object = /obj/structure/artifact/borger - weight = ARTIFACT_UNCOMMON - type_name = "Borger" +/datum/artifact_effect/borger + weight = ARTIFACT_RARE + type_name = "Borger Effect" activation_message = "opens up!" deactivation_message = "closes up." valid_activators = list( /datum/artifact_activator/touch/carbon, /datum/artifact_activator/touch/silicon ) - explict_examine = span_bolddanger("It is vaguely forboding, touching this might be a bad idea...") + research_value = 2500 + examine_hint = span_bolddanger("It is vaguely forboding, touching this might be a bad idea...") + examine_discovered = span_bolddanger("It will turn a random limb robotic if touched, touching this might be a bad idea...") /// The time between each limb replacement var/limb_replace_time = 1 SECONDS /// People who've already touched it once. Touching it again will cause it to react. @@ -16,9 +17,9 @@ /// The cooldown between borgings. COOLDOWN_DECLARE(borg_cooldown) -/datum/component/artifact/borger/effect_touched(mob/living/user) +/datum/artifact_effect/borger/effect_touched(mob/living/user) if(!iscarbon(user) || !COOLDOWN_FINISHED(src, borg_cooldown) || QDELETED(user.client) || did_robot_touch(user)) - holder.visible_message(span_smallnoticeital("[holder] does not react to [user].")) + our_artifact.holder.visible_message(span_smallnoticeital("[our_artifact.holder] does not react to [user].")) return if(!LAZYACCESS(first_touched, user)) @@ -54,14 +55,14 @@ addtimer(CALLBACK(carbon_target, TYPE_PROC_REF(/mob/, Robotize)), timer + 5) COOLDOWN_START(src, borg_cooldown, 10 SECONDS) -/datum/component/artifact/borger/proc/eat_limb(mob/living/carbon/victim) +/datum/artifact_effect/borger/proc/eat_limb(mob/living/carbon/victim) var/arm_name = victim.get_held_index_name(victim.active_hand_index) - victim.visible_message(span_warning("[holder] lashes out and clamps down on [victim], rapidly transmuting [victim.p_their()] [arm_name]!"), \ - span_userdanger("[holder] lashes out and clamps down onto your [arm_name], rapidly transmuting it into cold metal!")) + victim.visible_message(span_warning("[our_artifact.holder] lashes out and clamps down on [victim], rapidly transmuting [victim.p_their()] [arm_name]!"), \ + span_userdanger("[our_artifact.holder] lashes out and clamps down onto your [arm_name], rapidly transmuting it into cold metal!")) var/new_arm_type = (victim.active_hand_index % 2) ? /obj/item/bodypart/arm/left/robot : /obj/item/bodypart/arm/right/robot victim.del_and_replace_bodypart(new new_arm_type) victim.emote("scream") -/datum/component/artifact/borger/proc/did_robot_touch(mob/living/carbon/user) +/datum/artifact_effect/borger/proc/did_robot_touch(mob/living/carbon/user) var/obj/item/bodypart/arm/active_arm = user.get_active_hand() return istype(active_arm) && (active_arm.bodytype & BODYTYPE_ROBOTIC) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/bread.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/bread.dm new file mode 100644 index 000000000000..47e9791fbd5b --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/bread.dm @@ -0,0 +1,52 @@ +/datum/artifact_effect/bread + examine_discovered = "Summons bread?" + weight = ARTIFACT_UNCOMMON + discovered_credits = CARGO_CRATE_VALUE * 2 //Mmm bread + activation_message = "begins baking some fresh eldritch brand bread!" + deactivation_message = "runs out of bread!" + research_value = 500 + type_name = "Bread Teleportation Effect" + + COOLDOWN_DECLARE(bread_cd) + + var/bread_counter = 0 + + ///We sell BREAD. We sell LOAF. TOASTED, ROASTED... + var/static/list/obj/item/food/validbread = list( + /obj/item/food/bread/plain = 20, + /obj/item/food/bread/meat = 15, + /obj/item/food/bread/banana = 15, + /obj/item/food/bread/tofu = 10, + /obj/item/food/croissant = 10, + /obj/item/food/baguette = 10, + /obj/item/food/garlicbread = 10, + /obj/item/food/bread/creamcheese = 10, + /obj/item/food/frenchtoast = 8, + /obj/item/food/breadstick = 8, + /obj/item/food/butterbiscuit = 5, + /obj/item/food/bread/mimana = 5, + /obj/item/food/bread/sausage = 5, + /obj/item/food/bread/xenomeat = 1, + /obj/item/food/bread/spidermeat = 1 + ) + +/datum/artifact_effect/bread/effect_process() + if(!COOLDOWN_FINISHED(src,bread_cd)) + return + var/center_turf = get_turf(our_artifact.parent) + var/list/turf/valid_turfs = list() + if(!center_turf) + CRASH("[src] had attempted to trigger, but failed to find the center turf!") + for(var/turf/boi in range(3,center_turf)) + if(boi.density) + continue + valid_turfs += boi + var/obj/item/food/pickedbread = pick_weight(validbread) + new pickedbread(pick(valid_turfs)) + bread_counter++ + if(bread_counter > round(potency/10)) + bread_counter = 0 + toggle_active(FALSE) + return + COOLDOWN_START(src,bread_cd,(7.5 SECONDS)) + diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/cell.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/cell.dm new file mode 100644 index 000000000000..2da2af3b00ff --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/cell.dm @@ -0,0 +1,28 @@ +/datum/artifact_effect/cell + type_name = "Power Cell Effect" + weight = ARTIFACT_UNCOMMON + artifact_size = ARTIFACT_SIZE_TINY + valid_activators = list( + /datum/artifact_activator/range/heat, + /datum/artifact_activator/range/shock, + /datum/artifact_activator/range/radiation + ) + valid_type_paths = list(/obj/item/stock_parts/cell/artifact) + research_value = 500 + examine_discovered = span_warning("It appears to hold power") + +/datum/artifact_effect/cell/setup() + var/obj/item/stock_parts/cell/artifact/cell = our_artifact.holder + cell.maxcharge = rand(5 KW, 500 MW) // the heavenly battery + cell.charge = cell.maxcharge / 2 + cell.chargerate = rand(5000, round(cell.maxcharge * 0.4)) + potency += cell.maxcharge / 900 + potency += cell.chargerate / 4000 + +/datum/artifact_effect/cell/effect_activate() + var/obj/item/stock_parts/cell/artifact/cell = our_artifact.holder + cell.ratingdesc = TRUE + +/datum/artifact_effect/cell/effect_deactivate() + var/obj/item/stock_parts/cell/artifact/cell = our_artifact.holder + cell.ratingdesc = FALSE diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/cleaning.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/cleaning.dm new file mode 100644 index 000000000000..1b61aad86c44 --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/cleaning.dm @@ -0,0 +1,17 @@ +/datum/artifact_effect/soap + examine_hint = "Smells nice." + examine_discovered = "Seems to clean things." + artifact_size = ARTIFACT_SIZE_TINY + type_name = "Cleaning Effect" + +/datum/artifact_effect/soap/setup() + our_artifact.holder.AddComponent(/datum/component/slippery, 80) + our_artifact.holder.AddComponent(/datum/component/cleaner, 2 SECOND, 0.1, pre_clean_callback=CALLBACK(src, PROC_REF(should_clean)), on_cleaned_callback=CALLBACK(src, TYPE_PROC_REF(/datum/artifact_effect/soap,sorry_nothing))) + +/datum/artifact_effect/soap/proc/should_clean(datum/cleaning_source, atom/atom_to_clean, mob/living/cleaner) + if(isitem(our_artifact.holder)) + var/obj/item/yep_its_an_item = our_artifact.holder + return yep_its_an_item.check_allowed_items(atom_to_clean) + return FALSE +/datum/artifact_effect/soap/proc/sorry_nothing(datum/source, atom/target, mob/living/user, clean_succeeded) + return diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/emoter.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/emoter.dm similarity index 60% rename from monkestation/code/modules/art_sci_overrides/artifact_components/emoter.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/emoter.dm index 88c88d374bb0..772bd97c0ad5 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/emoter.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/emoter.dm @@ -1,7 +1,6 @@ -/datum/component/artifact/emotegen - associated_object = /obj/structure/artifact/emotegen +/datum/artifact_effect/emotegen weight = ARTIFACT_UNCOMMON - type_name = "Emote Forcefield" + type_name = "Emote Forcefield Effect" activation_message = "springs to life and starts emitting a forcefield!" deactivation_message = "shuts down, its forcefields shutting down with it." valid_activators = list( @@ -9,6 +8,9 @@ /datum/artifact_activator/touch/silicon, /datum/artifact_activator/range/force ) + + research_value = 150 + var/cooldown_time //cooldown AFTER the shield lowers var/radius var/shield_time @@ -25,10 +27,13 @@ "snore", "cry", ) + + examine_discovered = span_warning("It appears to radiate an emotional field") + var/list/picked_emotes = list() COOLDOWN_DECLARE(cooldown) -/datum/component/artifact/emotegen/setup() +/datum/artifact_effect/emotegen/setup() for(var/i = 1 to rand(3,4)) picked_emotes += pick(all_emotes) @@ -39,24 +44,24 @@ cooldown_time = shield_time / 3 potency += radius * 3 + shield_time / 30 -/datum/component/artifact/emotegen/effect_activate(silent) +/datum/artifact_effect/emotegen/effect_activate(silent) if(!COOLDOWN_FINISHED(src,cooldown)) - holder.visible_message(span_notice("[holder] wheezes, shutting down.")) - artifact_deactivate(TRUE) + our_artifact.holder.visible_message(span_notice("[our_artifact.holder] wheezes, shutting down.")) + our_artifact.artifact_deactivate(TRUE) return - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/component/artifact, artifact_deactivate)), shield_time) + addtimer(CALLBACK(our_artifact, TYPE_PROC_REF(/datum/component/artifact, artifact_deactivate)), shield_time) COOLDOWN_START(src,cooldown,shield_time + cooldown_time) -/datum/component/artifact/emotegen/effect_process() +/datum/artifact_effect/emotegen/effect_process() var/current_emote = pick(picked_emotes) - holder.anchored = TRUE - var/turf/our_turf = get_turf(holder) - for(var/turf/open/floor in range(radius,holder)) + our_artifact.holder.anchored = TRUE + var/turf/our_turf = get_turf(our_artifact.holder) + for(var/turf/open/floor in range(radius,our_artifact.holder)) if(floor == our_turf) continue for(var/mob/living/living in floor) living.emote(current_emote, intentional = FALSE) -/datum/component/artifact/emotegen/effect_deactivate() - holder.anchored = FALSE +/datum/artifact_effect/emotegen/effect_deactivate() + our_artifact.holder.anchored = FALSE diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/false_rod.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/false_rod.dm new file mode 100644 index 000000000000..27030a251101 --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/false_rod.dm @@ -0,0 +1,93 @@ +/datum/artifact_effect/false_rod + examine_hint = span_warning("You feel a binding aura connected to this.") + examine_discovered = span_warning("Will bind it self to the wearer, forcing upon them an oath to heal!") + weight = ARTIFACT_UNCOMMON + + artifact_size = ARTIFACT_SIZE_SMALL + type_name = "Oath-Bearing Rod Effect" + + var/list/first_touched + + var/mob/living/our_victim + + COOLDOWN_DECLARE(touch_cooldown) + +/datum/artifact_effect/false_rod/setup() + RegisterSignal(our_artifact.holder,COMSIG_ITEM_POST_EQUIPPED,TYPE_PROC_REF(/datum/artifact_effect/false_rod,on_pickup)) + +/datum/artifact_effect/false_rod/proc/on_pickup(obj/item/the_item,mob/taker,slot) + SIGNAL_HANDLER + if(!isliving(taker)) + return COMPONENT_EQUIPPED_FAILED + var/mob/living/user = taker + if(!(isitem(our_artifact.holder)) || !COOLDOWN_FINISHED(src,touch_cooldown)) + return COMPONENT_EQUIPPED_FAILED + if(!LAZYACCESS(first_touched, user)) + to_chat(user,span_bolddanger("You hesitate before touching [our_artifact.holder], feeling it will do something that cannot be un-done easily!")) + LAZYSET(first_touched, user, TRUE) + COOLDOWN_START(src, touch_cooldown, 7.5 SECONDS) // so you don't get fucked over by spam-clicking it + return COMPONENT_EQUIPPED_FAILED + addtimer(CALLBACK(src,PROC_REF(post_pickup),user),(0.2 SECOND)) + return + +/datum/artifact_effect/false_rod/on_destroy(atom/source) + our_victim?.remove_status_effect(/datum/status_effect/forced_oath) + . = ..() + +/datum/artifact_effect/false_rod/proc/post_pickup(mob/living/user) + to_chat(user,span_danger("[our_artifact.holder] forcefully melds with you, and a healing aura surrounds you!")) + ADD_TRAIT(our_artifact.holder,TRAIT_NODROP,CURSED_ITEM_TRAIT(our_artifact.holder.type)) + user.apply_status_effect(/datum/status_effect/forced_oath) + our_victim = user + return + +/datum/status_effect/forced_oath + id = "Forced Oath" + status_type = STATUS_EFFECT_UNIQUE + duration = -1 + tick_interval = 25 + alert_type = null + var/datum/component/aura_healing/our_aura + +/datum/status_effect/forced_oath/on_apply() + var/static/list/organ_healing = list( + ORGAN_SLOT_BRAIN = 0.7, + ) + //This is literally shitty Rod of Ascep. + our_aura = owner.AddComponent( \ + /datum/component/aura_healing, \ + range = 5, \ + brute_heal = 1, \ + burn_heal = 1, \ + toxin_heal = 1, \ + suffocation_heal = 1, \ + stamina_heal = 1, \ + clone_heal = 0.2, \ + simple_heal = 1, \ + organ_healing = organ_healing, \ + healing_color = "#375637", \ + ) + + var/datum/atom_hud/med_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + med_hud.show_to(owner) + return TRUE +/datum/status_effect/forced_oath/on_remove() + QDEL_NULL(our_aura) + var/datum/atom_hud/med_hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] + med_hud.hide_from(owner) +/datum/status_effect/forced_oath/get_examine_text() + return span_notice("[owner.p_they(TRUE)] seem[owner.p_s()] to have an aura of healing around [owner.p_them()].") +/datum/status_effect/forced_oath/tick() + if(owner.stat ==DEAD) + return + else + if(iscarbon(owner)) + if(owner.health < owner.maxHealth) + new /obj/effect/temp_visual/heal(get_turf(owner), "#375637") + owner.adjustBruteLoss(-1) + owner.adjustFireLoss(-1) + owner.adjustToxLoss(-1, forced = TRUE) //Because Slime People are people too + owner.adjustOxyLoss(-1, forced = TRUE) + owner.stamina.adjust(1) + owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, -1) + owner.adjustCloneLoss(-0.25) //Becasue apparently clone damage is the bastion of all health diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/forcegen.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/forcegen.dm similarity index 68% rename from monkestation/code/modules/art_sci_overrides/artifact_components/forcegen.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/forcegen.dm index 95be5fbb3305..04608b5b8764 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/forcegen.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/forcegen.dm @@ -11,13 +11,13 @@ resistance_flags = INDESTRUCTIBLE can_atmos_pass = ATMOS_PASS_DENSITY + /obj/structure/artifact_forcefield/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) playsound(loc, 'sound/weapons/egloves.ogg', 80, TRUE) -/datum/component/artifact/forcegen - associated_object = /obj/structure/artifact/forcegen +/datum/artifact_effect/forcegen weight = ARTIFACT_UNCOMMON - type_name = "Forcefield Generator" + type_name = "Forcefield Generator Effect" activation_message = "springs to life and starts emitting a forcefield!" deactivation_message = "shuts down, its forcefields shutting down with it." valid_activators = list( @@ -25,6 +25,11 @@ /datum/artifact_activator/touch/silicon, /datum/artifact_activator/range/force ) + + research_value = 5000 + + examine_discovered = span_warning("It appears to generate some kind of forcefield") + var/cooldown_time //cooldown AFTER the shield lowers var/shield_iconstate var/list/projected_forcefields = list() @@ -32,26 +37,25 @@ var/shield_time COOLDOWN_DECLARE(cooldown) -/datum/component/artifact/forcegen/setup() +/datum/artifact_effect/forcegen/setup() shield_iconstate = pick("shieldsparkles","empdisable","shield2","shield-old","shield-red","shield-green","shield-yellow") activation_sound = pick('sound/mecha/mech_shield_drop.ogg') deactivation_sound = pick('sound/mecha/mech_shield_raise.ogg','sound/magic/forcewall.ogg') - shield_time = rand(10,40) SECONDS + shield_time = rand(10,30) SECONDS radius = rand(1,3) cooldown_time = shield_time / 3 - potency += radius * 3 + shield_time / 30 -/datum/component/artifact/forcegen/effect_activate() +/datum/artifact_effect/forcegen/effect_activate() if(!COOLDOWN_FINISHED(src,cooldown)) - holder.visible_message(span_notice("[holder] wheezes, shutting down.")) - artifact_deactivate(TRUE) + our_artifact.holder.visible_message(span_notice("[our_artifact.holder] wheezes, shutting down.")) + our_artifact.artifact_deactivate(TRUE) return - holder.anchored = TRUE - var/turf/our_turf = get_turf(holder) + our_artifact.holder.anchored = TRUE + var/turf/our_turf = get_turf(our_artifact.holder) var/list/bad_turfs if(radius > 1) - bad_turfs = range(radius - 1, holder) - for(var/turf/open/floor in range(radius,holder)) + bad_turfs = range(radius - 1, our_artifact.holder) + for(var/turf/open/floor in range(radius,our_artifact.holder)) if(floor in bad_turfs) continue if(floor == our_turf) @@ -59,11 +63,11 @@ var/obj/field = new /obj/structure/artifact_forcefield(floor) field.icon_state = shield_iconstate projected_forcefields += field - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/component/artifact, artifact_deactivate)), shield_time) + addtimer(CALLBACK(our_artifact, TYPE_PROC_REF(/datum/component/artifact, artifact_deactivate)), shield_time) COOLDOWN_START(src,cooldown,shield_time + cooldown_time) -/datum/component/artifact/forcegen/effect_deactivate() - holder.anchored = FALSE +/datum/artifact_effect/forcegen/effect_deactivate() + our_artifact.holder.anchored = FALSE for(var/obj/field in projected_forcefields) projected_forcefields -= field qdel(field) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/gun.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/gun.dm similarity index 75% rename from monkestation/code/modules/art_sci_overrides/artifact_components/gun.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/gun.dm index 7425c524e47a..a574230764ad 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/gun.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/gun.dm @@ -1,26 +1,20 @@ #define LOWEST_POSSIBLE_CLICK_CD 3 #define HIGHEST_POSSIBLE_CLICK_CD 15 -/datum/component/artifact/gun - associated_object = /obj/item/gun/magic/artifact +/datum/artifact_effect/gun artifact_size = ARTIFACT_SIZE_SMALL - type_name = "Ranged Weapon" + type_name = "Ranged Weapon Effect" weight = ARTIFACT_VERYUNCOMMON //rare - xray_result = "COMPLEX" valid_activators = list( /datum/artifact_activator/range/heat, /datum/artifact_activator/range/shock, /datum/artifact_activator/range/radiation ) - valid_faults = list( - /datum/artifact_fault/ignite = 10, - /datum/artifact_fault/warp = 10, - /datum/artifact_fault/reagent/poison = 10, - /datum/artifact_fault/death = 2, - /datum/artifact_fault/tesla_zap = 5, - /datum/artifact_fault/grow = 10, - /datum/artifact_fault/explosion = 2, - ) + valid_type_paths = list(/obj/item/gun/magic/artifact) + + research_value = 500 + + examine_discovered = span_warning("It appears to be some sort of projectile weapon!") //list of projectile exclusive projectiles ///damage each shot does @@ -46,14 +40,11 @@ var/list/damage_types = list( BRUTE, BURN, - TOX, - OXY, - BRAIN, - STAMINA + TOX ) -/datum/component/artifact/gun/setup() - var/obj/item/gun/magic/artifact/our_wand = holder +/datum/artifact_effect/gun/setup() + var/obj/item/gun/magic/artifact/our_wand = our_artifact.holder var/obj/item/ammo_casing/casing = our_wand.chambered //randomize our casing casing.click_cooldown_override = rand(LOWEST_POSSIBLE_CLICK_CD, HIGHEST_POSSIBLE_CLICK_CD) @@ -62,7 +53,7 @@ spread += 0.1 spread += prob(65) ? rand(0.0, 0.2) : rand(0.3, 1.0) - damage = rand(-5, 25) + damage = rand(-10, 30) projectile_icon = pick("energy","scatterlaser","toxin","energy","spell","pulse1","bluespace","gauss","gaussweak","gaussstrong","redtrac","omnilaser","heavylaser","laser","infernoshot","cryoshot","arcane_barrage") dam_type = pick(damage_types) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/heal.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/heal.dm similarity index 59% rename from monkestation/code/modules/art_sci_overrides/artifact_components/heal.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/heal.dm index 9177d7dea38e..67c2e1a535f3 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/heal.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/heal.dm @@ -1,22 +1,23 @@ #define PROCESSES_PER_HEAL 5 -/datum/component/artifact/heal - associated_object = /obj/structure/artifact/heal +/datum/artifact_effect/heal weight = ARTIFACT_VERYUNCOMMON - type_name = "Single Healer" + type_name = "Single Healer Effect" activation_message = "starts emitting a soothing aura!" deactivation_message = "becomes silent." valid_activators = list( /datum/artifact_activator/touch/carbon, /datum/artifact_activator/touch/silicon ) - ///list of damage types we heal, this is randomly removed from at setup + + examine_discovered = span_warning("It appears to heal those who touch it.") + + research_value = 250 + + ///list of what we heal var/list/damage_types = list( BRUTE, BURN, - TOX, - OXY, - BRAIN, - CLONE, + TOX ) ///how much do we heal var/heal_amount @@ -24,29 +25,19 @@ var/process_count = 0 COOLDOWN_DECLARE(heal_cooldown) -/datum/component/artifact/heal/setup() - heal_amount = rand(1,15) - potency += heal_amount - var/type_amount = prob(75) ? 4 : rand(2,4) //75% to remove 4 types for 1 heal type or 25% for 2 or 4 types removed - while(type_amount) - type_amount-- - damage_types -= pick(damage_types) - potency += 5 * (length(damage_types) - 1) +/datum/artifact_effect/heal/setup() + heal_amount = rand(5,10) -/datum/component/artifact/heal/effect_touched(mob/living/user) +/datum/artifact_effect/heal/effect_touched(mob/living/user) if(!COOLDOWN_FINISHED(src, heal_cooldown)) return - var/damage_length = length(damage_types) for(var/dam_type in damage_types) - user.heal_damage_type( (heal_amount / damage_length), dam_type) + user.heal_damage_type( (heal_amount), dam_type) to_chat(user, span_notice("You feel slightly refreshed!")) new /obj/effect/temp_visual/heal(get_turf(user), COLOR_HEALING_CYAN) COOLDOWN_START(src, heal_cooldown, 5 SECONDS) -/datum/component/artifact/heal/effect_process() - if(potency < 75) - return - +/datum/artifact_effect/heal/effect_process() process_count++ if(process_count < PROCESSES_PER_HEAL) return diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/injector.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/injector.dm similarity index 64% rename from monkestation/code/modules/art_sci_overrides/artifact_components/injector.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/injector.dm index dc30a0192443..3d82ebf98ed0 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/injector.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/injector.dm @@ -1,18 +1,20 @@ -/datum/component/artifact/injector - associated_object = /obj/structure/artifact/injector +/datum/artifact_effect/injector weight = ARTIFACT_UNCOMMON - type_name = "Injector" + type_name = "Injector Effect" activation_message = "opens up to reveal a large needle!" deactivation_message = "pulls its needle inside, closing itself up." - xray_result = "SEGMENTED" var/max_reagents // the total amount to dose the victim with var/reagent_amount var/list/reagent_datums = list() var/cooldown_time = 10 SECONDS COOLDOWN_DECLARE(activation_cooldown) -/datum/component/artifact/injector/setup() - holder.create_reagents(200, NO_REACT | SEALED_CONTAINER) + research_value = 250 + + examine_discovered = span_warning("It appears to be some sort of chemical injector") + +/datum/artifact_effect/injector/setup() + our_artifact.holder.create_reagents(200, NO_REACT | SEALED_CONTAINER) reagent_amount = rand(10,25) max_reagents = rand(1,2) var/static/list/poisons_and_medicines = list() @@ -20,7 +22,7 @@ for(var/datum/reagent/reagent as anything in (subtypesof(/datum/reagent/toxin) + subtypesof(/datum/reagent/medicine))) if(initial(reagent.chemical_flags) & REAGENT_CAN_BE_SYNTHESIZED) poisons_and_medicines += reagent - switch(artifact_origin.type_name) + switch(our_artifact.artifact_origin.type_name) if(ORIGIN_NARSIE) for(var/i in 1 to max_reagents) reagent_datums += pick(poisons_and_medicines) //cult likes killing people ok @@ -36,12 +38,12 @@ reagent_datums += pick(silicon_reagents) potency += reagent_amount + max_reagents -/datum/component/artifact/injector/effect_touched(mob/living/user) +/datum/artifact_effect/injector/effect_touched(mob/living/user) if(!ishuman(user) || !COOLDOWN_FINISHED(src,activation_cooldown)) - holder.visible_message(span_smallnoticeital("[holder] does not react to [user].")) + our_artifact.holder.visible_message(span_smallnoticeital("[our_artifact.holder] does not react to [user].")) return for(var/reagent in reagent_datums) - holder.reagents.add_reagent(reagent, reagent_amount / reagent_datums.len) - holder.visible_message(span_danger("[holder] pricks [user] with its needle!"), span_userdanger("OW! You are pricked by [holder]!")) - holder.reagents.trans_to(user, holder.reagents.total_volume, transfered_by = holder, methods = INJECT) + our_artifact.holder.reagents.add_reagent(reagent, reagent_amount / reagent_datums.len) + our_artifact.holder.visible_message(span_danger("[our_artifact.holder] pricks [user] with its needle!"), span_userdanger("OW! You are pricked by [our_artifact.holder]!")) + our_artifact.holder.reagents.trans_to(user, our_artifact.holder.reagents.total_volume, transfered_by = our_artifact.holder, methods = INJECT) COOLDOWN_START(src,activation_cooldown,cooldown_time) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/itsasecret.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/itsasecret.dm new file mode 100644 index 000000000000..bcda23c9678a --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/itsasecret.dm @@ -0,0 +1,44 @@ +/datum/artifact_effect/toeverybody + examine_hint = "Seems...off somehow." + examine_discovered = "Temporarily tears holes in reality." + discovered_credits = CARGO_CRATE_VALUE * 100 //GDM + weight = ARTIFACT_VERYRARE/5 //Super rare + activation_message = "tears open the fabric of reality!" + + research_value = 10000 + + type_name = "Its a Secret to Everybody" + + super_secret = TRUE + + COOLDOWN_DECLARE(trigger_cd) + +/datum/artifact_effect/toeverybody/proc/returnthey(mob/living/carbon/human,turf/last_position) + human.forceMove(last_position) + return + +/datum/artifact_effect/toeverybody/effect_activate(silent) + if(!COOLDOWN_FINISHED(src,trigger_cd)) + return + var/list/mobs = list() + var/mob/living/carbon/human + + var/center_turf = get_turf(our_artifact.parent) + + if(!center_turf) + CRASH("[src] had attempted to trigger, but failed to find the center turf!") + + for(var/mob/living/carbon/mob in range(rand(3, 4), center_turf)) + mobs += mob + if(!length(mobs)) + return + human = pick(mobs) + if(!human) + return + + var/last_position = get_turf(human) + human.move_to_error_room() + COOLDOWN_START(src,trigger_cd,5 MINUTE) + addtimer(CALLBACK(src,PROC_REF(returnthey),human,last_position),5 SECOND) + return + diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/lamp.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/lamp.dm new file mode 100644 index 000000000000..9e4d4ae0dd1e --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/lamp.dm @@ -0,0 +1,38 @@ + +/datum/artifact_effect/lamp + weight = ARTIFACT_COMMON + type_name = "Lamp" + activation_message = "starts shining!" + deactivation_message = "stops shining." + examine_discovered = span_warning("It appears to be some sort of light source") + + artifact_size = ARTIFACT_SIZE_LARGE + + research_value = 250 + +/datum/artifact_effect/lamp/setup() + var/power + var/color = pick(COLOR_RED, COLOR_BLUE, COLOR_YELLOW, COLOR_GREEN, COLOR_PURPLE, COLOR_ORANGE) + var/range + switch(rand(1,100)) + if(1 to 75) + power = rand(2,5) + range = rand(2,5) + if(76 to 100) + range = rand(4,10) + power = rand(5,10) // the sun + + if(our_artifact.artifact_origin.type_name == ORIGIN_NARSIE && prob(40)) + color = COLOR_BLACK + our_artifact.holder.light_system = COMPLEX_LIGHT //We need this to avoid a crash for wrong lighting system. + our_artifact.holder.set_light(range, round(range*1.25),power,l_color = color,l_on = FALSE) + +/datum/artifact_effect/lamp/effect_touched(mob/user) + our_artifact.holder.set_light_on(!our_artifact.holder.light_on) //toggle + to_chat(user, span_hear("[our_artifact.holder] clicks.")) + +/datum/artifact_effect/lamp/effect_activate() + our_artifact.holder.set_light_on(TRUE) + +/datum/artifact_effect/lamp/effect_deactivate() + our_artifact.holder.set_light_on(FALSE) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/meat.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/meat.dm new file mode 100644 index 000000000000..5781d29458ca --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/meat.dm @@ -0,0 +1,54 @@ +/datum/artifact_effect/meat + examine_discovered = "Summons meat?" + weight = ARTIFACT_UNCOMMON + discovered_credits = CARGO_CRATE_VALUE * 2 //ME A T + activation_message = "begins stealing meat!" + deactivation_message = "gets caught stealing meat!" + research_value = 500 + type_name = "Meat Teleportation Effect" + + COOLDOWN_DECLARE(meat_cd) + + var/meat_counter = 0 + + ///MY MEAT BYCICLE IS BIGGER THAN YOURS - Kreig borderlands + var/static/list/obj/item/food/validmeat = list( + /obj/item/food/meat/slab = 20, + /obj/item/food/meat/slab/meatwheat = 20, + /obj/item/food/meat/slab/monkey = 15, + /obj/item/food/meat/slab/bugmeat = 15, + /obj/item/food/meat/slab/mothroach = 15, + /obj/item/food/meat/slab/mouse = 15, + /obj/item/food/meat/slab/pug = 10, + /obj/item/food/meat/slab/goliath = 10, + /obj/item/food/meat/slab/corgi = 10, + /obj/item/food/meat/slab/gorilla = 5, + /obj/item/food/meat/slab/bear = 5, + /obj/item/food/meat/slab/xeno = 5, + /obj/item/food/meat/slab/spider = 5, + /obj/item/food/meat/slab/human/mutant/slime = 1, + /obj/item/food/meat/slab/human/mutant/lizard = 1, + /obj/item/food/meat/slab/human = 1, + /obj/item/food/meat/slab/human/mutant/skeleton = 1, + ) + +/datum/artifact_effect/meat/effect_process() + if(!COOLDOWN_FINISHED(src,meat_cd)) + return + var/center_turf = get_turf(our_artifact.parent) + var/list/turf/valid_turfs = list() + if(!center_turf) + CRASH("[src] had attempted to trigger, but failed to find the center turf!") + for(var/turf/boi in range(3,center_turf)) + if(boi.density) + continue + valid_turfs += boi + var/obj/item/food/pickedmeat = pick_weight(validmeat) + new pickedmeat(pick(valid_turfs)) + meat_counter++ + if(meat_counter > round(potency/10)) + meat_counter = 0 + toggle_active(FALSE) + return + COOLDOWN_START(src,meat_cd,(10 SECONDS)) + diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/melee.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/melee.dm similarity index 72% rename from monkestation/code/modules/art_sci_overrides/artifact_components/melee.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/melee.dm index ea9e5a93e826..2d64f29344e3 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/melee.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/melee.dm @@ -2,33 +2,27 @@ #define SPECIAL_IGNITE "ignite" #define SPECIAL_TELEPORT "teleport" -/datum/component/artifact/melee - associated_object = /obj/item/melee/artifact +/datum/artifact_effect/melee artifact_size = ARTIFACT_SIZE_SMALL - type_name = "Melee Weapon" + type_name = "Melee Weapon Effect" weight = ARTIFACT_VERYUNCOMMON //rare - xray_result = "DENSE" valid_activators = list( /datum/artifact_activator/touch/silicon, /datum/artifact_activator/range/heat, /datum/artifact_activator/range/shock, /datum/artifact_activator/range/radiation ) - valid_faults = list( - /datum/artifact_fault/ignite = 10, - /datum/artifact_fault/warp = 10, - /datum/artifact_fault/reagent/poison = 10, - /datum/artifact_fault/death = 2, - /datum/artifact_fault/tesla_zap = 5, - /datum/artifact_fault/grow = 10, - /datum/artifact_fault/explosion = 2, - ) var/active_force //force when active var/active_reach var/active_woundbonus = 0 -/datum/component/artifact/melee/setup() //RNG incarnate - var/obj/item/melee/artifact/weapon = holder + valid_type_paths = list(/obj/item/melee/artifact) + research_value = 500 + + examine_discovered = span_warning("It appears to be some sort of melee weapon") + +/datum/artifact_effect/melee/setup() //RNG incarnate + var/obj/item/melee/artifact/weapon = our_artifact.holder weapon.special_cooldown_time = rand(3,8) SECONDS active_force = rand(-10,30) weapon.demolition_mod = rand(-1.0, 2.0) @@ -58,15 +52,15 @@ potency += 15 weapon.special = pick(SPECIAL_LAUNCH, SPECIAL_IGNITE, SPECIAL_TELEPORT) -/datum/component/artifact/melee/effect_activate() - var/obj/item/melee/artifact/weapon = holder +/datum/artifact_effect/melee/effect_activate() + var/obj/item/melee/artifact/weapon = our_artifact.holder weapon.reach = active_reach weapon.force = active_force weapon.wound_bonus = active_woundbonus weapon.throwforce = weapon.force -/datum/component/artifact/melee/effect_deactivate() - var/obj/item/melee/artifact/weapon = holder +/datum/artifact_effect/melee/effect_deactivate() + var/obj/item/melee/artifact/weapon = our_artifact.holder weapon.force = active_force / 3 weapon.throwforce = weapon.force weapon.reach = 1 diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/money.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/money.dm new file mode 100644 index 000000000000..6f40d0405932 --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/money.dm @@ -0,0 +1,12 @@ +/datum/artifact_effect/lodedsamoney + examine_hint = "Might sell well." + examine_discovered = "Generates an aura of value." + discovered_credits = CARGO_CRATE_VALUE * 25 //LODESA + weight = ARTIFACT_UNCOMMON + + type_name = "Economical Aura Effect" + research_value = 250 + +/datum/artifact_effect/lodedsamoney/setup() + discovered_credits *= ((potency+50)/75) + discovered_credits = round(discovered_credits) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/narsieoffering.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/narsieoffering.dm new file mode 100644 index 000000000000..6d1cc4510108 --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/narsieoffering.dm @@ -0,0 +1,52 @@ +/datum/artifact_effect/narsieoffering + examine_discovered = "Makes an offering to the dark gods." + type_name = "Dark Altar Effect" + weight = ARTIFACT_COMMON //Common because can only be on carbon touch narsie + + examine_hint = span_warning("You feel safe and complacent around this...") + valid_origins = list(ORIGIN_NARSIE) + + valid_activators = list(/datum/artifact_activator/touch/carbon) + + research_value = 250 + + var/blood_to_take = 1 + + var/stored_blood = 0 + + COOLDOWN_DECLARE(force_take_cooldown) + ///List of valid items this artifact can spawn when full on blood (needs 5 bodys of blood.) + var/static/list/obj/valid_spawns = list( + /obj/item/soulstone/anybody = 1, //Lucky you. + /obj/item/clothing/suit/hooded/cultrobes = 20, + /obj/item/clothing/suit/hooded/cultrobes/alt = 20, + /obj/item/clothing/suit/hooded/cultrobes/hardened = 10, + /obj/item/sharpener/cult = 35, + /obj/item/shield/mirror = 15 + ) + +/datum/artifact_effect/narsieoffering/setup() + blood_to_take = round(rand(BLOOD_VOLUME_NORMAL*0.1,BLOOD_VOLUME_NORMAL*0.9)) + +/datum/artifact_effect/narsieoffering/effect_touched(mob/living/user) + if(!COOLDOWN_FINISHED(src,force_take_cooldown)) + to_chat(user,"You feel [our_artifact.holder] is not yet ready for what it has planned...") + if(!user.blood_volume || !iscarbon(user)) + to_chat(user, span_info("You feel a need to give your non existant blood.")) + if(user.blood_volume <= blood_to_take) + to_chat(user,span_info("You feel a need to give more blood, but [our_artifact.holder] deems you too weak to do so!")) + var/yoinked_blood = min(blood_to_take,user.blood_volume) + user.blood_volume -= yoinked_blood + stored_blood += yoinked_blood + to_chat(user,span_boldwarning("You are compelled to give blood to the [our_artifact.holder]; and feel your blood volume lower somehow!")) + COOLDOWN_START(src,force_take_cooldown,5 SECOND) + + if(stored_blood >= BLOOD_VOLUME_NORMAL*5) + var/obj/tomake = pick_weight(valid_spawns) + var/obj/chosen = new tomake(our_artifact.holder.loc) + chosen.forceMove(our_artifact.holder.loc) + to_chat(user,span_info("[our_artifact.holder] is pleased with your work, and [chosen] appears from seemingly nowhere!")) + stored_blood -= BLOOD_VOLUME_NORMAL*5 + return + + diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/plushie_vendor.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/plushie_vendor.dm new file mode 100644 index 000000000000..9e3642f159fa --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/plushie_vendor.dm @@ -0,0 +1,30 @@ +/datum/artifact_effect/plushie + examine_hint = "Has some sort of claw mechanism." + + examine_discovered = "Its a claw machine of some kind" + + weight = ARTIFACT_UNCOMMON + + activation_message = "summons a toy of some kind!" + + type_name = "Toy Vender Effect" + research_value = 250 + + var/static/list/obj/item/toy/plush/plushies = list() + + COOLDOWN_DECLARE(plushiefact) + +/datum/artifact_effect/plushie/effect_activate(silent) + if(!length(plushies)) + plushies = typecacheof(/obj/item/toy/plush,ignore_root_path = TRUE) //I am not responsible for if this is a bad idea. + if(!COOLDOWN_FINISHED(src,plushiefact)) + return + var/obj/item/toy/plush/boi_path = pick(plushies) + var/obj/item/toy/plush/boi = new boi_path + boi.forceMove(our_artifact.holder.loc) + if(prob(clamp(potency-50,0,100))) + boi.AddComponent(/datum/component/ghost_object_control,boi,TRUE) + var/datum/component/ghost_object_control/spiritholder = boi.GetComponent(/datum/component/ghost_object_control) + if(!(spiritholder.bound_spirit)) + spiritholder.request_control(0.6) + COOLDOWN_START(src,plushiefact,3 MINUTE) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_effects/repulsor.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/repulsor.dm new file mode 100644 index 000000000000..8cefc3bbcfde --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/repulsor.dm @@ -0,0 +1,55 @@ + +/datum/artifact_effect/repulsor + weight = ARTIFACT_UNCOMMON + type_name = "Repulsor/Impulsor Effect" + activation_message = "opens up, a weird aura starts emitting from it!" + deactivation_message = "closes up." + var/attract = FALSE //if FALSE, repulse, otherwise, attract + var/strength + var/range + var/cooldown_time + COOLDOWN_DECLARE(cooldown) + + research_value = 1000 + + examine_discovered = span_warning("It appears to be some object mover") + +/datum/artifact_effect/repulsor/setup() + attract = prob(40) + range = rand(1,3) + cooldown_time = rand(3,5) SECONDS + strength = rand(MOVE_FORCE_DEFAULT,MOVE_FORCE_OVERPOWERING) + potency += cooldown_time / 4 + strength / 3000 + +/datum/artifact_effect/repulsor/effect_activate(silent) + addtimer(CALLBACK(our_artifact, TYPE_PROC_REF(/datum/component/artifact, artifact_deactivate)), 10 SECONDS) + +/datum/artifact_effect/repulsor/effect_touched(mob/user) + if(!COOLDOWN_FINISHED(src,cooldown)) + return + pulse() + COOLDOWN_START(src,cooldown,cooldown_time) + +/datum/artifact_effect/repulsor/effect_process() + . = ..() + if(prob(100 - potency)) + return + pulse() + +/datum/artifact_effect/repulsor/proc/pulse(datum/source,atom/movable/thrown, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) + SIGNAL_HANDLER + if(!our_artifact.active) + return + our_artifact.holder.visible_message(span_warning("[our_artifact.holder] emits a pulse of energy, throwing things [attract ? "towards it!" : "away from it!"]")) + var/owner_turf = get_turf(our_artifact.holder) + if(isnull(thrown)) + for(var/atom/movable/throwee in oview(range,our_artifact.holder)) + if(throwee.anchored) + continue + if(attract) + throwee.safe_throw_at(our_artifact.holder, strength / 3000, 1, force = strength) + else + var/throwtarget = get_edge_target_turf(get_turf(throwee), get_dir(owner_turf, get_step_away(throwee, owner_turf))) + throwee.safe_throw_at(throwtarget, strength / 3000, 1, force = strength) + else if(throwingdatum?.thrower) + thrown.safe_throw_at(throwingdatum.thrower, get_dist(our_artifact.holder, throwingdatum.thrower), 1, force = strength) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/smoke_artifacts.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/smoke_artifacts.dm similarity index 55% rename from monkestation/code/modules/art_sci_overrides/artifact_components/smoke_artifacts.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/smoke_artifacts.dm index 9255e0a53706..5a1e83890be3 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/smoke_artifacts.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/smoke_artifacts.dm @@ -1,10 +1,13 @@ -/datum/component/artifact/smoke - associated_object = /obj/structure/artifact/smoke +/datum/artifact_effect/smoke weight = ARTIFACT_UNCOMMON - type_name = "Smoke Machine" - activation_message = "starts spewing out smoke!" + type_name = "Smoke Machine (Colorful) Effect" + activation_message = "starts spewing out colorful smoke!" deactivation_message = "becomes silent." + research_value = 250 + + examine_discovered = span_warning("It appears to be some sort of checmical aerolyzer for coloring things") + var/list/valid_chemicals = list( /datum/reagent/colorful_reagent, /datum/reagent/colorful_reagent/powder/black, @@ -19,7 +22,7 @@ var/list/chemicals = list() var/smoke_range = 3 -/datum/component/artifact/smoke/setup() +/datum/artifact_effect/smoke/setup() per_chemical_amount = rand(5, 10) chemicals_chosen = rand(1, 5) smoke_range = rand(1, 5) @@ -28,14 +31,15 @@ for(var/i = 1 to chemicals_chosen) chemicals += pick(valid_chemicals) -/datum/component/artifact/smoke/effect_activate(silent) - for(var/chemical in chemicals) - do_chem_smoke(smoke_range, holder = holder, location = get_turf(holder), reagent_type = chemical, reagent_volume = per_chemical_amount, log = TRUE) - artifact_deactivate() +/datum/artifact_effect/smoke/effect_activate(silent) + if(our_artifact.holder) + for(var/chemical in chemicals) + do_chem_smoke(smoke_range, holder = our_artifact.holder, location = get_turf(our_artifact.holder), reagent_type = chemical, reagent_volume = per_chemical_amount, log = TRUE) + our_artifact.artifact_deactivate() -/datum/component/artifact/smoke/toxin - associated_object = /obj/structure/artifact/smoke/toxin +/datum/artifact_effect/smoke/toxin weight = ARTIFACT_RARE + type_name = "Smoke Machine (Harmful) Effect" activation_message = "starts spewing out toxic smoke!" valid_chemicals = list( /datum/reagent/toxin/bonehurtingjuice, @@ -43,19 +47,23 @@ /datum/reagent/toxin/mindbreaker, /datum/reagent/toxin/spewium, ) + examine_discovered = span_danger("It appears to be some sort of checmical aerolyzer for harming things!") -/datum/component/artifact/smoke/flesh - associated_object = /obj/structure/artifact/smoke/flesh +/datum/artifact_effect/smoke/flesh + type_name = "Smoke Machine (Synthflesh) Effect" weight = ARTIFACT_RARE activation_message = "starts spewing out flesh mending smoke!" valid_chemicals = list( /datum/reagent/medicine/c2/synthflesh ) + examine_discovered = span_info("It appears to be some sort of checmical aerolyzer for healing things!") -/datum/component/artifact/smoke/exotic - associated_object = /obj/structure/artifact/smoke/exotic +/datum/artifact_effect/smoke/exotic + type_name = "Smoke Machine (Exotic) Effect" weight = ARTIFACT_RARE activation_message = "starts spewing out exotic smoke!" + + examine_discovered = span_warning("It appears to be some sort of checmical aerolyzer for... not sure actually.") valid_chemicals = list( /datum/reagent/wittel, /datum/reagent/medicine/omnizine/protozine, diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/surgery.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/surgery.dm similarity index 52% rename from monkestation/code/modules/art_sci_overrides/artifact_components/surgery.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/surgery.dm index 8164e16fce72..c7bca8396e73 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/surgery.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/surgery.dm @@ -1,7 +1,6 @@ -/datum/component/artifact/surgery - associated_object = /obj/structure/artifact/surgery +/datum/artifact_effect/surgery weight = ARTIFACT_VERYUNCOMMON - type_name = "Surgery Object" + type_name = "Surgery Object Effect" activation_message = "springs to life!" deactivation_message = "becomes silent." valid_activators = list( @@ -10,14 +9,17 @@ ) COOLDOWN_DECLARE(surgery_cooldown) + research_value = 1250 -/datum/component/artifact/surgery/effect_touched(mob/living/user) + examine_discovered = span_warning("It appears to be some sort of automated surgery device") + +/datum/artifact_effect/surgery/effect_touched(mob/living/user) if(!COOLDOWN_FINISHED(src, surgery_cooldown)) - holder.visible_message(span_notice("[holder] wheezes, shutting down.")) + our_artifact.holder.visible_message(span_notice("[our_artifact.holder] wheezes, shutting down.")) return if(!ishuman(user)) return var/mob/living/carbon/human/human = user - human.bioscramble(holder.name) + human.bioscramble(our_artifact.holder.name) COOLDOWN_START(src,surgery_cooldown, 5 SECONDS) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_components/vomit.dm b/monkestation/code/modules/art_sci_overrides/artifact_effects/vomit.dm similarity index 54% rename from monkestation/code/modules/art_sci_overrides/artifact_components/vomit.dm rename to monkestation/code/modules/art_sci_overrides/artifact_effects/vomit.dm index 24b901492867..b3154d75e0d4 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_components/vomit.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_effects/vomit.dm @@ -1,7 +1,6 @@ -/datum/component/artifact/vomit - associated_object = /obj/structure/artifact/vomit +/datum/artifact_effect/vomit weight = ARTIFACT_UNCOMMON - type_name = "Vomiting Inducer" + type_name = "Vomiting Inducer Effect" activation_message = "starts emitting disgusting imagery!" deactivation_message = "falls silent, its aura dissipating!" valid_origins = list( @@ -15,7 +14,12 @@ var/bloody_vomit = FALSE COOLDOWN_DECLARE(cooldown) -/datum/component/artifact/vomit/setup() + research_value = 100 //To busy vomiting cant research + + + examine_discovered = span_warning("It appears to be some sort of sick prank") + +/datum/artifact_effect/vomit/setup() switch(rand(1,100)) if(1 to 84) range = rand(2,3) @@ -29,18 +33,12 @@ potency += spew_range bloody_vomit = prob(50) potency += (range) * 4 - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/component/artifact, artifact_deactivate)), round(30 * (potency * 10) SECONDS)) -/datum/component/artifact/vomit/on_examine(atom/source, mob/user, list/examine_list) - . = ..() - var/mob/living/carbon/carbon = user - if(active && istype(carbon) && carbon.stat < UNCONSCIOUS) - examine_list += span_warning("It has an [spew_organs ? "extremely" : ""] disgusting aura! [prob(20) ? "..is that a felinid?" : ""]") - carbon.vomit(blood = bloody_vomit, stun = (spew_organs ? TRUE : prob(25)), distance = spew_range) - if(spew_organs && prob(40)) - carbon.spew_organ() -/datum/component/artifact/vomit/effect_process() +/datum/artifact_effect/vomit/effect_activate(silent) + addtimer(CALLBACK(our_artifact, TYPE_PROC_REF(/datum/component/artifact,artifact_deactivate)),30 SECONDS) + +/datum/artifact_effect/vomit/effect_process() for(var/mob/living/carbon/viewed in view(range, src)) if(prob(100 - potency)) continue diff --git a/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_cell.dm b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_cell.dm index 5f20f628b830..092275d14b2e 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_cell.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_cell.dm @@ -4,11 +4,17 @@ resistance_flags = LAVA_PROOF | ACID_PROOF | INDESTRUCTIBLE ratingdesc = FALSE charge_light_type = null - var/datum/component/artifact/assoc_comp = /datum/component/artifact/cell + obj_flags = CAN_BE_HIT + var/datum/component/artifact/assoc_comp = /datum/component/artifact -ARTIFACT_SETUP(/obj/item/stock_parts/cell/artifact, SSobj) +ARTIFACT_SETUP(/obj/item/stock_parts/cell/artifact, SSobj, null, /datum/artifact_effect/cell, ARTIFACT_SIZE_TINY) /obj/item/stock_parts/cell/artifact/use(amount, force) //dont use power unless active . = FALSE if(assoc_comp.active) return ..() + +/obj/item/stock_parts/cell/artifact/attack_self(mob/user, modifiers) + . = ..() + to_chat(user,span_notice("You squeeze the [src] tightly.")) + on_artifact_touched(src,user,modifiers) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_effect_disk.dm b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_effect_disk.dm new file mode 100644 index 000000000000..f1c2820e49cb --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_effect_disk.dm @@ -0,0 +1,28 @@ +/obj/item/disk/artifact + name = "artifact data disk" + desc = "A disk for storing an artifacts effect data. Can be put into an xray machine to maybe copy artifact data, or an artifact wand for it's effect." + icon_state = "rndmajordisk" + custom_materials = list(/datum/material/iron=30, /datum/material/glass=10) + var/datum/artifact_effect/effect + var/datum/artifact_activator/activator + var/datum/artifact_fault/fault + var/read_only = FALSE //Well, it's still a floppy disk + obj_flags = UNIQUE_RENAME +/obj/item/disk/artifact/update_name(updates) + . = ..() + var/newname = "" + if(effect) + newname += " ([effect.type_name]) " + if(activator) + newname += " |[activator.name]| " + if(fault) + newname += " ![fault.name]! " + name = initial(name) + newname + +/obj/item/disk/artifact/attack_self(mob/user) + read_only = !read_only + to_chat(user, "You flip the write-protect tab to [src.read_only ? "protected" : "unprotected"].") + +/obj/item/disk/artifact/examine(mob/user) + . = ..() + . += "The write-protect tab is set to [src.read_only ? "protected" : "unprotected"]." diff --git a/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_gun.dm b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_gun.dm index 37c02bba1e0d..f337be6fb181 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_gun.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_gun.dm @@ -1,10 +1,21 @@ /obj/item/ammo_casing/magic/artifact projectile_type = /obj/projectile/magic/artifact - + var/datum/artifact_effect/gun/stored_comp /obj/item/ammo_casing/magic/artifact/ready_proj(atom/target, mob/living/user, quiet, zone_override = "", atom/fired_from) if(!loaded_projectile) return - var/datum/component/artifact/gun/gun = fired_from.GetComponent(/datum/component/artifact/gun) + var/datum/component/artifact/component = fired_from.GetComponent(/datum/component/artifact) + var/datum/artifact_effect/gun/gun + if(!stored_comp) + for(var/datum/artifact_effect/eff in component.artifact_effects) + if(istype(eff,/datum/artifact_effect/gun)) + gun = eff + stored_comp = gun + break + else + gun = stored_comp + if(!gun) + return loaded_projectile.damage = gun.damage / pellets loaded_projectile.icon_state = gun.projectile_icon loaded_projectile.damage_type = gun.dam_type @@ -39,9 +50,15 @@ pinless = TRUE recharge_rate = 1 antimagic_flags = null - var/datum/component/artifact/assoc_comp = /datum/component/artifact/gun + obj_flags = CAN_BE_HIT + var/datum/component/artifact/assoc_comp = /datum/component/artifact + +ARTIFACT_SETUP(/obj/item/gun/magic/artifact, SSobj, null, /datum/artifact_effect/gun, ARTIFACT_SIZE_SMALL) -ARTIFACT_SETUP(/obj/item/gun/magic/artifact, SSobj) +/obj/item/gun/magic/artifact/attack_self(mob/user, modifiers) + . = ..() + to_chat(user,span_notice("You squeeze the [src] tightly.")) + on_artifact_touched(src,user,modifiers) /obj/item/gun/magic/artifact/can_shoot() return assoc_comp.active diff --git a/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_item.dm b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_item.dm new file mode 100644 index 000000000000..e6eaf3e204db --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_item.dm @@ -0,0 +1,37 @@ +/obj/item/artifact_item + //This is literally just an artifact, but item sized for item generation of traits that require it. + + icon = 'icons/obj/artifacts.dmi' + icon_state = "narnar-1" + resistance_flags = LAVA_PROOF | ACID_PROOF | INDESTRUCTIBLE + icon = 'icons/obj/artifacts.dmi' + inhand_icon_state = "plasmashiv" + lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + obj_flags = CAN_BE_HIT + var/datum/component/artifact/assoc_comp = /datum/component/artifact + +ARTIFACT_SETUP(/obj/item/artifact_item, SSobj, null, null, ARTIFACT_SIZE_SMALL) + +/obj/item/artifact_item/attack_self(mob/user, modifiers) + . = ..() + to_chat(user,span_notice("You squeeze the [src] tightly.")) + on_artifact_touched(src,user,modifiers) + + +/obj/item/artifact_item_tiny + //This is literally just an artifact, but s m o l for item generation of traits that require it. + + icon = 'icons/obj/artifacts.dmi' + icon_state = "narnar-1" + resistance_flags = LAVA_PROOF | ACID_PROOF | INDESTRUCTIBLE + icon = 'icons/obj/artifacts.dmi' + var/datum/component/artifact/assoc_comp = /datum/component/artifact + obj_flags = CAN_BE_HIT + +ARTIFACT_SETUP(/obj/item/artifact_item_tiny, SSobj, null, null, ARTIFACT_SIZE_TINY) + +/obj/item/artifact_item_tiny/attack_self(mob/user, modifiers) + . = ..() + to_chat(user,span_notice("You squeeze the [src] tightly.")) + on_artifact_touched(src,user,modifiers) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_manipulators.dm b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_manipulators.dm new file mode 100644 index 000000000000..13661ae0735b --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_manipulators.dm @@ -0,0 +1,158 @@ +/obj/item/artifact_summon_wand + name = "artifact manipulation wand" + desc = "A one-use device capable of summoning an artifact from... somewhere.Use the item in hand to change modes. Right Click a disk onto it to load the disk. Right Click the item to attempt to summon an artifact, or slap an existing one to modify it." + icon = 'icons/obj/device.dmi' + icon_state = "memorizer2" + inhand_icon_state = "electronic" + worn_icon_state = "electronic" + lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' + w_class = WEIGHT_CLASS_SMALL + slot_flags = ITEM_SLOT_BELT + item_flags = NOBLUDGEON + var/obj/item/disk/artifact/slotted_disk + var/selected_mode = 0 + /// modes are- 0 = random, 1 = blank artifact,2 = disk copy, 3 = disc activator, 4 = disc fault, 5 = disc effect. + var/max_modes = 5 + +/obj/item/artifact_summon_wand/attack_self(mob/user, modifiers) + . = ..() + selected_mode++ + if(selected_mode > max_modes) + selected_mode = 0 + var/display_text = "cause a bug. Tell the coders quick!" + switch(selected_mode) + if(0) + display_text = "create a random artifact." + if(1) + display_text = "create a blank artifact." + if(2) + display_text = "create a copy of inserted disk" + if(3) + display_text = "create or modify an artifact with just the inserted disks activator." + if(4) + display_text = "create or modify an artifact with just the inserted disks fault." + if(5) + display_text = "create or modify an artifact with just the inserted disks effect." + to_chat(user,span_notice("You set [src] to [display_text]")) + +/obj/item/artifact_summon_wand/attackby_secondary(obj/item/weapon, mob/user, params) + . = ..() + if(istype(weapon,/obj/item/disk/artifact)) + if(slotted_disk) + to_chat(user,span_notice("You swap the disk inside [src]")) + weapon.forceMove(src) + if(!user.put_in_hand(slotted_disk)) + slotted_disk.forceMove(get_turf(user)) + slotted_disk = weapon + else + to_chat(user,span_notice("You slot [weapon] inside [src]")) + weapon.forceMove(src) + slotted_disk = weapon +/obj/item/artifact_summon_wand/attack_self_secondary(mob/user, modifiers) + . = ..() + summon_artifact(user) + +/obj/item/artifact_summon_wand/proc/summon_artifact(mob/user) + var/turf/attempt_location = get_turf(get_step(user,user.dir)) + if(attempt_location.density) + return + visible_message(span_notice("[user] begins to summon an artifact using [src]!"),span_notice("You begin attempting to summon an artifact using [src]...")) + if(do_after(user,5 SECOND)) + var/obj/new_artifact = spawn_artifact(attempt_location) + var/datum/component/artifact/art_comp = new_artifact.GetComponent(/datum/component/artifact) + if(!art_comp) + visible_message(span_notice("Something goes wrong, and [src] fizzles!")) + return + switch(selected_mode)//0 left blank, as we don't need to do anything else. + if(1) + art_comp.clear_out() + if(2) + art_comp.clear_out() + if(slotted_disk.activator) + art_comp.add_activator(slotted_disk.activator) + if(slotted_disk.fault) + art_comp.change_fault(slotted_disk.fault) + if(slotted_disk.effect) + art_comp.try_add_effect(slotted_disk.effect) + if(3) + art_comp.clear_out() + if(slotted_disk.activator) + art_comp.add_activator(slotted_disk.activator) + if(4) + art_comp.clear_out() + if(slotted_disk.fault) + art_comp.change_fault(slotted_disk.fault) + if(5) + art_comp.clear_out() + if(slotted_disk.effect) + art_comp.try_add_effect(slotted_disk.effect) + visible_message(span_notice("[new_artifact] appears from nowhere!"),span_notice("You summon [new_artifact], and [src] disintegrates!")) + if(slotted_disk) + if(!user.put_in_active_hand(slotted_disk)) + slotted_disk.forceMove(get_turf(user)) + slotted_disk = null + qdel(src) + else + visible_message(span_notice("Something goes wrong, and [src] fizzles!")) + +/obj/item/artifact_summon_wand/examine(mob/user) + . = ..() + if(slotted_disk) + . += span_notice("Contains [slotted_disk]") + switch (selected_mode) + if(0) + . += span_notice("Will currently try to summon a random artifact.") + if(1) + . += span_notice("Will currently try to summon a blank artifact") + if(2) + . += span_notice("Will currently try to copy the disk to a new or existing artifact.") + if(3) + . += span_notice("Will currently try to copy the disk activator to a new or existing artifact.") + if(4) + . += span_notice("Will currently try to copy the disk fault to a new or existing artifact.") + if(5) + . += span_notice("Will currently try to copy the disk effect to a new or existing artifact.") + +/obj/item/artifact_summon_wand/attack_atom(atom/attacked_atom, mob/living/user, params) + var/datum/component/artifact/art_comp = attacked_atom.GetComponent(/datum/component/artifact) + if(art_comp && slotted_disk) + visible_message(span_notice("[user] begins trying to configure [attacked_atom] with [src]!"),span_notice("You begin trying to configure the [attacked_atom] with [src]...")) + if(do_after(user,5 SECOND)) + var/added_anything = FALSE + switch(selected_mode) + if(0) + visible_message(span_notice("...but nothing changed!")) + if(1) + art_comp.clear_out() + visible_message(span_notice("[attacked_atom] is rendered inert!")) + added_anything = TRUE + if(2) + if(slotted_disk.activator) + added_anything |= art_comp.add_activator(slotted_disk.activator) + if(slotted_disk.fault) + added_anything |= art_comp.change_fault(slotted_disk.fault) + if(slotted_disk.effect) + added_anything |= art_comp.try_add_effect(slotted_disk.effect) + if(3) + if(slotted_disk.activator) + added_anything |= art_comp.add_activator(slotted_disk.activator) + if(4) + if(slotted_disk.fault) + added_anything |= art_comp.change_fault(slotted_disk.fault) + if(5) + if(slotted_disk.effect) + added_anything |= art_comp.try_add_effect(slotted_disk.effect) + if(added_anything) + visible_message(span_notice("[user] configures the [attacked_atom] with [src]!"),span_notice("You configure the [attacked_atom] with [src], which switftly disintegrates!")) + if(slotted_disk) + if(!user.put_in_active_hand(slotted_disk)) + slotted_disk.forceMove(get_turf(user)) + slotted_disk = null + qdel(src) + else + visible_message(span_notice("...but nothing changed!")) + else + visible_message(span_notice("Something goes wrong, and [src] fizzles!")) + return ..() //I TAKE NO RESPONSIBILITY FOR CALLING THIS L A S T. + diff --git a/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_melee.dm b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_melee.dm index 3ad1b89385d4..c8ef4201b472 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_melee.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_items/artifact_melee.dm @@ -10,12 +10,18 @@ inhand_icon_state = "plasmashiv" lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi' righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi' + obj_flags = CAN_BE_HIT var/special_cooldown_time var/special - var/datum/component/artifact/assoc_comp = /datum/component/artifact/melee + var/datum/component/artifact/assoc_comp = /datum/component/artifact COOLDOWN_DECLARE(special_cooldown) -ARTIFACT_SETUP(/obj/item/melee/artifact, SSobj) +ARTIFACT_SETUP(/obj/item/melee/artifact, SSobj, null, /datum/artifact_effect/melee, ARTIFACT_SIZE_SMALL) + +/obj/item/melee/artifact/attack_self(mob/user, modifiers) + . = ..() + to_chat(user,span_notice("You squeeze the [src] tightly.")) + on_artifact_touched(src,user,modifiers) /obj/item/melee/artifact/afterattack(mob/living/victim, mob/user, proximity) if(!istype(victim) || !assoc_comp.active || !COOLDOWN_FINISHED(src,special_cooldown) || !special || !proximity) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_objects/artifact_powergen.dm b/monkestation/code/modules/art_sci_overrides/artifact_objects/artifact_powergen.dm index b2a37bb18adc..b06a9c3d0a65 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_objects/artifact_powergen.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_objects/artifact_powergen.dm @@ -10,12 +10,10 @@ circuit = null density = TRUE anchored = FALSE - var/datum/component/artifact/assoc_comp = /datum/component/artifact/generator + var/datum/component/artifact/assoc_comp = /datum/component/artifact +ARTIFACT_SETUP(/obj/machinery/power/generator_artifact, SSmachines, null, /datum/artifact_effect/generator, null) -ARTIFACT_SETUP(/obj/machinery/power/generator_artifact, SSmachines) - -/datum/component/artifact/generator - associated_object = /obj/machinery/power/generator_artifact +/datum/artifact_effect/generator type_name = "Power Generator" weight = ARTIFACT_RARE valid_activators = list( @@ -29,16 +27,18 @@ ARTIFACT_SETUP(/obj/machinery/power/generator_artifact, SSmachines) /datum/artifact_origin/precursor, /datum/artifact_origin/martian, ) //narnar doesnt need power + + valid_type_paths = list(/obj/machinery/power/generator_artifact) + research_value = 10000 //Holy moly lucky you! activation_message = "begins emitting a faint, droning hum." deactivation_message = "shortcircuits!" - xray_result = "COMPLEX" COOLDOWN_DECLARE(sideeffect_cooldown) var/power_gen = 0 ///does the power output fluctuate var/unstable_generation = FALSE -/datum/component/artifact/generator/setup() //TODO: Make this use some weird scaling math to have it pick higher numbers at lower odds +/datum/artifact_effect/generator/setup() //TODO: Make this use some weird scaling math to have it pick higher numbers at lower odds if(prob(65)) power_gen = rand(1 KW, MAX_POSSIBLE_GEN / 2) else @@ -46,42 +46,42 @@ ARTIFACT_SETUP(/obj/machinery/power/generator_artifact, SSmachines) unstable_generation = prob(40) potency = power_gen / (6 KW) // 100 potency at 600kw generation -/datum/component/artifact/generator/effect_touched(mob/living/user) - var/obj/machinery/power/generator_artifact/powerholder = holder +/datum/artifact_effect/generator/effect_touched(mob/living/user) + var/obj/machinery/power/generator_artifact/powerholder = our_artifact.holder //if on cable and not setup, connect and setup if(!powerholder.anchored && locate(/obj/structure/cable) in get_turf(powerholder)) - powerholder.visible_message(span_warning("[holder] seems to snap to the cable!")) + powerholder.visible_message(span_warning("[our_artifact.holder] seems to snap to the cable!")) playsound(get_turf(powerholder), 'sound/items/deconstruct.ogg', 50, TRUE) powerholder.anchored = TRUE powerholder.connect_to_network() return - holder.Beam(user, icon_state = "lightning[rand(1,12)]", time = 0.5 SECONDS) + our_artifact.holder.Beam(user, icon_state = "lightning[rand(1,12)]", time = 0.5 SECONDS) playsound(get_turf(powerholder), 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) var/damage = user.electrocute_act(power_gen / 2 KW, powerholder, flags = SHOCK_NOSTUN) - to_chat(user, span_userdanger("You are hit by a burst of electricity from [holder]!")) + to_chat(user, span_userdanger("You are hit by a burst of electricity from [our_artifact.holder]!")) if(damage > 80) - var/turf/owner_turf = get_turf(holder) + var/turf/owner_turf = get_turf(our_artifact.holder) var/throwtarget = get_edge_target_turf(get_turf(user), get_dir(owner_turf, get_step_away(user, owner_turf))) user.safe_throw_at(throwtarget, power_gen / 38 KW, 1, force = MOVE_FORCE_EXTREMELY_STRONG) if(damage > 400 && prob(50)) - user.dust(just_ash = TRUE, drop_items = TRUE) - artifact_deactivate() //shortcircuit + user.death(FALSE) + our_artifact.artifact_deactivate() //shortcircuit if(prob(20)) //try to get yourself shocked with insuls many times to shortcircuit it (in retrospect this sucks) - artifact_deactivate() + our_artifact.artifact_deactivate() -/datum/component/artifact/generator/effect_process() //todo add more - if(!holder.anchored) +/datum/artifact_effect/generator/effect_process() //todo add more + if(!our_artifact.holder.anchored) return - var/obj/machinery/power/generator_artifact/powerholder = holder + var/obj/machinery/power/generator_artifact/powerholder = our_artifact.holder powerholder.add_avail(power_gen * (unstable_generation ? rand(0.1, 1) : 1)) if(power_gen < SIDEEFFECT_THRESHOLD || !COOLDOWN_FINISHED(src,sideeffect_cooldown)) //sorry boss no can do return COOLDOWN_START(src,sideeffect_cooldown,rand(4,8) SECONDS) //minor to medium side effects if(power_gen >= (SHITFUCK_THRESHOLD / 3)) - powerholder.visible_message(span_danger("\The [holder] lets out a shower of thunder!"), span_hear("You hear a loud electrical crack!")) + powerholder.visible_message(span_danger("\The [our_artifact.holder] lets out a shower of thunder!"), span_hear("You hear a loud electrical crack!")) playsound(get_turf(powerholder), 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) tesla_zap(powerholder, rand(2,3), power_gen / 3500) @@ -97,12 +97,12 @@ ARTIFACT_SETUP(/obj/machinery/power/generator_artifact, SSmachines) merger.assert_gas(/datum/gas/carbon_dioxide) merger.gases[/datum/gas/carbon_dioxide][MOLES] = rand(10,120) merger.temperature = rand(200,1000) - var/turf/holder_turf = get_turf(holder) + var/turf/holder_turf = get_turf(our_artifact.holder) holder_turf.assume_air(merger) -/datum/component/artifact/generator/effect_deactivate() - var/obj/machinery/power/generator_artifact/powerholder = holder +/datum/artifact_effect/generator/effect_deactivate() + var/obj/machinery/power/generator_artifact/powerholder = our_artifact.holder powerholder.disconnect_from_network() powerholder.anchored = FALSE playsound(get_turf(powerholder), 'sound/items/deconstruct.ogg', 50, TRUE) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_proto_datums.dm b/monkestation/code/modules/art_sci_overrides/artifact_proto_datums.dm new file mode 100644 index 000000000000..be213e1102cc --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/artifact_proto_datums.dm @@ -0,0 +1,25 @@ +/datum/design/artifact_summon_wand + name = "Artifact Wand" + desc = "A wand used to create or modify artifacts." + id = "artifact_wand" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron =HALF_SHEET_MATERIAL_AMOUNT, /datum/material/gold =SHEET_MATERIAL_AMOUNT, /datum/material/plasma =SHEET_MATERIAL_AMOUNT * 4, /datum/material/uranium =SHEET_MATERIAL_AMOUNT) + build_path = /obj/item/artifact_summon_wand + category = list( + RND_CATEGORY_EQUIPMENT + ) + lathe_time_factor = 0.2 + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE + +/datum/design/disk/artifact + name = "Artifact Disk" + desc = "A disk used to store artifact data." + id = "disk_artifact" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT, /datum/material/glass = SMALL_MATERIAL_AMOUNT/2) + build_path = /obj/item/disk/artifact + category = list( + RND_CATEGORY_EQUIPMENT + ) + lathe_time_factor = 0.1 + departmental_flags = DEPARTMENT_BITFLAG_SCIENCE diff --git a/monkestation/code/modules/art_sci_overrides/artifact_testers/analysis_form.dm b/monkestation/code/modules/art_sci_overrides/artifact_testers/analysis_form.dm index 871bd0f8eb03..7d11430f2492 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_testers/analysis_form.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_testers/analysis_form.dm @@ -34,7 +34,8 @@ contraband = STICKER_NOSPAWN var/chosen_origin = "" var/list/chosentriggers = list() - var/chosentype = "" + var/list/chosen_effects = list() + var/chosen_fault = "" /obj/item/sticker/analysis_form/attackby(obj/item/item, mob/living/user, params) if(istype(item, /obj/item/pen)) @@ -59,31 +60,44 @@ if("origin") chosen_origin = params["origin"] if("type") - chosentype = params["type"] + var/trig_type = params["type"] + if(trig_type in chosen_effects) + chosen_effects -= trig_type + else + chosen_effects += trig_type + if("fault") + chosen_fault = params["fault"] if("trigger") - var/trig = params["trigger"] - if(trig in chosentriggers) - chosentriggers -= trig + var/trig_act = params["trigger"] + if(trig_act in chosentriggers) + chosentriggers -= trig_act else - chosentriggers += trig + chosentriggers += trig_act if(attached) analyze_attached() /obj/item/sticker/analysis_form/ui_static_data(mob/user) . = ..() var/list/origins_names = list() - for(var/datum/artifact_origin/subtype as anything in subtypesof(/datum/artifact_origin)) + for(var/datum/artifact_origin/subtype as anything in subtypesof(/datum/artifact_origin)) origins_names += initial(subtype.name) + var/list/allfaults = list() + for(var/datum/artifact_fault/subtype as anything in subtypesof(/datum/artifact_fault)) + allfaults += initial(subtype.name) + var/list/trigger_names = list() for(var/datum/artifact_activator/subtype as anything in subtypesof(/datum/artifact_activator)) trigger_names += initial(subtype.name) var/list/artifact_names = list() - for(var/datum/component/artifact/subtype as anything in subtypesof(/datum/component/artifact)) + for(var/datum/artifact_effect/subtype as anything in subtypesof(/datum/artifact_effect)) + if(subtype.super_secret) + continue //shhhhh artifact_names += initial(subtype.type_name) .["allorigins"] = origins_names + .["allfaults"] = allfaults .["alltypes"] = artifact_names .["alltriggers"] = trigger_names return @@ -91,7 +105,8 @@ /obj/item/sticker/analysis_form/ui_data(mob/user) . = ..() .["chosenorigin"] = chosen_origin - .["chosentype"] = chosentype + .["chosenfault"] = chosen_fault + .["chosentype"] = chosen_effects .["chosentriggers"] = chosentriggers return . @@ -149,46 +164,60 @@ ..() /obj/item/sticker/analysis_form/proc/analyze_attached() + if(!attached) + return var/datum/component/artifact/to_analyze = attached.GetComponent(/datum/component/artifact) if(!to_analyze) return if(chosen_origin) to_analyze.holder.name = to_analyze.generated_name - if(chosentype) - to_analyze.holder.name += " ([chosentype])" + if(chosen_fault) + to_analyze.holder.name += " ![chosen_fault]! " + if(chosen_effects) + for(var/effect as anything in chosen_effects) + to_analyze.holder.name += " ([effect]) " + to_analyze.analysis = src + to_analyze.process_stimuli(STIMULUS_DATA,TRUE) /obj/item/sticker/analysis_form/proc/deanalyze_attached() var/datum/component/artifact/to_analyze = attached.GetComponent(/datum/component/artifact) if(!to_analyze) return to_analyze.holder.name = to_analyze.fake_name + QDEL_NULL(to_analyze.analysis) /obj/item/sticker/analysis_form/proc/get_export_value(datum/component/artifact/art) - var/correct = 0 - var/total_guesses = 0 - + var/baseval = CARGO_CRATE_VALUE + var/labeling_bonus = round(CARGO_CRATE_VALUE * 2.5) + var/bonus = 0 + for(var/datum/artifact_effect/discovered as anything in art.discovered_effects) + if(discovered.discovered_credits) + bonus += round(discovered.discovered_credits * ((discovered.potency + 25)/50)) + if(art.chosen_fault && art.fault_discovered) + bonus += art.chosen_fault.discovered_credits if(art.artifact_origin.type_name == chosen_origin) - correct ++ - if(chosen_origin) - total_guesses ++ - if(chosentype) - total_guesses ++ - if(art.type_name == chosentype) - correct ++ - for(var/name in chosentriggers) - total_guesses++ - - for(var/datum/artifact_activator/listed in art.activators) - if(listed.name != name) - continue - correct++ - - var/incorrect = total_guesses - correct - return round((CARGO_CRATE_VALUE/4) * art.potency * (max((ARTIFACT_COMMON - art.weight) * 0.01, 0.01) * max(correct - incorrect, 0.01))) + bonus += labeling_bonus + else + bonus -= labeling_bonus + if(chosen_effects) + for(var/name_effect in chosen_effects) + for(var/datum/artifact_effect/effect as anything in art.artifact_effects) + if(effect.type_name != name_effect) + bonus -= labeling_bonus + else + bonus += labeling_bonus + if(chosentriggers) + for(var/name_trigger in chosentriggers) + for(var/datum/artifact_activator/activator as anything in art.activators) + if(activator.name != name_trigger) + bonus -= labeling_bonus + else + bonus += labeling_bonus + return round(baseval + bonus) /obj/item/analysis_bin name = "analysis bin" - desc = "A bin made out of material to resist adhesion, for artifact analysis forms." + desc = "A bin containing a seemingly endless supply of fourms for artifact labeling. Correctly labeled artifacts sell for more!" icon = 'icons/obj/service/bureaucracy.dmi' icon_state = "analysisbin1" base_icon_state = "analysisbin" @@ -196,33 +225,24 @@ lefthand_file = 'icons/mob/inhands/items/sheets_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/sheets_righthand.dmi' w_class = WEIGHT_CLASS_NORMAL - var/forms = 15 - var/form_type = /obj/item/sticker/analysis_form + var/form_type = /obj/item/sticker/analysis_form /obj/item/analysis_bin/Initialize(mapload) . = ..() interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP AddElement(/datum/element/drag_pickup) -/obj/item/analysis_bin/update_icon_state() - icon_state = "[base_icon_state][forms > 0]" - return ..() - /obj/item/analysis_bin/attack_hand(mob/user, list/modifiers) if(isliving(user)) var/mob/living/living_mob = user if(!(living_mob.mobility_flags & MOBILITY_PICKUP)) return - if(forms) - forms-- - var/obj/item/form = new form_type - form.add_fingerprint(user) - form.forceMove(user.loc) - user.put_in_hands(form) - balloon_alert(user, "took form") - update_appearance() - else - balloon_alert(user, "empty!") + var/obj/item/form = new form_type + form.add_fingerprint(user) + form.forceMove(user.loc) + user.put_in_hands(form) + balloon_alert(user, "took form") + update_appearance() add_fingerprint(user) return ..() @@ -232,7 +252,6 @@ return qdel(item) balloon_alert(user, "form returned") - forms++ update_appearance() else return ..() diff --git a/monkestation/code/modules/art_sci_overrides/artifact_testers/xray.dm b/monkestation/code/modules/art_sci_overrides/artifact_testers/xray.dm index 70d25ee3243d..12cb72675d26 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_testers/xray.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_testers/xray.dm @@ -1,6 +1,6 @@ /obj/machinery/artifact_xray name = "artifact x-ray machine" - desc = "An x-ray machine, used to scan artifacts." + desc = "An x-ray machine, used to scan artifacts for what they do and research them. Can be Wrenched to turn on Destructive Scan mode, which when given a disk, may record artifact data." icon = 'icons/obj/machines/artifact_machines.dmi' icon_state = "xray-0" base_icon_state = "xray" @@ -8,27 +8,59 @@ circuit = /obj/item/circuitboard/machine/artifactxray use_power = IDLE_POWER_USE ///max radiation level - var/max_radiation = 3 + var/max_radiation = 4 ///chosen radiation level var/chosen_level = 1 var/pulse_time = 4 SECONDS var/pulse_cooldown_time = 3 SECONDS var/list/last_results = list("NO DATA") var/pulsing = FALSE + var/datum/techweb/stored_research + ///Chance to get a disk for an artifact trait on scan. Better scanner, better chance. + var/disk_chance = 20 + ///Are we going for disks, at the risk of destorying artifact? + var/destroy_artifact_mode = FALSE + ///Chance we accidentally destory the artifact on destuctive scan. Better laser, less chance. + var/destroy_chance = 75 + ///The disk we have inside of us, maybe. + var/obj/item/disk/artifact/our_disk COOLDOWN_DECLARE(message_cooldown) COOLDOWN_DECLARE(pulse_cooldown) /obj/machinery/artifact_xray/Initialize(mapload) . = ..() + if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research) + connect_techweb(SSresearch.science_tech) RefreshParts() +/obj/machinery/artifact_xray/Destroy() + if(stored_research) + log_research("[src] disconnected from techweb [stored_research] (destroyed).") + stored_research = null + QDEL_NULL(wires) + return ..() + + +/obj/machinery/artifact_xray/proc/connect_techweb(datum/techweb/new_techweb) + if(stored_research) + log_research("[src] disconnected from techweb [stored_research] when connected to [new_techweb].") + stored_research = new_techweb + +/obj/machinery/artifact_xray/multitool_act(mob/living/user, obj/item/multitool/tool) + if(!QDELETED(tool.buffer) && istype(tool.buffer, /datum/techweb)) + connect_techweb(tool.buffer) + return TRUE + return FALSE /obj/machinery/artifact_xray/RefreshParts() . = ..() var/power_usage = 250 - for(var/obj/item/stock_parts/micro_laser/laser in component_parts) - max_radiation = round(2.5 * laser.rating) + for(var/datum/stock_part/micro_laser/laser in component_parts) + max_radiation = laser.tier + destroy_chance = round(75 - (15* laser.tier)) for(var/datum/stock_part/capacitor/capac in component_parts) - power_usage -= 30 * capac.tier + power_usage -= round(30 * capac.tier) + for(var/datum/stock_part/scanning_module/scanner in component_parts) + disk_chance = round(20 * scanner.tier) update_mode_power_usage(ACTIVE_POWER_USE, power_usage) /obj/machinery/artifact_xray/update_icon_state() @@ -39,6 +71,12 @@ . = ..() if(!can_interact(user)) return + if(our_disk) + to_chat(user,"You eject the [our_disk.name]") + if(!user.put_in_active_hand(our_disk)) + our_disk.forceMove(get_turf(user)) + our_disk = null + return toggle_open() /obj/machinery/artifact_xray/proc/toggle_open() if(!COOLDOWN_FINISHED(src,pulse_cooldown)) @@ -49,14 +87,29 @@ else flick("xray-opening", src) open_machine() + if(our_disk) + our_disk.forceMove(src)//Hacky way of keeping the disk inside. /obj/machinery/artifact_xray/attackby(obj/item/item, mob/living/user, params) if(HAS_TRAIT(item, TRAIT_NODROP)) to_chat(user, span_warning("[item] is stuck to your hand, you can't put it inside [src]!")) return - if(state_open && COOLDOWN_FINISHED(src,pulse_cooldown)) - close_machine(item) + if(istype(item,/obj/item/disk/artifact)) + if(our_disk) + to_chat(user,"You swap [our_disk.name] for [item.name]") + if(!user.put_in_inactive_hand(our_disk)) + our_disk.forceMove(get_turf(user)) + item.forceMove(src) + our_disk = item + else + to_chat(user,"You insert [item.name]") + item.forceMove(src) + our_disk = item return + if(state_open) + if(COOLDOWN_FINISHED(src,pulse_cooldown)) + close_machine(item) + return ..() /obj/machinery/artifact_xray/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) @@ -89,7 +142,7 @@ return if(isliving(occupant)) if(!(obj_flags & EMAGGED)) - say("Cannot pulse with a living being inside!") + say("ERROR: Life-signs detected in chamber!") return var/datum/component/artifact/component = occupant.GetComponent(/datum/component/artifact) if(component) @@ -106,11 +159,52 @@ playsound(loc, 'sound/machines/chime.ogg', 30, FALSE) COOLDOWN_START(src,pulse_cooldown,pulse_cooldown_time) pulsing = FALSE - if(artifact) - last_results = list("STRUCTURAL ABNORMALITY ANALYSIS: [artifact.xray_result]", "SIZE: [artifact.artifact_size < ARTIFACT_SIZE_LARGE ? "SMALL" : "LARGE" ]") + if(artifact && stored_research) + var/research_added = 0 + if(!artifact.fault_discovered && artifact.chosen_fault) + artifact.freebies = 0 //No more freebies, you know what it does now. + artifact.fault_discovered = TRUE + research_added += artifact.chosen_fault.research_value + if(artifact.chosen_fault) + last_results = list("ARTIFACT FAULT DISCOVERED: [artifact.chosen_fault.name]", "SIZE: [artifact.artifact_size < ARTIFACT_SIZE_LARGE ? "SMALL" : "LARGE" ]") + else + research_added += 2500 + last_results = list("FLAWLESS ARTIFACT. NO FAULTS.", "SIZE: [artifact.artifact_size < ARTIFACT_SIZE_LARGE ? "SMALL" : "LARGE" ]") + if(length(artifact.discovered_effects) != length(artifact.artifact_effects)) + for(var/datum/artifact_effect/eff in artifact.artifact_effects) + artifact.discovered_effects += eff.type + research_added += eff.research_value + last_results += "ARTIFACT EFFECTS REVEALED." + if(!length(artifact.artifact_effects)) + last_results += "MUNDANE ARTIFACT DETECTED. NO NOTEABLE EFFECTS." + if(length(artifact.activators) != length(artifact.activators)) + for(var/datum/artifact_activator/activator in artifact.activators) + artifact.discovered_activators += activator.type + research_added += activator.research_value + last_results += "ARTIFACT ACTIVATORS REVEALED." + last_results+= "WARNING: ARTIFACT FAULT NOW ACTIVE." + if(research_added > 0 && !artifact.researched) + artifact.researched = TRUE + src.visible_message(span_notice("[src] blares: ") + span_robot("ARTIFACT RESEARCHED:[research_added] ADDED TO LINKED CONSOLE")) + stored_research.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = research_added)) + if(our_disk && destroy_artifact_mode) + destructive_scan_artifact(artifact) else - last_results = list("INCONCLUSIVE;", "NO SPECIAL PROPERTIES DETECTED") - + last_results = list("INCONCLUSIVE;", "NO SPECIAL PROPERTIES DETECTED OR NO RESEARCH CONSOLE LINKED.") + return + +/obj/machinery/artifact_xray/proc/destructive_scan_artifact(datum/component/artifact/the_artifact) + if(prob(disk_chance + (5*chosen_level))) + our_disk.effect = pick(the_artifact.artifact_effects) + our_disk.activator = pick(the_artifact.activators) + if(prob(100-destroy_chance)) //Better scanners means better chance of NOT getting fault + our_disk.fault = the_artifact.chosen_fault + our_disk.update_name() + src.visible_message(span_robot("NOTICE: DATA DISK RECORDED.")) + if(prob(destroy_chance + round(2.5 * chosen_level))) + the_artifact.clear_out() + src.visible_message(span_robot("WARNING: ARTIFACT RENDERED INERT.")) + return /obj/machinery/artifact_xray/ui_data(mob/user) . = ..() @@ -145,11 +239,17 @@ else if(!occupant_atom.anchored) return TRUE -/obj/machinery/artifact_xray/screwdriver_act(mob/living/user, obj/item/tool) +/obj/machinery/artifact_xray/wrench_act(mob/living/user, obj/item/tool) if(pulsing) return TOOL_ACT_SIGNAL_BLOCKING - . = default_deconstruction_screwdriver(user, base_icon_state, base_icon_state, tool) + destroy_artifact_mode = !destroy_artifact_mode + var/modestring = destroy_artifact_mode ? "DESTRUCTIVE SCAN" : "NON-DESTRUCTIVE SCAN" + to_chat(user,span_notice("[src] switched to [modestring] mode.")) + return TOOL_ACT_MELEE_CHAIN_BLOCKING + +/obj/machinery/artifact_xray/screwdriver_act(mob/living/user, obj/item/tool) + return pulsing ? TOOL_ACT_SIGNAL_BLOCKING : default_deconstruction_screwdriver(user, "xray-maint", "xray-1", tool) /obj/machinery/artifact_xray/crowbar_act(mob/living/user, obj/item/tool) return pulsing ? TOOL_ACT_SIGNAL_BLOCKING : default_deconstruction_crowbar(tool) diff --git a/monkestation/code/modules/art_sci_overrides/artifact_testers/zapper.dm b/monkestation/code/modules/art_sci_overrides/artifact_testers/zapper.dm index b877d2b4fe91..ca12f10a415c 100644 --- a/monkestation/code/modules/art_sci_overrides/artifact_testers/zapper.dm +++ b/monkestation/code/modules/art_sci_overrides/artifact_testers/zapper.dm @@ -1,6 +1,6 @@ /obj/machinery/artifact_zapper name = "artifact zapper" - desc = "A directed tesla coil, zaps the artifact that it is facing. VERY power-consuming." + desc = "A directed tesla coil, zaps the object that it is facing. VERY power-consuming. Can attempt to turn artifacts into wands if hit with a multi-tool." icon = 'icons/obj/machines/artifact_machines.dmi' icon_state = "zapper" base_icon_state = "zapper" @@ -12,6 +12,8 @@ ///chosen level var/chosen_level = 100 var/pulse_cooldown_time = 4 SECONDS + + var/into_wand_mode = FALSE COOLDOWN_DECLARE(pulse_cooldown) /obj/machinery/artifact_zapper/Initialize(mapload) @@ -59,14 +61,21 @@ component = object.GetComponent(/datum/component/artifact) if(component) break - if(!component) return Beam(component.parent, icon_state="lightning[rand(1,12)]", time = pulse_cooldown_time) playsound(get_turf(src), 'sound/magic/lightningshock.ogg', 60, TRUE, extrarange = 2) use_power(chosen_level) - component.process_stimuli(STIMULUS_SHOCK, chosen_level) + if(!into_wand_mode) + component.process_stimuli(STIMULUS_SHOCK, chosen_level) + else + if(prob(round(chosen_level/100))) + var/obj/item/artifact_summon_wand/wand = new(target_turf) + visible_message("[component.holder] is shocked into [wand]!") + else + visible_message("[component.holder] is shocked into oblivion!") + qdel(component.holder) COOLDOWN_START(src,pulse_cooldown, pulse_cooldown_time) @@ -84,11 +93,20 @@ to_chat(user,span_notice("You short out the safety sensors on the [src].")) playsound(src, SFX_SPARKS, 75, TRUE, SILENCED_SOUND_EXTRARANGE) + +/obj/machinery/artifact_zapper/multitool_act(mob/living/user, obj/item/tool) + if(!COOLDOWN_FINISHED(src,pulse_cooldown)) + return TOOL_ACT_SIGNAL_BLOCKING + into_wand_mode = !into_wand_mode + visible_message(span_info("[src] switches to [into_wand_mode ? "attempting to break down artifacts." : "just zapping artifacts." ]")) + return TOOL_ACT_MELEE_CHAIN_BLOCKING /obj/machinery/artifact_zapper/screwdriver_act(mob/living/user, obj/item/tool) if(!COOLDOWN_FINISHED(src,pulse_cooldown)) return TOOL_ACT_SIGNAL_BLOCKING . = default_deconstruction_screwdriver(user, base_icon_state, base_icon_state, tool) - /obj/machinery/artifact_zapper/crowbar_act(mob/living/user, obj/item/tool) return !COOLDOWN_FINISHED(src,pulse_cooldown) ? TOOL_ACT_SIGNAL_BLOCKING : default_deconstruction_crowbar(tool) + +/obj/machinery/artifact_zapper/wrench_act_secondary(mob/living/user, obj/item/tool) + return !COOLDOWN_FINISHED(src,pulse_cooldown) ? TOOL_ACT_SIGNAL_BLOCKING : default_unfasten_wrench(user, tool) diff --git a/monkestation/code/modules/art_sci_overrides/faults/_fault.dm b/monkestation/code/modules/art_sci_overrides/faults/_fault.dm index 607340139449..ee1961047340 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/_fault.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/_fault.dm @@ -4,12 +4,30 @@ var/visible_message ///the chance of us triggering on bad info var/trigger_chance = 0 + //how many credits do we get for discovering this? Should be negative. + var/discovered_credits = 0 + //If availible, warns users that this WILL fuck you up. Picks randomly from list + var/list/inspect_warning + ///Added by xray machine when discovered. + var/research_value = 0 + ///How likely the fault is to roll. + var/weight = ARTIFACT_COMMON + ///Our Artifact + var/datum/component/artifact/our_artifact -/datum/artifact_fault/proc/on_trigger(datum/component/artifact/component) +///called when the artifact gets a stimulus, and passes its trigger chance effect. +/datum/artifact_fault/proc/on_trigger() + return + +///Called when the artifact trait comes into existance +/datum/artifact_fault/proc/on_added() return /datum/artifact_fault/shutdown - name = "Generic Shutdown Fault" + name = "Random Shutdown Fault" + visible_message = "has something malfunction and shuts down!" + trigger_chance = 1 + /datum/artifact_fault/on_trigger(datum/component/artifact/component) if(component.active) diff --git a/monkestation/code/modules/art_sci_overrides/faults/bioscrambler.dm b/monkestation/code/modules/art_sci_overrides/faults/bioscrambler.dm new file mode 100644 index 000000000000..f6ee86615c5e --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/faults/bioscrambler.dm @@ -0,0 +1,21 @@ +/datum/artifact_fault/bioscramble + name = "Bioscrambling Fault" + trigger_chance = 3 + visible_message = "corrupts nearby biological life!" + + inspect_warning = list(span_danger("It looks like its made of patchwork flesh!"), + span_danger("It looks Frankenstien like!")) + + research_value = 250 + + weight = ARTIFACT_UNCOMMON + +/datum/artifact_fault/bioscramble/on_trigger() + var/center_turf = get_turf(our_artifact.parent) + + if(!center_turf) + CRASH("[src] had attempted to trigger, but failed to find the center turf!") + + for(var/mob/living/carbon/mob in range(rand(3, 4), center_turf)) + for(var/i in 1 to 3) + mob.bioscramble(our_artifact.holder) diff --git a/monkestation/code/modules/art_sci_overrides/faults/clowning.dm b/monkestation/code/modules/art_sci_overrides/faults/clowning.dm new file mode 100644 index 000000000000..891e99e825ab --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/faults/clowning.dm @@ -0,0 +1,19 @@ +/datum/artifact_fault/clown + name = "Funny Fault" + trigger_chance = 5 + inspect_warning = list("Smells faintly of bananas","Looks Funny.","Hates mimes.") + visible_message = "summons a portal to the HONK DIMENSION!" + discovered_credits = -500 + research_value = 250 + + weight = ARTIFACT_VERYRARE + +/datum/artifact_fault/clown/on_trigger() + var/center_turf = get_turf(our_artifact.parent) + + if(!center_turf) + CRASH("[src] had attempted to trigger, but failed to find the center turf!") + + var/obj/structure/spawner/clown/hehe = new(src) + + addtimer(CALLBACK(hehe,PROC_REF(Destroy)),3 MINUTE) diff --git a/monkestation/code/modules/art_sci_overrides/faults/explosion.dm b/monkestation/code/modules/art_sci_overrides/faults/explosion.dm index f7c028e58860..e75032695910 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/explosion.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/explosion.dm @@ -1,12 +1,16 @@ /datum/artifact_fault/explosion - name = "Explode" + name = "Exploding Fault" trigger_chance = 3 visible_message = "reaches a catastrophic overload, cracks forming at its surface!" -/datum/artifact_fault/explosion/on_trigger(datum/component/artifact/component) - component.holder.Shake(duration = 5 SECONDS, shake_interval = 0.08 SECONDS) - addtimer(CALLBACK(src, PROC_REF(payload), component), 5 SECONDS) + research_value = 500 //nanotrasen always likes weapons IMO -/datum/artifact_fault/explosion/proc/payload(datum/component/artifact/component) - explosion(component.holder, light_impact_range = 2, explosion_cause = src) - qdel(component.holder) + weight = ARTIFACT_UNCOMMON + +/datum/artifact_fault/explosion/on_trigger() + our_artifact.holder.Shake(duration = 5 SECONDS, shake_interval = 0.08 SECONDS) + addtimer(CALLBACK(src, PROC_REF(payload), our_artifact), 5 SECONDS) + +/datum/artifact_fault/explosion/proc/payload() + explosion(our_artifact.holder, light_impact_range = 2, explosion_cause = src) + qdel(our_artifact.holder) diff --git a/monkestation/code/modules/art_sci_overrides/faults/greg.dm b/monkestation/code/modules/art_sci_overrides/faults/greg.dm new file mode 100644 index 000000000000..84b18480cf62 --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/faults/greg.dm @@ -0,0 +1,16 @@ +/datum/artifact_fault/greg + name = "Greg Fault" + discovered_credits = 250 + research_value = 1000 + trigger_chance = 5 + weight = ARTIFACT_RARE + +/datum/artifact_fault/greg/on_added() + our_artifact.holder.AddComponent(/datum/component/ghost_object_control,our_artifact.holder,TRUE) + +/datum/artifact_fault/greg/on_trigger() + var/datum/component/ghost_object_control/spiritholder = our_artifact.holder.GetComponent(/datum/component/ghost_object_control) + + if(!(spiritholder.bound_spirit)) + spiritholder.request_control(0.8) + diff --git a/monkestation/code/modules/art_sci_overrides/faults/ignite.dm b/monkestation/code/modules/art_sci_overrides/faults/ignite.dm index 631f17f850ae..be0cb8498d11 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/ignite.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/ignite.dm @@ -1,10 +1,14 @@ /datum/artifact_fault/ignite - name = "Combust" - trigger_chance = 9 + name = "Combustion Fault" + trigger_chance = 10 visible_message = "starts rapidly heating up while covering everything around it in something that seems to be oil." -/datum/artifact_fault/ignite/on_trigger(datum/component/artifact/component) - var/center_turf = get_turf(component.parent) + research_value = 200 + + weight = ARTIFACT_UNCOMMON + +/datum/artifact_fault/ignite/on_trigger() + var/center_turf = get_turf(our_artifact.parent) if(!center_turf) CRASH("[src] had attempted to trigger, but failed to find the center turf!") diff --git a/monkestation/code/modules/art_sci_overrides/faults/just_death.dm b/monkestation/code/modules/art_sci_overrides/faults/just_death.dm index 8b7b2f8d3c45..c2585b17aef3 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/just_death.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/just_death.dm @@ -1,21 +1,29 @@ /datum/artifact_fault/death - name = "Instant Death" - trigger_chance = 1 + name = "Instant Death Fault" + trigger_chance = 50 //God forbid this actually rolls on a touch artifact,like it did during my testing. visible_message = "blows someone up with mind." + inspect_warning = list(span_danger("The grim reapers scythe seems to be reflected in its surface!"), + span_danger("An Aura of death surrounds this object!"), + span_danger("I'd bet 50/50 someone dies if this turns on!")) -/datum/artifact_fault/death/on_trigger(datum/component/artifact/component) + research_value = 10000 //Wow, this would make a fucking amazing weapon + + weight = ARTIFACT_VERYRARE +/datum/artifact_fault/death/on_trigger() var/list/mobs = list() var/mob/living/carbon/human - var/center_turf = get_turf(component.parent) + var/center_turf = get_turf(our_artifact.parent) if(!center_turf) CRASH("[src] had attempted to trigger, but failed to find the center turf!") - for(var/mob/living/carbon/mob in range(rand(3, 4), center_turf)) + for(var/mob/living/carbon/mob in range(rand(2, 3), center_turf)) mobs += mob + if(!length(mobs)) + return human = pick(mobs) if(!human) return - component.holder.Beam(human, icon_state = "lightning[rand(1,12)]", time = 0.5 SECONDS) + our_artifact.holder.Beam(human, icon_state = "lightning[rand(1,12)]", time = 0.5 SECONDS) human.death(FALSE) diff --git a/monkestation/code/modules/art_sci_overrides/faults/monkey_mode.dm b/monkestation/code/modules/art_sci_overrides/faults/monkey_mode.dm new file mode 100644 index 000000000000..753de53424a5 --- /dev/null +++ b/monkestation/code/modules/art_sci_overrides/faults/monkey_mode.dm @@ -0,0 +1,34 @@ +/datum/artifact_fault/monkey_mode + name = "Simian Spawner Fault" + trigger_chance = 5 + visible_message = "summons a mass of simians!" + + research_value = 250 + + weight = ARTIFACT_VERYUNCOMMON + +/datum/artifact_fault/monkey_mode/on_trigger() + var/monkey = rand(1,4) + var/center_turf = get_turf(our_artifact.parent) + var/list/turf/valid_turfs = list() + if(!center_turf) + CRASH("[src] had attempted to trigger, but failed to find the center turf!") + for(var/turf/boi in range(rand(3,6),center_turf)) + if(boi.density) + continue + valid_turfs += boi + for(var/i in 1 to monkey) + var/turf/spawnon = pick(valid_turfs) + valid_turfs -= spawnon + var/pain = roll(1,100) + var/mob/living/M //For monkey + switch(pain) + if(1 to 75) + M = new /mob/living/carbon/human/species/monkey/angry(spawnon) + if(75 to 95) + M = new /mob/living/basic/gorilla(spawnon) + if(95 to 100) + M = new /mob/living/basic/gorilla/lesser(spawnon)//OH GOD ITS TINY + if(M) //Just in case. + M.forceMove(spawnon) + diff --git a/monkestation/code/modules/art_sci_overrides/faults/reagents.dm b/monkestation/code/modules/art_sci_overrides/faults/reagents.dm index c2ab103e18cb..1b9840223db5 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/reagents.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/reagents.dm @@ -1,15 +1,17 @@ /datum/artifact_fault/reagent - name = "Generic Reagent Injector" + name = "Chemical Force Injector Fault" trigger_chance = 15 visible_message = "shoots a syringe out." var/list/reagents = list() -/datum/artifact_fault/reagent/on_trigger(datum/component/artifact/component) + research_value = 100 + +/datum/artifact_fault/reagent/on_trigger() . = ..() if(!length(reagents)) return - var/center_turf = get_turf(component.parent) + var/center_turf = get_turf(our_artifact.parent) if(!center_turf) CRASH("[src] had attempted to trigger, but failed to find the center turf!") @@ -21,7 +23,7 @@ /datum/artifact_fault/reagent/poison name = "Poison" -/datum/artifact_fault/reagent/poison/on_trigger(datum/component/artifact/component) +/datum/artifact_fault/reagent/poison/on_trigger() if(!reagents.len) //mostly copied from reagents.dm but oh well for(var/datum/reagent/reagent as anything in subtypesof(/datum/reagent/toxin)) if(initial(reagent.chemical_flags) & REAGENT_CAN_BE_SYNTHESIZED) diff --git a/monkestation/code/modules/art_sci_overrides/faults/say.dm b/monkestation/code/modules/art_sci_overrides/faults/say.dm index fca9f1d6e653..f9b56de690a1 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/say.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/say.dm @@ -1,19 +1,21 @@ /datum/artifact_fault/speech - name = "Generic Speech" - trigger_chance = 30 - var/list/speech = list() + name = "Talkative Fault" + trigger_chance = 25 + var/list/speech = list("Hello there.","I see you.","I know what you've done.","So hows your shift?","HELP ARTIFACT IS MAKING ME SPEAK","All is one.","One is all.") -/datum/artifact_fault/speech/on_trigger(datum/component/artifact/component) + research_value = 50 + +/datum/artifact_fault/speech/on_trigger() if(!length(speech)) return - var/center_turf = get_turf(component.parent) + var/center_turf = get_turf(our_artifact.parent) if(!center_turf) CRASH("[src] had attempted to trigger, but failed to find the center turf!") for(var/mob/living/living in range(rand(7, 10), center_turf)) - if(prob(50)) + if(prob(10)) living.say("; [pick(speech)]") else living.say("[pick(speech)]") diff --git a/monkestation/code/modules/art_sci_overrides/faults/size_change.dm b/monkestation/code/modules/art_sci_overrides/faults/size_change.dm index 847a555801ef..cfe4599826c4 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/size_change.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/size_change.dm @@ -1,33 +1,40 @@ /datum/artifact_fault/shrink - name = "Shrink" + name = "Shrinking Fault" trigger_chance = 13 visible_message = "starts to shrink." -/datum/artifact_fault/shrink/on_trigger(datum/component/artifact/component) - component.holder.transform = matrix(component.holder.transform, 0.9, 0.9, MATRIX_SCALE) - if(!isstructure(component.holder)) + research_value = 200 + +/datum/artifact_fault/shrink/on_trigger() + our_artifact.holder.transform = matrix(our_artifact.holder.transform, 0.9, 0.9, MATRIX_SCALE) + if(!isstructure(our_artifact.holder)) return - var/obj/structure/structure = component.holder + var/obj/structure/structure = our_artifact.holder structure.w_class-- if(structure.w_class < WEIGHT_CLASS_TINY) - component.holder.visible_message("[component.holder] vanishes into thin air!") - qdel(component.holder) + our_artifact.holder.visible_message("[our_artifact.holder] vanishes into thin air!") + qdel(our_artifact.holder) /datum/artifact_fault/grow - name = "Grow" + name = "Growing Fault" trigger_chance = 13 visible_message = "starts to grow." -/datum/artifact_fault/grow/on_trigger(datum/component/artifact/component) - if(!isitem(component.holder)) + var/trigger_count = 0 +/datum/artifact_fault/grow/on_trigger() + trigger_count++ + if(trigger_count<5) + our_artifact.holder.transform = matrix(our_artifact.holder.transform, 1.1, 1.1, MATRIX_SCALE) + else + our_artifact.holder.visible_message("[our_artifact.holder] can't possibly grow any larger!") + return + if(!isitem(our_artifact.holder)) return - var/obj/item/item = component.holder + var/obj/item/item = our_artifact.holder if(item.w_class > WEIGHT_CLASS_HUGE) return - component.holder.transform = matrix(component.holder.transform, 1.1, 1.1, MATRIX_SCALE) - item.w_class++ if(item.w_class > WEIGHT_CLASS_HUGE) - component.holder.visible_message("[component.holder] becomes to cumbersome to carry!") - component.holder.anchored = TRUE + our_artifact.holder.visible_message("[our_artifact.holder] becomes to cumbersome to carry!") + our_artifact.holder.anchored = TRUE diff --git a/monkestation/code/modules/art_sci_overrides/faults/warps.dm b/monkestation/code/modules/art_sci_overrides/faults/warps.dm index 6014fc2a03eb..72b8b99fbce4 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/warps.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/warps.dm @@ -1,14 +1,18 @@ /datum/artifact_fault/warp - name = "Generic Warp Artifact" + name = "Warping Fault" trigger_chance = 12 visible_message = "warps space sending everyone away." var/list/warp_areas = list() -/datum/artifact_fault/warp/on_trigger(datum/component/artifact/component) + research_value = 250 + + weight = ARTIFACT_UNCOMMON + +/datum/artifact_fault/warp/on_trigger() if(!length(warp_areas)) warp_areas = GLOB.the_station_areas var/turf/safe_turf = get_safe_random_station_turf(warp_areas) - var/center_turf = get_turf(component.parent) + var/center_turf = get_turf(our_artifact.parent) if(!center_turf) CRASH("[src] had attempted to trigger, but failed to find the center turf!") diff --git a/monkestation/code/modules/art_sci_overrides/faults/whispers.dm b/monkestation/code/modules/art_sci_overrides/faults/whispers.dm index b85fd5b57427..727c88a3f55c 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/whispers.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/whispers.dm @@ -1,13 +1,15 @@ /datum/artifact_fault/whisper - name = "Generic Whisper" - trigger_chance = 30 - var/list/whispers = list() + name = "Wispering Fault" + trigger_chance = 75 + var/list/whispers = list("Help me!","I've seen your sins","Egg.") -/datum/artifact_fault/whisper/on_trigger(datum/component/artifact/component) + research_value = 50 + +/datum/artifact_fault/whisper/on_trigger() if(!length(whispers)) return - var/center_turf = get_turf(component.parent) + var/center_turf = get_turf(our_artifact.parent) if(!center_turf) CRASH("[src] had attempted to trigger, but failed to find the center turf!") diff --git a/monkestation/code/modules/art_sci_overrides/faults/zap.dm b/monkestation/code/modules/art_sci_overrides/faults/zap.dm index 303bb44c248c..e09cadc74f5b 100644 --- a/monkestation/code/modules/art_sci_overrides/faults/zap.dm +++ b/monkestation/code/modules/art_sci_overrides/faults/zap.dm @@ -1,8 +1,23 @@ /datum/artifact_fault/tesla_zap - name = "Tesla Zap" + name = "Energetic Discharge Fault" trigger_chance = 12 - visible_message = "discharges a large amount of electricity." + visible_message = "discharges a large amount of electricity!" -/datum/artifact_fault/tesla_zap/on_trigger(datum/component/artifact/component) - . = ..() - tesla_zap(component.holder, rand(4, 7), ZAP_MOB_DAMAGE) + research_value = 200 + + weight = ARTIFACT_RARE + +/datum/artifact_fault/tesla_zap/on_trigger() + var/list/mobs = list() + + var/center_turf = get_turf(our_artifact.parent) + + if(!center_turf) + CRASH("[src] had attempted to trigger, but failed to find the center turf!") + var/shock_range = rand(4, 7) + for(var/mob/living/carbon/mob in range(shock_range, center_turf)) + mobs += mob + if(!length(mobs)) + return + + tesla_zap(our_artifact.holder, shock_range, ZAP_MOB_DAMAGE,shocked_targets = mobs) diff --git a/monkestation/code/modules/art_sci_overrides/generic_artifact_objects.dm b/monkestation/code/modules/art_sci_overrides/generic_artifact_objects.dm index 6443ef06db38..3192c5dd3e98 100644 --- a/monkestation/code/modules/art_sci_overrides/generic_artifact_objects.dm +++ b/monkestation/code/modules/art_sci_overrides/generic_artifact_objects.dm @@ -6,10 +6,11 @@ resistance_flags = LAVA_PROOF | ACID_PROOF | INDESTRUCTIBLE anchored = FALSE density = TRUE - var/datum/component/artifact/assoc_comp + var/datum/artifact_effect/forced_effect + var/datum/component/artifact/assoc_comp = /datum/component/artifact var/mutable_appearance/extra_effect -ARTIFACT_SETUP(/obj/structure/artifact, SSobj) +ARTIFACT_SETUP(/obj/structure/artifact, SSobj, null, forced_effect, null) /obj/effect/artifact_spawner name = "Random Artifact Spawner" @@ -22,54 +23,54 @@ ARTIFACT_SETUP(/obj/structure/artifact, SSobj) qdel(src) /obj/structure/artifact/bonk - assoc_comp = /datum/component/artifact/bonk + forced_effect = /datum/artifact_effect/bonk /obj/structure/artifact/bomb - assoc_comp = /datum/component/artifact/bomb/explosive + forced_effect = /datum/artifact_effect/bomb/explosive /obj/structure/artifact/bomb/devastating - assoc_comp = /datum/component/artifact/bomb/explosive/devastating + forced_effect = /datum/artifact_effect/bomb/explosive/devastating /obj/structure/artifact/bomb/gas - assoc_comp = /datum/component/artifact/bomb/gas + forced_effect = /datum/artifact_effect/bomb/gas /obj/structure/artifact/forcegen - assoc_comp = /datum/component/artifact/forcegen + forced_effect = /datum/artifact_effect/forcegen /obj/structure/artifact/heal - assoc_comp = /datum/component/artifact/heal + forced_effect = /datum/artifact_effect/heal /obj/structure/artifact/injector - assoc_comp = /datum/component/artifact/injector + forced_effect = /datum/artifact_effect/injector /obj/structure/artifact/lamp - assoc_comp = /datum/component/artifact/lamp + forced_effect = /datum/artifact_effect/lamp light_system = OVERLAY_LIGHT light_on = FALSE /obj/structure/artifact/repulsor - assoc_comp = /datum/component/artifact/repulsor + forced_effect = /datum/artifact_effect/repulsor /obj/structure/artifact/vomit - assoc_comp = /datum/component/artifact/vomit + forced_effect = /datum/artifact_effect/vomit /obj/structure/artifact/borger - assoc_comp = /datum/component/artifact/borger + forced_effect = /datum/artifact_effect/borger /obj/structure/artifact/emotegen - assoc_comp = /datum/component/artifact/emotegen + forced_effect = /datum/artifact_effect/emotegen /obj/structure/artifact/surgery - assoc_comp = /datum/component/artifact/surgery + forced_effect = /datum/artifact_effect/surgery /obj/structure/artifact/smoke - assoc_comp = /datum/component/artifact/smoke + forced_effect = /datum/artifact_effect/smoke /obj/structure/artifact/smoke/toxin - assoc_comp = /datum/component/artifact/smoke/toxin + forced_effect = /datum/artifact_effect/smoke/toxin /obj/structure/artifact/smoke/flesh - assoc_comp = /datum/component/artifact/smoke/flesh + forced_effect = /datum/artifact_effect/smoke/flesh /obj/structure/artifact/smoke/exotic - assoc_comp = /datum/component/artifact/smoke/exotic + forced_effect = /datum/artifact_effect/smoke/exotic diff --git a/monkestation/code/modules/art_sci_overrides/globals.dm b/monkestation/code/modules/art_sci_overrides/globals.dm index 25627d3e71a6..c8353234392e 100644 --- a/monkestation/code/modules/art_sci_overrides/globals.dm +++ b/monkestation/code/modules/art_sci_overrides/globals.dm @@ -1,2 +1,2 @@ -GLOBAL_LIST_INIT(artifact_rarity, list()) +GLOBAL_LIST_INIT(artifact_effect_rarity, list()) GLOBAL_LIST_INIT(running_artifact_list, list()) diff --git a/monkestation/code/modules/art_sci_overrides/new_procs.dm b/monkestation/code/modules/art_sci_overrides/new_procs.dm index 18826afdf0db..dd481d85caca 100644 --- a/monkestation/code/modules/art_sci_overrides/new_procs.dm +++ b/monkestation/code/modules/art_sci_overrides/new_procs.dm @@ -1,7 +1,7 @@ /proc/random_rgb_pairlists(list/red_pairs, list/green_pairs, list/blue_pairs, list/alpha_pairs) if(!length(red_pairs) || !length(blue_pairs) || !length(green_pairs) || !length(alpha_pairs)) return COLOR_CULT_RED - + if(!length(red_pairs) >= 2) red_pairs[2] = 255 if(!length(blue_pairs) >= 2) @@ -18,35 +18,37 @@ return rgb(red, green, blue, alpha) - -/proc/spawn_artifact(turf/loc, forced_origin) +///Spawn a new artifact +/proc/spawn_artifact(turf/loc, forced_origin = null, forced_effect = null) if (!loc) return - if(!length(GLOB.artifact_rarity)) + if(!length(GLOB.artifact_effect_rarity)) build_weighted_rarities() - var/list/weighted_list - - if(forced_origin) - weighted_list = GLOB.artifact_rarity[forced_origin] - else - weighted_list = GLOB.artifact_rarity["all"] + var/obj/type_of_artifact = pick_weight(list( + /obj/structure/artifact = 70, + /obj/item/artifact_item = 10, + /obj/item/artifact_item_tiny = 10, + /obj/item/stock_parts/cell/artifact = 2.5, + /obj/item/gun/magic/artifact = 2.5, + /obj/item/melee/artifact = 2.5, + /obj/machinery/power/generator_artifact = 2.5 + )) - var/datum/component/artifact/picked = pick_weight(weighted_list) - var/type = initial(picked.associated_object) - return new type(loc) + var/obj/A = new type_of_artifact(loc,forced_origin,forced_effect) + return A /proc/build_weighted_rarities() - GLOB.artifact_rarity["all"] = list() ///this needs to be created first for indexing sake + GLOB.artifact_effect_rarity["all"] = list() ///this needs to be created first for indexing sake for(var/datum/artifact_origin/origin as anything in subtypesof(/datum/artifact_origin)) - GLOB.artifact_rarity[initial(origin.type_name)] = list() + GLOB.artifact_effect_rarity[initial(origin.type_name)] = list() - for(var/datum/component/artifact/artifact_type as anything in subtypesof(/datum/component/artifact)) - var/weight = initial(artifact_type.weight) + for(var/datum/artifact_effect/artifact_effect as anything in subtypesof(/datum/artifact_effect)) + var/weight = initial(artifact_effect.weight) if(!weight) continue - GLOB.artifact_rarity["all"][artifact_type] = weight - for(var/origin in GLOB.artifact_rarity) - if(origin in initial(artifact_type.valid_origins)) - GLOB.artifact_rarity[origin][artifact_type] = weight + GLOB.artifact_effect_rarity["all"][artifact_effect] = weight + for(var/origin in GLOB.artifact_effect_rarity) + if(origin in initial(artifact_effect.valid_origins)) + GLOB.artifact_effect_rarity[origin][artifact_effect] = weight diff --git a/monkestation/code/modules/client/preferences/alt_jobs/titles.dm b/monkestation/code/modules/client/preferences/alt_jobs/titles.dm index f132695cbf6d..1e45300b1627 100644 --- a/monkestation/code/modules/client/preferences/alt_jobs/titles.dm +++ b/monkestation/code/modules/client/preferences/alt_jobs/titles.dm @@ -292,6 +292,7 @@ "Biorobotics Director", "Research Supervisor", "Chief Science Officer", + "Chief Artificer", ) /datum/job/roboticist @@ -318,6 +319,7 @@ "Xenoarchaeologist", "Research Assistant", "Graduate Student", + "Artificer" ) /datum/job/security_officer diff --git a/tgstation.dme b/tgstation.dme index e4d55f060368..54cff14c806e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6191,6 +6191,7 @@ #include "monkestation\code\modules\antimatter\code\control.dm" #include "monkestation\code\modules\antimatter\code\shielding.dm" #include "monkestation\code\modules\art_sci_overrides\artifact_origins.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_proto_datums.dm" #include "monkestation\code\modules\art_sci_overrides\generic_artifact_objects.dm" #include "monkestation\code\modules\art_sci_overrides\globals.dm" #include "monkestation\code\modules\art_sci_overrides\item_stimuli.dm" @@ -6201,23 +6202,36 @@ #include "monkestation\code\modules\art_sci_overrides\artifact_components\_base_component.dm" #include "monkestation\code\modules\art_sci_overrides\artifact_components\_base_component_signal_procs.dm" #include "monkestation\code\modules\art_sci_overrides\artifact_components\_base_subtype_helpers.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\bomb.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\bonk.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\borger.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\cell.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\emoter.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\forcegen.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\gun.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\heal.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\injector.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\lamp.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\melee.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\repulsor.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\smoke_artifacts.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\surgery.dm" -#include "monkestation\code\modules\art_sci_overrides\artifact_components\vomit.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_components\ghost_object.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\_artifact_effect.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\bomb.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\bonk.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\borger.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\bread.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\cell.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\cleaning.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\emoter.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\false_rod.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\forcegen.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\gun.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\heal.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\injector.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\itsasecret.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\lamp.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\meat.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\melee.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\money.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\narsieoffering.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\plushie_vendor.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\repulsor.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\smoke_artifacts.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\surgery.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_effects\vomit.dm" #include "monkestation\code\modules\art_sci_overrides\artifact_items\artifact_cell.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_items\artifact_effect_disk.dm" #include "monkestation\code\modules\art_sci_overrides\artifact_items\artifact_gun.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_items\artifact_item.dm" +#include "monkestation\code\modules\art_sci_overrides\artifact_items\artifact_manipulators.dm" #include "monkestation\code\modules\art_sci_overrides\artifact_items\artifact_melee.dm" #include "monkestation\code\modules\art_sci_overrides\artifact_objects\artifact_powergen.dm" #include "monkestation\code\modules\art_sci_overrides\artifact_testers\analysis_form.dm" @@ -6231,9 +6245,13 @@ #include "monkestation\code\modules\art_sci_overrides\asteroids\cartesian_plane.dm" #include "monkestation\code\modules\art_sci_overrides\asteroids\simple_asteroid.dm" #include "monkestation\code\modules\art_sci_overrides\faults\_fault.dm" +#include "monkestation\code\modules\art_sci_overrides\faults\bioscrambler.dm" +#include "monkestation\code\modules\art_sci_overrides\faults\clowning.dm" #include "monkestation\code\modules\art_sci_overrides\faults\explosion.dm" +#include "monkestation\code\modules\art_sci_overrides\faults\greg.dm" #include "monkestation\code\modules\art_sci_overrides\faults\ignite.dm" #include "monkestation\code\modules\art_sci_overrides\faults\just_death.dm" +#include "monkestation\code\modules\art_sci_overrides\faults\monkey_mode.dm" #include "monkestation\code\modules\art_sci_overrides\faults\reagents.dm" #include "monkestation\code\modules\art_sci_overrides\faults\say.dm" #include "monkestation\code\modules\art_sci_overrides\faults\size_change.dm" diff --git a/tgui/packages/tgui/interfaces/ArtifactForm.jsx b/tgui/packages/tgui/interfaces/ArtifactForm.jsx index 6da89c9386e4..1ce1a8e36154 100644 --- a/tgui/packages/tgui/interfaces/ArtifactForm.jsx +++ b/tgui/packages/tgui/interfaces/ArtifactForm.jsx @@ -8,13 +8,15 @@ export const ArtifactForm = (props) => { const { allorigins, chosenorigin, + allfaults, + chosenfault, alltypes, chosentype, alltriggers, chosentriggers, } = data; return ( - +
{allorigins.map((key) => ( @@ -31,13 +33,28 @@ export const ArtifactForm = (props) => { /> ))}
+
+ {allfaults.map((thing) => ( +
{alltypes.map((x) => (