From b61adb6ea26f8e4e9be5954819e2ed991a1384cb Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Tue, 14 Jul 2026 06:39:19 -0400 Subject: [PATCH] The Blood Of Psirens On My Hands I Cant Wash Away (#22740) SURPRISE! I hope you all had fun during the Psilence event! It was really fun spending 6 months coding all the infrastructure I required to make that encounter possible. Encountering an entire new enemy type was no doubt incredibly exciting to happen during a big canon round. Well as promised, these critters will start showing up more often now that the big reveal has occured. image image This PR adds new rare random events and overmap hazards for Psirens, allowing the basic varieties of them to appear in normal gameplay. They can also be summoned by technomancers. More to come later. :) --- aurorastation.dme | 1 + .../spells/summon/summon_creature.dm | 5 +- code/modules/events/event_container.dm | 6 ++ code/modules/events/wandering_psirens.dm | 75 +++++++++++++++++++ code/modules/overmap/events/event.dm | 28 +++++++ .../hellfirejag-introducing-psirens.yml | 5 ++ 6 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 code/modules/events/wandering_psirens.dm create mode 100644 html/changelogs/hellfirejag-introducing-psirens.yml diff --git a/aurorastation.dme b/aurorastation.dme index 3662c98958d..d18fb920ebe 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -2390,6 +2390,7 @@ #include "code\modules\events\vent_clog.dm" #include "code\modules\events\visitor.dm" #include "code\modules\events\wallrot.dm" +#include "code\modules\events\wandering_psirens.dm" #include "code\modules\ext_scripts\python.dm" #include "code\modules\fabrication\_fabricator.dm" #include "code\modules\fabrication\_fabricator_build_order.dm" diff --git a/code/game/gamemodes/technomancer/spells/summon/summon_creature.dm b/code/game/gamemodes/technomancer/spells/summon/summon_creature.dm index 0a8cf35cb20..12d94f1f995 100644 --- a/code/game/gamemodes/technomancer/spells/summon/summon_creature.dm +++ b/code/game/gamemodes/technomancer/spells/summon/summon_creature.dm @@ -34,7 +34,10 @@ "GREIMORIAN BOMBARDIER" = /mob/living/simple_animal/hostile/giant_spider/bombardier, "GREIMORIAN NURSE" = /mob/living/simple_animal/hostile/giant_spider/nurse, "CARP" = /mob/living/simple_animal/hostile/carp, - "BEAR" = /mob/living/simple_animal/hostile/bear + "BEAR" = /mob/living/simple_animal/hostile/bear, + "PSIREN LASHER" = /mob/living/simple_animal/hostile/psiren, + "PSIREN DARTER" = /mob/living/simple_animal/hostile/psiren/ranged, + "PSIREN OMEN" = /mob/living/simple_animal/hostile/psiren/omen ) cooldown = 30 instability_cost = 10 diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 4d98e80fe4f..10533c884e0 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -335,6 +335,9 @@ GLOBAL_LIST_INIT(severity_to_string, alist(EVENT_LEVEL_MUNDANE = "Mundane", EVEN new /datum/event_meta(EVENT_LEVEL_MODERATE, "APC Damage", /datum/event/apc_damage, 20, list(ASSIGNMENT_ENGINEER = 15, ASSIGNMENT_JANITOR = 20)), + new /datum/event_meta(EVENT_LEVEL_MODERATE, "Wandering Psirens", /datum/event/wandering_psirens, + 10, list(ASSIGNMENT_SECURITY = 15)), + ) // Severity Level, Event Name, Event Type, Base Weight, Role Weight(s), One Shot (TRUE/FALSE), Min Weight, Max Weight. Last two only used if set and non-zero. @@ -388,6 +391,9 @@ GLOBAL_LIST_INIT(severity_to_string, alist(EVENT_LEVEL_MUNDANE = "Mundane", EVEN 35, list(ASSIGNMENT_ENGINEER = 20), is_one_shot = TRUE, pop_needed = 12), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Wandering Psiren School", /datum/event/wandering_psirens, + 10, list(ASSIGNMENT_SECURITY = 15, ASSIGNMENT_MEDICAL = 5)), + ) #undef ASSIGNMENT_ANY diff --git a/code/modules/events/wandering_psirens.dm b/code/modules/events/wandering_psirens.dm new file mode 100644 index 00000000000..013ff01e35f --- /dev/null +++ b/code/modules/events/wandering_psirens.dm @@ -0,0 +1,75 @@ +/// Wandering Psirens, an event similar enough to Carp Migration that I can reuse much of the code. +/datum/event/wandering_psirens + announceWhen = 50 + endWhen = 900 + + var/list/spawned_psirens = list() + + var/list/despawn_turfs = list( + /turf/space, + /turf/simulated/floor/exoplanet/asteroid, + /turf/simulated/open, + /turf/simulated/floor/reinforced/airless // Station roof. + ) + +/datum/event/wandering_psirens/setup() + announceWhen = rand(40, 60) + endWhen = rand(600, 1200) + despawn_turfs = typecacheof(despawn_turfs) + +/datum/event/wandering_psirens/announce() + // Pings every "Psi-sensitive", will trigger feedback on people's mindshields. + for (var/mob/victim in GLOB.player_list) + if (SShallucinations.is_adpi_excluded(victim) || SShallucinations.is_adpi_blocked(victim)) + continue + + SShallucinations.send_adpi_message(victim, null, FALSE) + +/datum/event/wandering_psirens/start() + ..() + + if(severity == EVENT_LEVEL_MAJOR) + spawn_psirens(length(GLOB.landmarks_list)) + else if(severity == EVENT_LEVEL_MODERATE) + spawn_psirens(rand(4, 6)) //12 to 30 psirens + else + spawn_psirens(rand(1, 3), 1, 2) //1 to 6 psirens, alone or in pairs + +/datum/event/wandering_psirens/proc/spawn_psirens(num_groups, group_size_min = 3, group_size_max = 5) + set waitfor = FALSE + var/list/spawn_locations = list() + + for(var/obj/effect/landmark/C in GLOB.landmarks_list) + if(C.name == "carpspawn") // Reusing the carp landmarks. :) + spawn_locations.Add(C.loc) + spawn_locations = shuffle(spawn_locations) + num_groups = min(num_groups, spawn_locations.len) + + var/i = 1 + while (i <= num_groups) + var/group_size = rand(group_size_min, group_size_max) + for(var/j = 1, j <= group_size, j++) + if(prob(95)) + var/basic_psiren + if (prob(50)) + basic_psiren = new /mob/living/simple_animal/hostile/psiren(spawn_locations[i]) + else basic_psiren = new /mob/living/simple_animal/hostile/psiren/ranged(spawn_locations[i]) + spawned_psirens += WEAKREF(basic_psiren) + else + var/mob/living/simple_animal/hostile/psiren/omen/new_omen = new(spawn_locations[i]) + spawned_psirens += WEAKREF(new_omen) + CHECK_TICK + i++ + +/datum/event/wandering_psirens/end(faked) + ..() + + for (var/datum/weakref/psiren_weakref in spawned_psirens) + var/mob/living/simple_animal/hostile/psiren/psiren = psiren_weakref.resolve() + if (psiren && prob(50) && is_type_in_typecache(psiren.loc, despawn_turfs)) + spawned_psirens -= psiren_weakref + qdel(psiren_weakref) + spawned_psirens?.Cut() + +/datum/event/wandering_psirens/overmap + despawn_turfs = list(/turf/space) diff --git a/code/modules/overmap/events/event.dm b/code/modules/overmap/events/event.dm index c951befacc6..1bd94603d8c 100644 --- a/code/modules/overmap/events/event.dm +++ b/code/modules/overmap/events/event.dm @@ -328,6 +328,20 @@ can_be_destroyed = FALSE tooltip_text = "Unstable gravitic shear effects detected; wide-field artificial gravity should be powered down before transit." +/obj/effect/overmap/event/psiren + name = "psiren shoal" + events = list(/datum/event/wandering_psirens/overmap) + difficulty = EVENT_LEVEL_MODERATE + event_icon_states = list("carp") + movable_event_chance = 30 + tooltip_text = "Xenofauna: usually hostile." + +/obj/effect/overmap/event/psiren/major + name = "psiren school" + opacity = 1 + difficulty = EVENT_LEVEL_MAJOR + movable_event_chance = 15 + /obj/effect/overmap/event/MouseEntered(location, control, params) . = ..() openToolTip(usr, src, params, tooltip_text) @@ -402,3 +416,17 @@ radius = 12 hazards = /obj/effect/overmap/event/gravity_anomaly sectors = list(SECTOR_LEMURIAN_SEA, SECTOR_LEMURIAN_SEA_FAR) + +/datum/overmap_event/psiren + name = "psiren shoal" + count = 3 + radius = 1 + continuous = FALSE + hazards = /obj/effect/overmap/event/psiren + +/datum/overmap_event/psiren/major + name = "psiren school" + count = 2 + radius = 2 + opacity = 1 + hazards = /obj/effect/overmap/event/psiren/major diff --git a/html/changelogs/hellfirejag-introducing-psirens.yml b/html/changelogs/hellfirejag-introducing-psirens.yml new file mode 100644 index 00000000000..5a08ddf5b82 --- /dev/null +++ b/html/changelogs/hellfirejag-introducing-psirens.yml @@ -0,0 +1,5 @@ +author: Hellfirejag +delete-after: True +changes: + - rscadd: "Psirens can now visit the ship, both via overmap hazard, or as a random event." + - rscadd: "Technomancers can now summon the 3 basic Psiren types"