diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 16232a71cd5f..c6978d1c884e 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -27,6 +27,7 @@ #define APPRENTICE_ROBELESS "robeless" #define APPRENTICE_HEALING "healing" +#define IS_INFERNAL_AGENT(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/infernal_affairs)) //Blob /// blob gets a free reroll every X time @@ -57,6 +58,9 @@ /// because they have nothing else that supports an implant. #define UPLINK_IMPLANT_TELECRYSTAL_COST 4 +///Signal sent to a mob when they purchase an item from their uplink. +#define COMSIG_ON_UPLINK_PURCHASE "comsig_on_uplink_purchase" + //ERT Types #define ERT_BLUE "Blue" #define ERT_RED "Red" diff --git a/code/__DEFINES/contracts.dm b/code/__DEFINES/contracts.dm deleted file mode 100644 index c6e23394ba2d..000000000000 --- a/code/__DEFINES/contracts.dm +++ /dev/null @@ -1,44 +0,0 @@ -#define CONTRACT_POWER "power" -#define CONTRACT_WEALTH "wealth" -#define CONTRACT_PRESTIGE "prestige" -#define CONTRACT_MAGIC "magic" -#define CONTRACT_REVIVE "revive" -#define CONTRACT_FRIEND "friend" -#define CONTRACT_KNOWLEDGE "knowledge" -#define CONTRACT_UNWILLING "unwilling" - -#define BANE_SALT "salt" -#define BANE_LIGHT "light" -#define BANE_IRON "iron" -#define BANE_WHITECLOTHES "whiteclothes" -#define BANE_SILVER "silver" -#define BANE_HARVEST "harvest" -#define BANE_TOOLBOX "toolbox" - -#define OBLIGATION_FOOD "food" -#define OBLIGATION_FIDDLE "fiddle" -#define OBLIGATION_DANCEOFF "danceoff" -#define OBLIGATION_GREET "greet" -#define OBLIGATION_PRESENCEKNOWN "presenceknown" -#define OBLIGATION_SAYNAME "sayname" -#define OBLIGATION_ANNOUNCEKILL "announcekill" -#define OBLIGATION_ANSWERTONAME "answername" - -#define BAN_HURTWOMAN "hurtwoman" -#define BAN_CHAPEL "chapel" -#define BAN_HURTPRIEST "hurtpriest" -#define BAN_AVOIDWATER "avoidwater" -#define BAN_STRIKEUNCONSCIOUS "strikeunconscious" -#define BAN_HURTLIZARD "hurtlizard" -#define BAN_HURTANIMAL "hurtanimal" - -#define BANISH_WATER "water" -#define BANISH_COFFIN "coffin" -#define BANISH_FORMALDYHIDE "embalm" -#define BANISH_RUNES "runes" -#define BANISH_CANDLES "candles" -#define BANISH_DESTRUCTION "destruction" -#define BANISH_FUNERAL_GARB "funeral" - -#define LORE 1 -#define LAW 2 diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 1fa697d1e990..0ff03d6e6e95 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -6,58 +6,60 @@ //These are synced with the Database, if you change the values of the defines //then you MUST update the database! -#define ROLE_SYNDICATE "Syndicate" -#define ROLE_TRAITOR "Traitor" -#define ROLE_OPERATIVE "Operative" -#define ROLE_CLOWNOP "Clown Operative" -#define ROLE_CHANGELING "Changeling" -#define ROLE_WIZARD "Wizard" -#define ROLE_RAGINMAGES "Ragin Mages" -#define ROLE_BULLSHITMAGES "Bullshit Mages" -#define ROLE_MALF "Malf AI" -#define ROLE_REV "Revolutionary" -#define ROLE_REV_HEAD "Head Revolutionary" -#define ROLE_ALIEN "Xenomorph" -#define ROLE_PAI "pAI" -#define ROLE_CULTIST "Cultist" -#define ROLE_HERETIC "Heretic" -#define ROLE_BLOB "Blob" -#define ROLE_NINJA "Space Ninja" -#define ROLE_MONKEY "Monkey" -#define ROLE_ABDUCTOR "Abductor" -#define ROLE_REVENANT "Revenant" -#define ROLE_SERVANT_OF_RATVAR "Servant of Ratvar" -#define ROLE_BROTHER "Blood Brother" -#define ROLE_BRAINWASHED "Brainwashed Victim" -#define ROLE_HIVE "Hivemind Host" -#define ROLE_OBSESSED "Obsessed" -#define ROLE_SENTIENCE "Sentient Creature" -#define ROLE_MOUSE "Mouse" -#define ROLE_MIND_TRANSFER "Mind Transfer Potion" -#define ROLE_POSIBRAIN "Posibrain" -#define ROLE_DRONE "Drone" -#define ROLE_DEATHSQUAD "Deathsquad" -#define ROLE_LAVALAND "Lavaland" -#define ROLE_FUGITIVE "Fugitive" -#define ROLE_SHADOWLING "Shadowling" // Yogs -#define ROLE_VAMPIRE "Vampire" // Yogs -#define ROLE_GANG "gangster" // Yogs -#define ROLE_DARKSPAWN "darkspawn" // Yogs -#define ROLE_HOLOPARASITE "Holoparasite" // Yogs -#define ROLE_HORROR "Eldritch Horror" // Yogs -#define ROLE_INFILTRATOR "Infiltrator" // Yogs -#define ROLE_ZOMBIE "Zombie" -#define ROLE_BLOODSUCKER "Bloodsucker" -#define ROLE_VAMPIRICACCIDENT "Vampiric Accident" -#define ROLE_BLOODSUCKERBREAKOUT "Bloodsucker Breakout" -#define ROLE_MONSTERHUNTER "Monster Hunter" -#define ROLE_SPACE_DRAGON "Space Dragon" -#define ROLE_GOLEM "Golem" -#define ROLE_SINFULDEMON "Demon of Sin" -#define ROLE_GHOSTBEACON "Ghost Beacon" -#define ROLE_NIGHTMARE "Nightmare" -#define ROLE_DISEASE "Disease" -#define ROLE_PIRATE "Pirate" +#define ROLE_SYNDICATE "Syndicate" +#define ROLE_TRAITOR "Traitor" +#define ROLE_OPERATIVE "Operative" +#define ROLE_CLOWNOP "Clown Operative" +#define ROLE_CHANGELING "Changeling" +#define ROLE_WIZARD "Wizard" +#define ROLE_INFERNAL_AFFAIRS "Infernal Affairs Agent" +#define ROLE_INFERNAL_AFFAIRS_DEVIL "Infernal Devil" +#define ROLE_RAGINMAGES "Ragin Mages" +#define ROLE_BULLSHITMAGES "Bullshit Mages" +#define ROLE_MALF "Malf AI" +#define ROLE_REV "Revolutionary" +#define ROLE_REV_HEAD "Head Revolutionary" +#define ROLE_ALIEN "Xenomorph" +#define ROLE_PAI "pAI" +#define ROLE_CULTIST "Cultist" +#define ROLE_HERETIC "Heretic" +#define ROLE_BLOB "Blob" +#define ROLE_NINJA "Space Ninja" +#define ROLE_MONKEY "Monkey" +#define ROLE_ABDUCTOR "Abductor" +#define ROLE_REVENANT "Revenant" +#define ROLE_SERVANT_OF_RATVAR "Servant of Ratvar" +#define ROLE_BROTHER "Blood Brother" +#define ROLE_BRAINWASHED "Brainwashed Victim" +#define ROLE_HIVE "Hivemind Host" +#define ROLE_OBSESSED "Obsessed" +#define ROLE_SENTIENCE "Sentient Creature" +#define ROLE_MOUSE "Mouse" +#define ROLE_MIND_TRANSFER "Mind Transfer Potion" +#define ROLE_POSIBRAIN "Posibrain" +#define ROLE_DRONE "Drone" +#define ROLE_DEATHSQUAD "Deathsquad" +#define ROLE_LAVALAND "Lavaland" +#define ROLE_FUGITIVE "Fugitive" +#define ROLE_SHADOWLING "Shadowling" // Yogs +#define ROLE_VAMPIRE "Vampire" // Yogs +#define ROLE_GANG "gangster" // Yogs +#define ROLE_DARKSPAWN "darkspawn" // Yogs +#define ROLE_HOLOPARASITE "Holoparasite" // Yogs +#define ROLE_HORROR "Eldritch Horror" // Yogs +#define ROLE_INFILTRATOR "Infiltrator" // Yogs +#define ROLE_ZOMBIE "Zombie" +#define ROLE_BLOODSUCKER "Bloodsucker" +#define ROLE_VAMPIRICACCIDENT "Vampiric Accident" +#define ROLE_BLOODSUCKERBREAKOUT "Bloodsucker Breakout" +#define ROLE_MONSTERHUNTER "Monster Hunter" +#define ROLE_SPACE_DRAGON "Space Dragon" +#define ROLE_GOLEM "Golem" +#define ROLE_SINFULDEMON "Demon of Sin" +#define ROLE_GHOSTBEACON "Ghost Beacon" +#define ROLE_NIGHTMARE "Nightmare" +#define ROLE_DISEASE "Disease" +#define ROLE_PIRATE "Pirate" //Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR. @@ -68,9 +70,11 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_TRAITOR = /datum/antagonist/traitor, ROLE_OPERATIVE = /datum/antagonist/nukeop, ROLE_CLOWNOP = /datum/antagonist/nukeop/clownop, - ROLE_CHANGELING = /datum/antagonist/changeling, + ROLE_CHANGELING = /datum/antagonist/changeling, ROLE_WIZARD = /datum/antagonist/wizard, - ROLE_RAGINMAGES = /datum/antagonist/wizard, + ROLE_INFERNAL_AFFAIRS = /datum/antagonist/infernal_affairs, + ROLE_INFERNAL_AFFAIRS_DEVIL = /datum/antagonist/devil, + ROLE_RAGINMAGES = /datum/antagonist/wizard, ROLE_BULLSHITMAGES = /datum/antagonist/wizard, ROLE_MALF = /datum/antagonist/traitor/malf, ROLE_REV_HEAD = /datum/antagonist/rev/head, @@ -79,7 +83,7 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_HERETIC = /datum/antagonist/heretic, ROLE_BLOB = /datum/antagonist/blob, ROLE_NINJA = /datum/antagonist/ninja, - ROLE_MONKEY = /datum/antagonist/monkey, + ROLE_MONKEY = /datum/antagonist/monkey, ROLE_ABDUCTOR = /datum/antagonist/abductor, ROLE_REVENANT = /datum/antagonist/revenant, ROLE_SERVANT_OF_RATVAR = /datum/antagonist/clockcult, @@ -94,7 +98,7 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_HOLOPARASITE = /datum/antagonist/guardian, // Yogs ROLE_HORROR = /datum/antagonist/horror, // Yogs ROLE_INFILTRATOR = /datum/antagonist/infiltrator, // Yogs - ROLE_ZOMBIE = /datum/antagonist/zombie, + ROLE_ZOMBIE = /datum/antagonist/zombie, ROLE_BLOODSUCKER = /datum/antagonist/bloodsucker, ROLE_MONSTERHUNTER = /datum/antagonist/monsterhunter, ROLE_SPACE_DRAGON = /datum/antagonist/space_dragon, @@ -108,6 +112,6 @@ GLOBAL_LIST_INIT(special_roles, list( )) //Job defines for what happens when you fail to qualify for any job during job selection -#define BEOVERFLOW 1 -#define BERANDOMJOB 2 -#define RETURNTOLOBBY 3 +#define BEOVERFLOW 1 +#define BERANDOMJOB 2 +#define RETURNTOLOBBY 3 diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index cb8e7bc9a13b..2ba3c8850a0a 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -326,6 +326,7 @@ #define GENETIC_MUTATION "genetic" #define OBESITY "obesity" #define MAGIC_TRAIT "magic" +#define DEVIL_TRAIT "devil" #define TRAUMA_TRAIT "trauma" #define DISEASE_TRAIT "disease" #define SPECIES_TRAIT "species" diff --git a/code/controllers/subsystem/infernal_affairs.dm b/code/controllers/subsystem/infernal_affairs.dm new file mode 100644 index 000000000000..d8200dcb8833 --- /dev/null +++ b/code/controllers/subsystem/infernal_affairs.dm @@ -0,0 +1,64 @@ +/** + * ##infernal_affairs subsystem + * + * Supposed to handle the objectives of all Agents, ensuring they all have to kill eachother. + * Also keeps track of their Antag gear, to remove it when their soul is collected. + */ +SUBSYSTEM_DEF(infernal_affairs) + name = "Devil Affairs" + flags = SS_NO_INIT|SS_NO_FIRE + + ///List of all devils in-game. There is supposed to have only one, so this is in-case admins do some wacky shit. + var/list/datum/antagonist/devil/devils = list() + ///List of all Agents in the loop and the gear they have. + var/list/datum/antagonist/infernal_affairs/agent_datums = list() + +/** + * Enters a for() loop for all agents while assigning their target to be the first available agent. + * + * We assign all IAAs their position in the list to later assign them as objectives of one another. + * Lists starts at 1, so we will immediately imcrement to get their target. + * When the list goes over, we go back to the start AFTER incrementing the list, so they will have the first player as a target. + * We skip over Hellbound people, and when there's only one left alive, we'll end the loop. + */ +/datum/controller/subsystem/infernal_affairs/proc/update_objective_datums() + if(!agent_datums.len) + return + var/list_position = 1 + for(var/datum/antagonist/infernal_affairs/agents as anything in agent_datums) + if(!agents.active_objective) + agents.active_objective = new(src) + var/objective_set = FALSE + while(!objective_set) + list_position++ + if(list_position > agent_datums.len) + list_position = initial(list_position) + var/datum/antagonist/infernal_affairs/next_agent = agent_datums[list_position] + if(HAS_TRAIT(next_agent.owner, TRAIT_HELLBOUND)) + continue + if(next_agent == agents) + end_loop(agents) + objective_set = TRUE + break + if(agents.active_objective.target != agent_datums[list_position]) + agents.active_objective.target = agent_datums[list_position] + agents.active_objective.update_explanation_text() + agents.update_static_data(agents.owner.current) + objective_set = TRUE + break + return TRUE + +/** + * ## end_loop + * + * We unregister signal to stop listening for people in the loop, as it's over. + * We will then give the last man standing their hijack objective, to end the subsystem off + * Args: + * - last_man_standing: The antag datum of the last remaining player left alive. + */ +/datum/controller/subsystem/infernal_affairs/proc/end_loop(datum/antagonist/infernal_affairs/last_one_standing) + var/datum/objective/hijack/hijack_objective = new() + hijack_objective.owner = last_one_standing.owner + hijack_objective.explanation_text = hijack_objective + last_one_standing.objectives += hijack_objective + last_one_standing.update_static_data(last_one_standing.owner.current) diff --git a/code/datums/achievements/achievements.dm b/code/datums/achievements/achievements.dm index c78c87ff3c06..7bd316c34d6e 100644 --- a/code/datums/achievements/achievements.dm +++ b/code/datums/achievements/achievements.dm @@ -249,6 +249,12 @@ desc = "As a revenant, complete your objectives" id = GREENTEXT + 17 +/datum/achievement/greentext/devil + name = "Eternal Infernal" + desc = "As a devil, ascend to your greatest power" + id = GREENTEXT + 17 + + //end-greentext //start-redtext diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 4ed8b69605fe..6f03a9163a0d 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -346,32 +346,32 @@ if(!uplink_loc) // We've looked everywhere, let's just implant you implant = TRUE - + + var/datum/component/uplink/uplink_component + if(!implant) . = uplink_loc - var/datum/component/uplink/U = uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key) - if(!U) + uplink_component = uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key) + if(!uplink_component) CRASH("Uplink creation failed.") - U.setup_unlock_code() + uplink_component.setup_unlock_code() if(!silent) if(uplink_loc == R) - to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(U.unlock_code)] to unlock its hidden features.") + to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(uplink_component.unlock_code)] to unlock its hidden features.") else if(uplink_loc == PDA) - to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[U.unlock_code]\" into the ringtone select to unlock its hidden features.") + to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[uplink_component.unlock_code]\" into the ringtone select to unlock its hidden features.") else if(uplink_loc == P) - to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [english_list(U.unlock_code)] from its starting position to unlock its hidden features.") + to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [english_list(uplink_component.unlock_code)] from its starting position to unlock its hidden features.") if(uplink_owner) - uplink_owner.antag_memory += U.unlock_note + "
" + uplink_owner.antag_memory += uplink_component.unlock_note + "
" else - traitor_mob.mind.store_memory(U.unlock_note) + traitor_mob.mind.store_memory(uplink_component.unlock_note) else - var/obj/item/implant/uplink/starting/I = new(traitor_mob) - I.implant(traitor_mob, null, silent = TRUE) + var/obj/item/implant/uplink/starting/I = new() + uplink_component = I.implant(traitor_mob, null, silent = TRUE) if(!silent) to_chat(traitor_mob, "[employer] has cunningly implanted you with a Syndicate Uplink (although uplink implants cost valuable TC, so you will have slightly less). Simply trigger the uplink to access it.") - return I - - + return uplink_component //Link a new mobs mind to the creator of said mob. They will join any team they are currently on, and will only switch teams when their creator does. diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm index 8c0e6ff1c1f8..81e870cc473c 100644 --- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm +++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm @@ -219,6 +219,51 @@ M.add_antag_datum(new antag_datum()) return TRUE +////////////////////////////////////////////// +// // +// INFERNAL AFFAIRS // +// // +////////////////////////////////////////////// + +/datum/dynamic_ruleset/roundstart/infernal_affairs + name = "Devil Affairs" + antag_flag = ROLE_INFERNAL_AFFAIRS + antag_datum = /datum/antagonist/infernal_affairs + protected_roles = list("Chaplain","Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel", "Research Director", "Chief Engineer", "Chief Medical Officer", "Brig Physician") + restricted_roles = list("AI", "Cyborg") + required_candidates = 6 + weight = 0 + cost = 8 + scaling_cost = 2 + requirements = list(8,8,8,8,8,8,8,8,8,8) + antag_cap = list("denominator" = 24, "offset" = 3) + +/datum/dynamic_ruleset/roundstart/infernal_affairs/pre_execute(population) + . = ..() + var/num_traitors= get_antag_cap(population) + for(var/affair_number = 1 to num_traitors) + if(candidates.len <= 0) + break + var/mob/M = pick_n_take(candidates) + if(!SSinfernal_affairs.devils.len) + var/datum/antagonist/devil/devil_agent = new() + M.mind.add_antag_datum(devil_agent) + M.mind.special_role = ROLE_INFERNAL_AFFAIRS_DEVIL + else + assigned += M.mind + M.mind.special_role = ROLE_INFERNAL_AFFAIRS + M.mind.restricted_roles = restricted_roles + return TRUE + +/datum/dynamic_ruleset/roundstart/infernal_affairs/execute() + . = ..() + if(!.) + return FALSE + + SSinfernal_affairs.update_objective_datums() + + return TRUE + ////////////////////////////////////////////// // // // BLOOD CULT // diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 7213efde1add..ac6551e1ca39 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -233,6 +233,20 @@ GLOBAL_LIST_EMPTY(objectives) /datum/objective/assassinate/admin_edit(mob/admin) admin_simple_target_pick(admin) +/datum/objective/assassinate/internal + name = "assassinate internal" + +//We do not find a target, we'll be set manually in the game. +/datum/objective/assassinate/internal/find_target_by_role(role, role_type = FALSE, invert = FALSE) + return + +/datum/objective/assassinate/internal/update_explanation_text() + . = ..() + if(target && target.current) + explanation_text = "Assassinate [target.name], the [!target_role_type ? target.assigned_role : target.special_role]." + else + explanation_text = "Turn in the corpse of [target.name], who has been obliterated, to the Devil." + /datum/objective/assassinate/once name = "assassinate revival allowed" diff --git a/code/game/objects/items/implants/implantuplink.dm b/code/game/objects/items/implants/implantuplink.dm index 113a1eb191a7..f0b6a2a69ce4 100644 --- a/code/game/objects/items/implants/implantuplink.dm +++ b/code/game/objects/items/implants/implantuplink.dm @@ -7,11 +7,16 @@ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' var/starting_tc = 0 -/obj/item/implant/uplink/Initialize(mapload, _owner) +/obj/item/implant/uplink/Initialize(mapload) . = ..() - AddComponent(/datum/component/uplink, _owner, TRUE, FALSE, null, starting_tc) RegisterSignal(src, COMSIG_COMPONENT_REMOVING, PROC_REF(_component_removal)) +/obj/item/implant/uplink/implant(mob/living/target, mob/user, silent = FALSE, force = FALSE) + . = ..() + if(!.) + return FALSE + return AddComponent(/datum/component/uplink, target, TRUE, FALSE, null, starting_tc) + /** * Proc called when component is removed; ie. uplink component * diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index ecadf6fb6425..0d5448371ddd 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -295,7 +295,7 @@ "Ghost and Other Roles" = list(ROLE_BRAINWASHED, ROLE_DEATHSQUAD, ROLE_DRONE, ROLE_FUGITIVE, ROLE_HOLOPARASITE, ROLE_HORROR, ROLE_LAVALAND, ROLE_MIND_TRANSFER, ROLE_POSIBRAIN, ROLE_SENTIENCE, ROLE_MOUSE, ROLE_GOLEM, ROLE_GHOSTBEACON), "Antagonist Positions" = list(ROLE_ABDUCTOR, ROLE_ALIEN, ROLE_BLOB, ROLE_BLOODSUCKER, ROLE_BROTHER, ROLE_CHANGELING, ROLE_CULTIST, - ROLE_FUGITIVE, ROLE_HOLOPARASITE, ROLE_MALF, + ROLE_FUGITIVE, ROLE_HOLOPARASITE, ROLE_INFERNAL_AFFAIRS, ROLE_MALF, ROLE_MONKEY, ROLE_MONSTERHUNTER, ROLE_NINJA, ROLE_OPERATIVE, ROLE_REV, ROLE_REVENANT, ROLE_SINFULDEMON, ROLE_REV_HEAD, ROLE_SERVANT_OF_RATVAR, ROLE_SYNDICATE, diff --git a/code/modules/antagonists/devil_affairs/devil.dm b/code/modules/antagonists/devil_affairs/devil.dm new file mode 100644 index 000000000000..b43f3e556d1c --- /dev/null +++ b/code/modules/antagonists/devil_affairs/devil.dm @@ -0,0 +1,95 @@ +/datum/antagonist/devil + name = "Devil" + roundend_category = "infernal affairs agents" + antagpanel_category = "Devil Affairs" + job_rank = ROLE_INFERNAL_AFFAIRS_DEVIL + greentext_achieve = /datum/achievement/greentext/devil + + ///The amount of souls the devil has so far. + var/souls = 0 + ///List of Powers we currently have unlocked. + var/list/datum/action/devil_powers = list() + +/datum/antagonist/devil/on_gain() + . = ..() + SSinfernal_affairs.devils += src + obtain_power(/datum/action/cooldown/spell/pointed/summon_contract) + obtain_power(/datum/action/cooldown/spell/pointed/collect_soul) + +/datum/antagonist/devil/on_removal() + clear_power(/datum/action/cooldown/spell/pointed/summon_contract) + clear_power(/datum/action/cooldown/spell/pointed/collect_soul) + SSinfernal_affairs.devils -= src + return ..() + +/** + * ##update_souls_owned + * + * Used to edit the amount of souls a Devil has. This can be a negative number to take away. + * Will give Powers when getting to the proper level, or attempts to take them away if they go under + * That way this works for both adding and removing. + */ +/datum/antagonist/devil/proc/update_souls_owned(souls_adding) + souls += souls_adding + + switch(souls) + if(0) + clear_power(/datum/action/devil_transfer_body) + if(1) + obtain_power(/datum/action/devil_transfer_body) + clear_power(/datum/action/cooldown/spell/conjure_item/violin) + if(2) + obtain_power(/datum/action/cooldown/spell/conjure_item/violin) + clear_power(/datum/action/cooldown/spell/conjure_item/summon_pitchfork) + if(3) + obtain_power(/datum/action/cooldown/spell/conjure_item/summon_pitchfork) + clear_power(/datum/action/cooldown/spell/jaunt/infernal_jaunt) + if(4) + obtain_power(/datum/action/cooldown/spell/jaunt/infernal_jaunt) + if(7) + clear_power(/datum/action/cooldown/spell/summon_dancefloor) + clear_power(/datum/action/cooldown/spell/pointed/projectile/fireball/hellish) + clear_power(/datum/action/cooldown/spell/shapeshift/devil) + if(8) + obtain_power(/datum/action/cooldown/spell/summon_dancefloor) + obtain_power(/datum/action/cooldown/spell/pointed/projectile/fireball/hellish) + obtain_power(/datum/action/cooldown/spell/shapeshift/devil) + +/datum/antagonist/devil/proc/obtain_power(datum/action/new_power) + new_power = new new_power + devil_powers[new_power.type] = new_power + new_power.Grant(owner.current) + return TRUE + +///Called when a Bloodsucker loses a power: (power) +/datum/antagonist/devil/proc/clear_power(datum/action/removed_power) + if(devil_powers[removed_power]) + QDEL_NULL(devil_powers[removed_power]) + +/datum/action/cooldown/spell/pointed/summon_contract + background_icon_state = "bg_demon" + overlay_icon_state = "ab_goldborder" + +/datum/action/devil_transfer_body + background_icon_state = "bg_demon" + overlay_icon_state = "ab_goldborder" + +/datum/action/cooldown/spell/conjure_item/summon_pitchfork + background_icon_state = "bg_demon" + overlay_icon_state = "ab_goldborder" + +/datum/action/cooldown/spell/jaunt/infernal_jaunt + name = "Infernal Jaunt" + background_icon_state = "bg_demon" + overlay_icon_state = "ab_goldborder" + +/datum/action/cooldown/spell/conjure_item/violin + background_icon_state = "bg_demon" + overlay_icon_state = "ab_goldborder" + +/** + * Ascended Powers + */ +/datum/action/cooldown/spell/pointed/projectile/fireball/hellish + background_icon_state = "bg_demon" + overlay_icon_state = "ab_goldborder" diff --git a/code/modules/antagonists/devil_affairs/devil_powers/collect_soul.dm b/code/modules/antagonists/devil_affairs/devil_powers/collect_soul.dm new file mode 100644 index 000000000000..d70f790cd8de --- /dev/null +++ b/code/modules/antagonists/devil_affairs/devil_powers/collect_soul.dm @@ -0,0 +1,59 @@ +/datum/action/cooldown/spell/pointed/collect_soul + name = "Collect Soul" + desc = "This ranged spell allows you to take the soul out of someone indebted to you.." +// base_icon_state = "ignite" + + background_icon_state = "bg_demon" + overlay_icon_state = "ab_goldborder" + + school = SCHOOL_TRANSMUTATION + invocation = "P'y y'ur de'ts" + invocation_type = INVOCATION_WHISPER + + active_msg = span_notice("You prepare to collect a soul...") + sound = 'sound/magic/fireball.ogg' + cooldown_time = 1 MINUTES + spell_requirements = NONE + +/datum/action/cooldown/spell/pointed/collect_soul/is_valid_target(mob/living/target) + . = ..() + if(!.) + return FALSE + if(!target || !istype(target) || !target.mind) + return FALSE + if(target.stat != DEAD) + target.balloon_alert(owner, "target has to be dead!") + return FALSE + var/datum/antagonist/devil/devil_datum = owner.mind.has_antag_datum(/datum/antagonist/infernal_affairs) + if(!devil_datum) + return FALSE + var/datum/antagonist/infernal_affairs/agent_datum = target.mind.has_antag_datum(/datum/antagonist/infernal_affairs) + if(!agent_datum) + target.balloon_alert(owner, "not an agent!") + return FALSE + var/obj/item/paper/calling_card/card = locate() in target.get_all_contents() + if(!card) + target.balloon_alert(owner, "no card found!") + return FALSE + + return TRUE + +/datum/action/cooldown/spell/pointed/collect_soul/InterceptClickOn(mob/living/user, params, mob/living/target) + . = ..() + if(!.) + return FALSE + if(!do_after(user, 10 SECONDS, target)) + target.balloon_alert(user, "interrupted!") + return FALSE + + var/obj/item/paper/calling_card/card = locate() in target.get_all_contents() + //safety + if(!card) + target.balloon_alert(owner, "no card found!") + return FALSE + + target.balloon_alert(user, "soul ripped!") + var/datum/antagonist/infernal_affairs/agent_datum = target.mind.has_antag_datum(/datum/antagonist/infernal_affairs) + var/datum/antagonist/infernal_affairs/hunter_datum = card.signed_by_ref?.resolve() + agent_datum.soul_harvested(hunter_datum) + return TRUE diff --git a/code/modules/antagonists/devil_affairs/devil_powers/dancefloor.dm b/code/modules/antagonists/devil_affairs/devil_powers/dancefloor.dm new file mode 100644 index 000000000000..47176d277c02 --- /dev/null +++ b/code/modules/antagonists/devil_affairs/devil_powers/dancefloor.dm @@ -0,0 +1,53 @@ +/datum/action/cooldown/spell/summon_dancefloor + name = "Summon Dancefloor" + desc = "When what a Devil really needs is funk." + background_icon_state = "bg_demon" + overlay_icon_state = "ab_goldborder" + + spell_requirements = NONE + school = SCHOOL_EVOCATION + cooldown_time = 5 SECONDS //5 seconds, so the smoke can't be spammed + + button_icon = 'icons/mob/actions/actions_minor_antag.dmi' + button_icon_state = "funk" + + var/dancefloor_exists = FALSE + var/list/dancefloor_turfs + var/list/dancefloor_turfs_types + var/datum/effect_system/fluid_spread/smoke/transparent/dancefloor_devil/smoke + +/datum/action/cooldown/spell/summon_dancefloor/cast(atom/target) + . = ..() + LAZYINITLIST(dancefloor_turfs) + LAZYINITLIST(dancefloor_turfs_types) + + if(!smoke) + smoke = new() + smoke.set_up(0, get_turf(owner)) + smoke.start() + + if(dancefloor_exists) + dancefloor_exists = FALSE + for(var/i in 1 to dancefloor_turfs.len) + var/turf/T = dancefloor_turfs[i] + T.ChangeTurf(dancefloor_turfs_types[i], flags = CHANGETURF_INHERIT_AIR) + else + var/list/funky_turfs = RANGE_TURFS(1, owner) + for(var/turf/closed/solid in funky_turfs) + to_chat(owner, "You're too close to a wall.") + return + dancefloor_exists = TRUE + var/i = 1 + dancefloor_turfs.len = funky_turfs.len + dancefloor_turfs_types.len = funky_turfs.len + for(var/turf/T as anything in funky_turfs) + dancefloor_turfs[i] = T + dancefloor_turfs_types[i] = T.type + T.ChangeTurf((i % 2 == 0) ? /turf/open/floor/light/colour_cycle/dancefloor_a : /turf/open/floor/light/colour_cycle/dancefloor_b, flags = CHANGETURF_INHERIT_AIR) + i++ + +/datum/effect_system/fluid_spread/smoke/transparent/dancefloor_devil + effect_type = /obj/effect/particle_effect/fluid/smoke/transparent/dancefloor_devil + +/obj/effect/particle_effect/fluid/smoke/transparent/dancefloor_devil + lifetime = 2 diff --git a/code/modules/antagonists/devil_affairs/devil_powers/devil_form.dm b/code/modules/antagonists/devil_affairs/devil_powers/devil_form.dm new file mode 100644 index 000000000000..a8c5b901ca6b --- /dev/null +++ b/code/modules/antagonists/devil_affairs/devil_powers/devil_form.dm @@ -0,0 +1,10 @@ +/datum/action/cooldown/spell/shapeshift/devil + name = "Devil Form" + desc = "Take on the true shape of a devil." + invocation = "P'ease't d'y fo' ' w'lk!" + invocation_type = INVOCATION_WHISPER + spell_requirements = NONE + background_icon_state = "bg_demon" + overlay_icon_state = "ab_goldborder" + + possible_shapes = list(/mob/living/simple_animal/hostile/devil) diff --git a/code/modules/antagonists/devil_affairs/infernal_agent.dm b/code/modules/antagonists/devil_affairs/infernal_agent.dm new file mode 100644 index 000000000000..e29fc37a0bf2 --- /dev/null +++ b/code/modules/antagonists/devil_affairs/infernal_agent.dm @@ -0,0 +1,98 @@ +/datum/antagonist/infernal_affairs + name = "Infernal Affairs Agent" + roundend_category = "infernal affairs agents" + antagpanel_category = "Devil Affairs" + job_rank = ROLE_INFERNAL_AFFAIRS + preview_outfit = /datum/outfit/devil_affair_agent + + ///Reference to the Uplink, so we can mess with it when required. + var/datum/component/uplink/uplink_holder + ///The active objective this agent has to currently complete. + var/datum/objective/assassinate/internal/active_objective + + var/list/purchased_uplink_items = list() + +/datum/antagonist/infernal_affairs/on_gain(mob/living/mob_override) + . = ..() + SSinfernal_affairs.agent_datums += src + uplink_holder = owner.equip_traitor(employer = "The Devil", uplink_owner = src) + RegisterSignal(uplink_holder, COMSIG_ON_UPLINK_PURCHASE, PROC_REF(on_uplink_purchase)) + +/datum/antagonist/infernal_affairs/on_removal() + . = ..() + SSinfernal_affairs.agent_datums -= src + UnregisterSignal(uplink_holder, COMSIG_ON_UPLINK_PURCHASE) + QDEL_NULL(uplink_holder) + +/** + * ## on_uplink_purchase + * + * Called when an uplink item is purchased. + * We will keep track of their items to destroy them when the Agent dies. + */ +/datum/antagonist/infernal_affairs/proc/on_uplink_purchase(datum/component/uplink/source, atom/purchased_item, mob/living/purchaser) + SIGNAL_HANDLER + if(!isitem(purchased_item)) + return + purchased_uplink_items += purchased_item.get_all_contents() + +/** + * ##soul_harvested + * + * Handles making their mind unrevivable and the deletion of all their items, + * on top of all misc effects like updating objectives and giving rewards. + */ +/datum/antagonist/infernal_affairs/proc/soul_harvested(datum/antagonist/infernal_affairs/killer) + ADD_TRAIT(owner, TRAIT_HELLBOUND, DEVIL_TRAIT) + QDEL_LIST(purchased_uplink_items) + + //grant the soul to ALL devils, though without admin intervention there should only be one. + for(var/datum/antagonist/devil/devil as anything in SSinfernal_affairs.devils) + if(devil.owner.current) + devil.update_souls_owned(1) + + if(killer) + killer.uplink_holder.telecrystals += rand(3,5) + + SSinfernal_affairs.update_objective_datums() + +/datum/outfit/devil_affair_agent + name = "Devil Affairs Agent (Preview only)" + + uniform = /obj/item/clothing/under/rank/centcom_officer + head = /obj/item/clothing/head/devil_horns + glasses = /obj/item/clothing/glasses/sunglasses + r_hand = /obj/item/melee/transforming/energy/sword + +/datum/outfit/devil_affair_agent/post_equip(mob/living/carbon/human/owner, visualsOnly) + var/obj/item/melee/transforming/energy/sword/sword = locate() in owner.held_items + sword.transform_weapon(owner, TRUE) + +/obj/item/clothing/head/devil_horns + desc = "The one the only Devil." + icon_state = "devil_horns" + +/** + * ##calling card + * + * This item is required to be on someone to know if rewards should be given out. + */ +/obj/item/paper/calling_card + name = "calling card" + color = "#ff5050" + foldable = FALSE + info = {"**Death to Allentown.**

"} + + ///A weakref to the antag datum who signed the paper, so simply holding a paper for YOUR target doesn't make you eligible. + var/datum/weakref/signed_by_ref + +/obj/item/paper/calling_card/Initialize(mapload, datum/antagonist/infernal_affairs/agent_datum) + . = ..() + if(!agent_datum) + stack_trace("calling card made but does not have an agent datum. This will cause errors as it is expected!") + return INITIALIZE_HINT_QDEL + signed_by_ref = WEAKREF(agent_datum) + +/obj/item/paper/calling_card/Destroy() + signed_by_ref = null + return ..() diff --git a/code/modules/antagonists/devil_affairs/true_devil.dm b/code/modules/antagonists/devil_affairs/true_devil.dm new file mode 100644 index 000000000000..c1636a6403c4 --- /dev/null +++ b/code/modules/antagonists/devil_affairs/true_devil.dm @@ -0,0 +1,76 @@ +/mob/living/simple_animal/hostile/devil + name = "True Devil" + desc = "A pile of infernal energy, taking a vaguely humanoid form." + icon = 'icons/mob/32x64.dmi' + icon_state = "true_devil" + gender = NEUTER + + del_on_death = TRUE + dextrous = TRUE + spacewalk = TRUE + density = TRUE + pass_flags = NONE + health = 350 + maxHealth = 350 + ventcrawler = VENTCRAWLER_NONE + sight = (SEE_TURFS | SEE_OBJS) + status_flags = CANPUSH + mob_size = MOB_SIZE_LARGE + held_items = list(null, null) + +/mob/living/simple_animal/hostile/devil/Initialize(mapload) + grant_all_languages(TRUE, FALSE, TRUE) + return ..() + +/mob/living/simple_animal/hostile/devil/examine(mob/user) + . = list("This is [icon2html(src, user)] [src]!") + + //Left hand items + for(var/obj/item/I in held_items) + if(!(I.item_flags & ABSTRACT)) + . += "It is holding [I.get_examine_string(user)] in its [get_held_index_name(get_held_index_of_item(I))]." + + //Braindead + if(!client && stat != DEAD) + . += "The devil seems to be in deep contemplation." + + //Damaged + if(stat == DEAD) + . += span_deadsay("The hellfire seems to have been extinguished, for now at least.") + else if(health < (maxHealth/10)) + . += span_warning("You can see hellfire inside its gaping wounds.") + else if(health < (maxHealth/2)) + . += span_warning("You can see hellfire inside its wounds.") + . += "" + +/mob/living/simple_animal/hostile/devil/resist_buckle() + if(buckled) + buckled.user_unbuckle_mob(src,src) + visible_message( + span_warning("[src] easily breaks out of [p_their()] handcuffs!"), + span_notice("With just a thought your handcuffs fall off."), + ) + +/mob/living/simple_animal/hostile/devil/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) + return 666 + +/mob/living/simple_animal/hostile/devil/get_ear_protection() + return 2 + +/mob/living/simple_animal/hostile/devil/can_be_revived() + return 1 + +/mob/living/simple_animal/hostile/devil/is_literate() + return TRUE + +/mob/living/simple_animal/hostile/devil/ex_act(severity, ex_target) + var/b_loss + switch(severity) + if (EXPLODE_DEVASTATE) + b_loss = 500 + if (EXPLODE_HEAVY) + b_loss = 150 + if (EXPLODE_LIGHT) + b_loss = 30 + adjustBruteLoss(b_loss) + return ..() diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 0251a429a9f3..80aefaf43298 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -67,9 +67,7 @@ qdel(A.malf_picker) owner.remove_employee(company) if(uplink_holder) - var/datum/component/uplink/uplink = uplink_holder.GetComponent(/datum/component/uplink) - if(uplink)//remove uplink so they can't keep using it if admin abuse happens - uplink.RemoveComponent() + uplink_holder.RemoveComponent() UnregisterSignal(owner.current, COMSIG_MOVABLE_HEAR) SSticker.mode.traitors -= owner if(!silent && owner.current) @@ -295,7 +293,7 @@ /datum/antagonist/traitor/proc/equip(silent = FALSE) if(traitor_kind == TRAITOR_HUMAN) - uplink_holder = owner.equip_traitor(employer, silent, src) //yogs - uplink_holder = + uplink_holder = owner.equip_traitor(employer, silent, src) //yogs - keeps track of their uplink. /datum/antagonist/traitor/proc/assign_exchange_role() //set faction diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 7ba9e49c058a..ec19276c5649 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -7,7 +7,7 @@ held_items = list(null, null) /// List of /obj/item/organ in the mob. /// They don't go in the contents for some reason I don't want to know. - var/list/internal_organs = list() + var/list/internal_organs = list() /// List of /obj/item/organ in the mob by slot ID for easy access. /// They don't go in the contents for some reason I don't want to know. var/list/internal_organs_slot= list() diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index c88a58096077..864235d3a149 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -8,6 +8,7 @@ /datum/langtext // A datum to describe a piece of writing that stores a language value with it. var/text = "" // The text that is written. var/datum/language/lang // the language it's written in. + /datum/langtext/New(t,datum/language/l) text = t lang = l @@ -46,7 +47,8 @@ var/contact_poison // Reagent ID to transfer on contact var/contact_poison_volume = 0 var/next_write_time = 0 // prevent crash exploit - + ///Whether the paper can be folded into a paper airplane. + var/foldable = TRUE /obj/item/paper/pickup(user) if(contact_poison && ishuman(user)) diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm index 97985c89f6ff..f3ed1bf721d0 100644 --- a/code/modules/paperwork/paperplane.dm +++ b/code/modules/paperwork/paperplane.dm @@ -121,12 +121,25 @@ /obj/item/paper/examine(mob/user) . = ..() - . += span_notice("Alt-click [src] to fold it into a paper plane.") + if(foldable) + . += span_notice("Alt-click [src] to fold it into a paper plane.") /obj/item/paper/AltClick(mob/living/carbon/user, obj/item/I) + if(!foldable) + return ..() + var/datum/antagonist/infernal_affairs/affair_agent = IS_INFERNAL_AGENT(user) + if(affair_agent) + var/plane_response = tgui_input_list(user, "Do you wish for a plane a calling card?", "Your Calling", list("Calling Card", "Airplane")) + if(plane_response == "Calling Card") + user.balloon_alert(user, "folded paper.") + user.temporarilyRemoveItemFromInventory(src) + var/obj/item/paper/calling_card/new_card = new(user, affair_agent) + user.put_in_hands(new_card, no_sound = TRUE) + qdel(src) + return if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) return - to_chat(user, span_notice("You fold [src] into the shape of a plane!")) + user.balloon_alert(user, "folded paper.") user.temporarilyRemoveItemFromInventory(src) var/obj/item/paperplane/plane_type = /obj/item/paperplane //Origami Master diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index d90b6a4a74d6..e24809b355f9 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -126,12 +126,12 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) A = new spawn_path(get_turf(user)) else A = spawn_path - if(ishuman(user) && istype(A, /obj/item)) - var/mob/living/carbon/human/H = user - if(H.put_in_hands(A)) - to_chat(H, "[A] materializes into your hands!") - return A - to_chat(user, "[A] materializes onto the floor.") + var/mob/living/carbon/human/H = user + if(istype(H) && isitem(A) && H.put_in_hands(A)) + to_chat(H, "[A] materializes into your hands!") + else + to_chat(user, "[A] materializes onto the floor.") + SEND_SIGNAL(U, COMSIG_ON_UPLINK_PURCHASE, A, user) return A //Discounts (dynamically filled above) diff --git a/icons/mob/clothing/head/head.dmi b/icons/mob/clothing/head/head.dmi index 63de684a7a19..dc3c4b03f6ba 100644 Binary files a/icons/mob/clothing/head/head.dmi and b/icons/mob/clothing/head/head.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index 0f0e20e7be39..2d0b03d55c24 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/infernal_affairs.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/infernal_affairs.ts new file mode 100644 index 000000000000..ad06b9ecb619 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/infernal_affairs.ts @@ -0,0 +1,19 @@ +import { Antagonist, Category } from '../base'; +import { multiline } from 'common/string'; +import { TRAITOR_MECHANICAL_DESCRIPTION } from './traitor'; + +const InfernalAffairsAgent: Antagonist = { + key: 'infernalaffairsagent', + name: 'Infernal Affairs Agent', + description: [ + multiline` + Tricked by the Devil into selling your soul, + you must collect his other debts to pay back yours. + `, + + TRAITOR_MECHANICAL_DESCRIPTION, + ], + category: Category.Roundstart, +}; + +export default InfernalAffairsAgent; diff --git a/yogstation.dme b/yogstation.dme index 7ad82064c42c..651147963eb4 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -43,7 +43,6 @@ #include "code\__DEFINES\combat.dm" #include "code\__DEFINES\configuration.dm" #include "code\__DEFINES\construction.dm" -#include "code\__DEFINES\contracts.dm" #include "code\__DEFINES\cooldowns.dm" #include "code\__DEFINES\cult.dm" #include "code\__DEFINES\diseases.dm" @@ -344,6 +343,7 @@ #include "code\controllers\subsystem\garbage.dm" #include "code\controllers\subsystem\icon_smooth.dm" #include "code\controllers\subsystem\idlenpcpool.dm" +#include "code\controllers\subsystem\infernal_affairs.dm" #include "code\controllers\subsystem\input.dm" #include "code\controllers\subsystem\ipintel.dm" #include "code\controllers\subsystem\job.dm" @@ -1729,6 +1729,12 @@ #include "code\modules\antagonists\demon\sins\greed.dm" #include "code\modules\antagonists\demon\sins\pride.dm" #include "code\modules\antagonists\demon\sins\wrath.dm" +#include "code\modules\antagonists\devil_affairs\devil.dm" +#include "code\modules\antagonists\devil_affairs\infernal_agent.dm" +#include "code\modules\antagonists\devil_affairs\true_devil.dm" +#include "code\modules\antagonists\devil_affairs\devil_powers\collect_soul.dm" +#include "code\modules\antagonists\devil_affairs\devil_powers\dancefloor.dm" +#include "code\modules\antagonists\devil_affairs\devil_powers\devil_form.dm" #include "code\modules\antagonists\disease\disease_abilities.dm" #include "code\modules\antagonists\disease\disease_datum.dm" #include "code\modules\antagonists\disease\disease_disease.dm" diff --git a/yogstation/code/datums/components/uplink.dm b/yogstation/code/datums/components/uplink.dm index 364565590be9..9c736e6b55f4 100644 --- a/yogstation/code/datums/components/uplink.dm +++ b/yogstation/code/datums/components/uplink.dm @@ -18,5 +18,5 @@ if(canBuy) return ..() - to_chat(user, span_warning("The Syndicate only permits [U.name][U.name[LAZYLEN(U.name)] != "s" ? "s" : ""] to specific agents. \ - Your mission does not require this equipment.")) + to_chat(user, span_warning("The Syndicate only permits [U.name][U.name[LAZYLEN(U.name)] != "s" ? "s" : ""] \ + to specific agents. Your mission does not require this equipment.")) diff --git a/yogstation/code/modules/antagonists/traitor/datum_traitor.dm b/yogstation/code/modules/antagonists/traitor/datum_traitor.dm index 9de14d0e5974..ac02d1d00e28 100644 --- a/yogstation/code/modules/antagonists/traitor/datum_traitor.dm +++ b/yogstation/code/modules/antagonists/traitor/datum_traitor.dm @@ -1,2 +1,2 @@ /datum/antagonist/traitor - var/obj/item/uplink_holder \ No newline at end of file + var/datum/component/uplink/uplink_holder