mirror of
https://github.com/fulpstation/fulpstation.git
synced 2025-12-10 18:11:47 +00:00
* Pipe init runtime * Modular computer explosion runtime. * Waterbottle thrown by explosion runtime. * Spark runtime. Should systems continue after deletion ? * restore ghost appearance runtime * parallax update timer runtime. * borg unbuckling runtime * surgery cancel runtime. FALSE is not a null. * relic self deletion runtime. * dog collar runtime * Another part of that buckled_mobs robot runtime. * Let's go over all of these * free () Co-Authored-By: MrPerson <spamtaffic@gmail.com> Co-authored-by: MrPerson <spamtaffic@gmail.com>
701 lines
32 KiB
Plaintext
701 lines
32 KiB
Plaintext
//this is designed to replace the destructive analyzer
|
|
|
|
//NEEDS MAJOR CODE CLEANUP
|
|
|
|
#define SCANTYPE_POKE 1
|
|
#define SCANTYPE_IRRADIATE 2
|
|
#define SCANTYPE_GAS 3
|
|
#define SCANTYPE_HEAT 4
|
|
#define SCANTYPE_COLD 5
|
|
#define SCANTYPE_OBLITERATE 6
|
|
#define SCANTYPE_DISCOVER 7
|
|
|
|
#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 8
|
|
/obj/machinery/rnd/experimentor
|
|
name = "\improper E.X.P.E.R.I-MENTOR"
|
|
desc = "A \"replacement\" for the destructive analyzer with a slight tendency to catastrophically fail."
|
|
icon = 'icons/obj/machines/heavy_lathe.dmi'
|
|
icon_state = "h_lathe"
|
|
density = TRUE
|
|
use_power = IDLE_POWER_USE
|
|
circuit = /obj/item/circuitboard/machine/experimentor
|
|
var/recentlyExperimented = 0
|
|
var/mob/trackedIan
|
|
var/mob/trackedRuntime
|
|
var/badThingCoeff = 0
|
|
var/resetTime = 15
|
|
var/cloneMode = FALSE
|
|
var/list/item_reactions = list()
|
|
var/list/valid_items = list() //valid items for special reactions like transforming
|
|
var/list/critical_items_typecache //items that can cause critical reactions
|
|
var/banned_typecache // items that won't be produced
|
|
|
|
/obj/machinery/rnd/experimentor/proc/ConvertReqString2List(list/source_list)
|
|
var/list/temp_list = params2list(source_list)
|
|
for(var/O in temp_list)
|
|
temp_list[O] = text2num(temp_list[O])
|
|
return temp_list
|
|
|
|
|
|
/obj/machinery/rnd/experimentor/proc/SetTypeReactions()
|
|
// Don't need to keep this typecache around, only used in this proc once.
|
|
var/list/banned_typecache = typecacheof(list(
|
|
/obj/item/stock_parts/cell/infinite,
|
|
/obj/item/grenade/chem_grenade/tuberculosis
|
|
))
|
|
|
|
for(var/I in typesof(/obj/item))
|
|
if(ispath(I, /obj/item/relic))
|
|
item_reactions["[I]"] = SCANTYPE_DISCOVER
|
|
else
|
|
item_reactions["[I]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE)
|
|
|
|
if(is_type_in_typecache(I, banned_typecache))
|
|
continue
|
|
|
|
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
|
|
valid_items["[I]"] += 15
|
|
|
|
if(ispath(I, /obj/item/reagent_containers/food))
|
|
var/obj/item/tempCheck = I
|
|
if(initial(tempCheck.icon_state) != null) //check it's an actual usable item, in a hacky way
|
|
valid_items["[I]"] += rand(1,4)
|
|
|
|
/obj/machinery/rnd/experimentor/Initialize()
|
|
. = ..()
|
|
|
|
trackedIan = locate(/mob/living/simple_animal/pet/dog/corgi/Ian) in GLOB.mob_living_list
|
|
trackedRuntime = locate(/mob/living/simple_animal/pet/cat/Runtime) in GLOB.mob_living_list
|
|
SetTypeReactions()
|
|
|
|
critical_items_typecache = typecacheof(list(
|
|
/obj/item/construction/rcd,
|
|
/obj/item/grenade,
|
|
/obj/item/aicard,
|
|
/obj/item/storage/backpack/holding,
|
|
/obj/item/slime_extract,
|
|
/obj/item/onetankbomb,
|
|
/obj/item/transfer_valve))
|
|
|
|
/obj/machinery/rnd/experimentor/RefreshParts()
|
|
for(var/obj/item/stock_parts/manipulator/M in component_parts)
|
|
if(resetTime > 0 && (resetTime - M.rating) >= 1)
|
|
resetTime -= M.rating
|
|
for(var/obj/item/stock_parts/scanning_module/M in component_parts)
|
|
badThingCoeff += M.rating*2
|
|
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
|
|
badThingCoeff += M.rating
|
|
|
|
/obj/machinery/rnd/experimentor/examine(mob/user)
|
|
. = ..()
|
|
if(in_range(user, src) || isobserver(user))
|
|
. += "<span class='notice'>The status display reads: Malfunction probability reduced by <b>[badThingCoeff]%</b>.<br>Cooldown interval between experiments at <b>[resetTime*0.1]</b> seconds.</span>"
|
|
|
|
/obj/machinery/rnd/experimentor/proc/checkCircumstances(obj/item/O)
|
|
//snowflake check to only take "made" bombs
|
|
if(istype(O, /obj/item/transfer_valve))
|
|
var/obj/item/transfer_valve/T = O
|
|
if(!T.tank_one || !T.tank_two || !T.attached_device)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/obj/machinery/rnd/experimentor/Insert_Item(obj/item/O, mob/user)
|
|
if(user.a_intent != INTENT_HARM)
|
|
. = 1
|
|
if(!is_insertion_ready(user))
|
|
return
|
|
if(!user.transferItemToLoc(O, src))
|
|
return
|
|
loaded_item = O
|
|
to_chat(user, "<span class='notice'>You add [O] to the machine.</span>")
|
|
flick("h_lathe_load", src)
|
|
|
|
/obj/machinery/rnd/experimentor/default_deconstruction_crowbar(obj/item/O)
|
|
ejectItem()
|
|
. = ..(O)
|
|
|
|
/obj/machinery/rnd/experimentor/ui_interact(mob/user)
|
|
var/list/dat = list("<center>")
|
|
if(!linked_console)
|
|
dat += "<b><a href='byond://?src=[REF(src)];function=search'>Scan for R&D Console</A></b>"
|
|
if(loaded_item)
|
|
dat += "<b>Loaded Item:</b> [loaded_item]"
|
|
|
|
dat += "<div>Available tests:"
|
|
dat += "<b><a href='byond://?src=[REF(src)];item=[REF(loaded_item)];function=[SCANTYPE_POKE]'>Poke</A></b>"
|
|
dat += "<b><a href='byond://?src=[REF(src)];item=[REF(loaded_item)];function=[SCANTYPE_IRRADIATE];'>Irradiate</A></b>"
|
|
dat += "<b><a href='byond://?src=[REF(src)];item=[REF(loaded_item)];function=[SCANTYPE_GAS]'>Gas</A></b>"
|
|
dat += "<b><a href='byond://?src=[REF(src)];item=[REF(loaded_item)];function=[SCANTYPE_HEAT]'>Burn</A></b>"
|
|
dat += "<b><a href='byond://?src=[REF(src)];item=[REF(loaded_item)];function=[SCANTYPE_COLD]'>Freeze</A></b>"
|
|
dat += "<b><a href='byond://?src=[REF(src)];item=[REF(loaded_item)];function=[SCANTYPE_OBLITERATE]'>Destroy</A></b></div>"
|
|
if(istype(loaded_item,/obj/item/relic))
|
|
dat += "<b><a href='byond://?src=[REF(src)];item=[REF(loaded_item)];function=[SCANTYPE_DISCOVER]'>Discover</A></b>"
|
|
dat += "<b><a href='byond://?src=[REF(src)];function=eject'>Eject</A>"
|
|
var/list/listin = techweb_item_boost_check(src)
|
|
if(listin)
|
|
var/list/output = list("<b><font color='purple'>Research Boost Data:</font></b>")
|
|
var/list/res = list("<b><font color='blue'>Already researched:</font></b>")
|
|
var/list/boosted = list("<b><font color='red'>Already boosted:</font></b>")
|
|
for(var/node_id in listin)
|
|
var/datum/techweb_node/N = SSresearch.techweb_node_by_id(node_id)
|
|
var/str = "<b>[N.display_name]</b>: [listin[N]] points.</b>"
|
|
if(SSresearch.science_tech.researched_nodes[N.id])
|
|
res += str
|
|
else if(SSresearch.science_tech.boosted_nodes[N.id])
|
|
boosted += str
|
|
if(SSresearch.science_tech.visible_nodes[N.id]) //JOY OF DISCOVERY!
|
|
output += str
|
|
output += boosted + res
|
|
dat += output
|
|
else
|
|
dat += "<b>Nothing loaded.</b>"
|
|
dat += "<a href='byond://?src=[REF(src)];function=refresh'>Refresh</A>"
|
|
dat += "<a href='byond://?src=[REF(src)];close=1'>Close</A></center>"
|
|
var/datum/browser/popup = new(user, "experimentor","Experimentor", 700, 400, src)
|
|
popup.set_content(dat.Join("<br>"))
|
|
popup.open()
|
|
onclose(user, "experimentor")
|
|
|
|
/obj/machinery/rnd/experimentor/Topic(href, href_list)
|
|
if(..())
|
|
return
|
|
usr.set_machine(src)
|
|
|
|
var/scantype = href_list["function"]
|
|
var/obj/item/process = locate(href_list["item"]) in src
|
|
|
|
if(href_list["close"])
|
|
usr << browse(null, "window=experimentor")
|
|
return
|
|
if(scantype == "search")
|
|
var/obj/machinery/computer/rdconsole/D = locate(/obj/machinery/computer/rdconsole) in oview(3,src)
|
|
if(D)
|
|
linked_console = D
|
|
else if(scantype == "eject")
|
|
ejectItem()
|
|
else if(scantype == "refresh")
|
|
updateUsrDialog()
|
|
else
|
|
if(recentlyExperimented)
|
|
to_chat(usr, "<span class='warning'>[src] has been used too recently!</span>")
|
|
else if(!loaded_item)
|
|
to_chat(usr, "<span class='warning'>[src] is not currently loaded!</span>")
|
|
else if(!process || process != loaded_item) //Interface exploit protection (such as hrefs or swapping items with interface set to old item)
|
|
to_chat(usr, "<span class='danger'>Interface failure detected in [src]. Please try again.</span>")
|
|
else
|
|
var/dotype
|
|
if(text2num(scantype) == SCANTYPE_DISCOVER)
|
|
dotype = SCANTYPE_DISCOVER
|
|
else
|
|
dotype = matchReaction(process,scantype)
|
|
experiment(dotype,process)
|
|
use_power(750)
|
|
if(dotype != FAIL)
|
|
var/list/nodes = techweb_item_boost_check(process)
|
|
var/picked = pickweight(nodes) //This should work.
|
|
if(linked_console)
|
|
linked_console.stored_research.boost_with_path(SSresearch.techweb_node_by_id(picked), process.type)
|
|
updateUsrDialog()
|
|
|
|
/obj/machinery/rnd/experimentor/proc/matchReaction(matching,reaction)
|
|
var/obj/item/D = matching
|
|
if(D)
|
|
if(item_reactions.Find("[D.type]"))
|
|
var/tor = item_reactions["[D.type]"]
|
|
if(tor == text2num(reaction))
|
|
return tor
|
|
else
|
|
return FAIL
|
|
else
|
|
return FAIL
|
|
else
|
|
return FAIL
|
|
|
|
/obj/machinery/rnd/experimentor/proc/ejectItem(delete=FALSE)
|
|
if(loaded_item)
|
|
if(cloneMode)
|
|
visible_message("<span class='notice'>A duplicate [loaded_item] pops out!</span>")
|
|
var/type_to_make = loaded_item.type
|
|
new type_to_make(get_turf(pick(oview(1,src))))
|
|
cloneMode = FALSE
|
|
return
|
|
var/turf/dropturf = get_turf(pick(view(1,src)))
|
|
if(!dropturf) //Failsafe to prevent the object being lost in the void forever.
|
|
dropturf = drop_location()
|
|
loaded_item.forceMove(dropturf)
|
|
if(delete)
|
|
qdel(loaded_item)
|
|
loaded_item = null
|
|
|
|
/obj/machinery/rnd/experimentor/proc/throwSmoke(turf/where)
|
|
var/datum/effect_system/smoke_spread/smoke = new
|
|
smoke.set_up(0, where)
|
|
smoke.start()
|
|
|
|
|
|
/obj/machinery/rnd/experimentor/proc/experiment(exp,obj/item/exp_on)
|
|
recentlyExperimented = 1
|
|
icon_state = "h_lathe_wloop"
|
|
var/chosenchem
|
|
var/criticalReaction = is_type_in_typecache(exp_on, critical_items_typecache)
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
if(exp == SCANTYPE_POKE)
|
|
visible_message("<span class='notice'>[src] prods at [exp_on] with mechanical arms.</span>")
|
|
if(prob(EFFECT_PROB_LOW) && criticalReaction)
|
|
visible_message("<span class='notice'>[exp_on] is gripped in just the right way, enhancing its focus.</span>")
|
|
badThingCoeff++
|
|
else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
|
|
visible_message("<span class='danger'>[src] malfunctions and destroys [exp_on], lashing its arms out at nearby people!</span>")
|
|
for(var/mob/living/m in oview(1, src))
|
|
m.apply_damage(15, BRUTE, pick(BODY_ZONE_HEAD,BODY_ZONE_CHEST,BODY_ZONE_PRECISE_GROIN))
|
|
investigate_log("Experimentor dealt minor brute to [m].", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem(TRUE)
|
|
else if(prob(EFFECT_PROB_LOW-badThingCoeff))
|
|
visible_message("<span class='warning'>[src] malfunctions!</span>")
|
|
exp = SCANTYPE_OBLITERATE
|
|
else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
|
|
visible_message("<span class='danger'>[src] malfunctions, throwing the [exp_on]!</span>")
|
|
var/mob/living/target = locate(/mob/living) in oview(7,src)
|
|
if(target)
|
|
var/obj/item/throwing = loaded_item
|
|
investigate_log("Experimentor has thrown [loaded_item] at [key_name(target)]", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem()
|
|
if(throwing)
|
|
throwing.throw_at(target, 10, 1)
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
if(exp == SCANTYPE_IRRADIATE)
|
|
visible_message("<span class='danger'>[src] reflects radioactive rays at [exp_on]!</span>")
|
|
if(prob(EFFECT_PROB_LOW) && criticalReaction)
|
|
visible_message("<span class='notice'>[exp_on] has activated an unknown subroutine!</span>")
|
|
cloneMode = TRUE
|
|
investigate_log("Experimentor has made a clone of [exp_on]", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem()
|
|
else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
|
|
visible_message("<span class='danger'>[src] malfunctions, melting [exp_on] and leaking radiation!</span>")
|
|
radiation_pulse(src, 500)
|
|
ejectItem(TRUE)
|
|
else if(prob(EFFECT_PROB_LOW-badThingCoeff))
|
|
visible_message("<span class='warning'>[src] malfunctions, spewing toxic waste!</span>")
|
|
for(var/turf/T in oview(1, src))
|
|
if(!T.density)
|
|
if(prob(EFFECT_PROB_VERYHIGH) && !(locate(/obj/effect/decal/cleanable/greenglow) in T))
|
|
var/obj/effect/decal/cleanable/reagentdecal = new/obj/effect/decal/cleanable/greenglow(T)
|
|
reagentdecal.reagents.add_reagent(/datum/reagent/uranium/radium, 7)
|
|
else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
|
|
var/savedName = "[exp_on]"
|
|
ejectItem(TRUE)
|
|
var/newPath = text2path(pickweight(valid_items))
|
|
loaded_item = new newPath(src)
|
|
visible_message("<span class='warning'>[src] malfunctions, transforming [savedName] into [loaded_item]!</span>")
|
|
investigate_log("Experimentor has transformed [savedName] into [loaded_item]", INVESTIGATE_EXPERIMENTOR)
|
|
if(istype(loaded_item, /obj/item/grenade/chem_grenade))
|
|
var/obj/item/grenade/chem_grenade/CG = loaded_item
|
|
CG.prime()
|
|
ejectItem()
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
if(exp == SCANTYPE_GAS)
|
|
visible_message("<span class='warning'>[src] fills its chamber with gas, [exp_on] included.</span>")
|
|
if(prob(EFFECT_PROB_LOW) && criticalReaction)
|
|
visible_message("<span class='notice'>[exp_on] achieves the perfect mix!</span>")
|
|
new /obj/item/stack/sheet/mineral/plasma(get_turf(pick(oview(1,src))))
|
|
else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
|
|
visible_message("<span class='danger'>[src] destroys [exp_on], leaking dangerous gas!</span>")
|
|
chosenchem = pick(/datum/reagent/carbon,/datum/reagent/uranium/radium,/datum/reagent/toxin,/datum/reagent/consumable/condensedcapsaicin,/datum/reagent/drug/mushroomhallucinogen,/datum/reagent/drug/space_drugs,/datum/reagent/consumable/ethanol,/datum/reagent/consumable/ethanol/beepsky_smash)
|
|
var/datum/reagents/R = new/datum/reagents(50)
|
|
R.my_atom = src
|
|
R.add_reagent(chosenchem , 50)
|
|
investigate_log("Experimentor has released [chosenchem] smoke.", INVESTIGATE_EXPERIMENTOR)
|
|
var/datum/effect_system/smoke_spread/chem/smoke = new
|
|
smoke.set_up(R, 0, src, silent = TRUE)
|
|
playsound(src, 'sound/effects/smoke.ogg', 50, TRUE, -3)
|
|
smoke.start()
|
|
qdel(R)
|
|
ejectItem(TRUE)
|
|
else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
|
|
visible_message("<span class='danger'>[src]'s chemical chamber has sprung a leak!</span>")
|
|
chosenchem = pick(/datum/reagent/mutationtoxin/classic,/datum/reagent/nanomachines,/datum/reagent/toxin/acid)
|
|
var/datum/reagents/R = new/datum/reagents(50)
|
|
R.my_atom = src
|
|
R.add_reagent(chosenchem , 50)
|
|
var/datum/effect_system/smoke_spread/chem/smoke = new
|
|
smoke.set_up(R, 0, src, silent = TRUE)
|
|
playsound(src, 'sound/effects/smoke.ogg', 50, TRUE, -3)
|
|
smoke.start()
|
|
qdel(R)
|
|
ejectItem(TRUE)
|
|
warn_admins(usr, "[chosenchem] smoke")
|
|
investigate_log("Experimentor has released <font color='red'>[chosenchem]</font> smoke!", INVESTIGATE_EXPERIMENTOR)
|
|
else if(prob(EFFECT_PROB_LOW-badThingCoeff))
|
|
visible_message("<span class='warning'>[src] malfunctions, spewing harmless gas.</span>")
|
|
throwSmoke(loc)
|
|
else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
|
|
visible_message("<span class='warning'>[src] melts [exp_on], ionizing the air around it!</span>")
|
|
empulse(loc, 4, 6)
|
|
investigate_log("Experimentor has generated an Electromagnetic Pulse.", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem(TRUE)
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
if(exp == SCANTYPE_HEAT)
|
|
visible_message("<span class='notice'>[src] raises [exp_on]'s temperature.</span>")
|
|
if(prob(EFFECT_PROB_LOW) && criticalReaction)
|
|
visible_message("<span class='warning'>[src]'s emergency coolant system gives off a small ding!</span>")
|
|
playsound(src, 'sound/machines/ding.ogg', 50, TRUE)
|
|
var/obj/item/reagent_containers/food/drinks/coffee/C = new /obj/item/reagent_containers/food/drinks/coffee(get_turf(pick(oview(1,src))))
|
|
chosenchem = pick(/datum/reagent/toxin/plasma,/datum/reagent/consumable/capsaicin,/datum/reagent/consumable/ethanol)
|
|
C.reagents.remove_any(25)
|
|
C.reagents.add_reagent(chosenchem , 50)
|
|
C.name = "Cup of Suspicious Liquid"
|
|
C.desc = "It has a large hazard symbol printed on the side in fading ink."
|
|
investigate_log("Experimentor has made a cup of [chosenchem] coffee.", INVESTIGATE_EXPERIMENTOR)
|
|
else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
|
|
var/turf/start = get_turf(src)
|
|
var/mob/M = locate(/mob/living) in view(src, 3)
|
|
var/turf/MT = get_turf(M)
|
|
if(MT)
|
|
visible_message("<span class='danger'>[src] dangerously overheats, launching a flaming fuel orb!</span>")
|
|
investigate_log("Experimentor has launched a <font color='red'>fireball</font> at [M]!", INVESTIGATE_EXPERIMENTOR)
|
|
var/obj/projectile/magic/aoe/fireball/FB = new /obj/projectile/magic/aoe/fireball(start)
|
|
FB.preparePixelProjectile(MT, start)
|
|
FB.fire()
|
|
else if(prob(EFFECT_PROB_LOW-badThingCoeff))
|
|
visible_message("<span class='danger'>[src] malfunctions, melting [exp_on] and releasing a burst of flame!</span>")
|
|
explosion(loc, -1, 0, 0, 0, 0, flame_range = 2)
|
|
investigate_log("Experimentor started a fire.", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem(TRUE)
|
|
else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
|
|
visible_message("<span class='warning'>[src] malfunctions, melting [exp_on] and leaking hot air!</span>")
|
|
var/datum/gas_mixture/env = loc.return_air()
|
|
var/transfer_moles = 0.25 * env.total_moles()
|
|
var/datum/gas_mixture/removed = env.remove(transfer_moles)
|
|
if(removed)
|
|
var/heat_capacity = removed.heat_capacity()
|
|
if(heat_capacity == 0 || heat_capacity == null)
|
|
heat_capacity = 1
|
|
removed.temperature = min((removed.temperature*heat_capacity + 100000)/heat_capacity, 1000)
|
|
env.merge(removed)
|
|
air_update_turf()
|
|
investigate_log("Experimentor has released hot air.", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem(TRUE)
|
|
else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
|
|
visible_message("<span class='warning'>[src] malfunctions, activating its emergency coolant systems!</span>")
|
|
throwSmoke(loc)
|
|
for(var/mob/living/m in oview(1, src))
|
|
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(m)]", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem()
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
if(exp == SCANTYPE_COLD)
|
|
visible_message("<span class='notice'>[src] lowers [exp_on]'s temperature.</span>")
|
|
if(prob(EFFECT_PROB_LOW) && criticalReaction)
|
|
visible_message("<span class='warning'>[src]'s emergency coolant system gives off a small ding!</span>")
|
|
var/obj/item/reagent_containers/food/drinks/coffee/C = new /obj/item/reagent_containers/food/drinks/coffee(get_turf(pick(oview(1,src))))
|
|
playsound(src, 'sound/machines/ding.ogg', 50, TRUE) //Ding! Your death coffee is ready!
|
|
chosenchem = pick(/datum/reagent/uranium,/datum/reagent/consumable/frostoil,/datum/reagent/medicine/ephedrine)
|
|
C.reagents.remove_any(25)
|
|
C.reagents.add_reagent(chosenchem , 50)
|
|
C.name = "Cup of Suspicious Liquid"
|
|
C.desc = "It has a large hazard symbol printed on the side in fading ink."
|
|
investigate_log("Experimentor has made a cup of [chosenchem] coffee.", INVESTIGATE_EXPERIMENTOR)
|
|
else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
|
|
visible_message("<span class='danger'>[src] malfunctions, shattering [exp_on] and releasing a dangerous cloud of coolant!</span>")
|
|
var/datum/reagents/R = new/datum/reagents(50)
|
|
R.my_atom = src
|
|
R.add_reagent(/datum/reagent/consumable/frostoil , 50)
|
|
investigate_log("Experimentor has released frostoil gas.", INVESTIGATE_EXPERIMENTOR)
|
|
var/datum/effect_system/smoke_spread/chem/smoke = new
|
|
smoke.set_up(R, 0, src, silent = TRUE)
|
|
playsound(src, 'sound/effects/smoke.ogg', 50, TRUE, -3)
|
|
smoke.start()
|
|
qdel(R)
|
|
ejectItem(TRUE)
|
|
else if(prob(EFFECT_PROB_LOW-badThingCoeff))
|
|
visible_message("<span class='warning'>[src] malfunctions, shattering [exp_on] and leaking cold air!</span>")
|
|
var/datum/gas_mixture/env = loc.return_air()
|
|
var/transfer_moles = 0.25 * env.total_moles()
|
|
var/datum/gas_mixture/removed = env.remove(transfer_moles)
|
|
if(removed)
|
|
var/heat_capacity = removed.heat_capacity()
|
|
if(heat_capacity == 0 || heat_capacity == null)
|
|
heat_capacity = 1
|
|
removed.temperature = (removed.temperature*heat_capacity - 75000)/heat_capacity
|
|
env.merge(removed)
|
|
air_update_turf()
|
|
investigate_log("Experimentor has released cold air.", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem(TRUE)
|
|
else if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
|
|
visible_message("<span class='warning'>[src] malfunctions, releasing a flurry of chilly air as [exp_on] pops out!</span>")
|
|
var/datum/effect_system/smoke_spread/smoke = new
|
|
smoke.set_up(0, loc)
|
|
smoke.start()
|
|
ejectItem()
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
if(exp == SCANTYPE_OBLITERATE)
|
|
visible_message("<span class='warning'>[exp_on] activates the crushing mechanism, [exp_on] is destroyed!</span>")
|
|
if(linked_console.linked_lathe)
|
|
var/datum/component/material_container/linked_materials = linked_console.linked_lathe.GetComponent(/datum/component/material_container)
|
|
for(var/material in exp_on.custom_materials)
|
|
linked_materials.insert_amount_mat( min((linked_materials.max_amount - linked_materials.total_amount), (exp_on.custom_materials[material])), material)
|
|
if(prob(EFFECT_PROB_LOW) && criticalReaction)
|
|
visible_message("<span class='warning'>[src]'s crushing mechanism slowly and smoothly descends, flattening the [exp_on]!</span>")
|
|
new /obj/item/stack/sheet/plasteel(get_turf(pick(oview(1,src))))
|
|
else if(prob(EFFECT_PROB_VERYLOW-badThingCoeff))
|
|
visible_message("<span class='danger'>[src]'s crusher goes way too many levels too high, crushing right through space-time!</span>")
|
|
playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE, -3)
|
|
investigate_log("Experimentor has triggered the 'throw things' reaction.", INVESTIGATE_EXPERIMENTOR)
|
|
for(var/atom/movable/AM in oview(7,src))
|
|
if(!AM.anchored)
|
|
AM.throw_at(src,10,1)
|
|
else if(prob(EFFECT_PROB_LOW-badThingCoeff))
|
|
visible_message("<span class='danger'>[src]'s crusher goes one level too high, crushing right into space-time!</span>")
|
|
playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE, -3)
|
|
investigate_log("Experimentor has triggered the 'minor throw things' reaction.", INVESTIGATE_EXPERIMENTOR)
|
|
var/list/throwAt = list()
|
|
for(var/atom/movable/AM in oview(7,src))
|
|
if(!AM.anchored)
|
|
throwAt.Add(AM)
|
|
for(var/counter = 1, counter < throwAt.len, ++counter)
|
|
var/atom/movable/cast = throwAt[counter]
|
|
cast.throw_at(pick(throwAt),10,1)
|
|
ejectItem(TRUE)
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
if(exp == FAIL)
|
|
var/a = pick("rumbles","shakes","vibrates","shudders","honks")
|
|
var/b = pick("crushes","spins","viscerates","smashes","insults")
|
|
visible_message("<span class='warning'>[exp_on] [a], and [b], the experiment was a failure.</span>")
|
|
|
|
if(exp == SCANTYPE_DISCOVER)
|
|
visible_message("<span class='notice'>[src] scans the [exp_on], revealing its true nature!</span>")
|
|
playsound(src, 'sound/effects/supermatter.ogg', 50, 3, -1)
|
|
var/obj/item/relic/R = loaded_item
|
|
if (!R.revealed)
|
|
var/points = rand(3500,3750) // discovery reward
|
|
new /obj/item/research_notes(drop_location(src), points, "experimentation")
|
|
visible_message("<span class='notice'> This discovery netted [points] points for research.</span>")
|
|
R.reveal()
|
|
investigate_log("Experimentor has revealed a relic with <span class='danger'>[R.realProc]</span> effect.", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem()
|
|
|
|
//Global reactions
|
|
if(prob(EFFECT_PROB_VERYLOW-badThingCoeff) && loaded_item)
|
|
var/globalMalf = rand(1,100)
|
|
if(globalMalf < 15)
|
|
visible_message("<span class='warning'>[src]'s onboard detection system has malfunctioned!</span>")
|
|
item_reactions["[exp_on.type]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE)
|
|
ejectItem()
|
|
if(globalMalf > 16 && globalMalf < 35)
|
|
visible_message("<span class='warning'>[src] melts [exp_on], ian-izing the air around it!</span>")
|
|
throwSmoke(loc)
|
|
if(trackedIan)
|
|
throwSmoke(trackedIan.loc)
|
|
trackedIan.forceMove(loc)
|
|
investigate_log("Experimentor has stolen Ian!", INVESTIGATE_EXPERIMENTOR) //...if anyone ever fixes it...
|
|
else
|
|
new /mob/living/simple_animal/pet/dog/corgi(loc)
|
|
investigate_log("Experimentor has spawned a new corgi.", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem(TRUE)
|
|
if(globalMalf > 36 && globalMalf < 50)
|
|
visible_message("<span class='warning'>Experimentor draws the life essence of those nearby!</span>")
|
|
for(var/mob/living/m in view(4,src))
|
|
to_chat(m, "<span class='danger'>You feel your flesh being torn from you, mists of blood drifting to [src]!</span>")
|
|
m.apply_damage(50, BRUTE, BODY_ZONE_CHEST)
|
|
investigate_log("Experimentor has taken 50 brute a blood sacrifice from [m]", INVESTIGATE_EXPERIMENTOR)
|
|
if(globalMalf > 51 && globalMalf < 75)
|
|
visible_message("<span class='warning'>[src] encounters a run-time error!</span>")
|
|
throwSmoke(loc)
|
|
if(trackedRuntime)
|
|
throwSmoke(trackedRuntime.loc)
|
|
trackedRuntime.forceMove(drop_location())
|
|
investigate_log("Experimentor has stolen Runtime!", INVESTIGATE_EXPERIMENTOR)
|
|
else
|
|
new /mob/living/simple_animal/pet/cat(loc)
|
|
investigate_log("Experimentor failed to steal runtime, and instead spawned a new cat.", INVESTIGATE_EXPERIMENTOR)
|
|
ejectItem(TRUE)
|
|
if(globalMalf > 76 && globalMalf < 98)
|
|
visible_message("<span class='warning'>[src] begins to smoke and hiss, shaking violently!</span>")
|
|
use_power(500000)
|
|
investigate_log("Experimentor has drained power from its APC", INVESTIGATE_EXPERIMENTOR)
|
|
if(globalMalf == 99)
|
|
visible_message("<span class='warning'>[src] begins to glow and vibrate. It's going to blow!")
|
|
addtimer(CALLBACK(src, .proc/boom), 50)
|
|
if(globalMalf == 100)
|
|
visible_message("<span class='warning'>[src] begins to glow and vibrate. It's going to blow!")
|
|
addtimer(CALLBACK(src, .proc/honk), 50)
|
|
|
|
addtimer(CALLBACK(src, .proc/reset_exp), resetTime)
|
|
|
|
/obj/machinery/rnd/experimentor/proc/boom()
|
|
explosion(src, 1, 5, 10, 5, 1)
|
|
|
|
/obj/machinery/rnd/experimentor/proc/honk()
|
|
playsound(src, 'sound/items/bikehorn.ogg', 500)
|
|
new /obj/item/grown/bananapeel(loc)
|
|
|
|
/obj/machinery/rnd/experimentor/proc/reset_exp()
|
|
update_icon()
|
|
recentlyExperimented = FALSE
|
|
|
|
/obj/machinery/rnd/experimentor/update_icon()
|
|
icon_state = "h_lathe"
|
|
|
|
/obj/machinery/rnd/experimentor/proc/warn_admins(user, ReactionName)
|
|
var/turf/T = get_turf(user)
|
|
message_admins("Experimentor reaction: [ReactionName] generated by [ADMIN_LOOKUPFLW(user)] at [ADMIN_VERBOSEJMP(T)]")
|
|
log_game("Experimentor reaction: [ReactionName] generated by [key_name(user)] in [AREACOORD(T)]")
|
|
|
|
#undef SCANTYPE_POKE
|
|
#undef SCANTYPE_IRRADIATE
|
|
#undef SCANTYPE_GAS
|
|
#undef SCANTYPE_HEAT
|
|
#undef SCANTYPE_COLD
|
|
#undef SCANTYPE_OBLITERATE
|
|
#undef SCANTYPE_DISCOVER
|
|
|
|
#undef EFFECT_PROB_VERYLOW
|
|
#undef EFFECT_PROB_LOW
|
|
#undef EFFECT_PROB_MEDIUM
|
|
#undef EFFECT_PROB_HIGH
|
|
#undef EFFECT_PROB_VERYHIGH
|
|
|
|
#undef FAIL
|
|
|
|
|
|
//////////////////////////////////SPECIAL ITEMS////////////////////////////////////////
|
|
|
|
/obj/item/relic
|
|
name = "strange object"
|
|
desc = "What mysteries could this hold? Maybe Research & Development could find out."
|
|
icon = 'icons/obj/assemblies.dmi'
|
|
var/realName = "defined object"
|
|
var/revealed = FALSE
|
|
var/realProc
|
|
var/cooldownMax = 60
|
|
var/cooldown
|
|
|
|
/obj/item/relic/Initialize()
|
|
. = ..()
|
|
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/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(.proc/teleport,.proc/explode,.proc/rapidDupe,.proc/petSpray,.proc/flash,.proc/clean,.proc/corgicannon)
|
|
|
|
/obj/item/relic/attack_self(mob/user)
|
|
if(revealed)
|
|
if(cooldown)
|
|
to_chat(user, "<span class='warning'>[src] does not react!</span>")
|
|
return
|
|
else if(loc == user)
|
|
cooldown = TRUE
|
|
call(src,realProc)(user)
|
|
if(!QDELETED(src))
|
|
addtimer(CALLBACK(src, .proc/cd), cooldownMax)
|
|
else
|
|
to_chat(user, "<span class='notice'>You aren't quite sure what this is. Maybe R&D knows what to do with it?</span>")
|
|
|
|
/obj/item/relic/proc/cd()
|
|
cooldown = FALSE
|
|
|
|
//////////////// RELIC PROCS /////////////////////////////
|
|
|
|
/obj/item/relic/proc/throwSmoke(turf/where)
|
|
var/datum/effect_system/smoke_spread/smoke = new
|
|
smoke.set_up(0, get_turf(where))
|
|
smoke.start()
|
|
|
|
/obj/item/relic/proc/corgicannon(mob/user)
|
|
playsound(src, "sparks", rand(25,50), TRUE)
|
|
var/mob/living/simple_animal/pet/dog/corgi/C = new/mob/living/simple_animal/pet/dog/corgi(get_turf(user))
|
|
C.throw_at(pick(oview(10,user)), 10, rand(3,8), callback = CALLBACK(src, .proc/throwSmoke, C))
|
|
warn_admins(user, "Corgi Cannon", 0)
|
|
|
|
/obj/item/relic/proc/clean(mob/user)
|
|
playsound(src, "sparks", rand(25,50), TRUE)
|
|
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, "sparks", rand(25,50), TRUE)
|
|
var/obj/item/grenade/flashbang/CB = new/obj/item/grenade/flashbang(user.loc)
|
|
CB.prime()
|
|
warn_admins(user, "Flash")
|
|
|
|
/obj/item/relic/proc/petSpray(mob/user)
|
|
var/message = "<span class='danger'>[src] begins to shake, and in the distance the sound of rampaging animals arises!</span>"
|
|
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/fox, /mob/living/simple_animal/hostile/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, "<span class='warning'>[src] falls apart!</span>")
|
|
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 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,get_turf(src))),10,1)
|
|
counter = 0
|
|
QDEL_LIST_IN(dupes, rand(10, 100))
|
|
warn_admins(user, "Rapid duplicator", 0)
|
|
|
|
/obj/item/relic/proc/explode(mob/user)
|
|
to_chat(user, "<span class='danger'>[src] begins to heat up!</span>")
|
|
addtimer(CALLBACK(src, .proc/do_explode, user), rand(35, 100))
|
|
|
|
/obj/item/relic/proc/do_explode(mob/user)
|
|
if(loc == user)
|
|
visible_message("<span class='notice'>\The [src]'s top opens, releasing a powerful blast!</span>")
|
|
explosion(user.loc, 0, rand(1,5), rand(1,5), rand(1,5), rand(1,5), flame_range = 2)
|
|
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, "<span class='notice'>[src] begins to vibrate!</span>")
|
|
addtimer(CALLBACK(src, .proc/do_the_teleport, user), rand(10, 30))
|
|
|
|
/obj/item/relic/proc/do_the_teleport(mob/user)
|
|
var/turf/userturf = get_turf(user)
|
|
if(loc == user && !is_centcom_level(userturf.z)) //Because Nuke Ops bringing this back on their shuttle, then looting the ERT area is 2fun4you!
|
|
visible_message("<span class='notice'>[src] twists and bends, relocating itself!</span>")
|
|
throwSmoke(userturf)
|
|
do_teleport(user, userturf, 8, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
|
|
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(user)] in [AREACOORD(T)]"
|
|
if(priority) //For truly dangerous relics that may need an admin's attention. BWOINK!
|
|
message_admins("[RelicType] relic activated by [ADMIN_LOOKUPFLW(user)] in [ADMIN_VERBOSEJMP(T)]")
|
|
log_game(log_msg)
|
|
investigate_log(log_msg, "experimentor")
|