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
🆑

add: Space Dragons have a new ability to locate the areas they need to
create rifts in.

/🆑
This commit is contained in:
Leland Kemble
2026-04-15 10:58:25 +12:00
committed by GitHub
parent db55933767
commit 68dd7ae4a6
3 changed files with 64 additions and 5 deletions
@@ -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
@@ -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 ..()