[PTBF] [ready for review] Anomalous particulate processing objective. (#30649)

* pausing work on this till pickweight

* push

* more stuff

* proper file it

* these 2 would be interested

* and examine fix

* I should be more awake before resolving merge conflicts

* god you are stupid stop commiting every 2 seconds

* temp buff size change

* Event inhand descriptions

* behold the c o d e

* the rest of the owl

* sprite correction

* 2 more words to the list

* and this one

* yes I am having too much fun with this

* m o r e

* better glow, tech levels

* Apply suggestions from code review

Co-authored-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
Signed-off-by: Qwertytoforty <52090703+Qwertytoforty@users.noreply.github.com>

* message admins, variable

* Apply suggestions from code review

Co-authored-by: Taurtura <141481662+Taurtura@users.noreply.github.com>
Signed-off-by: Qwertytoforty <52090703+Qwertytoforty@users.noreply.github.com>

* PPPProcessor

---------

Signed-off-by: Qwertytoforty <52090703+Qwertytoforty@users.noreply.github.com>
Co-authored-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
Co-authored-by: Taurtura <141481662+Taurtura@users.noreply.github.com>
This commit is contained in:
Qwertytoforty
2025-10-24 21:01:03 -04:00
committed by GitHub
parent 07b2f76367
commit 2ecff9033a
27 changed files with 1009 additions and 38 deletions
+316 -4
View File
@@ -3,7 +3,7 @@
/obj/item/nuke_core
name = "plutonium core"
desc = "Extremely radioactive. Wear goggles."
icon = 'icons/obj/nuke_tools.dmi'
icon = 'icons/obj/theft_tools.dmi'
icon_state = "plutonium_core"
inhand_icon_state = "plutoniumcore"
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
@@ -39,7 +39,7 @@
/obj/item/nuke_core_container
name = "nuke core container"
desc = "A lead-lined secure container produced by the Syndicate for the express purpose of extracting the valuable radioactive cores of nuclear weapons."
icon = 'icons/obj/nuke_tools.dmi'
icon = 'icons/obj/theft_tools.dmi'
icon_state = "core_container_empty"
inhand_icon_state = "syringe_kit"
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF //Don't want people trying to break it open with acid, then destroying the core.
@@ -349,7 +349,7 @@
/obj/item/scalpel/supermatter
name = "supermatter scalpel"
desc = "A scalpel with a fragile tip of condensed hyper-noblium gas, searingly cold to the touch, that can safely shave a sliver off a supermatter crystal."
icon = 'icons/obj/nuke_tools.dmi'
icon = 'icons/obj/theft_tools.dmi'
icon_state = "supermatter_scalpel"
toolspeed = 0.5
damtype = BURN
@@ -363,7 +363,7 @@
/obj/item/retractor/supermatter
name = "supermatter extraction tongs"
desc = "A pair of tongs made from condensed hyper-noblium gas, searingly cold to the touch, that can safely grip a supermatter sliver."
icon = 'icons/obj/nuke_tools.dmi'
icon = 'icons/obj/theft_tools.dmi'
icon_state = "supermatter_tongs"
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
@@ -440,3 +440,315 @@
)
QDEL_NULL(sliver)
update_icon(UPDATE_ICON_STATE)
// This device is used to analyze and trigger the particulate
/obj/item/ppp_processor
name = "\improper Prototype Portable Particulate Processor"
desc = "The Prototype Portable Particulate Processor, or PPPProcessor, for short, is a device designed to energize, collect, \
and process anomalous particulate."
icon = 'icons/obj/theft_tools.dmi'
icon_state = "PPP_Processor_0"
worn_icon_state = "gun"
inhand_icon_state = "gun"
lefthand_file = 'icons/mob/inhands/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/guns_righthand.dmi'
force = 10
throwforce = 10
attack_verb = list("processed", "perforated", "pounded", "pasted", "proded", "punished", "plowed into", "pommeled", "pummeled", "penetrated", "probed", "pulsed", "pulverized", "pillaged", "persecuted", "pasted", "peppered", "plundered", "put down", "pushed")
origin_tech = "programming=6;plasma=6;syndicate=3"
new_attack_chain = TRUE
/// How many clouds have been processed?
var/clouds_processed = 0
/// Have we used it in hand to fully process the particulate and eject the canisters?
var/fully_processed_particulate = FALSE
/// Are we possibly processing particularly powerful packets?
var/presently_processing_particular_particultate = FALSE
/// The soundloop we use.
var/datum/looping_sound/kitchen/microwave/me_cro_wah_vey
/obj/item/ppp_processor/Initialize(mapload)
. = ..()
me_cro_wah_vey = new /datum/looping_sound/kitchen/microwave(list(src), FALSE)
/obj/item/ppp_processor/Destroy()
QDEL_NULL(me_cro_wah_vey)
return ..()
/obj/item/ppp_processor/examine(mob/user)
. = ..()
if(fully_processed_particulate)
. += "<span class='notice'>[src] has processed the data you now possess. All you need to do is present it after this shift.</span>"
return
if(clouds_processed < 3)
. += "<span class='notice'>[src] has only [clouds_processed] out of 3 samples.</span>"
if(clouds_processed == 3)
. += "<span class='notice'>[src] has all 3 samples. Use it in hand to process the particulate.</span>"
/obj/item/ppp_processor/activate_self(mob/user)
if(..())
return
if(fully_processed_particulate)
to_chat(user, "<span class='notice'>[src] has already processed and ejected the particulate canisters. Just make sure to escape with the processor!</span>")
return
if(clouds_processed < 3)
to_chat(user, "<span class='warning'>[src] has only [clouds_processed] out of 3 samples. You still need to collect more!</span>")
return
if(presently_processing_particular_particultate)
to_chat(user, "<span class='warning'>[src] is presently processing particularly powerful packets of your particular particulate. Wait for it to finish before proceeding.</span>")
return
to_chat(user, "<span class='notice'>[src] is presently processing the particulate. Please hold as processing finishes, and be aware it may eject collection canisters.</span>")
if(me_cro_wah_vey)
me_cro_wah_vey.start()
addtimer(CALLBACK(src, PROC_REF(perfectly_processed), user), 15 SECONDS)
presently_processing_particular_particultate = TRUE
/obj/item/ppp_processor/update_icon_state()
. = ..()
switch(clouds_processed)
if(-1)
icon_state = "PPP_Processor_-1"
if(0)
icon_state = "PPP_Processor_0"
if(1)
icon_state = "PPP_Processor_1"
if(2)
icon_state = "PPP_Processor_2"
if(3)
icon_state = "PPP_Processor_3"
/obj/item/ppp_processor/proc/collect()
clouds_processed++
update_icon()
/obj/item/ppp_processor/proc/perfectly_processed(mob/user)
if(!QDELETED(user))
to_chat(user, "<span class='notice'>[src] has perfectly processed the particulate. You may now use the canisters however you wish. Ensure the processor gets back to us.</span>")
me_cro_wah_vey.stop()
presently_processing_particular_particultate = FALSE
clouds_processed = -1
fully_processed_particulate = TRUE
update_icon()
var/list/potential_grenade_rewards = list()
potential_grenade_rewards += subtypesof(/obj/item/grenade/anomalous_canister)
potential_grenade_rewards += /obj/item/grenade/anomalous_canister
potential_grenade_rewards += /obj/effect/abstract/dummy_mini_spawner
potential_grenade_rewards -= /obj/item/grenade/anomalous_canister/mini
var/turf/our_turf = get_turf(src)
our_turf.visible_message("<span class='warning'>Three containers are ejected out of [src].</span>")
for(var/i in 1 to 3)
var/obj/item/new_toy = pick_n_take(potential_grenade_rewards)
new new_toy(get_turf(src))
/obj/item/clothing/glasses/hud/anomalous
name = "anomalous particulate scanner HUD"
desc = "A heads-up display that scans for anomalous particulate. Has a built in chameleon function, to help it blend in."
icon_state = "sunhudmed"
inhand_icon_state = "sunglasses"
hud_types = DATA_HUD_ANOMALOUS
var/datum/action/item_action/chameleon_change/chameleon_action
/obj/item/clothing/glasses/hud/anomalous/Initialize(mapload)
. = ..()
chameleon_action = new(src)
chameleon_action.chameleon_type = /obj/item/clothing/glasses
chameleon_action.chameleon_name = "HUD"
chameleon_action.chameleon_blacklist = list()
chameleon_action.initialize_disguises()
/obj/item/clothing/glasses/hud/anomalous/Destroy()
QDEL_NULL(chameleon_action)
return ..()
/obj/item/clothing/glasses/hud/anomalous/emp_act(severity)
. = ..()
chameleon_action.emp_randomise()
// The parent anomalous grenade type. Spawns a random anomaly.
/obj/item/grenade/anomalous_canister
name = "anomalous particulate canister"
desc = "This canister contains a cloud of charged anomalous particulate. It can be armed to create a temporary anomaly. \
Be careful, with a glass exterior, it may shatter early when thrown."
icon_state = "anomalous_canister"
inhand_icon_state = "emp"
origin_tech = "magnets=6;combat=6;syndicate=2"
/// The type of anomaly the canister will spawn.
var/obj/effect/anomaly/anomaly_type
/// The lifetime of the anomaly.
var/anomaly_lifetime = 45 SECONDS
/// How many anomalies the grenade will spawn
var/number_of_anomalies = 1
/// Have we primed? It contains a cloud of particulate matter. Breaking it is going to let the anomaly out.
var/has_primed = FALSE
/// Chance to be a varient that the glass will shatter when thrown earlier than expected. The smaller canisters are more metal spheres, and will not.
var/shatter_chance = 20
/obj/item/grenade/anomalous_canister/Initialize(mapload)
. = ..()
anomaly_type = pick(subtypesof(/obj/effect/anomaly))
if(prob(shatter_chance))
AddElement(/datum/element/shatters_when_thrown, /obj/effect/decal/cleanable/glass, 1, "shatter")
/obj/item/grenade/anomalous_canister/Destroy()
prime()
return ..()
/obj/item/grenade/anomalous_canister/prime()
if(has_primed)
return
has_primed = TRUE
var/turf/our_turf = get_turf(src)
our_turf.visible_message("<span class='danger'>[src] shatters open, the [(number_of_anomalies - 1) ? "clouds" : "cloud"] of particulate rapidly forming into something more!</span>")
playsound(src, "shatter", 70, TRUE)
update_mob()
for(var/i in 1 to number_of_anomalies)
var/obj/effect/anomaly/A = new anomaly_type(our_turf, anomaly_lifetime, FALSE)
A.anomalous_canister_setup()
if(!QDELETED(src))
qdel(src)
/obj/item/grenade/anomalous_canister/dual_core
name = "dual clouded anomalous particulate canister"
icon_state = "anomalous_canister_dual"
number_of_anomalies = 2
anomaly_lifetime = 30 SECONDS
/obj/item/grenade/anomalous_canister/dual_core/examine(mob/user)
. = ..()
. += "<span class='notice'>Two smaller clouds of particulate are swirling around in this canister. It will likely form into two anomalies.</span>"
/obj/item/grenade/anomalous_canister/condensed
name = "condensed anomalous particulate canister"
icon_state = "anomalous_canister_condensed"
anomaly_lifetime = 90 SECONDS
/obj/item/grenade/anomalous_canister/condensed/examine(mob/user)
. = ..()
. += "<span class='notice'>A large cloud of resiliant particulate is floating in this canister. It will last longer than other anomalies.</span>"
/obj/item/grenade/anomalous_canister/stabilized
name = "stabilized anomalous particulate canister"
desc = "The cloud of this particulate has stabilized enough for the computer to predict the anomaly it will condense into..."
icon_state = "anomalous_canister_stable"
/obj/item/grenade/anomalous_canister/stabilized/examine(mob/user)
. = ..()
. += "<span class='notice'>The predicted result for the cloud to condense into is displayed as \an [anomaly_type::name]!</span>"
/obj/effect/abstract/dummy_mini_spawner
/obj/effect/abstract/dummy_mini_spawner/Initialize(mapload)
. = ..()
var/turf/our_turf = get_turf(src)
our_turf.visible_message("<span class='warning'>One of the containers splits into 3 smaller capsules!</span>")
for(var/i in 1 to 3)
new /obj/item/grenade/anomalous_canister/mini(our_turf)
return INITIALIZE_HINT_QDEL
/obj/item/grenade/anomalous_canister/mini
name = "miniature anomalous particulate canister"
desc = "This small sphere contains a small cloud of particulate. Likely won't form an anomally, but should still have a noticable impact"
icon_state = "anomalous_canister_mini"
w_class = 1
shatter_chance = 0
/obj/item/grenade/anomalous_canister/mini/prime()
if(has_primed)
return
has_primed = TRUE
update_mob()
var/turf/our_turf = get_turf(src)
our_turf.visible_message("<span class='danger'>[src] activates and...</span>")
playsound(src, "shatter", 70, TRUE)
switch(anomaly_type)
if(/obj/effect/anomaly/bluespace) // Teleport and slow combat for 15
if(!is_teleport_allowed(z))
visible_message("<span class='warning'>[src]'s fragments begin rapidly vibrating and blink out of existence.</span>")
qdel(src)
return
for(var/mob/living/L in range(7, our_turf))
do_teleport(L, get_turf(L), 7, sound_in = 'sound/effects/phasein.ogg')
L.apply_status_effect(STATUS_EFFECT_BLUESPACESLOWDOWN)
if(/obj/effect/anomaly/flux) // shock
for(var/mob/living/L in view(7, our_turf))
L.Beam(get_turf(src), icon_state = "lightning[rand(1, 12)]", icon = 'icons/effects/effects.dmi', time = 5) // What? Why are we beaming from the mob to the turf? Turf to mob generates really odd results.
L.electrocute_act(20, "electrical blast", flags = SHOCK_NOGLOVES)
L.KnockDown(6 SECONDS)
if(/obj/effect/anomaly/grav) // repulse
var/list/thrownatoms = list()
var/atom/throwtarget
var/distfromcaster
for(var/turf/T in range(7, our_turf)) // Done this way so things don't get thrown all around hilariously.
for(var/atom/movable/AM in T)
thrownatoms += AM
for(var/am in thrownatoms)
var/atom/movable/AM = am
if(AM == src || AM.anchored || AM.move_resist == INFINITY)
continue
throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(AM, src)))
distfromcaster = get_dist(src, AM)
if(distfromcaster == 0)
if(isliving(AM))
var/mob/living/M = AM
M.Weaken(8 SECONDS)
M.adjustBruteLoss(5)
to_chat(M, "<span class='userdanger'>You're slammed into the floor by an anomalous force!</span>")
else
new /obj/effect/temp_visual/gravpush(get_turf(AM), get_dir(src, AM)) // created sparkles will disappear on their own
if(isliving(AM))
var/mob/living/M = AM
M.Weaken(3 SECONDS)
to_chat(M, "<span class='userdanger'>You're thrown back by a anomalous force!</span>")
spawn(0)
AM.throw_at(throwtarget, ((clamp((5 - (clamp(distfromcaster - 2, 0, distfromcaster))), 3, 5))), 1) // So stuff gets tossed around at the same time.
if(/obj/effect/anomaly/pyro) // burn
var/datum/gas_mixture/air = new()
air.set_temperature(1000)
air.set_toxins(20)
air.set_oxygen(20)
our_turf.blind_release_air(air)
for(var/mob/living/L in view(7, our_turf))
L.adjust_fire_stacks(6)
L.IgniteMob()
if(/obj/effect/anomaly/cryo) // weaker anomaly grenade
for(var/turf/simulated/floor/T in view(4, our_turf))
T.MakeSlippery(TURF_WET_ICE)
for(var/mob/living/carbon/C in T)
C.adjust_bodytemperature(-230)
C.apply_status_effect(/datum/status_effect/freon)
if(/obj/effect/anomaly/bhole) // big smoke that doesn't last as long as a smoke grenade
var/datum/effect_system/smoke_spread/smoke
smoke = new /datum/effect_system/smoke_spread/bad()
smoke.set_up(20, FALSE, src)
playsound(our_turf, 'sound/effects/smoke.ogg', 50, TRUE, -3)
smoke.start()
if(!QDELETED(src))
qdel(src)
/obj/item/paper/guides/antag/anomalous_particulate
name = "Particulate gathering instructions"
info = {"<b>Instructions on your new PPPProcessor and HUD</b><br>
<br>
First off, equip your glasses. You will need them to find the particulate. We heavily advise against losing them.<br>
<br>
This will allow you to identify the uncharged anomalous particulate aboard the station. It can be anywhere, stalk out rooms and or use cameras to find it.\
It will look like <b>purple sparkles, with a yellow and red square targeting highlight.</b><br>
<br>
Afterwords, approach the particulate with the PPPProcessor, and use it on the particulate. It will charge and capture a sample of it.<br>
<br>
<b>Warning:</b> Charged particulate is dangerous. Wear the goggles and leave the area. Try not to get caught in doing so.<br>
<br>
After collecting 3 diffrent unique samples (We will not accept a sample another agent has collected), use the scanner in hand to begin processing the particulate.<br>
<br>
After a short processing period, processing will be complete and you can bring the processor back to us. Additionally, 3 collection cansiters should eject.<br>
<br>
Feel free to use the canisters however you wish, they should be effective weapons, though do write down the results for us.
<br><hr>
<font size =\"1\"><i>We are not liable for any health conditions you may recive from scanning particulate or using the canisters.</i></font>
"}
@@ -518,6 +518,16 @@
new /obj/item/nuke_core_container/supermatter(src)
new /obj/item/paper/guides/antag/supermatter_sliver(src)
/obj/item/storage/box/syndie_kit/anomalous_particulate
desc = "It's just an ordinary box."
icon_state = "box"
/obj/item/storage/box/syndie_kit/anomalous_particulate/populate_contents()
new /obj/item/ppp_processor(src)
new /obj/item/clothing/glasses/hud/anomalous(src)
new /obj/item/paper/guides/antag/anomalous_particulate(src)
/obj/item/storage/box/syndie_kit/revolver
name = "\improper .357 revolver kit"