From 233a9b51b9ed64a9dcc455dbb65620508f3df5d2 Mon Sep 17 00:00:00 2001
From: Anorak2020 <145682013+Anorak2024@users.noreply.github.com>
Date: Sat, 26 Oct 2024 12:06:12 +0300
Subject: [PATCH] add: Experimentor relics rework (#5683)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Experimentor relics rework
* Experimentor relics rework
* bugfix
* Added beer, non alcogolic beer & beer2 into perfect_mix
* bugfix
* bugfix + some sprites
* + fauna bomb icon
* inhand sprites + bugfix
* bugfix
* bugfix
* bugfix
* new attack returns
* bugfix
* bugfix
* Update code/modules/mob/living/simple_animal/hostile/hostile.dm
Co-authored-by: Den109G <87372121+Den109G@users.noreply.github.com>
* Update code/game/objects/items/weapons/tuned_anomalous_teleporter.dm
Co-authored-by: Den109G <87372121+Den109G@users.noreply.github.com>
* Update code/modules/research/experimentor.dm
Co-authored-by: Den109G <87372121+Den109G@users.noreply.github.com>
* Update code/modules/research/experimentor.dm
Co-authored-by: Den109G <87372121+Den109G@users.noreply.github.com>
* павп
* аыва
* balance
* fixes
* forgot rapidsyringe_experimental subcategory
---------
Co-authored-by: Den109G <87372121+Den109G@users.noreply.github.com>
---
code/game/objects/effects/anomalies.dm | 16 +
code/game/objects/items/anomaly_beacon.dm | 30 ++
code/game/objects/items/devices/paicard.dm | 4 +-
.../items/weapons/experimental_syringe_gun.dm | 68 +++
.../items/weapons/grenades/fauna_bomb.dm | 64 +++
.../objects/items/weapons/grenades/grenade.dm | 2 +-
.../weapons/tuned_anomalous_teleporter.dm | 74 +++
.../living/simple_animal/hostile/hostile.dm | 10 +
.../simple_animal/hostile/mining/hivelord.dm | 2 +
.../mob/living/simple_animal/simple_animal.dm | 14 +
code/modules/research/experimentor.dm | 459 +++++++++++-------
.../mob/inhands/relics_production/inhandl.dmi | Bin 0 -> 740 bytes
.../mob/inhands/relics_production/inhandr.dmi | Bin 0 -> 740 bytes
icons/obj/weapons/techrelic.dmi | Bin 0 -> 1601 bytes
paradise.dme | 4 +
15 files changed, 563 insertions(+), 184 deletions(-)
create mode 100644 code/game/objects/items/anomaly_beacon.dm
create mode 100644 code/game/objects/items/weapons/experimental_syringe_gun.dm
create mode 100644 code/game/objects/items/weapons/grenades/fauna_bomb.dm
create mode 100644 code/game/objects/items/weapons/tuned_anomalous_teleporter.dm
create mode 100644 icons/mob/inhands/relics_production/inhandl.dmi
create mode 100644 icons/mob/inhands/relics_production/inhandr.dmi
create mode 100644 icons/obj/weapons/techrelic.dmi
diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm
index b7adbe7f282..5f15b415f03 100644
--- a/code/game/objects/effects/anomalies.dm
+++ b/code/game/objects/effects/anomalies.dm
@@ -59,6 +59,22 @@
return ..()
/obj/effect/anomaly/process()
+ for(var/obj/item/I in get_turf(src))
+ if(!I.origin_tech)
+ continue
+ if (istype(I, /obj/item/relict_production/rapid_dupe))
+ var/amount = rand(1, 3)
+ for (var/i; i <= amount; i++)
+ new /obj/item/relic(get_turf(I))
+ var/datum/effect_system/smoke_spread/smoke = new
+ smoke.set_up(5, get_turf(I))
+ smoke.start()
+ qdel(I)
+ continue
+ if (prob(2))
+ new /obj/item/relic(get_turf(I))
+ qdel(I)
+
anomalyEffect()
if(death_time < world.time)
if(loc)
diff --git a/code/game/objects/items/anomaly_beacon.dm b/code/game/objects/items/anomaly_beacon.dm
new file mode 100644
index 00000000000..113136a524a
--- /dev/null
+++ b/code/game/objects/items/anomaly_beacon.dm
@@ -0,0 +1,30 @@
+/obj/item/assembly/anomaly_beacon
+ icon = 'icons/obj/weapons/techrelic.dmi'
+ icon_state = "beacon"
+ item_state = "beacon"
+ lefthand_file = 'icons/mob/inhands/relics_production/inhandl.dmi'
+ righthand_file = 'icons/mob/inhands/relics_production/inhandr.dmi'
+ name = "anomaly beacon"
+ desc = "A device that draws power from bluespace and creates a permanent tracking beacon."
+ origin_tech = "bluespace=6"
+
+/obj/item/assembly/anomaly_beacon/activate()
+ var/obj/effect/anomaly/anomaly_path = pick(subtypesof(/obj/effect/anomaly/))
+ var/newAnomaly = new anomaly_path(get_turf(src))
+ notify_ghosts("[name] has an object of interest: [newAnomaly]!", title = "Something's Interesting!", source = newAnomaly, action = NOTIFY_FOLLOW)
+ qdel(src)
+
+/obj/item/assembly/anomaly_beacon/attack_self(mob/user)
+ activate()
+
+/datum/crafting_recipe/anomaly_beacon
+ name = "Anomaly beacon"
+ result = /obj/item/assembly/anomaly_beacon
+ tools = list(TOOL_SCREWDRIVER)
+ reqs = list(/obj/item/assembly/signaler/anomaly = 1,
+ /obj/item/relict_production/rapid_dupe = 1,
+ /obj/item/radio/beacon = 1,
+ /obj/item/stack/cable_coil = 5)
+ time = 300
+ category = CAT_WEAPONRY
+ subcategory = CAT_WEAPON
diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm
index 6914b59cc95..b291e1b0067 100644
--- a/code/game/objects/items/devices/paicard.dm
+++ b/code/game/objects/items/devices/paicard.dm
@@ -5,7 +5,7 @@
item_state = "pai"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
- origin_tech = "programming=2"
+ origin_tech = "programming=3;powerstorage=2" // Or it will be cloned in the experimentor
var/request_cooldown = 5 // five seconds
var/last_request
var/obj/item/radio/headset/radio
@@ -531,7 +531,7 @@
icon = 'icons/obj/pda.dmi'
icon_state = "pai-spai"
w_class = WEIGHT_CLASS_TINY
- origin_tech = "programming=2;syndicate=2"
+ origin_tech = "programming=3;syndicate=2" // Or it will be cloned in the experimentor
var/extra_memory = 50
var/used = TRUE
diff --git a/code/game/objects/items/weapons/experimental_syringe_gun.dm b/code/game/objects/items/weapons/experimental_syringe_gun.dm
new file mode 100644
index 00000000000..e6095af7b03
--- /dev/null
+++ b/code/game/objects/items/weapons/experimental_syringe_gun.dm
@@ -0,0 +1,68 @@
+/obj/item/gun/syringe/rapidsyringe/experimental
+ name = "experimental syringe gun"
+ desc = "Эксперементальный шприцемет с 6 слотами для шприцев, встроенным, самовосполняющимся хранилищем химикатов и новейшей системой автозаправки шприцев."
+ origin_tech = "combat=3;biotech=4;bluespace=5"
+ icon = 'icons/obj/weapons/techrelic.dmi'
+ item_state = "strynggun"
+ lefthand_file = 'icons/mob/inhands/relics_production/inhandl.dmi'
+ righthand_file = 'icons/mob/inhands/relics_production/inhandr.dmi'
+ icon_state = "strynggun"
+ materials = list(MAT_METAL=2000, MAT_GLASS=2000, MAT_BLUESPACE=400)
+ var/obj/item/reagent_containers/glass/beaker/large/ready_reagents = new
+ var/obj/item/reagent_containers/glass/beaker/large/processed_reagents = new
+ var/synth_speed = 5
+ var/bank_size = 100
+ origin_tech = "bluespace=4;biotech=5"
+
+/obj/item/gun/syringe/rapidsyringe/experimental/Initialize()
+ . = ..()
+ START_PROCESSING(SSobj, src)
+
+/obj/item/gun/syringe/rapidsyringe/experimental/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/item/gun/syringe/rapidsyringe/experimental/attackby(obj/item/A, mob/user)
+ if(istype(A, /obj/item/reagent_containers/syringe))
+ var/in_clip = length(syringes) + (chambered.BB ? 1 : 0)
+ if(in_clip < max_syringes)
+ if(!user.drop_transfer_item_to_loc(A, src))
+ return ..()
+ balloon_alert(user, "заряжено!")
+ syringes.Add(A)
+ process_chamber() // Chamber the syringe if none is already
+ return ATTACK_CHAIN_BLOCKED_ALL
+ else
+ balloon_alert(user, "недостаточно места!")
+ return ATTACK_CHAIN_PROCEED
+ else if(istype(A, /obj/item/reagent_containers/glass))
+ var/obj/item/reagent_containers/glass/RC = A
+ if (!RC.reagents.reagent_list)
+ return ..()
+ ready_reagents.reagents.clear_reagents()
+ processed_reagents.reagents.clear_reagents()
+ RC.reagents.trans_to(ready_reagents, bank_size)
+ ready_reagents.reagents.trans_to(processed_reagents, synth_speed)
+ balloon_alert(user, "синтезируемый набор веществ изменен!")
+ return ATTACK_CHAIN_BLOCKED_ALL
+ else
+ return ..()
+
+/obj/item/gun/syringe/rapidsyringe/experimental/process()
+ for (var/obj/item/reagent_containers/syringe/S in syringes)
+ ready_reagents.reagents.trans_to(S, ready_reagents.reagents.total_volume)
+ for (var/datum/reagent/R in processed_reagents.reagents.reagent_list)
+ if (R.can_synth)
+ ready_reagents.reagents.add_reagent(R.id, R.volume)
+
+/datum/crafting_recipe/rapidsyringe_experimental
+ name = "Experemintal syringe gun"
+ result = /obj/item/gun/syringe/rapidsyringe/experimental
+ tools = list(TOOL_SCREWDRIVER, TOOL_WRENCH)
+ reqs = list(/obj/item/relict_production/perfect_mix = 1,
+ /obj/item/assembly/signaler/anomaly/vortex = 1,
+ /obj/item/gun/syringe/rapidsyringe = 1,
+ /obj/item/stock_parts/matter_bin = 1)
+ time = 300
+ category = CAT_WEAPONRY
+ subcategory = CAT_WEAPON
diff --git a/code/game/objects/items/weapons/grenades/fauna_bomb.dm b/code/game/objects/items/weapons/grenades/fauna_bomb.dm
new file mode 100644
index 00000000000..6ca2c4314be
--- /dev/null
+++ b/code/game/objects/items/weapons/grenades/fauna_bomb.dm
@@ -0,0 +1,64 @@
+/obj/item/grenade/fauna_bomb
+ name = "fauna bomb"
+ desc = "Эксперементальная, многоразовая граната, создающая фауну агрессивную ко всем, кроме активировавшего гранату."
+ w_class = WEIGHT_CLASS_SMALL
+ icon = 'icons/obj/weapons/techrelic.dmi'
+ icon_state = "bomb"
+ item_state = "bomb"
+ lefthand_file = 'icons/mob/inhands/relics_production/inhandl.dmi'
+ righthand_file = 'icons/mob/inhands/relics_production/inhandr.dmi'
+ var/deliveryamt = 8
+ var/amount = 3
+ COOLDOWN_DECLARE(fauna_bomb_cooldown)
+ var/mob/activator
+ origin_tech = "bluespace=4;biotech=5"
+
+/obj/item/grenade/fauna_bomb/attack_self(mob/user)
+ if(!COOLDOWN_FINISHED(src, fauna_bomb_cooldown))
+ to_chat(user, span_warning("[src] is still recharging!"))
+ return
+
+ COOLDOWN_START(src, fauna_bomb_cooldown, 60 SECONDS)
+ activator = user
+ return ..(user, FALSE)
+
+/obj/item/grenade/fauna_bomb/prime()
+ active = FALSE
+ playsound(get_turf(src), 'sound/items/rawr.ogg', 100, TRUE)
+ var/faction = activator.name + "_fauna_bomb"
+ activator.faction |= faction
+ var/list/mob/living/simple_animal/mobs = list()
+
+ var/mob/living/simple_animal/spawn_mob_type = pick(/mob/living/simple_animal/hostile/asteroid/hivelord/legion, /mob/living/simple_animal/hostile/asteroid/goliath, /mob/living/simple_animal/hostile/asteroid/marrowweaver)
+
+ for(var/i in 1 to amount)
+ var/mob/living/simple_animal/new_mob = new spawn_mob_type(get_turf(src))
+ mobs.Add(new_mob)
+ new_mob.set_leash(activator, 10)
+ new_mob.faction |= faction
+ if(prob(50))
+ for(var/j = 1, j <= rand(1, 3), j++)
+ step(new_mob, pick(NORTH, SOUTH, EAST, WEST))
+
+ if(prob(40))
+ to_chat(activator, span_warning("[src] falls apart!"))
+ qdel(src)
+
+ sleep(600)
+ for (var/mob/mob in mobs)
+ mob.dust()
+
+/obj/item/grenade/fauna_bomb/update_icon_state()
+ return
+
+/datum/crafting_recipe/fauna_bomb
+ name = "Fauna bomb"
+ result = /obj/item/grenade/fauna_bomb
+ tools = list(TOOL_SCREWDRIVER)
+ reqs = list(/obj/item/relict_production/pet_spray = 1,
+ /obj/item/assembly/signaler/anomaly/pyro = 1,
+ /obj/item/grenade/chem_grenade/adv_release = 1,
+ /obj/item/stack/cable_coil = 5)
+ time = 300
+ category = CAT_WEAPONRY
+ subcategory = CAT_WEAPON
diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm
index 8e27a202b85..96ebb79d2f1 100644
--- a/code/game/objects/items/weapons/grenades/grenade.dm
+++ b/code/game/objects/items/weapons/grenades/grenade.dm
@@ -56,7 +56,7 @@
/obj/item/grenade/attack_self(mob/user)
if(!active && clown_check(user))
- to_chat(user, "You prime the [name]! [det_time/10] seconds!")
+ to_chat(user, span_warning("You prime the [name]! [det_time/10] seconds!"))
active = TRUE
update_icon(UPDATE_ICON_STATE)
add_fingerprint(user)
diff --git a/code/game/objects/items/weapons/tuned_anomalous_teleporter.dm b/code/game/objects/items/weapons/tuned_anomalous_teleporter.dm
new file mode 100644
index 00000000000..620ea5f9222
--- /dev/null
+++ b/code/game/objects/items/weapons/tuned_anomalous_teleporter.dm
@@ -0,0 +1,74 @@
+/obj/item/tuned_anomalous_teleporter
+ name = "tuned anomalous teleporter"
+ desc = "A portable item using blue-space technology."
+ icon = 'icons/obj/weapons/techrelic.dmi'
+ icon_state = "teleport"
+ lefthand_file = 'icons/mob/inhands/relics_production/inhandl.dmi'
+ righthand_file = 'icons/mob/inhands/relics_production/inhandr.dmi'
+ item_state = "teleport"
+ throwforce = 0
+ w_class = WEIGHT_CLASS_SMALL
+ throw_speed = 3
+ throw_range = 5
+ materials = list(MAT_METAL=10000)
+ origin_tech = "magnets=3;bluespace=4"
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ /// Variable contains next time hand tele can be used to make it not EMP proof
+ var/emp_timer = 0
+ COOLDOWN_DECLARE(tuned_anomalous_teleporter_cooldown) // declare cooldown for teleportations
+ COOLDOWN_DECLARE(emp_cooldown) // declare cooldown for EMP
+ var/base_cooldown = 20 SECONDS // cooldown for teleportations
+ var/emp_cooldown_min = 10 SECONDS // min cooldown for emp
+ var/emp_cooldown_max = 15 SECONDS // max cooldown for emp
+ var/tp_range = 5 // range of teleportations
+ origin_tech = "bluespace=5"
+
+/obj/item/tuned_anomalous_teleporter/attack_self(mob/user)
+ if(!COOLDOWN_FINISHED(src, emp_cooldown))
+ do_sparks(5, FALSE, loc)
+ to_chat(user, span_warning("[src] attempts to teleport you, but abruptly shuts off."))
+ return FALSE
+ if(!COOLDOWN_FINISHED(src, tuned_anomalous_teleporter_cooldown))
+ to_chat(user, span_warning("[src] is still recharging."))
+ return FALSE
+
+ COOLDOWN_START(src, tuned_anomalous_teleporter_cooldown, base_cooldown)
+
+ var/datum/teleport/TP = new /datum/teleport()
+ var/crossdir = angle2dir((dir2angle(user.dir)) % 360)
+ var/turf/T1 = get_turf(user)
+ for(var/i in 1 to tp_range)
+ T1 = get_step(T1, crossdir)
+ var/datum/effect_system/smoke_spread/s1 = new
+ var/datum/effect_system/smoke_spread/s2 = new
+ s1.set_up(5, FALSE, user)
+ s2.set_up(5, FALSE, user)
+ TP.start(user, T1, FALSE, TRUE, s1, s2, 'sound/effects/phasein.ogg', )
+ TP.doTeleport()
+
+/obj/item/tuned_anomalous_teleporter/emp_act(severity)
+ make_inactive(severity)
+ return ..()
+
+/obj/item/tuned_anomalous_teleporter/proc/make_inactive(severity)
+ var/time = rand(emp_cooldown_min, emp_cooldown_max) * (severity == EMP_HEAVY ? 2 : 1)
+ COOLDOWN_START(src, emp_cooldown, time)
+
+/obj/item/tuned_anomalous_teleporter/examine(mob/user)
+ . = ..()
+ if(emp_timer > world.time)
+ . += span_warning("It looks inactive.")
+
+/datum/crafting_recipe/tuned_anomalous_teleporter
+ name = "Tuned anomalous teleporter"
+ result = /obj/item/tuned_anomalous_teleporter
+ tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
+ reqs = list(/obj/item/relict_production/strange_teleporter = 1,
+ /obj/item/assembly/signaler/anomaly/bluespace = 1,
+ /obj/item/gps = 1,
+ /obj/item/stack/ore/bluespace_crystal,
+ /obj/item/stack/sheet/metal = 2,
+ /obj/item/stack/cable_coil = 5)
+ time = 300
+ category = CAT_MISC
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index ebf48eaaa54..32908854ec8 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -272,8 +272,18 @@
var/possible_target_distance = get_dist(targets_from, A)
if(target_dist < possible_target_distance)
Targets -= A
+
+ var/list/mob/high_priority_targets = list()
+ for(var/mob/T in Targets)
+ if (!(T.UID() in low_priority_targets))
+ high_priority_targets.Add(T)
+
+ if (high_priority_targets.len)
+ Targets = high_priority_targets
+
if(!Targets.len)//We didnt find nothin!
return
+
var/chosen_target = pick(Targets)//Pick the remaining targets (if any) at random
return chosen_target
diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
index ec04e0c4281..860a9c43c4a 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
@@ -209,6 +209,8 @@
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/death(gibbed)
visible_message("The skulls on [src] wail in anger as they flee from their dying host!")
var/turf/T = get_turf(src)
+ if (!T) // When legion dusts T = null. Maybe not onli this way.
+ return
for(var/i in 1 to 2)
new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/weaken(T)
if(T)
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 0538a1d6465..49f45d9499b 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -133,6 +133,10 @@
var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while
var/SStun = 0 // stun variable
+ var/list/low_priority_targets = list()
+
+ var/atom/leash // autodust on a big distance
+ var/leash_radius = 10
/mob/living/simple_animal/Initialize(mapload)
. = ..()
@@ -301,6 +305,12 @@
/mob/living/simple_animal/handle_environment(datum/gas_mixture/environment)
+ if (leash)
+ var/dist = get_dist(src, leash)
+ if (dist > leash_radius)
+ src.dust()
+ return
+
var/atmos_suitable = TRUE
if(!HAS_TRAIT(src, TRAIT_NO_BREATH))
@@ -789,3 +799,7 @@
if(!can_collar)
return
AddElement(/datum/element/strippable, create_strippable_list(list(/datum/strippable_item/pet_collar)))
+
+/mob/living/simple_animal/proc/set_leash(atom/A, radius)
+ leash = A
+ leash_radius = radius
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index b0deac1cb8d..78594494b1d 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -29,6 +29,7 @@
var/resetTime = 15
var/cloneMode = FALSE
var/cloneCount = 0
+ var/clone_next = FALSE // Clones the next inserted technological item.
/// The distance to your rnd console. Useful for creative mapping.
var/console_dist = 3
var/list/item_reactions = list()
@@ -69,10 +70,9 @@
/obj/machinery/r_n_d/experimentor/proc/SetTypeReactions()
var/probWeight = 0
for(var/I in typesof(/obj/item))
- if(istype(I,/obj/item/relic)) //does istype even work here
- item_reactions["[I]"] = SCANTYPE_DISCOVER
- else
- item_reactions["[I]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE)
+ if(istype(I,/obj/item/relic))
+ continue
+ item_reactions["[I]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE)
if(ispath(I,/obj/item/stock_parts) || ispath(I,/obj/item/grenade/chem_grenade) || ispath(I,/obj/item/kitchen))
var/obj/item/tempCheck = I
if(initial(tempCheck.icon_state) != null) //check it's an actual usable item, in a hacky way
@@ -145,24 +145,52 @@
if(disabled)
to_chat(user, span_warning("The [name] is offline."))
return ATTACK_CHAIN_PROCEED
+
if(!linked_console)
to_chat(user, span_warning("The [name] should be linked to an R&D console first."))
return ATTACK_CHAIN_PROCEED
+
if(loaded_item)
to_chat(user, span_warning("The [name] is already loaded."))
return ATTACK_CHAIN_PROCEED
+
if(!checkCircumstances(I))
to_chat(user, span_warning("The [I.name] is not yet valid for [src] and must be completed."))
return ATTACK_CHAIN_PROCEED
+
if(!I.origin_tech)
to_chat(user, span_warning("The [I.name] has no technological origin."))
return ATTACK_CHAIN_PROCEED
- var/list/temp_tech = ConvertReqString2List(I.origin_tech)
- if(!length(temp_tech))
- to_chat(user, span_warning("The [I.name] has no technological origin."))
+
+ if(clone_next)
+ var/list/temp_tech = ConvertReqString2List(I.origin_tech)
+ var/techs_sum = 0
+ for(var/T in temp_tech)
+ techs_sum += temp_tech[T]
+
+ if(istype(I, /obj/item/relic) || (techs_sum > 4 || isstorage(I)) && !istype(I, /obj/item/storage/backpack/holding))
+ to_chat(user, span_warning("Этот предмет слишком сложен для копирования. Попробуйте вставить что-то попроще."))
+ return ATTACK_CHAIN_PROCEED
+
+ if (I.type in subtypesof(/obj/item/stack))
+ var/obj/item/stack/stack = I
+ if (stack.amount > 1)
+ to_chat(user, span_warning("Предмет должен быть цельным."))
+ return ATTACK_CHAIN_PROCEED
+
+ investigate_log("Experimentor has made a clone of [I]", INVESTIGATE_EXPERIMENTOR)
+ throwSmoke(get_turf(pick(oview(1,src))))
+ for (var/i = 1; i <= badThingCoeff; i++)
+ visible_message(span_notice("A duplicate [I] pops out!"))
+ var/type_to_make = I.type
+ new type_to_make(get_turf(pick(oview(1,src))))
+
+ clone_next = FALSE
return ATTACK_CHAIN_PROCEED
+
if(!user.drop_transfer_item_to_loc(I, src))
- return ..()
+ return ATTACK_CHAIN_PROCEED
+
loaded_item = I
to_chat(user, span_notice("You have added [I] to [src]."))
flick("h_lathe_load", src)
@@ -214,8 +242,6 @@
dat += "
Burn"
dat += "
Freeze"
dat += "
Destroy
"
- if(istype(loaded_item,/obj/item/relic))
- dat += "
Discover
"
dat += "
Eject"
else
dat += "Nothing loaded."
@@ -229,10 +255,10 @@
/obj/machinery/r_n_d/experimentor/proc/matchReaction(matching,reaction)
var/obj/item/D = matching
if(D)
- if(item_reactions.Find("[D.type]"))
+ if(istype(D, /obj/item/relic) || item_reactions.Find("[D.type]"))
var/tor = item_reactions["[D.type]"]
- if(tor == text2num(reaction))
- return tor
+ if(istype(D, /obj/item/relic) || tor == text2num(reaction))
+ return text2num(reaction)
else
return FAIL
else
@@ -276,14 +302,9 @@
else
counter = 1
-/obj/machinery/r_n_d/experimentor/proc/experiment(exp,obj/item/exp_on)
- recentlyExperimented = TRUE
- update_icon(UPDATE_ICON_STATE)
- var/chosenchem
- var/criticalReaction = (exp_on.type in critical_items) ? TRUE : FALSE
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_POKE)
- visible_message("[src] prods at [exp_on] with mechanical arms.")
+/obj/machinery/r_n_d/experimentor/proc/scan_poke(exp, obj/item/exp_on, chosenchem, criticalReaction, isRelict)
+ visible_message("[src] prods at [exp_on] with mechanical arms.")
+ if(!isRelict)
if(prob(EFFECT_PROB_LOW) && criticalReaction)
visible_message("[exp_on] is gripped in just the right way, enhancing its focus.")
badThingCoeff++
@@ -305,9 +326,21 @@
ejectItem()
if(throwing)
throwing.throw_at(target, 10, 1)
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_IRRADIATE)
- visible_message("[src] reflects radioactive rays at [exp_on]!")
+ else if(prob(EFFECT_PROB_VERYLOW))
+ visible_message("The [exp_on] begins to vibrate!")
+ playsound(src.loc, 'sound/effects/supermatter.ogg', 50, 3, -1)
+ ejectItem()
+ throwSmoke(get_turf(exp_on))
+ var/obj/item/relict_production/strange_teleporter/teleporter = new /obj/item/relict_production/strange_teleporter(get_turf(exp_on))
+ teleporter.icon_state = exp_on.icon_state
+ qdel(exp_on)
+ else
+ exp = FAIL
+
+
+/obj/machinery/r_n_d/experimentor/proc/scan_irradiate(exp, obj/item/exp_on, chosenchem, criticalReaction, isRelict)
+ visible_message("[src] reflects radioactive rays at [exp_on]!")
+ if(!isRelict)
if(prob(EFFECT_PROB_LOW) && criticalReaction)
visible_message("[exp_on] has activated an unknown subroutine!")
cloneMode = TRUE
@@ -337,36 +370,52 @@
var/obj/item/grenade/chem_grenade/CG = loaded_item
CG.prime()
ejectItem()
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_GAS)
- visible_message("[src] fills its chamber with gas, [exp_on] included.")
+ else if(prob(EFFECT_PROB_VERYLOW))
+ visible_message("The [exp_on] has activated an unknown subroutine!")
+ clone_next = TRUE
+ ejectItem()
+ qdel(exp_on)
+
+ var/T = rand(1, linked_console.files.known_tech.len)
+ var/datum/tech/KT = linked_console.files.known_tech[linked_console.files.known_tech[T]]
+ var/new_level = linked_console.files.UpdateTech(linked_console.files.known_tech[T], KT.level + 1)
+ var/tech_log = "[T] [new_level], "
+ if(tech_log)
+ investigate_log("[usr] increased tech experimentoring [loaded_item]: [tech_log]. ", INVESTIGATE_RESEARCH)
+ else
+ exp = FAIL
+
+
+/obj/machinery/r_n_d/experimentor/proc/scan_gas(exp, obj/item/exp_on, chosenchem, criticalReaction, isRelict)
+ visible_message("[src] fills its chamber with gas, [exp_on] included.")
+ if(!isRelict)
if(prob(EFFECT_PROB_LOW) && criticalReaction)
visible_message("[exp_on] achieves the perfect mix!")
new /obj/item/stack/sheet/mineral/plasma(get_turf(pick(oview(1,src))))
if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
visible_message("[src] destroys [exp_on], leaking dangerous gas!")
chosenchem = pick("carbon","radium","toxin","condensedcapsaicin","psilocybin","space_drugs","ethanol","beepskysmash")
- var/datum/reagents/R = new/datum/reagents(400)
- R.my_atom = src
- R.add_reagent(chosenchem , 375)
+ var/datum/reagents/inner_reagent = new/datum/reagents(400)
+ inner_reagent.my_atom = src
+ inner_reagent.add_reagent(chosenchem , 375)
investigate_log("Experimentor has released [chosenchem] smoke.", INVESTIGATE_EXPERIMENTOR)
var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, src, TRUE)
+ smoke.set_up(inner_reagent, src, TRUE)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start()
- qdel(R)
+ qdel(inner_reagent)
ejectItem(TRUE)
if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
visible_message("[src]'s chemical chamber has sprung a leak!")
chosenchem = pick("mutationtoxin","nanomachines","sacid")
- var/datum/reagents/R = new/datum/reagents(400)
- R.my_atom = src
- R.add_reagent(chosenchem , 375)
+ var/datum/reagents/inner_reagent = new/datum/reagents(400)
+ inner_reagent.my_atom = src
+ inner_reagent.add_reagent(chosenchem , 375)
var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, src, TRUE)
+ smoke.set_up(inner_reagent, src, TRUE)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start()
- qdel(R)
+ qdel(inner_reagent)
ejectItem(TRUE)
warn_admins(usr, "[chosenchem] smoke")
investigate_log("Experimentor has released [chosenchem] smoke!", INVESTIGATE_EXPERIMENTOR)
@@ -378,9 +427,20 @@
empulse(src.loc, 4, 0) //change this to 4,6 once the EXPERI-Mentor is moved.
investigate_log("Experimentor has generated an Electromagnetic Pulse.", INVESTIGATE_EXPERIMENTOR)
ejectItem(TRUE)
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_HEAT)
- visible_message("[src] raises [exp_on]'s temperature.")
+ else if(prob(EFFECT_PROB_LOW))
+ visible_message("[exp_on] achieves the perfect mix!")
+ playsound(src.loc, 'sound/effects/supermatter.ogg', 50, 3, -1)
+ ejectItem()
+ throwSmoke(get_turf(exp_on))
+ new /obj/item/relict_production/perfect_mix(get_turf(exp_on))
+ qdel(exp_on)
+ else
+ exp = FAIL
+
+
+/obj/machinery/r_n_d/experimentor/proc/scan_heat(exp, obj/item/exp_on, chosenchem, criticalReaction, isRelict)
+ visible_message("[src] raises [exp_on]'s temperature.")
+ if(!isRelict)
if(prob(EFFECT_PROB_LOW) && criticalReaction)
visible_message("[src]'s emergency coolant system gives off a small ding!")
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
@@ -430,9 +490,21 @@
m.apply_damage(5,BURN,pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_PRECISE_GROIN))
investigate_log("Experimentor has dealt minor burn damage to [key_name_log(m)]", INVESTIGATE_EXPERIMENTOR)
ejectItem()
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_COLD)
- visible_message("[src] lowers [exp_on]'s temperature.")
+ else if(prob(EFFECT_PROB_LOW))
+ visible_message("[exp_on] begins to shake, and in the distance the sound of rampaging animals arises!")
+ playsound(src.loc, 'sound/effects/supermatter.ogg', 50, 3, -1)
+ ejectItem()
+ throwSmoke(get_turf(exp_on))
+ var/obj/item/relict_production/pet_spray/R = new /obj/item/relict_production/pet_spray(get_turf(exp_on))
+ R.icon_state = exp_on.icon_state
+ qdel(exp_on)
+ else
+ exp = FAIL
+
+
+/obj/machinery/r_n_d/experimentor/proc/scan_cold(exp, obj/item/exp_on, chosenchem, criticalReaction, isRelict)
+ visible_message("[src] lowers [exp_on]'s temperature.")
+ if(!isRelict)
if(prob(EFFECT_PROB_LOW) && criticalReaction)
visible_message("[src]'s emergency coolant system gives off a small ding!")
var/obj/item/reagent_containers/food/drinks/coffee/C = new /obj/item/reagent_containers/food/drinks/coffee(get_turf(pick(oview(1,src))))
@@ -445,15 +517,15 @@
investigate_log("Experimentor has made a cup of [chosenchem] coffee.", INVESTIGATE_EXPERIMENTOR)
if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
visible_message("[src] malfunctions, shattering [exp_on] and releasing a dangerous cloud of coolant!")
- var/datum/reagents/R = new/datum/reagents(400)
- R.my_atom = src
- R.add_reagent("frostoil" , 375)
+ var/datum/reagents/inner_reagent = new/datum/reagents(400)
+ inner_reagent.my_atom = src
+ inner_reagent.add_reagent("frostoil" , 375)
investigate_log("Experimentor has released frostoil gas.", INVESTIGATE_EXPERIMENTOR)
var/datum/effect_system/smoke_spread/chem/smoke = new
- smoke.set_up(R, src, TRUE)
+ smoke.set_up(inner_reagent, src, TRUE)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start()
- qdel(R)
+ qdel(inner_reagent)
ejectItem(TRUE)
if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src] malfunctions, shattering [exp_on] and leaking cold air!")
@@ -475,9 +547,21 @@
smoke.set_up(1,0, src.loc, 0)
smoke.start()
ejectItem()
- ////////////////////////////////////////////////////////////////////////////////////////////////
- if(exp == SCANTYPE_OBLITERATE)
- visible_message("[exp_on] activates the crushing mechanism, [exp_on] is destroyed!")
+ else if(prob(EFFECT_PROB_LOW))
+ visible_message("[exp_on] emits a loud pop!")
+ playsound(src.loc, 'sound/effects/supermatter.ogg', 50, 3, -1)
+ ejectItem()
+ throwSmoke(get_turf(exp_on))
+ var/obj/item/relict_production/R = new /obj/item/relict_production/rapid_dupe(get_turf(exp_on))
+ R.icon_state = exp_on.icon_state
+ qdel(exp_on)
+ else
+ exp = FAIL
+
+
+/obj/machinery/r_n_d/experimentor/proc/scan_obliterate(exp, obj/item/exp_on, chosenchem, criticalReaction, isRelict)
+ visible_message("[exp_on] activates the crushing mechanism.")
+ if(!isRelict)
if(prob(EFFECT_PROB_LOW) && criticalReaction)
visible_message("[src]'s crushing mechanism slowly and smoothly descends, flattening the [exp_on]!")
new /obj/item/stack/sheet/plasteel(get_turf(pick(oview(1,src))))
@@ -507,22 +591,46 @@
spawn(0)
cast.throw_at(pick(throwAt),10,1)
ejectItem(TRUE)
- ////////////////////////////////////////////////////////////////////////////////////////////////
+ else if(prob(EFFECT_PROB_LOW))
+ visible_message("[src]'s crushing mechanism slowly and smoothly descends, flattening the [exp_on]!")
+ badThingCoeff++
+ var/list/obj/item/stack/sheet/mineral/minreals = list(/obj/item/stack/sheet/mineral/diamond, /obj/item/stack/sheet/mineral/gold, /obj/item/stack/sheet/glass,/obj/item/stack/sheet/metal,/obj/item/stack/sheet/mineral/plasma,/obj/item/stack/sheet/mineral/silver,/obj/item/stack/sheet/mineral/titanium,/obj/item/stack/sheet/mineral/uranium,/obj/item/stack/sheet/mineral/tranquillite,/obj/item/stack/sheet/mineral/bananium)
+ // Plastinium and abductor alloy are alloys, not processed ores.
+ for (var/i = 1; i <= 3; ++i)
+ var/obj/item/stack/sheet/mineral/m0 = pick(minreals)
+ var/obj/item/stack/sheet/mineral/M = new m0(get_turf(exp_on))
+ M.amount = 10
+ qdel(exp_on)
+ ejectItem(TRUE)
+ else
+ exp = FAIL
+
+
+/obj/machinery/r_n_d/experimentor/proc/experiment(exp, obj/item/exp_on)
+ recentlyExperimented = TRUE
+ update_icon(UPDATE_ICON_STATE)
+ var/chosenchem
+ var/criticalReaction = (exp_on.type in critical_items) ? TRUE : FALSE
+ var/isRelict = istype(exp_on, /obj/item/relic)
+
+ if(exp == SCANTYPE_POKE)
+ scan_poke(exp, exp_on, chosenchem, criticalReaction, isRelict)
+ if(exp == SCANTYPE_IRRADIATE)
+ scan_irradiate(exp, exp_on, chosenchem, criticalReaction, isRelict)
+ if(exp == SCANTYPE_GAS)
+ scan_gas(exp, exp_on, chosenchem, criticalReaction, isRelict)
+ if(exp == SCANTYPE_HEAT)
+ scan_heat(exp, exp_on, chosenchem, criticalReaction, isRelict)
+ if(exp == SCANTYPE_COLD)
+ scan_cold(exp, exp_on, chosenchem, criticalReaction, isRelict)
+ if(exp == SCANTYPE_OBLITERATE)
+ scan_obliterate(exp, exp_on, chosenchem, criticalReaction, isRelict)
+
if(exp == FAIL)
var/a = pick("rumbles","shakes","vibrates","shudders")
var/b = pick("crushes","spins","viscerates","smashes","insults")
visible_message("[exp_on] [a], and [b], the experiment was a failure.")
- if(exp == SCANTYPE_DISCOVER)
- visible_message("[src] scans the [exp_on], revealing its true nature!")
- playsound(src.loc, 'sound/effects/supermatter.ogg', 50, 3, -1)
- var/obj/item/relic/R = loaded_item
- R.reveal()
- investigate_log("Experimentor has revealed a relic with [R.realProc] effect.", INVESTIGATE_EXPERIMENTOR)
- ejectItem()
-
- //Global reactions
-
if(prob(EFFECT_PROB_VERYLOW) && prob(13))
visible_message("Experimentor draws the life essence of those nearby!")
for(var/mob/living/m in view(4,src))
@@ -647,6 +755,114 @@
#undef FAIL
+/obj/item/relict_production
+ name = "perfect mix"
+ desc = "Странный объект без эффекта и иконки. Щитспавн онли."
+ icon_state = ""
+ icon = 'icons/obj/assemblies.dmi'
+ origin_tech = "bluespace=3;materials=3"
+ var/cooldown = 5 SECONDS
+ COOLDOWN_DECLARE(relict_production_cooldown)
+
+/obj/item/relict_production/attack_self(mob/user)
+ if(!COOLDOWN_FINISHED(src, relict_production_cooldown))
+ to_chat(user, "[src] is not ready yet.")
+ return FALSE
+ COOLDOWN_START(src, relict_production_cooldown, cooldown)
+ return TRUE
+
+/obj/item/relict_production/perfect_mix
+ name = "perfect mix"
+ desc = "Странный объект из которого можно бесконечно заполнять емкости какой-то жидкостью."
+ icon_state = "beaker"
+ item_state = "beaker"
+ icon = 'icons/obj/weapons/techrelic.dmi'
+ lefthand_file = 'icons/mob/inhands/relics_production/inhandl.dmi'
+ righthand_file = 'icons/mob/inhands/relics_production/inhandr.dmi'
+ origin_tech = "materials=4;bluespace=3"
+ var/datum/reagent/inner_reagent
+ var/transfer = 10
+
+/obj/item/relict_production/perfect_mix/New()
+ . = ..()
+ inner_reagent = pick(/datum/reagent/uranium, /datum/reagent/plasma, /datum/reagent/consumable/capsaicin, /datum/reagent/consumable/frostoil, /datum/reagent/space_cleaner, /datum/reagent/consumable/drink/coffee, pick(/datum/reagent/consumable/drink/non_alcoholic_beer, /datum/reagent/consumable/ethanol/beer, /datum/reagent/beer2))
+
+/obj/item/relict_production/perfect_mix/afterattack(atom/target, mob/user, proximity)
+ if(istype(target, /obj/item/reagent_containers/glass))
+ var/obj/item/reagent_containers/glass/beaker = target
+ beaker.reagents.add_reagent(inner_reagent.id, transfer)
+ to_chat(user, "You have poured 10 units of content into this.")
+ else
+ to_chat(user, "You can't pour [src]'s content into this.")
+
+/obj/item/relict_production/strange_teleporter
+ name = "strange teleporter"
+ desc = "Странный объект телепортирующий вас при активации."
+ icon_state = "prox-multitool2"
+ icon = 'icons/obj/assemblies.dmi'
+ origin_tech = "materials=4;bluespace=4"
+ cooldown = 10 SECONDS
+
+/obj/item/relict_production/strange_teleporter/attack_self(mob/user)
+ if(!..())
+ return
+ to_chat(user, "[src] begins to vibrate!")
+ spawn(rand(10,30))
+ var/turf/userturf = get_turf(user)
+ if(src.loc == user && is_teleport_allowed(userturf.z))
+ visible_message("The [src] twists and bends, relocating itself!")
+ var/datum/effect_system/smoke_spread/smoke = new
+ smoke.set_up(5, get_turf(user))
+ smoke.start()
+ do_teleport(user, userturf, 8, asoundin = 'sound/effects/phasein.ogg')
+ smoke = new
+ smoke.set_up(5, get_turf(user))
+ smoke.start()
+
+/obj/item/relict_production/pet_spray
+ name = "pet spray"
+ desc = "Странный объект создающий враждебных существ."
+ icon_state = "armor-igniter-analyzer"
+ icon = 'icons/obj/assemblies.dmi'
+ origin_tech = "biotech=5"
+ cooldown = 60 SECONDS
+
+/obj/item/relict_production/pet_spray/attack_self(mob/user)
+ if(!..())
+ return
+ var/message = "[src] begins to shake, and in the distance the sound of rampaging animals arises!"
+ visible_message(message)
+ to_chat(user, message)
+ var/amount = rand(1,3)
+ var/list/possible_mobs = list(/mob/living/simple_animal/hostile/bear,
+ /mob/living/simple_animal/hostile/poison/bees,
+ /mob/living/simple_animal/hostile/carp,
+ /mob/living/simple_animal/hostile/alien,
+ /mob/living/simple_animal/butterfly,
+ /mob/living/simple_animal/pet/dog/corgi
+ )
+ var/mob/to_spawn = pick(possible_mobs)
+
+ for(var/i in 1 to amount)
+ var/mob/living/simple_animal/S
+ S = new to_spawn(get_turf(src))
+ S.faction |= "petSpraySummon"
+ S.gold_core_spawnable = HOSTILE_SPAWN
+ S.low_priority_targets += user.UID()
+ if(prob(50))
+ for(var/j = 1, j <= rand(1, 3), j++)
+ step(S, pick(NORTH, SOUTH, EAST, WEST))
+
+ if(prob(60))
+ to_chat(user, "[src] falls apart!")
+ qdel(src)
+
+/obj/item/relict_production/rapid_dupe
+ name = "rapid dupe"
+ desc = "Странный объект создающий другие странные объекты при контакте с аномалиями."
+ icon_state = "shock_kit"
+ icon = 'icons/obj/assemblies.dmi'
+ origin_tech = "materials=5"
//////////////////////////////////SPECIAL ITEMS////////////////////////////////////////
@@ -659,127 +875,8 @@
var/realName = "defined object"
var/revealed = FALSE
var/realProc
- var/cooldownMax = 60
- var/cooldown
- var/floof
/obj/item/relic/New()
..()
icon_state = pick("shock_kit","armor-igniter-analyzer","infra-igniter0","infra-igniter1","radio-multitool","prox-radio1","radio-radio","timer-multitool0","radio-igniter-tank")
realName = "[pick("broken","twisted","spun","improved","silly","regular","badly made")] [pick("device","object","toy","suspicious tech","gear")]"
- floof = pick(/mob/living/simple_animal/pet/dog/corgi, /mob/living/simple_animal/pet/cat, /mob/living/simple_animal/pet/dog/fox, /mob/living/simple_animal/mouse, /mob/living/simple_animal/pet/dog/pug, /mob/living/simple_animal/lizard, /mob/living/simple_animal/diona, /mob/living/simple_animal/butterfly, /mob/living/carbon/human/lesser/monkey)
-
-
-/obj/item/relic/proc/reveal()
- if(revealed) //Re-rolling your relics seems a bit overpowered, yes?
- return
- revealed = TRUE
- name = realName
- cooldownMax = rand(60,300)
- realProc = pick("teleport","explode","rapidDupe","petSpray","flash","clean","floofcannon")
- origin_tech = pick("engineering=[rand(2,5)]","magnets=[rand(2,5)]","plasmatech=[rand(2,5)]","programming=[rand(2,5)]","powerstorage=[rand(2,5)]")
-
-/obj/item/relic/attack_self(mob/user)
- if(revealed)
- if(cooldown)
- to_chat(user, "[src] does not react!")
- return
- else if(src.loc == user)
- cooldown = TRUE
- call(src,realProc)(user)
- spawn(cooldownMax)
- cooldown = FALSE
- else
- to_chat(user, "You aren't quite sure what to do with this, yet.")
-
-//////////////// RELIC PROCS /////////////////////////////
-
-/obj/item/relic/proc/throwSmoke(turf/where)
- var/datum/effect_system/smoke_spread/smoke = new
- smoke.set_up(1,0, where, 0)
- smoke.start()
-
-/obj/item/relic/proc/floofcannon(mob/user)
- playsound(src.loc, "sparks", rand(25, 50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
- var/mob/living/C = new floof(get_turf(user))
- C.throw_at(pick(oview(10,user)),10,rand(3,8))
- throwSmoke(get_turf(C))
- warn_admins(user, "Floof Cannon", 0)
-
-/obj/item/relic/proc/clean(mob/user)
- playsound(src.loc, "sparks", rand(25, 50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
- var/obj/item/grenade/chem_grenade/cleaner/CL = new/obj/item/grenade/chem_grenade/cleaner(get_turf(user))
- CL.prime()
- warn_admins(user, "Smoke", 0)
-
-/obj/item/relic/proc/flash(mob/user)
- playsound(src.loc, "sparks", rand(25, 50), TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
- var/obj/item/grenade/flashbang/CB = new/obj/item/grenade/flashbang(get_turf(user))
- CB.prime()
- warn_admins(user, "Flash")
-
-/obj/item/relic/proc/petSpray(mob/user)
- var/message = "[src] begins to shake, and in the distance the sound of rampaging animals arises!"
- visible_message(message)
- to_chat(user, message)
- var/animals = rand(1,25)
- var/counter
- var/list/valid_animals = list(/mob/living/simple_animal/parrot,/mob/living/simple_animal/butterfly,/mob/living/simple_animal/pet/cat,/mob/living/simple_animal/pet/dog/corgi,/mob/living/simple_animal/crab,/mob/living/simple_animal/pet/dog/fox,/mob/living/simple_animal/lizard,/mob/living/simple_animal/mouse,/mob/living/simple_animal/pet/dog/pug,/mob/living/simple_animal/hostile/bear,/mob/living/simple_animal/hostile/poison/bees,/mob/living/simple_animal/hostile/carp)
- for(counter = 1; counter < animals; counter++)
- var/mobType = pick(valid_animals)
- new mobType(get_turf(src))
- warn_admins(user, "Mass Mob Spawn")
- if(prob(60))
- to_chat(user, "[src] falls apart!")
- qdel(src)
-
-/obj/item/relic/proc/rapidDupe(mob/user)
- audible_message("[src] emits a loud pop!")
- var/list/dupes = list()
- var/counter
- var/max = rand(5,10)
- for(counter = 1; counter < max; counter++)
- var/obj/item/relic/R = new src.type(get_turf(src))
- R.name = name
- R.desc = desc
- R.realName = realName
- R.realProc = realProc
- R.revealed = TRUE
- dupes |= R
- spawn()
- R.throw_at(pick(oview(7,get_turf(src))),10,1)
- counter = 0
- spawn(rand(10,100))
- for(counter = 1; counter <= dupes.len; counter++)
- var/obj/item/relic/R = dupes[counter]
- qdel(R)
- warn_admins(user, "Rapid duplicator", 0)
-
-/obj/item/relic/proc/explode(mob/user)
- to_chat(user, "[src] begins to heat up!")
- spawn(rand(35,100))
- if(src.loc == user)
- visible_message("The [src]'s top opens, releasing a powerful blast!")
- explosion(user.loc, -1, rand(1,5), rand(1,5), rand(1,5), rand(1,5), flame_range = 2, cause = src)
- warn_admins(user, "Explosion")
- qdel(src) //Comment this line to produce a light grenade (the bomb that keeps on exploding when used)!!
-
-/obj/item/relic/proc/teleport(mob/user)
- to_chat(user, "The [src] begins to vibrate!")
- spawn(rand(10,30))
- var/turf/userturf = get_turf(user)
- if(src.loc == user && is_teleport_allowed(userturf.z)) //Because Nuke Ops bringing this back on their shuttle, then looting the ERT area is 2fun4you!
- visible_message("The [src] twists and bends, relocating itself!")
- throwSmoke(userturf)
- do_teleport(user, userturf, 8, asoundin = 'sound/effects/phasein.ogg')
- throwSmoke(get_turf(user))
- warn_admins(user, "Teleport", 0)
-
-//Admin Warning proc for relics
-/obj/item/relic/proc/warn_admins(mob/user, RelicType, priority = 1)
- var/turf/T = get_turf(src)
- var/log_msg = "[RelicType] relic used by [key_name_log(user)] in [COORD(T)]"
- if(priority) //For truly dangerous relics that may need an admin's attention. BWOINK!
- message_admins("[RelicType] relic activated by [key_name_admin(user)] in [ADMIN_COORDJMP(T)]")
- add_game_logs(log_msg)
- investigate_log(log_msg, INVESTIGATE_EXPERIMENTOR)
diff --git a/icons/mob/inhands/relics_production/inhandl.dmi b/icons/mob/inhands/relics_production/inhandl.dmi
new file mode 100644
index 0000000000000000000000000000000000000000..9a95b0f2c2ed8b638ea4cc05ae936e4b1b0862c3
GIT binary patch
literal 740
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