From d91e1f4c4d9c86bc4a275ef19f45e8927dd93cae Mon Sep 17 00:00:00 2001 From: Sakura Date: Wed, 2 Feb 2022 10:43:22 -0500 Subject: [PATCH] Create antag_datum.dm.bak --- .../antagonists/_common/antag_datum.dm.bak | 490 ++++++++++++++++++ 1 file changed, 490 insertions(+) create mode 100644 code/modules/antagonists/_common/antag_datum.dm.bak diff --git a/code/modules/antagonists/_common/antag_datum.dm.bak b/code/modules/antagonists/_common/antag_datum.dm.bak new file mode 100644 index 0000000000..3b155cbd00 --- /dev/null +++ b/code/modules/antagonists/_common/antag_datum.dm.bak @@ -0,0 +1,490 @@ +GLOBAL_LIST_EMPTY(antagonists) + +/datum/antagonist + ///Public name for this antagonist. Appears for player prompts and round-end reports. + var/name = "Antagonist" + ///Section of roundend report, datums with same category will be displayed together, also default header for the section + var/roundend_category = "other antagonists" + ///Set to false to hide the antagonists from roundend report + var/show_in_roundend = TRUE + ///If false, the roundtype will still convert with this antag active + var/prevent_roundtype_conversion = TRUE + ///Mind that owns this datum + var/datum/mind/owner + ///Silent will prevent the gain/lose texts to show + var/silent = FALSE + ///Whether or not the person will be able to have more than one datum + var/can_coexist_with_others = TRUE + ///List of datums this type can't coexist with + var/list/typecache_datum_blacklist = list() + ///The define string we use to identify the role for bans/player polls to spawn a random new one in. + var/job_rank + ///Should replace jobbanned player with ghosts if granted. + var/replace_banned = TRUE + ///List of the objective datums that this role currently has, completing all objectives at round-end will cause this antagonist to greentext. + var/list/objectives = list() + ///String dialogue that is added to the player's in-round notes and memories regarding specifics of that antagonist, eg. the nuke code for nuke ops, or your unlock code for traitors. + var/antag_memory = "" + ///typepath of moodlet that the mob will gain when granted this antagonist type. + var/antag_moodlet + + ///What is the configuration of this antagonist's hud icon, such as it's screen position and style, so thatit doesn't break other in-game hud icons. + var/antag_hud_type + ///Name of the antag hud we provide to this mob. + var/antag_hud_name + /// If above 0, this is the multiplier for the speed at which we hijack the shuttle. Do not directly read, use hijack_speed(). + var/hijack_speed = 0 + /// If set to true, the antag will not be added to the living antag list. + var/soft_antag = FALSE + /// The battlecry this antagonist shouts when suiciding with C4/X4. + var/suicide_cry = "" + //Antag panel properties + ///This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind + var/show_in_antagpanel = TRUE + ///Antagpanel will display these together, REQUIRED + var/antagpanel_category = "Uncategorized" + ///Will append antagonist name in admin listings - use for categories that share more than one antag type + var/show_name_in_check_antagonists = FALSE + /// Should this antagonist be shown as antag to ghosts? Shouldn't be used for stealthy antagonists like traitors + var/show_to_ghosts = FALSE + + /* CIT SPECIFIC */ + /// Quirks that will be removed upon gaining this antag. Pacifist and mute are default. + var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) + /// Amount of threat this antag poses, for dynamic mode + var/threat = 0 + + var/delete_on_mind_deletion = TRUE + + var/list/skill_modifiers + /* CIT SPECIFIC end */ + + //ANTAG UI + + ///name of the UI that will try to open, right now having nothing means this won't exist but in the future all should. + var/ui_name + ///button to access antag interface + var/datum/action/antag_info/info_button + +/datum/antagonist/New() + GLOB.antagonists += src + typecache_datum_blacklist = typecacheof(typecache_datum_blacklist) + +/datum/antagonist/Destroy() + GLOB.antagonists -= src + if(!owner) + stack_trace("Destroy()ing antagonist datum when it has no owner.") + else + LAZYREMOVE(owner.antag_datums, src) + owner = null + return ..() + +/datum/antagonist/proc/can_be_owned(datum/mind/new_owner) + . = TRUE + var/datum/mind/tested = new_owner || owner + if(tested.has_antag_datum(type)) + return FALSE + for(var/i in tested.antag_datums) + var/datum/antagonist/A = i + if(is_type_in_typecache(src, A.typecache_datum_blacklist)) + return FALSE + +//This will be called in add_antag_datum before owner assignment. +//Should return antag datum without owner. +/datum/antagonist/proc/specialization(datum/mind/new_owner) + return src + +///Called by the transfer_to() mind proc after the mind (mind.current and new_character.mind) has moved but before the player (key and client) is transfered. +/datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body) + SHOULD_CALL_PARENT(TRUE) + remove_innate_effects(old_body) +<<<<<<< HEAD + if(old_body && old_body.stat != DEAD && !length(old_body.mind?.antag_datums)) +======= + if(!soft_antag && old_body.stat != DEAD && !LAZYLEN(old_body.mind?.antag_datums)) +>>>>>>> upstream/master + old_body.remove_from_current_living_antags() + apply_innate_effects(new_body) + if(!soft_antag && new_body.stat != DEAD) + new_body.add_to_current_living_antags() + +//This handles the application of antag huds/special abilities +/datum/antagonist/proc/apply_innate_effects(mob/living/mob_override) + return + +//This handles the removal of antag huds/special abilities +/datum/antagonist/proc/remove_innate_effects(mob/living/mob_override) + return + +/// This is called when the antagonist is being mindshielded. +/datum/antagonist/proc/pre_mindshield(mob/implanter, mob/living/mob_override) + SIGNAL_HANDLER + // return COMPONENT_MINDSHIELD_PASSED + +/// This is called when the antagonist is successfully mindshielded. +/datum/antagonist/proc/on_mindshield(mob/implanter, mob/living/mob_override) + SIGNAL_HANDLER + return + +// Adds the specified antag hud to the player. Usually called in an antag datum file +/datum/antagonist/proc/add_antag_hud(antag_hud_type, antag_hud_name, mob/living/mob_override) + var/datum/atom_hud/antag/hud = GLOB.huds[antag_hud_type] + hud.join_hud(mob_override) + set_antag_hud(mob_override, antag_hud_name) + + +// Removes the specified antag hud from the player. Usually called in an antag datum file +/datum/antagonist/proc/remove_antag_hud(antag_hud_type, mob/living/mob_override) + var/datum/atom_hud/antag/hud = GLOB.huds[antag_hud_type] + hud.leave_hud(mob_override) + set_antag_hud(mob_override, null) + + +/// Handles adding and removing the clumsy mutation from clown antags. Gets called in apply/remove_innate_effects +/datum/antagonist/proc/handle_clown_mutation(mob/living/mob_override, message, removing = TRUE) + if(!ishuman(mob_override) || owner.assigned_role != "Clown") + return + var/mob/living/carbon/human/human_override = mob_override + if(removing) // They're a clown becoming an antag, remove clumsy + human_override.dna.remove_mutation(CLOWNMUT) + if(!silent && message) + to_chat(human_override, span_boldnotice("[message]")) + else + human_override.dna.add_mutation(CLOWNMUT) // We're removing their antag status, add back clumsy + + +//Assign default team and creates one for one of a kind team antagonists +/datum/antagonist/proc/create_team(datum/team/team) + return + +///Called by the add_antag_datum() mind proc after the instanced datum is added to the mind's antag_datums list. +/datum/antagonist/proc/on_gain() + SHOULD_CALL_PARENT(TRUE) + if(!owner) + CRASH("[src] ran on_gain() without a mind") + if(!owner.current) + CRASH("[src] ran on_gain() on a mind without a mob") + if(ui_name)//in the future, this should entirely replace greet. + info_button = new(owner.current, src) + info_button.Grant(owner.current) + if(!silent) + greet() + if(ui_name) + to_chat(owner.current, span_big("You are \a [src].")) + to_chat(owner.current, span_boldnotice("For more info, read the panel. you can always come back to it using the button in the top left.")) + info_button.Trigger() + apply_innate_effects() + give_antag_moodies() + remove_blacklisted_quirks() + // RegisterSignal(owner, COMSIG_PRE_MINDSHIELD_IMPLANT, .proc/pre_mindshield) + // RegisterSignal(owner, COMSIG_MINDSHIELD_IMPLANTED, .proc/on_mindshield) + if(is_banned(owner.current) && replace_banned) + replace_banned_player() + // else if(owner.current.client?.holder && (CONFIG_GET(flag/auto_deadmin_antagonists) || owner.current.client.prefs?.toggles & DEADMIN_ANTAGONIST)) + // owner.current.client.holder.auto_deadmin() + if(!soft_antag && owner.current.stat != DEAD) + owner.current.add_to_current_living_antags() + + // cit skill + if(skill_modifiers) + for(var/A in skill_modifiers) + ADD_SINGLETON_SKILL_MODIFIER(owner, A, type) + var/datum/skill_modifier/job/M = GLOB.skill_modifiers[GET_SKILL_MOD_ID(A, type)] + if(istype(M)) + M.name = "[name] Training" + owner.current.AddComponent(/datum/component/activity) + SEND_SIGNAL(owner.current, COMSIG_MOB_ANTAG_ON_GAIN, src) + + +/** + * Proc that checks the sent mob aganst the banlistfor this antagonist. + * Returns FALSE if no mob is sent, or the mob is not found to be banned. + * + * * mob/M: The mob that you are looking for on the banlist. + */ +/datum/antagonist/proc/is_banned(mob/M) + if(!M) + return FALSE + . = (jobban_isbanned(M, ROLE_SYNDICATE) || QDELETED(M) || (job_rank && (jobban_isbanned(M,job_rank) || QDELETED(M)))) + +/** + * Proc that replaces a player who cannot play a specific antagonist due to being banned via a poll, and alerts the player of their being on the banlist. + */ +/datum/antagonist/proc/replace_banned_player() + set waitfor = FALSE + + var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [name]?", "[name]", job_rank, 50, owner.current) + if(LAZYLEN(candidates)) + var/mob/dead/observer/C = pick(candidates) + to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!") + message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner)]) to replace a jobbanned player.") + owner.current.ghostize(0) + C.transfer_ckey(owner.current, FALSE) + +/** + * Called by the remove_antag_datum() and remove_all_antag_datums() mind procs for the antag datum to handle its own removal and deletion. + */ +/datum/antagonist/proc/on_removal() + SHOULD_CALL_PARENT(TRUE) + if(!owner) + CRASH("Antag datum with no owner.") + + remove_innate_effects() + clear_antag_moodies() + LAZYREMOVE(owner.antag_datums, src) + // cit skill + for(var/A in skill_modifiers) + owner.remove_skill_modifier(GET_SKILL_MOD_ID(A, type)) + // end + if(!LAZYLEN(owner.antag_datums) && !soft_antag) + owner.current.remove_from_current_living_antags() + if(info_button) + QDEL_NULL(info_button) + if(!silent && owner.current) + farewell() + // UnregisterSignal(owner, COMSIG_PRE_MINDSHIELD_IMPLANT) + // UnregisterSignal(owner, COMSIG_MINDSHIELD_IMPLANTED) + var/datum/team/team = get_team() + if(team) + team.remove_member(owner) + qdel(src) + +/** + * Proc that sends fluff or instructional messages to the player when they are given this antag datum. + * Use this proc for playing sounds, sending alerts, or helping to setup non-gameplay influencing aspects of the antagonist type. + */ +/datum/antagonist/proc/greet() + return + +/** + * Proc that sends fluff or instructional messages to the player when they lose this antag datum. + * Use this proc for playing sounds, sending alerts, or otherwise informing the player that they're no longer a specific antagonist type. + */ +/datum/antagonist/proc/farewell() + return + +/** + * Proc that assigns this antagonist's ascribed moodlet to the player. + */ +/datum/antagonist/proc/give_antag_moodies() + if(!antag_moodlet) + return + SEND_SIGNAL(owner.current, COMSIG_ADD_MOOD_EVENT, "antag_moodlet", antag_moodlet) + +/** + * Proc that removes this antagonist's ascribed moodlet from the player. + */ +/datum/antagonist/proc/clear_antag_moodies() + if(!antag_moodlet) + return + SEND_SIGNAL(owner.current, COMSIG_CLEAR_MOOD_EVENT, "antag_moodlet") + +/** + * Removes invalid quirks. + */ +/datum/antagonist/proc/remove_blacklisted_quirks() + var/mob/living/L = owner.current + if(istype(L)) + for(var/q in L.roundstart_quirks) + var/datum/quirk/Q = q + if(Q.type in blacklisted_quirks) + if(initial(Q.antag_removal_text)) + to_chat(L, "[initial(Q.antag_removal_text)]") + qdel(Q) + +/** + * Proc that will return the team this antagonist belongs to, when called. Helpful with antagonists that may belong to multiple potential teams in a single round, like families. + */ +/datum/antagonist/proc/get_team() + return + +/** + * Proc that sends string information for the end-round report window to the server. + * This runs on every instance of every antagonist that exists at the end of the round. + * This is the body of the message, sandwiched between roundend_report_header and roundend_report_footer. + */ +/datum/antagonist/proc/roundend_report() + var/list/report = list() + + if(!owner) + CRASH("Antagonist datum without owner") + + report += printplayer(owner) + + var/objectives_complete = TRUE + if(objectives.len) + report += printobjectives(objectives) + for(var/datum/objective/objective in objectives) + if(objective.completable && !objective.check_completion()) + objectives_complete = FALSE + break + + if(objectives.len == 0 || objectives_complete) + report += "The [name] was successful!" + else + report += "The [name] has failed!" + + return report.Join("
") + +/** + * Proc that sends string data for the round-end report. + * Displayed before roundend_report and roundend_report_footer. + * Appears at start of roundend_catagory section. + */ +/datum/antagonist/proc/roundend_report_header() + return "The [roundend_category] were:
" + +/** + * Proc that sends string data for the round-end report. + * Displayed after roundend_report and roundend_report_footer. + * Appears at the end of the roundend_catagory section. + */ +/datum/antagonist/proc/roundend_report_footer() + return + + +//ADMIN TOOLS + +//Called when using admin tools to give antag status +/datum/antagonist/proc/admin_add(datum/mind/new_owner,mob/admin) + message_admins("[key_name_admin(admin)] made [key_name_admin(new_owner)] into [name].") + log_admin("[key_name(admin)] made [key_name(new_owner)] into [name].") + new_owner.add_antag_datum(src) + +//Called when removing antagonist using admin tools +/datum/antagonist/proc/admin_remove(mob/user) + if(!user) + return + message_admins("[key_name_admin(user)] has removed [name] antagonist status from [key_name_admin(owner)].") + log_admin("[key_name(user)] has removed [name] antagonist status from [key_name(owner)].") + on_removal() + +//gamemode/proc/is_mode_antag(antagonist/A) => TRUE/FALSE + +/** + * Additional data to display in the antagonist panel section. + * For example, nuke disk code, genome count, etc + */ +/datum/antagonist/proc/antag_panel_data() + return "" + +/datum/antagonist/proc/enabled_in_preferences(datum/mind/M) + if(job_rank) + if(M.current && M.current.client && (job_rank in M.current.client.prefs.be_special)) + return TRUE + else + return FALSE + return TRUE + +/// List of ["Command"] = CALLBACK(), user will be appeneded to callback arguments on execution +/datum/antagonist/proc/get_admin_commands() + . = list() + +/datum/antagonist/Topic(href,href_list) + if(!check_rights(R_ADMIN)) + return + //Antag memory edit + if (href_list["memory_edit"]) + edit_memory(usr) + owner.traitor_panel() + return + + //Some commands might delete/modify this datum clearing or changing owner + var/datum/mind/persistent_owner = owner + + var/commands = get_admin_commands() + for(var/admin_command in commands) + if(href_list["command"] == admin_command) + var/datum/callback/C = commands[admin_command] + C.Invoke(usr) + persistent_owner.traitor_panel() + return + +/datum/antagonist/proc/edit_memory(mob/user) + var/new_memo = stripped_multiline_input(user, "Write new memory", "Memory", antag_memory, MAX_MESSAGE_LEN) + if (isnull(new_memo)) + return + antag_memory = new_memo + +/** + * Gets how fast we can hijack the shuttle, return 0 for can not hijack. + * Defaults to hijack_speed var, override for custom stuff like buffing hijack speed for hijack objectives or something. + */ +/datum/antagonist/proc/hijack_speed() + var/datum/objective/hijack/H = locate() in objectives + if(!isnull(H?.hijack_speed_override)) + return H.hijack_speed_override + return hijack_speed + +/** + * Gets our threat level. Override this proc for custom functionality/dynamic threat level. + */ +/datum/antagonist/proc/threat() + . = CONFIG_GET(keyed_list/antag_threat)[lowertext(name)] + if(. == null) + return threat + +//This one is created by admin tools for custom objectives +/datum/antagonist/custom + antagpanel_category = "Custom" + show_name_in_check_antagonists = TRUE //They're all different + var/datum/team/custom_team + +/datum/antagonist/custom/create_team(datum/team/team) + custom_team = team + +/datum/antagonist/custom/get_team() + return custom_team + +/datum/antagonist/custom/admin_add(datum/mind/new_owner,mob/admin) + var/custom_name = stripped_input(admin, "Custom antagonist name:", "Custom antag", "Antagonist") + if(custom_name) + name = custom_name + else + return + ..() + +///ANTAGONIST UI STUFF + +/datum/antagonist/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, ui_name, name) + ui.open() + +/datum/antagonist/ui_state(mob/user) + return GLOB.always_state + +///generic helper to send objectives as data through tgui. supports smart objectives too! +/datum/antagonist/proc/get_objectives() + var/objective_count = 1 + var/list/objective_data = list() + //all obj + for(var/datum/objective/objective in objectives) + objective_data += list(list( + "count" = objective_count, + "name" = objective.name, + "explanation" = objective.explanation_text, + "complete" = objective.completed, + )) + objective_count++ + return objective_data + +//button for antags to review their descriptions/info + +/datum/action/antag_info + name = "Open Antag Information:" + button_icon_state = "round_end" + var/datum/antagonist/antag_datum + +/datum/action/antag_info/New(Target, datum/antagonist/antag_datum) + . = ..() + src.antag_datum = antag_datum + name += " [antag_datum.name]" + +/datum/action/antag_info/Trigger() + if(antag_datum) + antag_datum.ui_interact(owner) + +/datum/action/antag_info/IsAvailable() + return TRUE