mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 17:52:36 +00:00
161 lines
6.2 KiB
Plaintext
161 lines
6.2 KiB
Plaintext
/**
|
|
* Component which lets ghosts click on a mob to take control of it
|
|
*/
|
|
/datum/component/ghost_direct_control
|
|
/// Message to display upon successful possession
|
|
var/assumed_control_message
|
|
/// Type of ban you can get to prevent you from accepting this role
|
|
var/ban_type
|
|
/// Any extra checks which need to run before we take over
|
|
var/datum/callback/extra_control_checks
|
|
/// Callback run after someone successfully takes over the body
|
|
var/datum/callback/after_assumed_control
|
|
/// If we're currently awaiting the results of a ghost poll
|
|
var/awaiting_ghosts = FALSE
|
|
|
|
/datum/component/ghost_direct_control/Initialize(
|
|
ban_type = ROLE_SENTIENCE,
|
|
role_name = null,
|
|
poll_question = null,
|
|
poll_candidates = TRUE,
|
|
poll_announce_chosen = TRUE,
|
|
poll_length = 10 SECONDS,
|
|
poll_chat_border_icon = null,
|
|
poll_ignore_key = POLL_IGNORE_SENTIENCE_POTION,
|
|
assumed_control_message = null,
|
|
datum/callback/extra_control_checks,
|
|
datum/callback/after_assumed_control,
|
|
)
|
|
. = ..()
|
|
if (!isliving(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
src.ban_type = ban_type
|
|
src.assumed_control_message = assumed_control_message || "You are [parent]!"
|
|
src.extra_control_checks = extra_control_checks
|
|
src.after_assumed_control = after_assumed_control
|
|
|
|
var/mob/mob_parent = parent
|
|
LAZYADD(GLOB.joinable_mobs[format_text("[initial(mob_parent.name)]")], mob_parent)
|
|
|
|
if (poll_candidates)
|
|
INVOKE_ASYNC(src, PROC_REF(request_ghost_control), poll_question, role_name || "[parent]", poll_length, poll_ignore_key, poll_announce_chosen, poll_chat_border_icon)
|
|
|
|
/datum/component/ghost_direct_control/RegisterWithParent()
|
|
. = ..()
|
|
RegisterSignal(parent, COMSIG_ATOM_ATTACK_GHOST, PROC_REF(on_ghost_clicked))
|
|
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined))
|
|
RegisterSignal(parent, COMSIG_MOB_LOGIN, PROC_REF(on_login))
|
|
|
|
/datum/component/ghost_direct_control/UnregisterFromParent()
|
|
UnregisterSignal(parent, list(COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_EXAMINE, COMSIG_MOB_LOGIN))
|
|
return ..()
|
|
|
|
/datum/component/ghost_direct_control/Destroy(force)
|
|
extra_control_checks = null
|
|
after_assumed_control = null
|
|
|
|
var/mob/mob_parent = parent
|
|
var/list/spawners = GLOB.joinable_mobs[format_text("[initial(mob_parent.name)]")]
|
|
LAZYREMOVE(spawners, mob_parent)
|
|
if(!LAZYLEN(spawners))
|
|
GLOB.joinable_mobs -= format_text("[initial(mob_parent.name)]")
|
|
return ..()
|
|
|
|
/// Inform ghosts that they can possess this
|
|
/datum/component/ghost_direct_control/proc/on_examined(datum/source, mob/user, list/examine_text)
|
|
SIGNAL_HANDLER
|
|
if (!isobserver(user))
|
|
return
|
|
var/mob/living/our_mob = parent
|
|
if (our_mob.stat == DEAD || our_mob.key || awaiting_ghosts)
|
|
return
|
|
examine_text += span_boldnotice("You could take control of this mob by clicking on it.")
|
|
|
|
/// Send out a request for a brain
|
|
/datum/component/ghost_direct_control/proc/request_ghost_control(poll_question, role_name, poll_length, poll_ignore_key, poll_announce_chosen, poll_chat_border_icon)
|
|
if(!(GLOB.ghost_role_flags & GHOSTROLE_SPAWNER))
|
|
return
|
|
awaiting_ghosts = TRUE
|
|
var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
|
|
question = poll_question,
|
|
check_jobban = ban_type,
|
|
poll_time = poll_length,
|
|
checked_target = parent,
|
|
ignore_category = poll_ignore_key,
|
|
alert_pic = parent,
|
|
role_name_text = role_name,
|
|
chat_text_border_icon = poll_chat_border_icon,
|
|
announce_chosen = poll_announce_chosen,
|
|
)
|
|
awaiting_ghosts = FALSE
|
|
if(isnull(chosen_one))
|
|
return
|
|
assume_direct_control(chosen_one)
|
|
|
|
/// A ghost clicked on us, they want to get in this body
|
|
/datum/component/ghost_direct_control/proc/on_ghost_clicked(mob/our_mob, mob/dead/observer/hopeful_ghost)
|
|
SIGNAL_HANDLER
|
|
if (our_mob.key)
|
|
qdel(src)
|
|
return
|
|
if (!hopeful_ghost.client)
|
|
return
|
|
if (!(GLOB.ghost_role_flags & GHOSTROLE_SPAWNER))
|
|
to_chat(hopeful_ghost, span_warning("Ghost roles have been temporarily disabled!"))
|
|
return
|
|
if (awaiting_ghosts)
|
|
to_chat(hopeful_ghost, span_warning("Ghost candidate selection currently in progress!"))
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
if (!SSticker.HasRoundStarted())
|
|
to_chat(hopeful_ghost, span_warning("You cannot assume control of this until after the round has started!"))
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
INVOKE_ASYNC(src, PROC_REF(attempt_possession), our_mob, hopeful_ghost)
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
/// We got far enough to establish that this mob is a valid target, let's try to posssess it
|
|
/datum/component/ghost_direct_control/proc/attempt_possession(mob/our_mob, mob/dead/observer/hopeful_ghost)
|
|
var/ghost_asked = tgui_alert(usr, "Become [our_mob]?", "Are you sure?", list("Yes", "No"))
|
|
if (ghost_asked != "Yes" || QDELETED(our_mob))
|
|
return
|
|
assume_direct_control(hopeful_ghost)
|
|
|
|
/// Grant possession of our mob, component is now no longer required
|
|
/datum/component/ghost_direct_control/proc/assume_direct_control(mob/harbinger)
|
|
if (QDELETED(src))
|
|
to_chat(harbinger, span_warning("Offer to possess creature has expired!"))
|
|
return
|
|
if (is_banned_from(harbinger.ckey, list(ban_type)))
|
|
to_chat(harbinger, span_warning("You are banned from playing as this role!"))
|
|
return
|
|
if (!(GLOB.ghost_role_flags & GHOSTROLE_SPAWNER))
|
|
to_chat(harbinger, span_warning("Ghost roles have been temporarily disabled!"))
|
|
return
|
|
var/mob/living/new_body = parent
|
|
if (new_body.stat == DEAD)
|
|
to_chat(harbinger, span_warning("This body has passed away, it is of no use!"))
|
|
return
|
|
if (new_body.key)
|
|
to_chat(harbinger, span_warning("[parent] has already become sapient!"))
|
|
qdel(src)
|
|
return
|
|
if (extra_control_checks && !extra_control_checks.Invoke(harbinger))
|
|
return
|
|
|
|
harbinger.log_message("took control of [new_body].", LOG_GAME)
|
|
// doesn't transfer mind because that transfers antag datum as well
|
|
new_body.PossessByPlayer(harbinger.ckey)
|
|
|
|
// Already qdels due to below proc but just in case
|
|
qdel(src)
|
|
|
|
/// When someone assumes control, get rid of our component
|
|
/datum/component/ghost_direct_control/proc/on_login(mob/harbinger)
|
|
SIGNAL_HANDLER
|
|
// This proc is called the very moment .key is set, so we need to force mind to initialize here if we want the invoke to affect the mind of the mob
|
|
if(isnull(harbinger.mind))
|
|
harbinger.mind_initialize()
|
|
to_chat(harbinger, span_boldnotice(assumed_control_message))
|
|
after_assumed_control?.Invoke(harbinger)
|
|
qdel(src)
|