diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm
index 4c21191bc6f..176fd79b61b 100644
--- a/code/game/objects/effects/spawners/lootdrop.dm
+++ b/code/game/objects/effects/spawners/lootdrop.dm
@@ -115,5 +115,6 @@
/obj/item/weapon/weldingtool = 3,
/obj/item/weapon/wirecutters = 1,
/obj/item/weapon/wrench = 4,
+ /obj/item/weapon/relic = 3,
"" = 11
)
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 12573d44897..53b70b20478 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -6,12 +6,13 @@
#define SCANTYPE_HEAT 4
#define SCANTYPE_COLD 5
#define SCANTYPE_OBLITERATE 6
+#define SCANTYPE_DISCOVER 7
-#define EFFECT_PROB_VERYLOW 10
-#define EFFECT_PROB_LOW 20
-#define EFFECT_PROB_MEDIUM 45
-#define EFFECT_PROB_HIGH 65
-#define EFFECT_PROB_VERYHIGH 85
+#define EFFECT_PROB_VERYLOW 20
+#define EFFECT_PROB_LOW 35
+#define EFFECT_PROB_MEDIUM 50
+#define EFFECT_PROB_HIGH 75
+#define EFFECT_PROB_VERYHIGH 95
#define FAIL 7
/obj/machinery/r_n_d/experimentor
@@ -63,7 +64,10 @@
/obj/machinery/r_n_d/experimentor/proc/SetTypeReactions()
var/probWeight = 0
for(var/I in typesof(/obj/item))
- item_reactions["[I]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE)
+ if(istype(I,/obj/item/weapon/relic))
+ item_reactions["[I]"] = SCANTYPE_DISCOVER
+ else
+ item_reactions["[I]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE)
if(ispath(I,/obj/item/weapon/stock_parts) || ispath(I,/obj/item/weapon/grenade/chem_grenade) || ispath(I,/obj/item/weapon/kitchen))
var/obj/item/tempCheck = new I()
if(tempCheck.icon_state != null) //check it's an actual usable item, in a hacky way
@@ -186,6 +190,8 @@
dat += "
Burn"
dat += "
Freeze"
dat += "
Destroy
"
+ if(istype(loaded_item,/obj/item/weapon/relic))
+ dat += "
Discover
"
dat += "
Eject"
else
dat += "Nothing loaded."
@@ -215,11 +221,11 @@
if(loaded_item)
if(cloneMode && cloneCount > 0)
visible_message("A duplicate [loaded_item] pops out!")
- new loaded_item(pick(oview(1,src)))
+ new loaded_item(get_turf(pick(oview(1,src))))
--cloneCount
if(cloneCount == 0)
cloneMode = FALSE
- loaded_item.loc = pick(oview(1,src))
+ loaded_item.loc = get_turf(pick(oview(1,src)))
if(delete)
qdel(loaded_item)
loaded_item = null
@@ -242,13 +248,6 @@
else
counter = 1
-/*
-#define EFFECT_PROB_VERYLOW 10
-#define EFFECT_PROB_LOW 20
-#define EFFECT_PROB_MEDIUM 45
-#define EFFECT_PROB_HIGH 65
-#define EFFECT_PROB_VERYHIGH 85
-*/
/obj/machinery/r_n_d/experimentor/proc/experiment(var/exp,var/obj/item/exp_on)
recentlyExperimented = 1
icon_state = "h_lathe_wloop"
@@ -264,10 +263,10 @@
for(var/mob/living/m in oview(1))
m.apply_damage(15,"brute",pick("head","chest","groin"))
ejectItem(TRUE)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
+ if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src] malfunctions!.")
exp = SCANTYPE_OBLITERATE
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
+ if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
visible_message("[src] malfunctions, throwing the [exp_on]!.")
var/mob/living/target = locate(/mob/living) in oview(7,src)
if(target)
@@ -287,13 +286,13 @@
for(var/mob/living/m in oview(1))
m.apply_effect(25,IRRADIATE)
ejectItem(TRUE)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
+ if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src] malfunctions, spewing toxic waste!.")
for(var/turf/T in oview(1))
if(!T.density)
if(prob(EFFECT_PROB_VERYHIGH))
new /obj/effect/decal/cleanable/greenglow(T)
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
+ if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
var/savedName = "[exp_on]"
ejectItem(TRUE)
var/newPath = pickWeighted(valid_items)
@@ -308,7 +307,7 @@
visible_message("[src] fills it's chamber with gas, [exp_on] included.")
if(prob(EFFECT_PROB_LOW) && criticalReaction)
visible_message("[exp_on] achieves the perfect mix!")
- new /obj/item/stack/sheet/mineral/plasma(pick(oview(1,src)))
+ 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!.")
var/list/chems = list("carbon","radium","toxin","condensedcapsaicin","mushroomhallucinogen","space_drugs","ethanol","beepskysmash")
@@ -321,10 +320,22 @@
smoke.start()
R.delete()
ejectItem(TRUE)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
+ if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
+ visible_message("[src]'s chemical chamber has sprung a leak!.")
+ var/list/chems = list("mutationtoxin","amutationtoxin","nanites","xenomicrobes")
+ var/datum/reagents/R = new/datum/reagents(50)
+ R.my_atom = src
+ R.add_reagent(pick(chems), 50)
+ var/datum/effect/effect/system/chem_smoke_spread/smoke = new
+ smoke.set_up(R, 1, 0, src, 0, silent = 1)
+ playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
+ smoke.start()
+ R.delete()
+ ejectItem(TRUE)
+ if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src] malfunctions, spewing harmless gas!.")
throwSmoke(src.loc)
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
+ if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
visible_message("[src] melts [exp_on], ionizing the air around it!.")
empulse(src.loc, 8, 10)
ejectItem(TRUE)
@@ -333,17 +344,20 @@
visible_message("[src] raises [exp_on]'s temperature.")
if(prob(EFFECT_PROB_LOW) && criticalReaction)
visible_message("[src]'s emergency coolant system gives off a small beep!")
- var/obj/item/weapon/reagent_containers/food/drinks/coffee/C = new /obj/item/weapon/reagent_containers/food/drinks/coffee(pick(oview(1,src)))
+ var/obj/item/weapon/reagent_containers/food/drinks/coffee/C = new /obj/item/weapon/reagent_containers/food/drinks/coffee(get_turf(pick(oview(1,src))))
var/list/chems = list("plasma","capsaicin","ethanol")
C.reagents.remove_any(25)
C.reagents.add_reagent(pick(chems),25)
C.name = "Cup of Suspicious Liquid"
C.desc = "It has a large hazard symbol printed on the side in fading ink."
if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
+ visible_message("[src] activates it's heat-seeking system!")
+ new/datum/round_event/meteor_wave()
+ if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src] malfunctions, melting [exp_on] and releasing a burst of flame!.")
explosion(src.loc, -1, 0, 0, 0, 0, flame_range = 2)
ejectItem(TRUE)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
+ if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
visible_message("[src] malfunctions, melting [exp_on] and leaking hot air!.")
var/datum/gas_mixture/env = src.loc.return_air()
var/transfer_moles = 0.25 * env.total_moles()
@@ -356,7 +370,7 @@
env.merge(removed)
air_update_turf()
ejectItem(TRUE)
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
+ if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
visible_message("[src] malfunctions, activating it's emergency coolant systems!.")
throwSmoke(src.loc)
for(var/mob/living/m in oview(1))
@@ -367,7 +381,7 @@
visible_message("[src] lowers [exp_on]'s temperature.")
if(prob(EFFECT_PROB_LOW) && criticalReaction)
visible_message("[src]'s emergency coolant system gives off a small ping!")
- var/obj/machinery/vending/coffee/C = new /obj/machinery/vending/coffee(pick(oview(1,src)))
+ var/obj/machinery/vending/coffee/C = new /obj/machinery/vending/coffee(get_turf(pick(oview(1,src))))
var/list/chems = list("uranium","frostoil","hyperzine")
C.reagents.remove_any(25)
C.reagents.add_reagent(pick(chems),25)
@@ -384,7 +398,7 @@
smoke.start()
R.delete()
ejectItem(TRUE)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
+ if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src] malfunctions, shattering [exp_on] and leaking cold air!.")
var/datum/gas_mixture/env = src.loc.return_air()
var/transfer_moles = 0.25 * env.total_moles()
@@ -397,7 +411,7 @@
env.merge(removed)
air_update_turf()
ejectItem(TRUE)
- else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
+ if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
visible_message("[src] malfunctions, releasing a flurry of chilly air as [exp_on] pops out!.")
var/datum/effect/effect/system/harmless_smoke_spread/smoke = new
smoke.set_up(1,0, src.loc, 0)
@@ -408,7 +422,7 @@
visible_message("[exp_on] activates the crushing mechanism, [exp_on] is destroyed!")
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(pick(oview(1,src)))
+ new /obj/item/stack/sheet/plasteel(get_turf(pick(oview(1,src))))
if(linked_console.linked_lathe)
linked_console.linked_lathe.m_amount += min((linked_console.linked_lathe.max_material_storage - linked_console.linked_lathe.TotalMaterials()), (exp_on.m_amt))
linked_console.linked_lathe.g_amount += min((linked_console.linked_lathe.max_material_storage - linked_console.linked_lathe.TotalMaterials()), (exp_on.g_amt))
@@ -423,7 +437,7 @@
for(counter = 1, counter < throwAt.len, ++counter)
var/cast = throwAt[counter]
cast:throw_at(src,10,1)
- else if(prob(EFFECT_PROB_LOW-badThingCoeff))
+ if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src]'s crusher goes one level too high, crushing right into space-time!.")
playsound(src.loc, 'sound/effects/supermatter.ogg', 50, 1, -3)
var/list/oViewStuff = oview(7,src)
@@ -442,6 +456,12 @@
var/b = pick("crushes","spins","viscerates","smashes","insults")
visible_message("[exp_on] [a], and [b], the experiment was a failiure!")
+ if(exp == SCANTYPE_DISCOVER)
+ visible_message("[src] scans the [exp_on], revealing it's true nature!.")
+ playsound(src.loc, 'sound/effects/supermatter.ogg', 50, 3, -1)
+ var/obj/item/weapon/relic/R = loaded_item
+ R.reveal()
+ ejectItem()
//Global reactions
if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
@@ -466,7 +486,7 @@
m.apply_damage(50,"brute","chest")
var/list/reqs = ConvertReqString2List(exp_on.origin_tech)
for(var/T in reqs)
- T = T + 1
+ reqs[T] = reqs[T] + 1
exp_on.origin_tech = ConvertReqList2String(reqs)
if(globalMalf > 51 && globalMalf < 75)
visible_message("[src] encounters a run-time error!")
@@ -535,3 +555,109 @@
#undef EFFECT_PROB_VERYHIGH
#undef FAIL
+
+
+//////////////////////////////////SPECIAL ITEMS////////////////////////////////////////
+
+/obj/item/weapon/relic
+ name = "strange object"
+ desc = "What mysteries could this hold?"
+ icon = 'icons/obj/assemblies.dmi'
+ origin_tech = "combat=1;plasmatech=1;powerstorage=1;materials=1"
+ var/realName = "defined object"
+ var/revealed = FALSE
+ var/realProc
+ var/cooldownMax = 60
+ var/cooldown
+
+/obj/item/weapon/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","illegal tech","weapon")]"
+
+
+/obj/item/weapon/relic/proc/reveal()
+ revealed = TRUE
+ name = realName
+ cooldownMax = rand(60,300)
+ realProc = pick("teleport","explode","rapidDupe","petSpray","flash","clean","corgicannon")
+
+/obj/item/weapon/relic/attack_self(mob/user as mob)
+ if(revealed)
+ if(cooldown)
+ user << "[src] does not react."
+ return
+ else if(src.loc == user)
+ call(src,realProc)(user)
+ cooldown = TRUE
+ spawn(cooldownMax)
+ cooldown = FALSE
+ else
+ user << "You aren't quite sure what to do with this, yet."
+
+//////////////// RELIC PROCS /////////////////////////////
+
+/obj/item/weapon/relic/proc/throwSmoke(var/turf/where)
+ var/datum/effect/effect/system/harmless_smoke_spread/smoke = new
+ smoke.set_up(1,0, where, 0)
+ smoke.start()
+
+/obj/item/weapon/relic/proc/corgicannon(var/mob/user)
+ playsound(src.loc, "sparks", rand(25,50), 1)
+ var/mob/living/simple_animal/corgi/C = new/mob/living/simple_animal/corgi(get_turf(user))
+ C.throw_at(pick(oview(10,user)),10,rand(3,8))
+ throwSmoke(get_turf(C))
+
+/obj/item/weapon/relic/proc/clean(var/mob/user)
+ playsound(src.loc, "sparks", rand(25,50), 1)
+ var/obj/item/weapon/grenade/chem_grenade/cleaner/CL = new/obj/item/weapon/grenade/chem_grenade/cleaner(get_turf(user))
+ CL.prime()
+
+/obj/item/weapon/relic/proc/flash(var/mob/user)
+ playsound(src.loc, "sparks", rand(25,50), 1)
+ var/obj/item/weapon/grenade/flashbang/CB = new/obj/item/weapon/grenade/flashbang(get_turf(user))
+ CB.prime()
+
+/obj/item/weapon/relic/proc/petSpray(var/mob/user)
+ visible_message("[src] begans to shake, and in the distance the sound of rampaging animals arises!")
+ 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/cat,/mob/living/simple_animal/corgi,/mob/living/simple_animal/crab,/mob/living/simple_animal/fox,/mob/living/simple_animal/lizard,/mob/living/simple_animal/mouse,/mob/living/simple_animal/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))
+
+/obj/item/weapon/relic/proc/rapidDupe(var/mob/user)
+ visible_message("[src] emits a loud pop!")
+ var/list/dupes = list()
+ var/counter
+ var/max = rand(5,45)
+ for(counter = 1; counter < max; counter++)
+ var/obj/item/weapon/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
+ R.throw_at(pick(oview(7,src)),10,1)
+ counter = 0
+ spawn(rand(10,100))
+ for(counter = 1; counter < dupes.len; counter++)
+ var/obj/item/weapon/relic/R = dupes[counter]
+ qdel(R)
+
+/obj/item/weapon/relic/proc/explode(var/mob/user)
+ visible_message("[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)
+
+/obj/item/weapon/relic/proc/teleport(var/mob/user)
+ visible_message("The [src] begins to vibrate!")
+ spawn(rand(10,30))
+ if(src.loc == user)
+ visible_message("The [src] twists and bends, relocating itself!")
+ throwSmoke(get_turf(user))
+ do_teleport(user, get_turf(user), 8, asoundin = 'sound/effects/phasein.ogg')
+ throwSmoke(get_turf(user))
\ No newline at end of file