Files
Alexis 21b4095dfd [MDB IGNORE] [IDB IGNORE] Upstream Sync - 04/17/2026 (#5453)
Upstream 04/17/2026

fixes https://github.com/Bubberstation/Bubberstation/issues/5549

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>
Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com>
Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com>
Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com>
Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com>
Co-authored-by: loganuk <fakeemail123@aol.com>
Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com>
Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com>
Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com>
Co-authored-by: Lucy <lucy@absolucy.moe>
Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com>
Co-authored-by: Isratosh <Isratosh@hotmail.com>
Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com>
Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com>
Co-authored-by: Alexander V. <volas@ya.ru>
Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com>
Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Tim <timothymtorres@gmail.com>
Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com>
Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com>
Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com>
Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com>
Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com>
Co-authored-by: Josh <josh.adam.powell@gmail.com>
Co-authored-by: Josh Powell <josh.powell@softwire.com>
Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com>
Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com>
Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com>
Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
2026-05-16 00:56:00 +02:00

207 lines
7.7 KiB
Plaintext

/datum/mafia_role
var/name = JOB_ASSISTANT
var/desc = "You are a crewmember without any special abilities."
var/win_condition = "kill all mafia and solo killing roles."
var/team = MAFIA_TEAM_TOWN
///how the random setup chooses which roles get put in
var/role_type = TOWN_OVERFLOW
///role flags (special status of roles like detection immune)
var/role_flags = NONE
///The mafia controller board this mafia role is tied to, in case there's several Mafia games at once.
var/datum/mafia_controller/mafia_game_controller
///The mafia popup we edit text to give different alerts for (such as when to vote).
var/atom/movable/screen/mafia_popup/mafia_alert
///List of all mafia abilities this role is able to perform.
var/list/datum/mafia_ability/role_unique_actions = list()
///The player's written notes, that they can send to chat at any time.
var/written_notes
///The ckey of the person playing as this Mafia role, CAN BE NULL IN FAVOR OF player_pda.
var/player_key
///The PDA of the person playing as this Mafia role, CAN BE NULL IN FAVOR OF player_key.
var/obj/item/modular_computer/player_pda
///List of all messages this role got throughout the game.
var/list/role_messages = list()
var/mob/living/carbon/human/body
var/obj/effect/landmark/mafia/assigned_landmark
///The Mafia innate action panel that allows players to view the game's state.
var/datum/action/innate/mafia_panel/mafia_panel
///how many votes submitted when you vote. used in voting and deciding victory.
var/vote_power = 1
///what they get equipped with when they are revealed
var/datum/outfit/revealed_outfit = /datum/outfit/mafia/assistant
///what the role gets when it wins a game
var/winner_award = /datum/award/achievement/mafia/assistant
///so mafia have to also kill them to have a majority
var/game_status = MAFIA_ALIVE
///icon state in the mafia dmi of the hud of the role, used in the mafia ui
var/hud_icon = SECHUD_ASSISTANT
///icon state in the mafia dmi of the hud of the role, used in the mafia ui
var/revealed_icon = "assistant"
///set this to something cool for antagonists and their window will look different
var/special_ui_theme
///The cooldown between being able to send your will in chat.
COOLDOWN_DECLARE(note_chat_sending_cooldown)
/datum/mafia_role/New(datum/mafia_controller/new_game)
. = ..()
src.mafia_game_controller = new_game
mafia_panel = new(null, new_game)
for(var/datum/mafia_ability/abilities as anything in role_unique_actions + /datum/mafia_ability/voting)
role_unique_actions += new abilities(src)
role_unique_actions -= abilities
/datum/mafia_role/Destroy(force)
UnregisterSignal(body, list(COMSIG_MOB_SAY, COMSIG_MOB_DEADSAY))
QDEL_NULL(mafia_alert)
QDEL_NULL(mafia_panel)
QDEL_LIST(role_unique_actions)
//we null these instead of qdel because Mafia controller's mapdeleter deletes it all.
assigned_landmark = null
body = null
role_messages.Cut()
return ..()
/datum/mafia_role/proc/register_body(mob/living/carbon/human/new_body)
if(body)
UnregisterSignal(new_body, list(COMSIG_MOB_SAY, COMSIG_MOB_DEADSAY))
mafia_panel.Remove(body)
body = new_body
RegisterSignal(new_body, COMSIG_MOB_SAY, PROC_REF(handle_speech))
RegisterSignal(new_body, COMSIG_MOB_DEADSAY, PROC_REF(handle_speech_dead))
mafia_panel.Grant(new_body)
/**
* send_message_to_player
*
* Sends a message to a player, checking if they are playing through a PDA or not.
* Args:
* * message - The message to send to the person
* * balloon_alert - Whether it should be as a balloon alert, only if it's to a non-PDA user.
*/
/datum/mafia_role/proc/send_message_to_player(message, balloon_alert = FALSE)
if(player_pda)
role_messages += message
return
if(balloon_alert)
body.balloon_alert(body, message)
return
to_chat(body, message)
/**
* handle_speech
*
* Handles Mafia roles talking in chat.
* First we'll go through their abilities for Ability-specific speech,
* if none affects it, we will go to day chat (if it is indeed day).
*/
/datum/mafia_role/proc/handle_speech(datum/source, list/speech_args)
SIGNAL_HANDLER
for(var/datum/mafia_ability/abilities as anything in role_unique_actions)
if(abilities.handle_speech(source, speech_args))
return
if(mafia_game_controller.phase == MAFIA_PHASE_NIGHT)
return
var/message = "[source]: [html_decode(speech_args[SPEECH_MESSAGE])]"
mafia_game_controller.send_message(message, log_only = TRUE)
///Same as handle_speech, but for dead players.
/datum/mafia_role/proc/handle_speech_dead(datum/source, message)
SIGNAL_HANDLER
var/message_sent = span_changeling("<b>\[DEAD CHAT\] [source]</b>: [message]")
mafia_game_controller.send_message(message_sent, team = MAFIA_TEAM_DEAD)
return MOB_DEADSAY_SIGNAL_INTERCEPT
/**
* Puts the player in their body and keeps track of their previous one to put them back in later.
* Adds the playing_mafia trait so people examining them will know why they're currently lacking a soul.
*/
/datum/mafia_role/proc/put_player_in_body(client/player)
if(player.mob.mind)
body.AddComponent( \
/datum/component/temporary_body, \
old_mind = player.mob.mind, \
)
body.PossessByPlayer(player.key)
ADD_TRAIT(body, TRAIT_CORPSELOCKED, MAFIA_TRAIT)
/**
* Tests kill immunities, if nothing prevents the kill, kills this role.
*
* Does not count as visiting, see visit proc.
*/
/datum/mafia_role/proc/kill(datum/mafia_controller/game, datum/mafia_role/attacker, lynch = FALSE)
if(game_status == MAFIA_DEAD)
return FALSE
if(attacker && (attacker.role_flags & ROLE_ROLEBLOCKED))
return FALSE
if(SEND_SIGNAL(src, COMSIG_MAFIA_ON_KILL, game, attacker, lynch) & MAFIA_PREVENT_KILL)
return FALSE
game_status = MAFIA_DEAD
//can now hear dead chat speaking.
team |= MAFIA_TEAM_DEAD
body.death()
if(lynch)
reveal_role(game, verbose = TRUE)
game.living_roles -= src
return TRUE
/datum/mafia_role/proc/greet()
mafia_alert = new(body, src)
SEND_SOUND(body, 'sound/ambience/misc/ambifailure.ogg')
to_chat(body, span_danger("You are the [name]."))
to_chat(body, span_danger("[desc]"))
switch(team)
if(MAFIA_TEAM_MAFIA)
to_chat(body,span_danger("You and your co-conspirators win if you outnumber crewmembers."))
if(MAFIA_TEAM_TOWN)
to_chat(body,span_danger("You are a crewmember. Find out and lynch the changelings!"))
if(MAFIA_TEAM_SOLO)
to_chat(body,span_danger("You are not aligned to town or mafia. Accomplish your own objectives!"))
to_chat(body, "<span class='warningplain'><b>Be sure to read <a href=\"https://tgstation13.org/wiki/Mafia\">the wiki page</a> to learn more, if you have no idea what's going on.</b></span>")
/datum/mafia_role/proc/reveal_role(datum/mafia_controller/game, verbose = FALSE)
if((role_flags & ROLE_REVEALED))
return
if(verbose)
game.send_message("<span class='big bold notice'>It is revealed that the true role of [body] [game_status == MAFIA_ALIVE ? "is" : "was"] [name]!</span>")
var/list/oldoutfit = body.get_equipped_items()
for(var/thing in oldoutfit)
qdel(thing)
special_reveal_equip(game)
body.equipOutfit(revealed_outfit)
role_flags |= ROLE_REVEALED
/datum/mafia_role/proc/special_reveal_equip(datum/mafia_controller/game)
return
/datum/mafia_role/proc/show_help(clueless)
var/list/result = list()
var/team_desc = ""
var/team_span = ""
var/the = TRUE
switch(team)
if(MAFIA_TEAM_TOWN)
team_desc = "Town"
team_span = "nicegreen"
if(MAFIA_TEAM_MAFIA)
team_desc = "Mafia"
team_span = "red"
if(MAFIA_TEAM_SOLO)
team_desc = "Nobody"
team_span = "comradio"
the = FALSE
result += span_notice("The [span_bold("[name]")] is aligned with [the ? "the " : ""]<span class='[team_span]'>[team_desc]</span>")
result += "<span class='bold notice'>\"[initial(desc)]\"</span>"
result += span_notice("[name] wins when they [win_condition]")
to_chat(clueless, result.Join("</br>"))