From 68dd7ae4a6804c9ebfcd289037397b2b88bf5db0 Mon Sep 17 00:00:00 2001 From: Leland Kemble <70413276+lelandkemble@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:58:25 -0400 Subject: [PATCH] Gives Space Dragons a locator for the areas they need to go to (#95725) ## About The Pull Request Gives Space Dragons an ability that lets them find out in what direction an area of their choosing(from within their rift summon locations) is. The ability acts very similarly to the heretic's living heart ability, except it will provide direction even if you are above or below your intended area. ## Why It's Good For The Game It'd be nice to be able to find areas that you don't know the specific location of due to a vague name or something, but the primary utility of this is that Space Dragons spawn in space, away from the station, without sight to the station. If they go the wrong direction, they'll be stuck in deep space without a hope of navigation. This is a lesser problem in real space, because you can navigate to some degree via the background stars, but on Icebox you have precisely zero information and precisely zero way to gain any besides simply stumbling upon the station. This sucks, especially when you only have five minutes to find the station, find a suitable location on the station, and place your rift there. ## Changelog :cl: add: Space Dragons have a new ability to locate the areas they need to create rifts in. /:cl: --- .../antagonists/space_dragon/carp_rift.dm | 63 ++++++++++++++++-- .../antagonists/space_dragon/space_dragon.dm | 6 ++ icons/mob/actions/actions_space_dragon.dmi | Bin 1484 -> 2257 bytes 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/code/modules/antagonists/space_dragon/carp_rift.dm b/code/modules/antagonists/space_dragon/carp_rift.dm index 7345de2fcc8..ac1b2967dfd 100644 --- a/code/modules/antagonists/space_dragon/carp_rift.dm +++ b/code/modules/antagonists/space_dragon/carp_rift.dm @@ -18,14 +18,16 @@ if(!dragon) return var/area/rift_location = get_area(owner) - if(!(rift_location in dragon.chosen_rift_areas)) - owner.balloon_alert(owner, "can't summon a rift here! check your objectives!") - return for(var/obj/structure/carp_rift/rift as anything in dragon.rift_list) var/area/used_location = get_area(rift) if(used_location == rift_location) owner.balloon_alert(owner, "already summoned a rift here!") return + + if(!(rift_location in dragon.chosen_rift_areas)) + owner.balloon_alert(owner, "can't summon a rift here! check your objectives!") + return + var/turf/rift_spawn_turf = get_turf(dragon) if(isopenspaceturf(rift_spawn_turf)) owner.balloon_alert(dragon, "needs stable ground!") @@ -50,6 +52,52 @@ ASSERT(dragon.rift_ability == src) // Badmin protection. QDEL_NULL(dragon.rift_ability) // Deletes this action when used successfully, we re-gain a new one on success later. +/// Points towards a chosen location in which a rift can be placed +/datum/action/innate/locate_rift + name = "Locate Rift" + desc = "Find out where a potential rift location is." + background_icon_state = "bg_default" + overlay_icon_state = "bg_default_border" + button_icon = 'icons/mob/actions/actions_space_dragon.dmi' + button_icon_state = "locate_carp_rift" + +/datum/action/innate/locate_rift/Activate() + var/datum/antagonist/space_dragon/dragon_datum = owner.mind?.has_antag_datum(/datum/antagonist/space_dragon) + var/mob/living/dragon_mob = dragon_datum?.owner.current + if(!dragon_mob) + return + if(!is_station_level(dragon_mob.z)) + dragon_mob.balloon_alert(dragon_mob, "too far offstation!") + return + + var/area/chosen_area = tgui_input_list(owner, "Select the area you'd like to be pointed towards.", "Locate Rift", dragon_datum.chosen_rift_areas) + if(!chosen_area) + return + if(chosen_area == get_area(dragon_mob)) + dragon_mob.balloon_alert(dragon_mob, "already here!") + return + + var/turf/chosen_turf = pick(get_area_turfs(chosen_area)) + + var/message = "" + if(chosen_turf.z != dragon_mob.z) + message = "[chosen_turf.z > dragon_mob.z ? "above" : "below"] you, " + else + switch(get_dist(dragon_mob, chosen_turf)) // Exact same numbers as the heretic heart tracker + if(0 to 15) + message = "very near, " + if(16 to 31) + message = "near, " + if(32 to 127) + message = "far, " + else + message = "very far, " + + message += dir2text(get_dir(dragon_mob, chosen_turf)) + message += "!" + + dragon_mob.balloon_alert(dragon_mob, message) + /** * # Carp Rift * @@ -207,8 +255,8 @@ // Is the rift now fully charged? if(time_charged >= max_charge) charge_state = CHARGE_COMPLETED - var/area/A = get_area(src) - priority_announce("Spatial object has reached peak energy charge in [initial(A.name)], please stand-by.", "[command_name()] Wildlife Observations", has_important_message = TRUE) + var/area/location = get_area(src) + priority_announce("Spatial object has reached peak energy charge in [initial(location.name)], please stand-by.", "[command_name()] Wildlife Observations", has_important_message = TRUE) atom_integrity = INFINITY icon_state = "carp_rift_charged" set_light_color(LIGHT_COLOR_DIM_YELLOW) @@ -216,11 +264,16 @@ set_armor(/datum/armor/immune) resistance_flags = INDESTRUCTIBLE dragon.rifts_charged += 1 + dragon.chosen_rift_areas -= location if(dragon.rifts_charged != 3 && !dragon.objective_complete) dragon.rift_ability = new() dragon.rift_ability.Grant(dragon.owner.current) dragon.riftTimer = 0 dragon.rift_empower() + return + + dragon.locate_rift_ability.Remove(dragon.owner.current) + QDEL_NULL(dragon.locate_rift_ability) // Early return, nothing to do after this point. return diff --git a/code/modules/antagonists/space_dragon/space_dragon.dm b/code/modules/antagonists/space_dragon/space_dragon.dm index c71b5302b6e..c451312a7a6 100644 --- a/code/modules/antagonists/space_dragon/space_dragon.dm +++ b/code/modules/antagonists/space_dragon/space_dragon.dm @@ -10,6 +10,8 @@ var/list/datum/mind/carp = list() /// The innate ability to summon rifts var/datum/action/innate/summon_rift/rift_ability + /// The innate ability to find where rift locations are + var/datum/action/innate/locate_rift/locate_rift_ability /// Current time since the the last rift was activated. If set to -1, does not increment. var/riftTimer = 0 /// Maximum amount of time which can pass without a rift before Space Dragon despawns. @@ -66,6 +68,7 @@ /datum/antagonist/space_dragon/on_gain() forge_objectives() rift_ability = new() + locate_rift_ability = new() owner.set_assigned_role(SSjob.get_job_type(/datum/job/space_dragon)) return ..() @@ -80,6 +83,7 @@ antag.add_faction(FACTION_CARP) // Give the ability over if we have one rift_ability?.Grant(antag) + locate_rift_ability?.Grant(antag) wavespeak = antag.AddComponent( \ /datum/component/mind_linker, \ network_name = "Wavespeak", \ @@ -96,12 +100,14 @@ UnregisterSignal(antag, COMSIG_LIVING_DEATH) antag.remove_faction(FACTION_CARP) rift_ability?.Remove(antag) + locate_rift_ability?.Remove(antag) QDEL_NULL(wavespeak) /datum/antagonist/space_dragon/Destroy() rift_list = null carp = null QDEL_NULL(rift_ability) + QDEL_NULL(locate_rift_ability) QDEL_NULL(wavespeak) chosen_rift_areas.Cut() return ..() diff --git a/icons/mob/actions/actions_space_dragon.dmi b/icons/mob/actions/actions_space_dragon.dmi index 48d73fd6f47a039ae20d651548f5754704352525..60b57615a0359fc315e99dd2e6d05513c062a9c0 100644 GIT binary patch literal 2257 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