mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 05:00:55 +01:00
* Re-pr of #70522 "Space Dragon Update: Up Close and Personal" * Update mind_linker.dm * Update hivemind.dm --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: lessthanthree <83487515+lessthnthree@users.noreply.github.com>
This commit is contained in:
co-authored by
MrMelbert
lessthanthree
parent
856e059850
commit
33adb63d55
@@ -10,10 +10,6 @@
|
||||
var/network_name = "Mind Link"
|
||||
/// The color of the network when talking in chat
|
||||
var/chat_color
|
||||
/// The message sent to someone when linked up.
|
||||
var/link_message
|
||||
/// The message sent to someone when unlinked.
|
||||
var/unlink_message
|
||||
/// A list of all signals that will call qdel() on our component if triggered. Optional.
|
||||
var/list/signals_which_destroy_us
|
||||
/// A callback invoked after an unlink is done. Optional.
|
||||
@@ -24,25 +20,25 @@
|
||||
var/speech_action_icon_state = "link_speech"
|
||||
/// The icon background for the speech action handed out.
|
||||
var/speech_action_background_icon_state = "bg_alien"
|
||||
/// The master's linking action, which allows them to link people to the network.
|
||||
var/datum/action/linker_action
|
||||
/// The border icon state for the speech action handed out.
|
||||
var/speech_action_overlay_state = "bg_alien_border"
|
||||
/// The master's speech action. The owner of the link shouldn't lose this as long as the link remains.
|
||||
var/datum/action/innate/linked_speech/master_speech
|
||||
VAR_FINAL/datum/action/innate/linked_speech/master_speech
|
||||
/// An assoc list of [mob/living]s to [datum/action/innate/linked_speech]s. All the mobs that are linked to our network.
|
||||
var/list/mob/living/linked_mobs = list()
|
||||
VAR_FINAL/list/mob/living/linked_mobs = list()
|
||||
|
||||
/datum/component/mind_linker/Initialize(
|
||||
// Customization related settings
|
||||
network_name = "Mind Link",
|
||||
chat_color = "#008CA2",
|
||||
linker_action_path,
|
||||
link_message,
|
||||
unlink_message,
|
||||
signals_which_destroy_us,
|
||||
datum/callback/post_unlink_callback,
|
||||
speech_action_icon = 'icons/mob/actions/actions_slime.dmi',
|
||||
speech_action_icon_state = "link_speech",
|
||||
speech_action_background_icon_state = "bg_alien",
|
||||
)
|
||||
speech_action_overlay_state = "bg_alien_border",
|
||||
// Optional
|
||||
signals_which_destroy_us,
|
||||
datum/callback/post_unlink_callback,
|
||||
)
|
||||
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
@@ -51,8 +47,9 @@
|
||||
|
||||
src.network_name = network_name
|
||||
src.chat_color = chat_color
|
||||
src.link_message = link_message || "You are now connected to [owner.real_name]'s [network_name]."
|
||||
src.unlink_message = unlink_message || "You are no longer connected to [owner.real_name]'s [network_name]."
|
||||
src.speech_action_icon = speech_action_icon
|
||||
src.speech_action_icon_state = speech_action_icon_state
|
||||
src.speech_action_background_icon_state = speech_action_background_icon_state
|
||||
|
||||
if(islist(signals_which_destroy_us))
|
||||
src.signals_which_destroy_us = signals_which_destroy_us
|
||||
@@ -63,12 +60,6 @@
|
||||
src.speech_action_icon_state = speech_action_icon_state
|
||||
src.speech_action_background_icon_state = speech_action_background_icon_state
|
||||
|
||||
if(ispath(linker_action_path))
|
||||
linker_action = new linker_action_path(src)
|
||||
linker_action.Grant(owner)
|
||||
else
|
||||
stack_trace("[type] was created without a valid linker_action_path. No one will be able to link to it.")
|
||||
|
||||
/* ORIGINAL CODE
|
||||
master_speech = new(src)
|
||||
master_speech.Grant(owner)
|
||||
@@ -80,13 +71,10 @@
|
||||
master_speech.Grant(owner)
|
||||
//SKYRAT EDIT END
|
||||
|
||||
to_chat(owner, span_boldnotice("You establish a [network_name], allowing you to link minds to communicate telepathically."))
|
||||
|
||||
/datum/component/mind_linker/Destroy(force, silent)
|
||||
for(var/mob/living/remaining_mob as anything in linked_mobs)
|
||||
unlink_mob(remaining_mob)
|
||||
linked_mobs.Cut()
|
||||
QDEL_NULL(linker_action)
|
||||
QDEL_NULL(master_speech)
|
||||
QDEL_NULL(post_unlink_callback)
|
||||
return ..()
|
||||
@@ -127,20 +115,19 @@
|
||||
if(to_link == owner)
|
||||
return FALSE
|
||||
|
||||
to_chat(to_link, span_notice(link_message))
|
||||
to_chat(owner, span_notice("You connect [to_link]'s mind to your [network_name]."))
|
||||
|
||||
for(var/mob/living/other_link as anything in linked_mobs)
|
||||
to_chat(other_link, span_notice("You feel a new presence within [owner.real_name]'s [network_name]."))
|
||||
|
||||
var/datum/action/innate/linked_speech/new_link = new(src)
|
||||
new_link.Grant(to_link)
|
||||
|
||||
linked_mobs[to_link] = new_link
|
||||
RegisterSignals(to_link, list(COMSIG_LIVING_DEATH, COMSIG_PARENT_QDELETING, COMSIG_MINDSHIELD_IMPLANTED), PROC_REF(unlink_mob))
|
||||
RegisterSignals(to_link, list(COMSIG_LIVING_DEATH, COMSIG_PARENT_QDELETING), PROC_REF(sig_unlink_mob))
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/component/mind_linker/proc/sig_unlink_mob(mob/living/to_unlink)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
unlink_mob(to_unlink)
|
||||
|
||||
/**
|
||||
* Unlinks [to_unlink] from our network, deleting their speech action
|
||||
* and cleaning up anything involved.
|
||||
@@ -148,25 +135,17 @@
|
||||
* Also invokes post_unlink_callback, if supplied.
|
||||
*/
|
||||
/datum/component/mind_linker/proc/unlink_mob(mob/living/to_unlink)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!linked_mobs[to_unlink])
|
||||
return
|
||||
return FALSE
|
||||
|
||||
to_chat(to_unlink, span_warning(unlink_message))
|
||||
post_unlink_callback?.Invoke(to_unlink)
|
||||
|
||||
UnregisterSignal(to_unlink, list(COMSIG_LIVING_DEATH, COMSIG_PARENT_QDELETING, COMSIG_MINDSHIELD_IMPLANTED))
|
||||
UnregisterSignal(to_unlink, list(COMSIG_LIVING_DEATH, COMSIG_PARENT_QDELETING))
|
||||
|
||||
var/datum/action/innate/linked_speech/old_link = linked_mobs[to_unlink]
|
||||
linked_mobs -= to_unlink
|
||||
qdel(old_link)
|
||||
|
||||
var/mob/living/owner = parent
|
||||
|
||||
to_chat(owner, span_warning("You feel someone disconnect from your [network_name]."))
|
||||
for(var/mob/living/other_link as anything in linked_mobs)
|
||||
to_chat(other_link, span_warning("You feel a pressence disappear from [owner.real_name]'s [network_name]."))
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Signal proc sent from any signals given to us initialize.
|
||||
@@ -181,6 +160,84 @@
|
||||
|
||||
qdel(src)
|
||||
|
||||
/// Subtype of mind linker (I know) which is more active rather than passive,
|
||||
/// which involves the master linking people manually rather than people being added automatically.
|
||||
/datum/component/mind_linker/active_linking
|
||||
/// The message sent to someone when linked up.
|
||||
var/link_message
|
||||
/// The message sent to someone when unlinked.
|
||||
var/unlink_message
|
||||
/// The master's linking action, which allows them to link people to the network.
|
||||
VAR_FINAL/datum/action/linker_action
|
||||
|
||||
/datum/component/mind_linker/active_linking/Initialize(
|
||||
// Customization related settings
|
||||
network_name = "Mind Link",
|
||||
chat_color = "#008CA2",
|
||||
speech_action_icon = 'icons/mob/actions/actions_slime.dmi',
|
||||
speech_action_icon_state = "link_speech",
|
||||
speech_action_background_icon_state = "bg_alien",
|
||||
speech_action_overlay_state = "bg_alien_border",
|
||||
// Optional
|
||||
signals_which_destroy_us,
|
||||
datum/callback/post_unlink_callback,
|
||||
// Optional for this subtype
|
||||
link_message,
|
||||
unlink_message,
|
||||
// Required for this subtype
|
||||
linker_action_path,
|
||||
)
|
||||
|
||||
. = ..()
|
||||
if(. == COMPONENT_INCOMPATIBLE)
|
||||
return
|
||||
|
||||
var/mob/living/owner = parent
|
||||
src.link_message = link_message || "You are now connected to [owner.real_name]'s [network_name]."
|
||||
src.unlink_message = unlink_message || "You are no longer connected to [owner.real_name]'s [network_name]."
|
||||
|
||||
if(ispath(linker_action_path))
|
||||
linker_action = new linker_action_path(src)
|
||||
linker_action.Grant(owner)
|
||||
else
|
||||
stack_trace("[type] was created without a valid linker_action_path. No one will be able to link to it.")
|
||||
|
||||
to_chat(owner, span_boldnotice("You establish a [network_name], allowing you to link minds to communicate telepathically."))
|
||||
|
||||
/datum/component/mind_linker/active_linking/Destroy()
|
||||
QDEL_NULL(linker_action)
|
||||
return ..()
|
||||
|
||||
/datum/component/mind_linker/active_linking/link_mob(mob/living/to_link)
|
||||
if(HAS_TRAIT(to_link, TRAIT_MINDSHIELD)) // Mindshield implant - no dice
|
||||
return FALSE
|
||||
if(to_link.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0))
|
||||
return FALSE
|
||||
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
RegisterSignal(to_link, COMSIG_MINDSHIELD_IMPLANTED, PROC_REF(sig_unlink_mob))
|
||||
var/mob/living/owner = parent
|
||||
to_chat(to_link, span_notice(link_message))
|
||||
to_chat(owner, span_notice("You connect [to_link]'s mind to your [network_name]."))
|
||||
for(var/mob/living/other_link as anything in linked_mobs)
|
||||
to_chat(other_link, span_notice("You feel a new presence within [owner.real_name]'s [network_name]."))
|
||||
|
||||
/datum/component/mind_linker/active_linking/unlink_mob(mob/living/to_unlink)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
|
||||
UnregisterSignal(to_unlink, COMSIG_MINDSHIELD_IMPLANTED)
|
||||
var/mob/living/owner = parent
|
||||
to_chat(to_unlink, span_warning(unlink_message))
|
||||
to_chat(owner, span_warning("You feel someone disconnect from your [network_name]."))
|
||||
for(var/mob/living/other_link as anything in linked_mobs)
|
||||
to_chat(other_link, span_warning("You feel a pressence disappear from [owner.real_name]'s [network_name]."))
|
||||
|
||||
// Used in mind linker to talk to everyone in the network.
|
||||
/datum/action/innate/linked_speech
|
||||
name = "Mind Link Speech"
|
||||
desc = "Send a psychic message to everyone connected to your Link."
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Proximity monitor applies forced gravity to all turfs in range.
|
||||
/datum/proximity_monitor/advanced/gravity
|
||||
edge_is_a_field = TRUE
|
||||
var/gravity_value = 0
|
||||
@@ -10,9 +11,10 @@
|
||||
|
||||
/datum/proximity_monitor/advanced/gravity/setup_field_turf(turf/target)
|
||||
. = ..()
|
||||
if (isnull(modified_turfs[target]))
|
||||
if(!isnull(modified_turfs[target]))
|
||||
return
|
||||
if(HAS_TRAIT(target, TRAIT_FORCED_GRAVITY))
|
||||
return
|
||||
|
||||
target.AddElement(/datum/element/forced_gravity, gravity_value)
|
||||
modified_turfs[target] = gravity_value
|
||||
|
||||
@@ -20,5 +22,44 @@
|
||||
. = ..()
|
||||
if(isnull(modified_turfs[target]))
|
||||
return
|
||||
target.RemoveElement(/datum/element/forced_gravity, modified_turfs[target])
|
||||
var/grav_value = modified_turfs[target] || 0
|
||||
target.RemoveElement(/datum/element/forced_gravity, grav_value)
|
||||
modified_turfs -= target
|
||||
|
||||
// Subtype which pops up a balloon alert when a mob enters the field
|
||||
/datum/proximity_monitor/advanced/gravity/warns_on_entrance
|
||||
/// This is a list of mob refs that have recently entered the field.
|
||||
/// We track it so that we don't spam a player who is stutter stepping in and out with balloon alerts.
|
||||
var/list/recently_warned
|
||||
|
||||
/datum/proximity_monitor/advanced/gravity/warns_on_entrance/setup_field_turf(turf/target)
|
||||
. = ..()
|
||||
for(var/mob/living/guy in target)
|
||||
warn_mob(guy, target)
|
||||
|
||||
/datum/proximity_monitor/advanced/gravity/warns_on_entrance/cleanup_field_turf(turf/target)
|
||||
. = ..()
|
||||
for(var/mob/living/guy in target)
|
||||
warn_mob(guy, target)
|
||||
|
||||
/datum/proximity_monitor/advanced/gravity/warns_on_entrance/field_edge_crossed(atom/movable/movable, turf/location)
|
||||
. = ..()
|
||||
if(isliving(movable))
|
||||
warn_mob(movable, location)
|
||||
|
||||
/datum/proximity_monitor/advanced/gravity/warns_on_entrance/field_edge_uncrossed(atom/movable/movable, turf/location)
|
||||
. = ..()
|
||||
if(isliving(movable))
|
||||
warn_mob(movable, location)
|
||||
|
||||
/datum/proximity_monitor/advanced/gravity/warns_on_entrance/proc/warn_mob(mob/living/to_warn, turf/location)
|
||||
var/mob_ref_key = REF(to_warn)
|
||||
if(mob_ref_key in recently_warned)
|
||||
return
|
||||
|
||||
location.balloon_alert(to_warn, "gravity [(location in modified_turfs) ? "shifts!" : "reverts..."]")
|
||||
LAZYADD(recently_warned, mob_ref_key)
|
||||
addtimer(CALLBACK(src, PROC_REF(clear_recent_warning), mob_ref_key), 3 SECONDS)
|
||||
|
||||
/datum/proximity_monitor/advanced/gravity/warns_on_entrance/proc/clear_recent_warning(mob_ref_key)
|
||||
LAZYREMOVE(recently_warned, mob_ref_key)
|
||||
|
||||
@@ -574,8 +574,6 @@
|
||||
|
||||
var/mob/living/simple_animal/hostile/space_dragon/S = new (pick(spawn_locs))
|
||||
player_mind.transfer_to(S)
|
||||
player_mind.set_assigned_role(SSjob.GetJobType(/datum/job/space_dragon))
|
||||
player_mind.special_role = ROLE_SPACE_DRAGON
|
||||
player_mind.add_antag_datum(/datum/antagonist/space_dragon)
|
||||
|
||||
playsound(S, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1)
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
if(!dragon)
|
||||
return
|
||||
var/area/rift_location = get_area(owner)
|
||||
if(!(rift_location.area_flags & VALID_TERRITORY))
|
||||
to_chat(owner, span_warning("You can't summon a rift here! Try summoning somewhere secure within the station!"))
|
||||
if(!(rift_location in dragon.chosen_rift_areas))
|
||||
owner.balloon_alert(owner, "can't summon a rift here!")
|
||||
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)
|
||||
to_chat(owner, span_warning("You've already summoned a rift in this area! You have to summon again somewhere else!"))
|
||||
owner.balloon_alert(owner, "already summoned a rift here!")
|
||||
return
|
||||
var/turf/rift_spawn_turf = get_turf(dragon)
|
||||
if(isopenspaceturf(rift_spawn_turf))
|
||||
@@ -64,7 +64,7 @@
|
||||
light_color = LIGHT_COLOR_PURPLE
|
||||
light_range = 10
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
density = TRUE
|
||||
plane = MASSIVE_OBJ_PLANE
|
||||
/// The amount of time the rift has charged for.
|
||||
var/time_charged = 0
|
||||
@@ -77,11 +77,13 @@
|
||||
/// Current charge state of the rift.
|
||||
var/charge_state = CHARGE_ONGOING
|
||||
/// The interval for adding additional space carp spawns to the rift.
|
||||
var/carp_interval = 60
|
||||
var/carp_interval = 45
|
||||
/// The time since an extra carp was added to the ghost role spawning pool.
|
||||
var/last_carp_inc = 0
|
||||
/// A list of all the ckeys which have used this carp rift to spawn in as carps.
|
||||
var/list/ckey_list = list()
|
||||
/// Gravity aura for the rift, makes all turfs nearby forced grav.
|
||||
var/datum/proximity_monitor/advanced/gravity/warns_on_entrance/gravity_aura
|
||||
|
||||
/datum/armor/structure_carp_rift
|
||||
energy = 100
|
||||
@@ -98,14 +100,25 @@
|
||||
|
||||
AddComponent( \
|
||||
/datum/component/aura_healing, \
|
||||
range = 0, \
|
||||
range = 1, \
|
||||
simple_heal = 5, \
|
||||
limit_to_trait = TRAIT_HEALS_FROM_CARP_RIFTS, \
|
||||
healing_color = COLOR_BLUE, \
|
||||
)
|
||||
|
||||
gravity_aura = new(
|
||||
/* host = */src,
|
||||
/* range = */15,
|
||||
/* ignore_if_not_on_turf = */TRUE,
|
||||
/* gravity = */1,
|
||||
)
|
||||
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/structure/carp_rift/Destroy()
|
||||
QDEL_NULL(gravity_aura)
|
||||
return ..()
|
||||
|
||||
// Carp rifts always take heavy explosion damage. Discourages the use of maxcaps
|
||||
// and favours more weaker explosives to destroy the portal
|
||||
// as they have the same effect on the portal.
|
||||
@@ -183,7 +196,7 @@
|
||||
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.", "Central Command Wildlife Observations")
|
||||
priority_announce("Spatial object has reached peak energy charge in [initial(A.name)], please stand-by.", "Central Command Wildlife Observations", has_important_message = TRUE)
|
||||
atom_integrity = INFINITY
|
||||
icon_state = "carp_rift_charged"
|
||||
set_light_color(LIGHT_COLOR_DIM_YELLOW)
|
||||
@@ -230,12 +243,13 @@
|
||||
to_chat(user, span_warning("The rift already summoned enough carp!"))
|
||||
return FALSE
|
||||
|
||||
if(!dragon)
|
||||
if(isnull(dragon))
|
||||
return
|
||||
var/mob/living/newcarp = new dragon.minion_to_spawn(loc)
|
||||
newcarp.faction = dragon.owner.current.faction
|
||||
newcarp.AddElement(/datum/element/nerfed_pulling, GLOB.typecache_general_bad_things_to_easily_move)
|
||||
newcarp.AddElement(/datum/element/prevent_attacking_of_types, GLOB.typecache_general_bad_hostile_attack_targets, "this tastes awful!")
|
||||
dragon.wavespeak?.link_mob(newcarp)
|
||||
|
||||
if(!is_listed)
|
||||
ckey_list += user.ckey
|
||||
|
||||
@@ -21,9 +21,13 @@
|
||||
/// Whether or not Space Dragon has completed their objective, and thus triggered the ending sequence.
|
||||
var/objective_complete = FALSE
|
||||
/// What mob to spawn from ghosts using this dragon's rifts
|
||||
var/minion_to_spawn = /mob/living/basic/carp
|
||||
var/minion_to_spawn = /mob/living/basic/carp/advanced
|
||||
/// What AI mobs to spawn from this dragon's rifts
|
||||
var/ai_to_spawn = /mob/living/basic/carp
|
||||
/// Wavespeak mind linker, to allow telepathy between dragon and carps
|
||||
var/datum/component/mind_linker/wavespeak
|
||||
/// What areas are we allowed to place rifts in?
|
||||
var/list/chosen_rift_areas = list()
|
||||
|
||||
/datum/antagonist/space_dragon/greet()
|
||||
. = ..()
|
||||
@@ -33,16 +37,42 @@
|
||||
Today, we will snuff out one of those lights.</b>")
|
||||
to_chat(owner, span_boldwarning("You have five minutes to find a safe location to place down the first rift. If you take longer than five minutes to place a rift, you will be returned from whence you came."))
|
||||
owner.announce_objectives()
|
||||
SEND_SOUND(owner.current, sound('sound/magic/demon_attack1.ogg'))
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/magic/demon_attack1.ogg', 80)
|
||||
|
||||
/datum/antagonist/space_dragon/forge_objectives()
|
||||
var/static/list/area/allowed_areas
|
||||
if(!allowed_areas)
|
||||
// Areas that will prove a challeng for the dragon and are provocative to the crew.
|
||||
allowed_areas = typecacheof(list(
|
||||
/area/station/command,
|
||||
/area/station/engineering,
|
||||
/area/station/science,
|
||||
/area/station/security,
|
||||
))
|
||||
|
||||
var/list/possible_areas = typecache_filter_list(get_sorted_areas(), allowed_areas)
|
||||
for(var/area/possible_area as anything in possible_areas)
|
||||
if(initial(possible_area.outdoors) || !(possible_area.area_flags & VALID_TERRITORY))
|
||||
possible_areas -= possible_area
|
||||
|
||||
for(var/i in 1 to 5)
|
||||
chosen_rift_areas += pick_n_take(possible_areas)
|
||||
|
||||
var/datum/objective/summon_carp/summon = new
|
||||
summon.dragon = src
|
||||
objectives += summon
|
||||
summon.owner = owner
|
||||
summon.update_explanation_text()
|
||||
|
||||
/datum/antagonist/space_dragon/on_gain()
|
||||
forge_objectives()
|
||||
rift_ability = new()
|
||||
owner.special_role = ROLE_SPACE_DRAGON
|
||||
owner.set_assigned_role(SSjob.GetJobType(/datum/job/space_dragon))
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/space_dragon/on_removal()
|
||||
owner.special_role = null
|
||||
owner.set_assigned_role(SSjob.GetJobType(/datum/job/unassigned))
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/space_dragon/apply_innate_effects(mob/living/mob_override)
|
||||
@@ -52,6 +82,15 @@
|
||||
antag.faction |= FACTION_CARP
|
||||
// Give the ability over if we have one
|
||||
rift_ability?.Grant(antag)
|
||||
wavespeak = antag.AddComponent( \
|
||||
/datum/component/mind_linker, \
|
||||
network_name = "Wavespeak", \
|
||||
chat_color = "#635BAF", \
|
||||
signals_which_destroy_us = list(COMSIG_LIVING_DEATH), \
|
||||
speech_action_icon = 'icons/mob/actions/actions_space_dragon.dmi', \
|
||||
speech_action_icon_state = "wavespeak", \
|
||||
)
|
||||
RegisterSignal(wavespeak, COMSIG_PARENT_QDELETING, PROC_REF(clear_wavespeak))
|
||||
|
||||
/datum/antagonist/space_dragon/remove_innate_effects(mob/living/mob_override)
|
||||
var/mob/living/antag = mob_override || owner.current
|
||||
@@ -59,11 +98,14 @@
|
||||
UnregisterSignal(antag, COMSIG_LIVING_DEATH)
|
||||
antag.faction -= FACTION_CARP
|
||||
rift_ability?.Remove(antag)
|
||||
QDEL_NULL(wavespeak)
|
||||
|
||||
/datum/antagonist/space_dragon/Destroy()
|
||||
rift_list = null
|
||||
carp = null
|
||||
QDEL_NULL(rift_ability)
|
||||
QDEL_NULL(wavespeak)
|
||||
chosen_rift_areas.Cut()
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/space_dragon/get_preview_icon()
|
||||
@@ -77,6 +119,10 @@
|
||||
|
||||
return icon
|
||||
|
||||
/datum/antagonist/space_dragon/proc/clear_wavespeak()
|
||||
SIGNAL_HANDLER
|
||||
wavespeak = null
|
||||
|
||||
/**
|
||||
* Checks to see if we need to do anything with the current state of the dragon's rifts.
|
||||
*
|
||||
@@ -132,11 +178,10 @@
|
||||
objective_complete = TRUE
|
||||
permanant_empower()
|
||||
var/datum/objective/summon_carp/main_objective = locate() in objectives
|
||||
if(main_objective)
|
||||
main_objective.completed = TRUE
|
||||
main_objective?.completed = TRUE
|
||||
priority_announce("A large amount of lifeforms have been detected approaching [station_name()] at extreme speeds. \
|
||||
Remaining crew are advised to evacuate as soon as possible.", "Central Command Wildlife Observations")
|
||||
sound_to_playing_players('sound/creatures/space_dragon_roar.ogg')
|
||||
Remaining crew are advised to evacuate as soon as possible.", "Central Command Wildlife Observations", has_important_message = TRUE)
|
||||
sound_to_playing_players('sound/creatures/space_dragon_roar.ogg', volume = 75)
|
||||
for(var/obj/structure/carp_rift/rift as anything in rift_list)
|
||||
rift.carp_stored = 999999
|
||||
rift.time_charged = rift.max_charge
|
||||
@@ -177,8 +222,19 @@
|
||||
owner.current.remove_movespeed_modifier(/datum/movespeed_modifier/dragon_rage)
|
||||
|
||||
/datum/objective/summon_carp
|
||||
var/datum/antagonist/space_dragon/dragon
|
||||
explanation_text = "Summon and protect the rifts to flood the station with carp."
|
||||
explanation_text = "Summon 3 rifts in order to flood the station with carp."
|
||||
|
||||
/datum/objective/summon_carp/update_explanation_text()
|
||||
var/datum/antagonist/space_dragon/dragon_owner = owner.has_antag_datum(/datum/antagonist/space_dragon)
|
||||
if(isnull(dragon_owner))
|
||||
return
|
||||
|
||||
var/list/converted_names = list()
|
||||
for(var/area/possible_area as anything in dragon_owner.chosen_rift_areas)
|
||||
converted_names += possible_area.get_original_area_name()
|
||||
|
||||
explanation_text = initial(explanation_text)
|
||||
explanation_text += " Your possible rift locations are: [english_list(converted_names)]"
|
||||
|
||||
/datum/antagonist/space_dragon/roundend_report()
|
||||
var/list/parts = list()
|
||||
@@ -197,7 +253,17 @@
|
||||
parts += "<span class='greentext big'>The [name] was successful!</span>"
|
||||
else
|
||||
parts += "<span class='redtext big'>The [name] has failed!</span>"
|
||||
if(carp.len)
|
||||
parts += "<span class='header'>The [name] was assisted by:</span>"
|
||||
parts += printplayerlist(carp)
|
||||
|
||||
if(length(carp))
|
||||
parts += "<br><span class='header'>The [name] was assisted by:</span>"
|
||||
parts += "<ul class='playerlist'>"
|
||||
var/list/players_to_carp_taken = list()
|
||||
for(var/datum/mind/carpy as anything in carp)
|
||||
players_to_carp_taken[carpy.key] += 1
|
||||
var/list = ""
|
||||
for(var/carp_user in players_to_carp_taken)
|
||||
list += "<li><b>[carp_user]<b>, who played <b>[players_to_carp_taken[carp_user]]</b> space carps.</li>"
|
||||
parts += list
|
||||
parts += "</ul>"
|
||||
|
||||
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
|
||||
var/mob/living/simple_animal/hostile/space_dragon/dragon = new (spawn_location)
|
||||
dragon.key = key
|
||||
dragon.mind.set_assigned_role(SSjob.GetJobType(/datum/job/space_dragon))
|
||||
dragon.mind.special_role = ROLE_SPACE_DRAGON
|
||||
dragon.mind.add_antag_datum(/datum/antagonist/space_dragon)
|
||||
playsound(dragon, 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1)
|
||||
message_admins("[ADMIN_LOOKUPFLW(dragon)] has been made into a Space Dragon by an event.")
|
||||
|
||||
@@ -256,4 +256,8 @@
|
||||
disk_overlay = mutable_appearance('icons/mob/simple/carp.dmi', "disk_overlay")
|
||||
new_overlays += disk_overlay
|
||||
|
||||
/mob/living/basic/carp/advanced
|
||||
health = 40
|
||||
obj_damage = 15
|
||||
|
||||
#undef RARE_CAYENNE_CHANCE
|
||||
|
||||
@@ -695,10 +695,11 @@
|
||||
project_action = new(src)
|
||||
project_action.Grant(grant_to)
|
||||
|
||||
grant_to.AddComponent(/datum/component/mind_linker, \
|
||||
grant_to.AddComponent( \
|
||||
/datum/component/mind_linker/active_linking, \
|
||||
network_name = "Slime Link", \
|
||||
linker_action_path = /datum/action/innate/link_minds, \
|
||||
signals_which_destroy_us = list(COMSIG_SPECIES_LOSS), \
|
||||
linker_action_path = /datum/action/innate/link_minds, \
|
||||
)
|
||||
|
||||
//Species datums don't normally implement destroy, but JELLIES SUCK ASS OUT OF A STEEL STRAW
|
||||
|
||||
@@ -73,14 +73,16 @@
|
||||
|
||||
var/on_unlink_message = "Your mind shatters as [src]'s Mansus Link leaves your mind."
|
||||
|
||||
AddComponent(/datum/component/mind_linker, \
|
||||
AddComponent( \
|
||||
/datum/component/mind_linker/active_linking, \
|
||||
network_name = "Mansus Link", \
|
||||
chat_color = "#568b00", \
|
||||
post_unlink_callback = CALLBACK(src, PROC_REF(after_unlink)), \
|
||||
speech_action_background_icon_state = "bg_heretic", \
|
||||
speech_action_overlay_state = "bg_heretic_border", \
|
||||
linker_action_path = /datum/action/cooldown/spell/pointed/manse_link, \
|
||||
link_message = on_link_message, \
|
||||
unlink_message = on_unlink_message, \
|
||||
post_unlink_callback = CALLBACK(src, PROC_REF(after_unlink)), \
|
||||
speech_action_background_icon_state = "bg_heretic", \
|
||||
)
|
||||
|
||||
/mob/living/simple_animal/hostile/heretic_summon/raw_prophet/attack_animal(mob/living/simple_animal/user, list/modifiers)
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
name = "Space Dragon"
|
||||
desc = "A vile, leviathan-esque creature that flies in the most unnatural way. Looks slightly similar to a space carp."
|
||||
gender = NEUTER
|
||||
maxHealth = 320
|
||||
health = 320
|
||||
maxHealth = 400
|
||||
health = 400
|
||||
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0.5, OXY = 1)
|
||||
combat_mode = TRUE
|
||||
speed = 0
|
||||
@@ -283,7 +283,7 @@
|
||||
for(var/obj/machinery/door/D in T.contents)
|
||||
if(D.density)
|
||||
return
|
||||
delayFire += 1.5
|
||||
delayFire += 1.0
|
||||
addtimer(CALLBACK(src, PROC_REF(dragon_fire_line), T), delayFire)
|
||||
|
||||
/**
|
||||
@@ -295,25 +295,52 @@
|
||||
* Arguments:
|
||||
* * turf/T - The turf to trigger the effects on.
|
||||
*/
|
||||
/mob/living/simple_animal/hostile/space_dragon/proc/dragon_fire_line(turf/T)
|
||||
/mob/living/simple_animal/hostile/space_dragon/proc/dragon_fire_line(turf/fire_turf)
|
||||
var/list/hit_list = list()
|
||||
hit_list += src
|
||||
new /obj/effect/hotspot(T)
|
||||
T.hotspot_expose(700,50,1)
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(L in hit_list)
|
||||
new /obj/effect/hotspot(fire_turf)
|
||||
fire_turf.hotspot_expose(700,50,1)
|
||||
for(var/mob/living/living_target in fire_turf.contents)
|
||||
if(living_target.faction_check_mob(src) && living_target != src)
|
||||
hit_list += living_target
|
||||
start_carp_speedboost(living_target)
|
||||
if(living_target in hit_list)
|
||||
continue
|
||||
if(L.mind?.has_antag_datum(/datum/antagonist/space_carp))
|
||||
if(living_target.mind?.has_antag_datum(/datum/antagonist/space_carp))
|
||||
continue
|
||||
hit_list += L
|
||||
L.adjustFireLoss(30)
|
||||
to_chat(L, span_userdanger("You're hit by [src]'s fire breath!"))
|
||||
hit_list += living_target
|
||||
living_target.adjustFireLoss(30)
|
||||
to_chat(living_target, span_userdanger("You're hit by [src]'s fire breath!"))
|
||||
// deals damage to mechs
|
||||
for(var/obj/vehicle/sealed/mecha/M in T.contents)
|
||||
if(M in hit_list)
|
||||
for(var/obj/vehicle/sealed/mecha/mech_target in fire_turf.contents)
|
||||
if(mech_target in hit_list)
|
||||
continue
|
||||
hit_list += M
|
||||
M.take_damage(50, BRUTE, MELEE, 1)
|
||||
hit_list += mech_target
|
||||
mech_target.take_damage(50, BRUTE, MELEE, 1)
|
||||
|
||||
/**
|
||||
* Applies the speed boost to carps when hit by space dragon's flame breath
|
||||
*
|
||||
* Applies the dragon rage effect to carps temporarily, giving them a glow and a speed boost.
|
||||
* This lasts for 8 seconds.
|
||||
* Arguments:
|
||||
* * mob/living/target - The carp being affected.
|
||||
*/
|
||||
/mob/living/simple_animal/hostile/space_dragon/proc/start_carp_speedboost(mob/living/target)
|
||||
target.add_filter("anger_glow", 3, list("type" = "outline", "color" = "#ff330030", "size" = 2))
|
||||
target.add_movespeed_modifier(/datum/movespeed_modifier/dragon_rage)
|
||||
addtimer(CALLBACK(src, PROC_REF(end_carp_speedboost), target), 8 SECONDS)
|
||||
|
||||
/**
|
||||
* Remove the speed boost from carps when hit by space dragon's flame breath
|
||||
*
|
||||
* Removes the dragon rage effect from carps, removing their glow and speed boost.
|
||||
* Arguments:
|
||||
* * mob/living/target - The carp being affected.
|
||||
*/
|
||||
/mob/living/simple_animal/hostile/space_dragon/proc/end_carp_speedboost(mob/living/target)
|
||||
target.remove_filter("anger_glow")
|
||||
target.remove_movespeed_modifier(/datum/movespeed_modifier/dragon_rage)
|
||||
|
||||
/**
|
||||
* Handles consuming and storing consumed things inside Space Dragon
|
||||
@@ -325,7 +352,7 @@
|
||||
*/
|
||||
/mob/living/simple_animal/hostile/space_dragon/proc/eat(atom/movable/A)
|
||||
if(A && A.loc != src)
|
||||
playsound(src, 'sound/magic/demon_attack1.ogg', 100, TRUE)
|
||||
playsound(src, 'sound/magic/demon_attack1.ogg', 60, TRUE)
|
||||
visible_message(span_warning("[src] swallows [A] whole!"))
|
||||
A.forceMove(src)
|
||||
return TRUE
|
||||
@@ -357,7 +384,7 @@
|
||||
/mob/living/simple_animal/hostile/space_dragon/proc/useGust(timer)
|
||||
if(timer != 10)
|
||||
pixel_y = pixel_y + 2;
|
||||
addtimer(CALLBACK(src, PROC_REF(useGust), timer + 1), 1.5)
|
||||
addtimer(CALLBACK(src, PROC_REF(useGust), timer + 1), 1.2)
|
||||
return
|
||||
pixel_y = 0
|
||||
icon_state = "spacedragon_gust_2"
|
||||
@@ -366,20 +393,22 @@
|
||||
overlay.appearance_flags = RESET_COLOR
|
||||
add_overlay(overlay)
|
||||
playsound(src, 'sound/effects/gravhit.ogg', 100, TRUE)
|
||||
var/gust_locs = spiral_range_turfs(gust_distance, get_turf(src))
|
||||
var/list/hit_things = list()
|
||||
for(var/turf/T in gust_locs)
|
||||
for(var/mob/living/L in T.contents)
|
||||
if(L == src)
|
||||
continue
|
||||
hit_things += L
|
||||
visible_message(span_boldwarning("[L] is knocked back by the gust!"))
|
||||
to_chat(L, span_userdanger("You're knocked back by the gust!"))
|
||||
var/dir_to_target = get_dir(get_turf(src), get_turf(L))
|
||||
var/throwtarget = get_edge_target_turf(target, dir_to_target)
|
||||
L.safe_throw_at(throwtarget, 10, 1, src)
|
||||
L.Paralyze(50)
|
||||
for (var/mob/living/candidate in view(gust_distance, src))
|
||||
if(candidate == src || candidate.faction_check_mob(src))
|
||||
continue
|
||||
visible_message(span_boldwarning("[candidate] is knocked back by the gust!"))
|
||||
to_chat(candidate, span_userdanger("You're knocked back by the gust!"))
|
||||
var/dir_to_target = get_dir(get_turf(src), get_turf(candidate))
|
||||
var/throwtarget = get_edge_target_turf(target, dir_to_target)
|
||||
candidate.safe_throw_at(throwtarget, 10, 1, src)
|
||||
candidate.Paralyze(50)
|
||||
addtimer(CALLBACK(src, PROC_REF(reset_status)), 4 + ((tiredness * tiredness_mult) / 10))
|
||||
tiredness = tiredness + (gust_tiredness * tiredness_mult)
|
||||
|
||||
/mob/living/simple_animal/hostile/space_dragon/spawn_with_antag
|
||||
|
||||
/mob/living/simple_animal/hostile/space_dragon/spawn_with_antag/mind_initialize()
|
||||
. = ..()
|
||||
mind.add_antag_datum(/datum/antagonist/space_dragon)
|
||||
|
||||
#undef DARKNESS_THRESHOLD
|
||||
|
||||
@@ -262,6 +262,7 @@
|
||||
/mob/living/simple_animal/hostile/smspider,
|
||||
/mob/living/simple_animal/hostile/smspider/overcharged,
|
||||
/mob/living/simple_animal/hostile/space_dragon,
|
||||
/mob/living/simple_animal/hostile/space_dragon/spawn_with_antag,
|
||||
/mob/living/simple_animal/hostile/vatbeast,
|
||||
/mob/living/simple_animal/hostile/venus_human_trap,
|
||||
/mob/living/simple_animal/hostile/wizard,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 959 B After Width: | Height: | Size: 1.4 KiB |
@@ -16,11 +16,11 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
ui_icon = "users"
|
||||
|
||||
///The network that the user is currently hosting
|
||||
var/datum/component/mind_linker/nif/user_network
|
||||
var/datum/component/mind_linker/active_linking/nif/user_network
|
||||
///What networks are the user connected to?
|
||||
var/list/network_list = list()
|
||||
///What network is the user sending messages to? This is saved from the keyboard so the user doesn't have to change the channel every time.
|
||||
var/datum/component/mind_linker/nif/active_network
|
||||
var/datum/component/mind_linker/active_linking/nif/active_network
|
||||
///The physical keyboard item being used to send messages
|
||||
var/obj/item/hivemind_keyboard/linked_keyboard
|
||||
///What action is being used to summon the Keyboard?
|
||||
@@ -29,7 +29,7 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
/datum/nifsoft/hivemind/New()
|
||||
. = ..()
|
||||
|
||||
user_network = linked_mob.AddComponent(/datum/component/mind_linker/nif, \
|
||||
user_network = linked_mob.AddComponent(/datum/component/mind_linker/active_linking/nif, \
|
||||
network_name = "Hivemind Link", \
|
||||
linker_action_path = /datum/action/innate/hivemind_config, \
|
||||
)
|
||||
@@ -54,7 +54,7 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
|
||||
linked_keyboard = null
|
||||
|
||||
for(var/datum/component/mind_linker/nif/hivemind as anything in network_list)
|
||||
for(var/datum/component/mind_linker/active_linking/nif/hivemind as anything in network_list)
|
||||
hivemind.linked_mobs -= linked_mob
|
||||
var/mob/living/hivemind_owner = hivemind.parent
|
||||
|
||||
@@ -90,7 +90,7 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
|
||||
/datum/action/innate/hivemind_config/Activate()
|
||||
. = ..()
|
||||
var/datum/component/mind_linker/nif/link = target
|
||||
var/datum/component/mind_linker/active_linking/nif/link = target
|
||||
|
||||
var/choice = tgui_input_list(owner, "Chose your option", "Hivemind Configuration Menu", list("Link a user","Remove a user","Change Hivemind color","Change active Hivemind","Leave a Hivemind", "Toggle invites"))
|
||||
if(!choice)
|
||||
@@ -119,7 +119,7 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
var/mob/living/carbon/human/user = owner
|
||||
var/datum/nifsoft/hivemind/hivemind = user.find_nifsoft(/datum/nifsoft/hivemind)
|
||||
|
||||
var/datum/component/mind_linker/nif/new_active_hivemind = tgui_input_list(user, "Choose a Hivemind to set as active.", "Switch Hivemind", hivemind.network_list)
|
||||
var/datum/component/mind_linker/active_linking/nif/new_active_hivemind = tgui_input_list(user, "Choose a Hivemind to set as active.", "Switch Hivemind", hivemind.network_list)
|
||||
if(!new_active_hivemind)
|
||||
return FALSE
|
||||
|
||||
@@ -137,7 +137,7 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
var/list/network_list = hivemind.network_list
|
||||
network_list -= hivemind.user_network
|
||||
|
||||
var/datum/component/mind_linker/nif/hivemind_to_leave = tgui_input_list(user, "Choose a Hivemind to disconnect from.", "Remove Hivemind", network_list)
|
||||
var/datum/component/mind_linker/active_linking/nif/hivemind_to_leave = tgui_input_list(user, "Choose a Hivemind to disconnect from.", "Remove Hivemind", network_list)
|
||||
if(!hivemind_to_leave)
|
||||
return FALSE
|
||||
|
||||
@@ -181,21 +181,21 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
///Does the component check to see if the person being linked has a mindshield or anti-magic?
|
||||
var/linking_protection = TRUE
|
||||
|
||||
/datum/component/mind_linker/nif
|
||||
/datum/component/mind_linker/active_linking/nif
|
||||
speech_action = FALSE
|
||||
linking_protection = FALSE
|
||||
|
||||
///What is the name of the hivemind? This is mostly here for the TGUI selection menus.
|
||||
var/name = ""
|
||||
|
||||
/datum/component/mind_linker/nif/New()
|
||||
/datum/component/mind_linker/active_linking/nif/New()
|
||||
. = ..()
|
||||
|
||||
var/mob/living/owner = parent
|
||||
name = owner.name + "'s " + network_name
|
||||
|
||||
///Lets the user add someone to their Hivemind through a choice menu that shows everyone that has the Hivemind NIFSoft.
|
||||
/datum/component/mind_linker/nif/proc/invite_user()
|
||||
/datum/component/mind_linker/active_linking/nif/proc/invite_user()
|
||||
var/list/hivemind_users = GLOB.hivemind_users.Copy()
|
||||
var/mob/living/carbon/human/owner = parent
|
||||
|
||||
@@ -226,7 +226,7 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
to_chat(owner, span_abductor("[person_to_add] has now been added to your Hivemind"))
|
||||
|
||||
///Removes a user from the list of connected people within a hivemind
|
||||
/datum/component/mind_linker/nif/proc/remove_user()
|
||||
/datum/component/mind_linker/active_linking/nif/proc/remove_user()
|
||||
var/mob/living/carbon/human/owner = parent
|
||||
var/mob/living/carbon/human/person_to_remove = tgui_input_list(owner, "Choose a person to remove from your Hivemind.", "Remove User", linked_mobs)
|
||||
|
||||
@@ -244,7 +244,7 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
to_chat(person_to_remove, span_abductor("You have now been removed from [owner]'s Hivemind."))
|
||||
to_chat(owner, span_abductor("[person_to_remove] has now been removed from your Hivemind."))
|
||||
|
||||
/datum/component/mind_linker/nif/proc/change_chat_color()
|
||||
/datum/component/mind_linker/active_linking/nif/proc/change_chat_color()
|
||||
var/mob/living/carbon/human/owner = parent
|
||||
var/new_chat_color = input(owner, "", "Choose Color", COLOR_ASSEMBLY_GREEN) as color
|
||||
|
||||
@@ -262,7 +262,7 @@ GLOBAL_LIST_EMPTY(hivemind_users)
|
||||
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
|
||||
inhand_icon_state = "electronic"
|
||||
///What Hivemind are messages being sent to?
|
||||
var/datum/component/mind_linker/nif/connected_network
|
||||
var/datum/component/mind_linker/active_linking/nif/connected_network
|
||||
//Who owns the controller?
|
||||
var/datum/weakref/source_user
|
||||
|
||||
|
||||
Reference in New Issue
Block a user