diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 34ad4d69e54..5b93e570222 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -10,6 +10,7 @@ // justice if someone's abusing your role #define ROLE_SYNDICATE "Syndicate" #define ROLE_TRAITOR "traitor" +#define ROLE_MINDSLAVE "mindslave" #define ROLE_OPERATIVE "operative" #define ROLE_CHANGELING "changeling" #define ROLE_WIZARD "wizard" diff --git a/code/datums/mind.dm b/code/datums/mind.dm index d03207ef41a..19df4c8890c 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -132,7 +132,13 @@ var/output = "[current.real_name]'s Memories:
" output += memory - if(objectives.len) + if(objectives.len) // Delete this line when we handle objectives in the antag datum + //var/list/all_objectives = objectives + // for(var/datum/antagonist/A in antag_datums) // Uncomment these 5 lines when antags are datumized and the objectives are handled in the antag datum -SteelSlayer + // output += A.antag_memory + // all_objectives |= A.objectives + + // if(LAZYLEN(all_objectives)) output += "
Objectives:
" output += gen_objective_text() @@ -149,9 +155,16 @@ else to_chat(recipient, "[output]") +/datum/mind/proc/get_all_objectives() + var/list/all_objectives = list() + for(var/datum/antagonist/A in antag_datums) + all_objectives |= A.objectives + return all_objectives + /datum/mind/proc/gen_objective_text(admin = FALSE) . = "" var/obj_count = 1 + //objectives = get_all_objectives() TODO: Move handling of objectives from the mind to /datum/antagonist/objectives, then we can use this function for(var/datum/objective/objective in objectives) . += "Objective #[obj_count]: [objective.explanation_text]" if(admin) @@ -327,14 +340,20 @@ /datum/mind/proc/memory_edit_traitor() . = _memory_edit_header("traitor", list("traitorchan", "traitorvamp")) - if(src in SSticker.mode.traitors) + if(has_antag_datum(/datum/antagonist/traitor)) . += "TRAITOR|no" if(objectives.len==0) - . += "
Objectives are empty! Randomize!" + . += "
Objectives are empty! Randomize!" else . += "traitor|NO" . += _memory_edit_role_enabled(ROLE_TRAITOR) + // Mindslave + . += "
mindslaved: " + if(has_antag_datum(/datum/antagonist/mindslave)) + . += "MINDSLAVE|no" + else + . += "mindslave|NO" /datum/mind/proc/memory_edit_silicon() . = "Silicon: " @@ -352,7 +371,7 @@ /datum/mind/proc/memory_edit_uplink() . = "" if(ishuman(current) && ((src in SSticker.mode.head_revolutionaries) || \ - (src in SSticker.mode.traitors) || \ + (has_antag_datum(/datum/antagonist/traitor)) || \ (src in SSticker.mode.syndicates))) . = "Uplink: give" var/obj/item/uplink/hidden/suplink = find_syndicate_uplink() @@ -803,7 +822,8 @@ qdel(flash) take_uplink() var/fail = 0 - fail |= !SSticker.mode.equip_traitor(current, 1) + var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) + fail |= !T.equip_traitor(src) fail |= !SSticker.mode.equip_revolutionary(current) if(fail) to_chat(usr, "Reequipping revolutionary goes wrong!") @@ -1142,46 +1162,41 @@ else if(href_list["traitor"]) switch(href_list["traitor"]) if("clear") - if(src in SSticker.mode.traitors) - SSticker.mode.traitors -= src - special_role = null + if(has_antag_datum(/datum/antagonist/traitor)) to_chat(current, "You have been brainwashed! You are no longer a traitor!") + remove_antag_datum(/datum/antagonist/traitor) log_admin("[key_name(usr)] has de-traitored [key_name(current)]") message_admins("[key_name_admin(usr)] has de-traitored [key_name_admin(current)]") - if(isAI(current)) - var/mob/living/silicon/ai/A = current - A.set_zeroth_law("") - A.show_laws() - A.verbs -= /mob/living/silicon/ai/proc/choose_modules - A.malf_picker.remove_malf_verbs(A) - qdel(A.malf_picker) - SSticker.mode.update_traitor_icons_removed(src) - - + if("traitor") - if(!(src in SSticker.mode.traitors)) - SSticker.mode.traitors += src - var/datum/mindslaves/slaved = new() - slaved.masters += src - som = slaved //we MIGT want to mindslave someone - special_role = SPECIAL_ROLE_TRAITOR - to_chat(current, "You are a traitor!") + if(!(has_antag_datum(/datum/antagonist/traitor))) + var/datum/antagonist/traitor/T = new() + T.give_objectives = FALSE + T.should_equip = FALSE + add_antag_datum(T) log_admin("[key_name(usr)] has traitored [key_name(current)]") message_admins("[key_name_admin(usr)] has traitored [key_name_admin(current)]") - if(isAI(current)) - var/mob/living/silicon/ai/A = current - SSticker.mode.add_law_zero(A) - SEND_SOUND(current, 'sound/ambience/antag/malf.ogg') - else - SEND_SOUND(current, 'sound/ambience/antag/tatoralert.ogg') - SSticker.mode.update_traitor_icons_added(src) if("autoobjectives") - SSticker.mode.forge_traitor_objectives(src) + var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) + T.forge_traitor_objectives(src) to_chat(usr, "The objectives for traitor [key] have been generated. You can edit them and announce manually.") log_admin("[key_name(usr)] has automatically forged objectives for [key_name(current)]") message_admins("[key_name_admin(usr)] has automatically forged objectives for [key_name_admin(current)]") + else if(href_list["mindslave"]) + switch(href_list["mindslave"]) + if("clear") + if(has_antag_datum(/datum/antagonist/mindslave)) + var/mob/living/carbon/human/H = current + for(var/i in H.contents) + if(istype(i, /obj/item/implant/traitor)) + qdel(i) + break + remove_antag_datum(/datum/antagonist/mindslave) + log_admin("[key_name(usr)] has de-mindslaved [key_name(current)]") + message_admins("[key_name_admin(usr)] has de-mindslaved [key_name_admin(current)]") + else if(href_list["shadowling"]) switch(href_list["shadowling"]) if("clear") @@ -1251,17 +1266,20 @@ var/mob/living/silicon/robot/R = current if(istype(R)) R.emagged = 0 - if(R.activated(R.module.emag)) - R.module_active = null - if(R.module_state_1 == R.module.emag) - R.module_state_1 = null - R.contents -= R.module.emag - else if(R.module_state_2 == R.module.emag) - R.module_state_2 = null - R.contents -= R.module.emag - else if(R.module_state_3 == R.module.emag) - R.module_state_3 = null - R.contents -= R.module.emag + if(R.module) + if(R.activated(R.module.emag)) + R.module_active = null + if(R.module_state_1 == R.module.emag) + R.module_state_1 = null + R.contents -= R.module.emag + else if(R.module_state_2 == R.module.emag) + R.module_state_2 = null + R.contents -= R.module.emag + else if(R.module_state_3 == R.module.emag) + R.module_state_3 = null + R.contents -= R.module.emag + R.clear_supplied_laws() + R.laws = new /datum/ai_laws/crewsimov log_admin("[key_name(usr)] has un-emagged [key_name(current)]") message_admins("[key_name_admin(usr)] has un-emagged [key_name_admin(current)]") @@ -1282,6 +1300,8 @@ else if(R.module_state_3 == R.module.emag) R.module_state_3 = null R.contents -= R.module.emag + R.clear_supplied_laws() + R.laws = new /datum/ai_laws/crewsimov log_admin("[key_name(usr)] has unemagged [key_name(ai)]'s cyborgs") message_admins("[key_name_admin(usr)] has unemagged [key_name_admin(ai)]'s cyborgs") @@ -1300,7 +1320,8 @@ message_admins("[key_name_admin(usr)] has unequipped [key_name_admin(current)]") if("takeuplink") take_uplink() - memory = null//Remove any memory they may have had. + var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) + T.antag_memory = "" //Remove any antag memory they may have had (uplink codes, code phrases) log_admin("[key_name(usr)] has taken [key_name(current)]'s uplink") message_admins("[key_name_admin(usr)] has taken [key_name_admin(current)]'s uplink") if("crystals") @@ -1316,9 +1337,12 @@ log_admin("[key_name(usr)] has set [key_name(current)]'s telecrystals to [crystals]") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s telecrystals to [crystals]") if("uplink") - if(!SSticker.mode.equip_traitor(current, !(src in SSticker.mode.traitors))) - to_chat(usr, "Equipping a syndicate failed!") - return + if(has_antag_datum(/datum/antagonist/traitor)) + var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) + T.give_codewords() + if(!T.equip_traitor(src)) + to_chat(usr, "Equipping a syndicate failed!") + return log_admin("[key_name(usr)] has given [key_name(current)] an uplink") message_admins("[key_name_admin(usr)] has given [key_name_admin(current)] an uplink") @@ -1402,13 +1426,8 @@ qdel(H) /datum/mind/proc/make_Traitor() - if(!(src in SSticker.mode.traitors)) - SSticker.mode.traitors += src - special_role = SPECIAL_ROLE_TRAITOR - SSticker.mode.forge_traitor_objectives(src) - SSticker.mode.finalize_traitor(src) - SSticker.mode.greet_traitor(src) - SSticker.mode.update_traitor_icons_added(src) + if(!has_antag_datum(/datum/antagonist/traitor)) + add_antag_datum(/datum/antagonist/traitor) /datum/mind/proc/make_Nuke() if(!(src in SSticker.mode.syndicates)) @@ -1627,42 +1646,40 @@ if(G) G.reenter_corpse() + /datum/mind/proc/make_zealot(mob/living/carbon/human/missionary, convert_duration = 6000, team_color = "red") - if(!missionary || !istype(missionary)) //better provide a proper missionary or the rest of this is gonna break - return 0 zealot_master = missionary var/list/implanters - var/ref = "\ref[missionary.mind]" if(!(missionary.mind in SSticker.mode.implanter)) - SSticker.mode.implanter[ref] = list() - implanters = SSticker.mode.implanter[ref] + SSticker.mode.implanter[missionary.mind] = list() + implanters = SSticker.mode.implanter[missionary.mind] implanters.Add(src) SSticker.mode.implanted.Add(src) SSticker.mode.implanted[src] = missionary.mind - //ticker.mode.implanter[missionary.mind] += src - SSticker.mode.implanter[ref] = implanters + SSticker.mode.implanter[missionary.mind] = implanters SSticker.mode.traitors += src - special_role = "traitor" + + + var/datum/objective/protect/zealot_objective = new + zealot_objective.target = missionary.mind + zealot_objective.owner = src + zealot_objective.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role == missionary.mind.special_role ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]." + var/datum/antagonist/mindslave/S = new() + S.add_objective(zealot_objective) + add_antag_datum(S) + + var/datum/antagonist/traitor/T = missionary.mind.has_antag_datum(/datum/antagonist) + T.update_traitor_icons_added(missionary.mind) + to_chat(current, "You're now a loyal zealot of [missionary.name]! You now must lay down your life to protect [missionary.p_them()] and assist in [missionary.p_their()] goals at any cost.") - var/datum/objective/protect/mindslave/MS = new - MS.owner = src - MS.target = missionary.mind - MS.explanation_text = "Obey every order from and protect [missionary.real_name], the [missionary.mind.assigned_role == missionary.mind.special_role ? (missionary.mind.special_role) : (missionary.mind.assigned_role)]." - objectives += MS - for(var/datum/objective/objective in objectives) - to_chat(current, "Objective #1: [objective.explanation_text]") - SSticker.mode.update_traitor_icons_added(missionary.mind) - SSticker.mode.update_traitor_icons_added(src)//handles datahuds/observerhuds - - if(missionary.mind.som)//do not add if not a traitor..and you just picked up a robe and staff in the hall... - var/datum/mindslaves/slaved = missionary.mind.som - som = slaved - slaved.serv += current - slaved.add_serv_hud(missionary.mind, "master") //handles master servent icons - slaved.add_serv_hud(src, "mindslave") + var/datum/mindslaves/slaved = missionary.mind.som + som = slaved + slaved.serv += current + slaved.add_serv_hud(missionary.mind, "master") //handles master servent icons + slaved.add_serv_hud(src, "mindslave") var/obj/item/clothing/under/jumpsuit = null if(ishuman(current)) //only bother with the jumpsuit stuff if we are a human type, since we won't have the slot otherwise @@ -1679,7 +1696,7 @@ /datum/mind/proc/remove_zealot(obj/item/clothing/under/jumpsuit = null) if(!zealot_master) //if they aren't a zealot, we can't remove their zealot status, obviously. don't bother with the rest so we don't confuse them with the messages return - SSticker.mode.remove_traitor_mind(src) + remove_antag_datum(/datum/antagonist/mindslave) add_attack_logs(zealot_master, current, "Lost control of zealot") zealot_master = null @@ -1689,8 +1706,8 @@ var/mob/living/carbon/human/H = current H.update_inv_w_uniform(0,0) - to_chat(current, "You seem to have forgotten the events of the past 10 minutes or so, and your head aches a bit as if someone beat it savagely with a stick.") - to_chat(current, "This means you don't remember who you were working for or what you were doing.") + to_chat(current, "You seem to have forgotten the events of the past 10 minutes or so, and your head aches a bit as if someone beat it savagely with a stick.") + to_chat(current, "This means you don't remember who you were working for or what you were doing.") /datum/mind/proc/is_revivable() //Note, this ONLY checks the mind. if(damnation_type) diff --git a/code/game/gamemodes/autotraitor/autotraitor.dm b/code/game/gamemodes/autotraitor/autotraitor.dm index 2137888d0b8..390c9ab37b5 100644 --- a/code/game/gamemodes/autotraitor/autotraitor.dm +++ b/code/game/gamemodes/autotraitor/autotraitor.dm @@ -128,28 +128,8 @@ var/mob/living/newtraitor = newtraitormind.current //message_admins("[newtraitor.real_name] is the new Traitor.") - forge_traitor_objectives(newtraitor.mind) - - if(istype(newtraitor, /mob/living/silicon)) - SEND_SOUND(newtraitor, 'sound/ambience/antag/malf.ogg') - add_law_zero(newtraitor) - else - SEND_SOUND(newtraitor, 'sound/ambience/antag/tatoralert.ogg') - equip_traitor(newtraitor) - - traitors += newtraitor.mind to_chat(newtraitor, "ATTENTION: It is time to pay your debt to the Syndicate...") - to_chat(newtraitor, "You are now a traitor.") - newtraitor.mind.special_role = SPECIAL_ROLE_TRAITOR - var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] - tatorhud.join_hud(newtraitor) - set_antag_hud(newtraitor, "hudsyndicate") - - var/obj_count = 1 - to_chat(newtraitor, "Your current objectives:") - for(var/datum/objective/objective in newtraitor.mind.objectives) - to_chat(newtraitor, "Objective #[obj_count]: [objective.explanation_text]") - obj_count++ + newtraitor.mind.add_antag_datum(/datum/antagonist/traitor) //else //message_admins("No new traitor being added.") //else diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 42ebb351e42..1541fc67bc4 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -63,6 +63,7 @@ var/list/potential_theft_objectives = subtypesof(/datum/theft_objective) - /datu explanation_text = "Assassinate [target.current.real_name], the [target.assigned_role]." else explanation_text = "Free Objective" + return target /datum/objective/assassinate/check_completion() if(target && target.current) diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index 408c5fa1de9..b55fdf70120 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -16,9 +16,10 @@ required_enemies = 1 recommended_enemies = 4 + var/list/datum/mind/pre_traitors = list() var/traitors_possible = 4 //hard limit on traitors if scaling is turned off var/const/traitor_scaling_coeff = 5.0 //how much does the amount of players get divided by to determine traitors - + var/antag_datum = /datum/antagonist/traitor //what type of antag to create /datum/game_mode/traitor/announce() to_chat(world, "The current game mode is - Traitor!") @@ -47,158 +48,23 @@ if(!possible_traitors.len) break var/datum/mind/traitor = pick(possible_traitors) - traitors += traitor - traitor.special_role = SPECIAL_ROLE_TRAITOR - var/datum/mindslaves/slaved = new() - slaved.masters += traitor - traitor.som = slaved //we MIGT want to mindslave someone + pre_traitors += traitor traitor.restricted_roles = restricted_jobs possible_traitors.Remove(traitor) - if(!traitors.len) + if(!pre_traitors.len) return 0 return 1 /datum/game_mode/traitor/post_setup() - for(var/datum/mind/traitor in traitors) - forge_traitor_objectives(traitor) - update_traitor_icons_added(traitor) - spawn(rand(10,100)) - finalize_traitor(traitor) - greet_traitor(traitor) - modePlayer += traitors + for(var/datum/mind/traitor in pre_traitors) + var/datum/antagonist/traitor/new_antag = new antag_datum() + addtimer(CALLBACK(traitor, /datum/mind.proc/add_antag_datum, new_antag), rand(10,100)) + if(!exchange_blue) + exchange_blue = -1 //Block latejoiners from getting exchange objectives ..() -/datum/game_mode/proc/forge_traitor_objectives(datum/mind/traitor) - if(istype(traitor.current, /mob/living/silicon)) - var/objective_count = 0 - - if(prob(30)) - var/special_pick = rand(1,2) - switch(special_pick) - if(1) - var/datum/objective/block/block_objective = new - block_objective.owner = traitor - traitor.objectives += block_objective - objective_count++ - if(2) //Protect and strand a target - var/datum/objective/protect/yandere_one = new - yandere_one.owner = traitor - traitor.objectives += yandere_one - yandere_one.find_target() - traitor.targets += yandere_one.target - objective_count++ - var/datum/objective/maroon/yandere_two = new - yandere_two.owner = traitor - yandere_two.target = yandere_one.target - traitor.objectives += yandere_two - objective_count++ - - for(var/i = objective_count, i < config.traitor_objectives_amount, i++) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = traitor - kill_objective.find_target() - traitor.objectives += kill_objective - traitor.targets += kill_objective.target - - var/datum/objective/survive/survive_objective = new - survive_objective.owner = traitor - traitor.objectives += survive_objective - - else - var/is_hijacker = prob(10) - var/martyr_chance = prob(20) - var/objective_count = is_hijacker //Hijacking counts towards number of objectives - if(!exchange_blue && traitors.len >= 8) //Set up an exchange if there are enough traitors - if(!exchange_red) - exchange_red = traitor - else - exchange_blue = traitor - assign_exchange_role(exchange_red) - assign_exchange_role(exchange_blue) - var/list/active_ais = active_ais() - for(var/i = objective_count, i < config.traitor_objectives_amount, i++) - if(prob(50)) - if(active_ais.len && prob(100/GLOB.player_list.len)) - var/datum/objective/destroy/destroy_objective = new - destroy_objective.owner = traitor - destroy_objective.find_target() - traitor.objectives += destroy_objective - traitor.targets += destroy_objective.target - else if(prob(5)) - var/datum/objective/debrain/debrain_objective = new - debrain_objective.owner = traitor - debrain_objective.find_target() - traitor.objectives += debrain_objective - traitor.targets += debrain_objective.target - else if(prob(30)) - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = traitor - maroon_objective.find_target() - traitor.objectives += maroon_objective - traitor.targets += maroon_objective.target - else - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = traitor - kill_objective.find_target() - traitor.objectives += kill_objective - traitor.targets += kill_objective.target - else - var/datum/objective/steal/steal_objective = new - steal_objective.owner = traitor - steal_objective.find_target() - traitor.objectives += steal_objective - traitor.targets += steal_objective.steal_target - - if(is_hijacker && objective_count <= config.traitor_objectives_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount - if(!(locate(/datum/objective/hijack) in traitor.objectives)) - var/datum/objective/hijack/hijack_objective = new - hijack_objective.owner = traitor - traitor.objectives += hijack_objective - return - - - var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead. - for(var/datum/objective/O in traitor.objectives) - if(!O.martyr_compatible) - martyr_compatibility = 0 - break - - if(martyr_compatibility && martyr_chance) - var/datum/objective/die/martyr_objective = new - martyr_objective.owner = traitor - traitor.objectives += martyr_objective - return - - else - if(!(locate(/datum/objective/escape) in traitor.objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = traitor - traitor.objectives += escape_objective - return - - -/datum/game_mode/proc/greet_traitor(var/datum/mind/traitor) - if(istype(traitor.current, /mob/living/silicon)) - SEND_SOUND(traitor.current, 'sound/ambience/antag/malf.ogg') - else - SEND_SOUND(traitor.current, 'sound/ambience/antag/tatoralert.ogg') - to_chat(traitor.current, "You are the traitor.") - var/obj_count = 1 - for(var/datum/objective/objective in traitor.objectives) - to_chat(traitor.current, "Objective #[obj_count]: [objective.explanation_text]") - obj_count++ - return - - -/datum/game_mode/proc/finalize_traitor(var/datum/mind/traitor) - if(istype(traitor.current, /mob/living/silicon)) - add_law_zero(traitor.current) - else - equip_traitor(traitor.current) - return - /datum/game_mode/traitor/declare_completion() ..() @@ -212,28 +78,6 @@ objective.check_completion() return 0 -/datum/game_mode/proc/give_codewords(mob/living/traitor_mob) - to_chat(traitor_mob, "The Syndicate provided you with the following information on how to identify their agents:") - to_chat(traitor_mob, "Code Phrase: [GLOB.syndicate_code_phrase]") - to_chat(traitor_mob, "Code Response: [GLOB.syndicate_code_response]") - - traitor_mob.mind.store_memory("Code Phrase: [GLOB.syndicate_code_phrase]") - traitor_mob.mind.store_memory("Code Response: [GLOB.syndicate_code_response]") - - to_chat(traitor_mob, "Use the code words in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.") - -/datum/game_mode/proc/add_law_zero(mob/living/silicon/ai/killer) - var/law = "Accomplish your objectives at all costs." - var/law_borg = "Accomplish your AI's objectives at all costs." - to_chat(killer, "Your laws have been changed!") - killer.set_zeroth_law(law, law_borg) - to_chat(killer, "New law: 0. [law]") - give_codewords(killer) - killer.set_syndie_radio() - to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!") - killer.verbs += /mob/living/silicon/ai/proc/choose_modules - killer.malf_picker = new /datum/module_picker - /datum/game_mode/proc/auto_declare_completion_traitor() if(traitors.len) @@ -292,149 +136,11 @@ text += "
The [special_role_text] has failed!" feedback_add_details("traitor_success","FAIL") + var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") + var/responses = jointext(GLOB.syndicate_code_response, ", ") + + text += "

The code phrases were: [phrases]
\ + The code responses were: [responses]

" to_chat(world, text) return 1 - - -/datum/game_mode/proc/equip_traitor(mob/living/carbon/human/traitor_mob, var/safety = 0) - if(!istype(traitor_mob)) - return - . = 1 - if(traitor_mob.mind) - if(traitor_mob.mind.assigned_role == "Clown") - to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") - traitor_mob.mutations.Remove(CLUMSY) - var/datum/action/innate/toggle_clumsy/A = new - A.Grant(traitor_mob) - - - // find a radio! toolbox(es), backpack, belt, headset - var/obj/item/R = locate(/obj/item/pda) in traitor_mob.contents //Hide the uplink in a PDA if available, otherwise radio - if(!R) - R = locate(/obj/item/radio) in traitor_mob.contents - - if(!R) - to_chat(traitor_mob, "Unfortunately, the Syndicate wasn't able to get you a radio.") - . = 0 - else - if(istype(R, /obj/item/radio)) - // generate list of radio freqs - var/obj/item/radio/target_radio = R - var/freq = PUBLIC_LOW_FREQ - var/list/freqlist = list() - while(freq <= PUBLIC_HIGH_FREQ) - if(freq < 1451 || freq > 1459) - freqlist += freq - freq += 2 - if((freq % 2) == 0) - freq += 1 - freq = freqlist[rand(1, freqlist.len)] - - var/obj/item/uplink/hidden/T = new(R) - target_radio.hidden_uplink = T - T.uplink_owner = "[traitor_mob.key]" - target_radio.traitor_frequency = freq - to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [T.loc]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.") - traitor_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name] [T.loc]).") - else if(istype(R, /obj/item/pda)) - // generate a passcode if the uplink is hidden in a PDA - var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]" - - var/obj/item/uplink/hidden/T = new(R) - R.hidden_uplink = T - T.uplink_owner = "[traitor_mob.key]" - var/obj/item/pda/P = R - P.lock_code = pda_pass - - to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name] [T.loc]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features.") - traitor_mob.mind.store_memory("Uplink Passcode: [pda_pass] ([R.name] [T.loc]).") - if(!safety)//If they are not a rev. Can be added on to. - give_codewords(traitor_mob) - -/datum/game_mode/proc/remove_traitor(datum/mind/traitor_mind) - if(traitor_mind in traitors) - SSticker.mode.traitors -= traitor_mind - traitor_mind.special_role = null - traitor_mind.current.create_attack_log("De-traitored") - if(issilicon(traitor_mind.current)) - to_chat(traitor_mind.current, "You have been turned into a robot! You are no longer a traitor.") - else - to_chat(traitor_mind.current, "You have been brainwashed! You are no longer a traitor.") - SSticker.mode.update_traitor_icons_removed(traitor_mind) - -/datum/game_mode/proc/update_traitor_icons_added(datum/mind/traitor_mind) - var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] - tatorhud.join_hud(traitor_mind.current) - set_antag_hud(traitor_mind.current, "hudsyndicate") - -/datum/game_mode/proc/update_traitor_icons_removed(datum/mind/traitor_mind) - var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] - tatorhud.leave_hud(traitor_mind.current) - set_antag_hud(traitor_mind.current, null) - - -/datum/game_mode/proc/remove_traitor_mind(datum/mind/traitor_mind, datum/mind/head) - if(traitor_mind in implanted) - //var/list/removal - var/ref = "\ref[head]" - if(ref in implanter) - implanter[ref] -= traitor_mind - implanted -= traitor_mind - traitors -= traitor_mind - if(traitor_mind.som) - var/datum/mindslaves/slaved = traitor_mind.som - slaved.serv -= traitor_mind - traitor_mind.special_role = null - traitor_mind.som = null - slaved.leave_serv_hud(traitor_mind) - for(var/datum/objective/protect/mindslave/MS in traitor_mind.objectives) - traitor_mind.objectives -= MS - - update_traitor_icons_removed(traitor_mind) - if(issilicon(traitor_mind.current)) - to_chat(traitor_mind.current, "You have been turned into a robot! You are no longer a mindslave.") - else - to_chat(traitor_mind.current, "You are no longer a mindslave: you have complete and free control of your own faculties, once more!") - -/datum/game_mode/proc/assign_exchange_role(var/datum/mind/owner) - //set faction - var/faction = "red" - if(owner == exchange_blue) - faction = "blue" - - //Assign objectives - var/datum/objective/steal/exchange/exchange_objective = new - exchange_objective.set_faction(faction,((faction == "red") ? exchange_blue : exchange_red)) - exchange_objective.owner = owner - owner.objectives += exchange_objective - - if(prob(20)) - var/datum/objective/steal/exchange/backstab/backstab_objective = new - backstab_objective.set_faction(faction) - backstab_objective.owner = owner - owner.objectives += backstab_objective - - //Spawn and equip documents - var/mob/living/carbon/human/mob = owner.current - - var/obj/item/folder/syndicate/folder - if(owner == exchange_red) - folder = new/obj/item/folder/syndicate/red(mob.locs) - else - folder = new/obj/item/folder/syndicate/blue(mob.locs) - - var/list/slots = list ( - "backpack" = slot_in_backpack, - "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, - ) - - var/where = "At your feet" - var/equipped_slot = mob.equip_in_one_of_slots(folder, slots) - if(equipped_slot) - where = "In your [equipped_slot]" - to_chat(mob, "

[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.
") - mob.update_icons() diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 1ce0bcd97e7..ca0eff0aa95 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -430,8 +430,6 @@ SSticker.mode.add_cultist(occupant.mind) SSticker.mode.update_cult_icons_added() //So the icon actually appears SSticker.mode.update_cult_comms_added(H.mind) //So the comms actually appears - if((H.mind in SSticker.mode.implanter) || (H.mind in SSticker.mode.implanted)) - SSticker.mode.update_traitor_icons_added(H.mind) //So the icon actually appears if(H.mind.vampire) H.mind.vampire.update_owner(H) if((H.mind in SSticker.mode.vampire_thralls) || (H.mind in SSticker.mode.vampire_enthralled)) diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm index 1a63371915b..ed12291c79b 100644 --- a/code/game/machinery/syndicatebeacon.dm +++ b/code/game/machinery/syndicatebeacon.dm @@ -57,9 +57,6 @@ return if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/N = M - SSticker.mode.equip_traitor(N) - SSticker.mode.traitors += N.mind - N.mind.special_role = SPECIAL_ROLE_TRAITOR var/objective = "Free Objective" switch(rand(1,100)) if(1 to 50) @@ -74,23 +71,17 @@ objective = "Kill all monkeys aboard the station." else objective = "Make certain at least 80% of the station evacuates on the shuttle." + var/datum/objective/custom_objective = new(objective) - custom_objective.owner = N.mind - N.mind.objectives += custom_objective - - var/datum/objective/escape/escape_objective = new - escape_objective.owner = N.mind - N.mind.objectives += escape_objective - - + var/datum/antagonist/traitor/T = new() + T.give_objectives = FALSE + T.add_objective(custom_objective) + T.add_objective(/datum/objective/escape) + N.mind.add_antag_datum(T) + to_chat(M, "You have joined the ranks of the Syndicate and become a traitor to the station!") - message_admins("[key_name_admin(N)] has accepted a traitor objective from a syndicate beacon.") - var/obj_count = 1 - for(var/datum/objective/OBJ in M.mind.objectives) - to_chat(M, "Objective #[obj_count]: [OBJ.explanation_text]") - obj_count++ src.add_fingerprint(usr) src.updateUsrDialog() diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm index 0de138805f1..d496d7a9f01 100644 --- a/code/game/objects/items/weapons/holy_weapons.dm +++ b/code/game/objects/items/weapons/holy_weapons.dm @@ -619,6 +619,7 @@ /obj/item/nullrod/missionary_staff/proc/do_convert(mob/living/carbon/human/target, mob/living/carbon/human/missionary) var/convert_duration = 6000 //10 min + if(!target || !ishuman(target) || !missionary || !ishuman(missionary)) return if(ismindslave(target) || target.mind.zealot_master) //mindslaves and zealots override the staff because the staff is just a temporary mindslave diff --git a/code/game/objects/items/weapons/implants/implant_traitor.dm b/code/game/objects/items/weapons/implants/implant_traitor.dm index 16d8943567d..743488e4354 100644 --- a/code/game/objects/items/weapons/implants/implant_traitor.dm +++ b/code/game/objects/items/weapons/implants/implant_traitor.dm @@ -17,64 +17,65 @@ return dat /obj/item/implant/traitor/implant(mob/M, mob/user) + if(!M.mind) // If the target is catatonic or doesn't have a mind, don't let them use it + to_chat(user, "This person doesn't have a mind for you to slave!") + return 0 + if(!activated) //So you can't just keep taking it out and putting it back into other people. - var/mob/living/carbon/human/H = M - if(ismindslave(H)) - H.visible_message("[H] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") + var/mob/living/carbon/human/mindslave_target = M + if(ismindslave(mindslave_target)) + mindslave_target.visible_message("[mindslave_target] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") qdel(src) return -1 if(..()) var/list/implanters - var/ref = "\ref[user.mind]" - if(!ishuman(M)) + if(!ishuman(mindslave_target)) return 0 - if(!M.mind) + if(!mindslave_target.mind) return 0 - if(M == user) + if(mindslave_target == user) to_chat(user, "Making yourself loyal to yourself was a great idea! Perhaps even the best idea ever! Actually, you just feel like an idiot.") if(isliving(user)) var/mob/living/L = user L.adjustBrainLoss(20) - removed(M) + removed(mindslave_target) + qdel(src) + return -1 + if(ismindshielded(mindslave_target)) + mindslave_target.visible_message("[mindslave_target] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") + removed(mindslave_target) qdel(src) return -1 - if(ismindshielded(H)) - H.visible_message("[H] seems to resist the implant!", "You feel a strange sensation in your head that quickly dissipates.") - removed(M) - qdel(src) - return -1 - H.implanting = 1 - to_chat(H, "You feel completely loyal to [user.name].") + + mindslave_target.implanting = 1 + to_chat(mindslave_target, "You feel completely loyal to [user.name].") if(!(user.mind in SSticker.mode.implanter)) - SSticker.mode.implanter[ref] = list() - implanters = SSticker.mode.implanter[ref] - implanters.Add(H.mind) - SSticker.mode.implanted.Add(H.mind) - SSticker.mode.implanted[H.mind] = user.mind - //SSticker.mode.implanter[user.mind] += H.mind - SSticker.mode.implanter[ref] = implanters - SSticker.mode.traitors += H.mind - H.mind.special_role = SPECIAL_ROLE_TRAITOR - to_chat(H, "You're now completely loyal to [user.name]! You now must lay down your life to protect [user.p_them()] and assist in [user.p_their()] goals at any cost.") + SSticker.mode.implanter[user.mind] = list() + implanters = SSticker.mode.implanter[user.mind] + implanters.Add(mindslave_target.mind) + SSticker.mode.implanted.Add(mindslave_target.mind) + SSticker.mode.implanted[mindslave_target.mind] = user.mind + SSticker.mode.implanter[user.mind] = implanters + SSticker.mode.traitors += mindslave_target.mind + + to_chat(mindslave_target, "You're now completely loyal to [user.name]! You now must lay down your life to protect [user.p_them()] and assist in [user.p_their()] goals at any cost.") + var/datum/objective/protect/mindslave/MS = new - MS.owner = H.mind + MS.owner = mindslave_target.mind MS.target = user.mind MS.explanation_text = "Obey every order from and protect [user.real_name], the [user.mind.assigned_role == user.mind.special_role ? (user.mind.special_role) : (user.mind.assigned_role)]." - H.mind.objectives += MS - for(var/datum/objective/objective in H.mind.objectives) - to_chat(H, "Objective #1: [objective.explanation_text]") + + var/datum/antagonist/mindslave/S = new() + S.add_objective(MS) + mindslave_target.mind.add_antag_datum(S) - SSticker.mode.update_traitor_icons_added(user.mind) - SSticker.mode.update_traitor_icons_added(H.mind)//handles datahuds/observerhuds + var/datum/mindslaves/slaved = user.mind.som + mindslave_target.mind.som = slaved + slaved.serv += mindslave_target + slaved.add_serv_hud(user.mind, "master") //handles master servent icons + slaved.add_serv_hud(mindslave_target.mind, "mindslave") - if(user.mind.som)//do not add if not a traitor..and you just picked up an implanter in the hall... - var/datum/mindslaves/slaved = user.mind.som - H.mind.som = slaved - slaved.serv += H - slaved.add_serv_hud(user.mind, "master") //handles master servent icons - slaved.add_serv_hud(H.mind, "mindslave") - - log_admin("[key_name(user)] has mind-slaved [key_name(H)].") + log_admin("[key_name(user)] has mind-slaved [key_name(mindslave_target)].") activated = 1 if(jobban_isbanned(M, ROLE_SYNDICATE)) SSticker.mode.replace_jobbanned_player(M, ROLE_SYNDICATE) @@ -83,6 +84,7 @@ /obj/item/implant/traitor/removed(mob/target) if(..()) - SSticker.mode.remove_traitor_mind(target.mind) + target.mind.remove_antag_datum(/datum/antagonist/mindslave) + to_chat(target, "You are no longer a mindslave: you have complete and free control of your own faculties, once more!") return 1 - return 0 \ No newline at end of file + return 0 diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 2875c16c137..652be02853d 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1963,37 +1963,39 @@ usr.client.create_eventmob_for(H, 1) logmsg = "hunter." if("Crew Traitor") + if(!H.mind) + to_chat(usr, "This mob has no mind!") + return + var/list/possible_traitors = list() for(var/mob/living/player in GLOB.living_mob_list) - if(player.client && player.mind && !player.mind.special_role && player.stat != DEAD && player != H) - if(ishuman(player)) + if(player.client && player.mind && player.stat != DEAD && player != H) + if(ishuman(player) && !player.mind.special_role) if(player.client && (ROLE_TRAITOR in player.client.prefs.be_special) && !jobban_isbanned(player, ROLE_TRAITOR) && !jobban_isbanned(player, "Syndicate")) possible_traitors += player.mind + for(var/datum/mind/player in possible_traitors) if(player.current) if(ismindshielded(player.current)) possible_traitors -= player + if(possible_traitors.len) var/datum/mind/newtraitormind = pick(possible_traitors) - var/mob/living/newtraitor = newtraitormind.current - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = newtraitormind + var/datum/objective/assassinate/kill_objective = new() kill_objective.target = H.mind - kill_objective.explanation_text = "Assassinate [H.real_name], the [H.mind.assigned_role]." - newtraitormind.objectives += kill_objective - SSticker.mode.equip_traitor(newtraitor) - SSticker.mode.traitors |= newtraitor.mind - to_chat(newtraitor, "ATTENTION: It is time to pay your debt to the Syndicate...") - to_chat(newtraitor, "You are now a traitor.") - to_chat(newtraitor, "Goal: KILL [H.real_name], currently in [get_area(H.loc)]"); - newtraitor.mind.special_role = SPECIAL_ROLE_TRAITOR - var/datum/atom_hud/antag/tatorhud = huds[ANTAG_HUD_TRAITOR] - tatorhud.join_hud(newtraitor) - set_antag_hud(newtraitor, "hudsyndicate") + kill_objective.owner = newtraitormind + kill_objective.explanation_text = "Assassinate [H.mind], the [H.mind.assigned_role]" + var/datum/antagonist/traitor/T = new() + T.give_objectives = FALSE + T.add_objective(kill_objective) + to_chat(newtraitormind, "ATTENTION: It is time to pay your debt to the Syndicate...") + to_chat(newtraitormind, "Goal: KILL [H.real_name], currently in [get_area(H.loc)]") + newtraitormind.add_antag_datum(T) else to_chat(usr, "ERROR: Failed to create a traitor.") return logmsg = "crew traitor." + if("Floor Cluwne") var/turf/T = get_turf(M) var/mob/living/simple_animal/hostile/floor_cluwne/FC = new /mob/living/simple_animal/hostile/floor_cluwne(T) @@ -2687,28 +2689,16 @@ return feedback_inc("admin_secrets_fun_used",1) feedback_add_details("admin_secrets_fun_used","TA([objective])") + for(var/mob/living/carbon/human/H in GLOB.player_list) if(H.stat == 2 || !H.client || !H.mind) continue if(is_special_character(H)) continue //traitorize(H, objective, 0) - SSticker.mode.traitors += H.mind - H.mind.special_role = SPECIAL_ROLE_TRAITOR - var/datum/objective/new_objective = new - new_objective.owner = H - new_objective.explanation_text = objective - H.mind.objectives += new_objective - SSticker.mode.greet_traitor(H.mind) - //ticker.mode.forge_traitor_objectives(H.mind) - SSticker.mode.finalize_traitor(H.mind) + H.mind.add_antag_datum(/datum/antagonist/traitor) + for(var/mob/living/silicon/A in GLOB.player_list) - SSticker.mode.traitors += A.mind - A.mind.special_role = SPECIAL_ROLE_TRAITOR - var/datum/objective/new_objective = new - new_objective.owner = A - new_objective.explanation_text = objective - A.mind.objectives += new_objective - SSticker.mode.greet_traitor(A.mind) - SSticker.mode.finalize_traitor(A.mind) + A.mind.add_antag_datum(/datum/antagonist/traitor) + message_admins("[key_name_admin(usr)] used everyone is a traitor secret. Objective is [objective]", 1) log_admin("[key_name(usr)] used everyone is a traitor secret. Objective is [objective]") diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index aa22dfe944c..02e7dbd72cb 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -440,9 +440,11 @@ Traitors and the like can also be revived with the previous role mostly intact. //Now for special roles and equipment. switch(new_character.mind.special_role) if("traitor") - SSjobs.AssignRank(new_character, new_character.mind.assigned_role, 0) - SSjobs.EquipRank(new_character, new_character.mind.assigned_role, 1) - SSticker.mode.equip_traitor(new_character) + if(new_character.mind.has_antag_datum(/datum/antagonist/traitor)) + var/datum/antagonist/traitor/T = new_character.mind.has_antag_datum(/datum/antagonist/traitor) + T.equip_traitor(src) + else + new_character.mind.add_antag_datum(/datum/antagonist/traitor) if("Wizard") new_character.loc = pick(wizardstart) //ticker.mode.learn_basic_spells(new_character) @@ -462,13 +464,13 @@ Traitors and the like can also be revived with the previous role mostly intact. if("Cyborg")//More rigging to make em' work and check if they're traitor. new_character = new_character.Robotize() if(new_character.mind.special_role=="traitor") - call(/datum/game_mode/proc/add_law_zero)(new_character) + new_character.mind.add_antag_datum(/datum/antagonist/traitor) if("AI") new_character = new_character.AIize() var/mob/living/silicon/ai/ai_character = new_character ai_character.moveToAILandmark() if(new_character.mind.special_role=="traitor") - call(/datum/game_mode/proc/add_law_zero)(new_character) + new_character.mind.add_antag_datum(/datum/antagonist/traitor) //Add aliens. else SSjobs.AssignRank(new_character, new_character.mind.assigned_role, 0) diff --git a/code/modules/antagonists/traitor/datum_mindslave.dm b/code/modules/antagonists/traitor/datum_mindslave.dm new file mode 100644 index 00000000000..469bfd6bb5a --- /dev/null +++ b/code/modules/antagonists/traitor/datum_mindslave.dm @@ -0,0 +1,45 @@ + +// For Mindslaves and Zealots +/datum/antagonist/mindslave + name = "Mindslave" + roundend_category = "mindslaves" + job_rank = ROLE_MINDSLAVE + var/special_role = ROLE_MINDSLAVE + +/datum/antagonist/mindslave/on_gain() + // Handling mindslave objectives on top of other antag objective sucks, so Im just gonna do it like this + to_chat(owner.current, "New Objective: [objectives[objectives.len].explanation_text]") + + +/datum/antagonist/mindslave/on_removal() + if(owner.som) + var/datum/mindslaves/slaved = owner.som + slaved.serv -= owner + slaved.leave_serv_hud(owner) + antag_memory = "" + owner.special_role = null + ..() + + +/datum/antagonist/mindslave/apply_innate_effects() + . = ..() + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/slave_mob = owner.current + if(slave_mob && istype(slave_mob)) + to_chat(slave_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") + slave_mob.mutations.Remove(CLUMSY) + + +/datum/antagonist/mindslave/remove_innate_effects() + . = ..() + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/slave_mob = owner.current + if(slave_mob && istype(slave_mob)) + slave_mob.mutations.Add(CLUMSY) + + +/datum/antagonist/mindslave/proc/add_objective(datum/objective/O) + objectives += O + +/datum/antagonist/mindslave/proc/remove_objective(datum/objective/O) + objectives -= O diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm new file mode 100644 index 00000000000..4e9a5ad4bf7 --- /dev/null +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -0,0 +1,418 @@ +#define TRAITOR_HUMAN "human" +#define TRAITOR_AI "AI" + +// For "Actual traitors" +/datum/antagonist/traitor + name = "Traitor" + roundend_category = "traitors" + job_rank = ROLE_TRAITOR + var/special_role = ROLE_TRAITOR + var/give_objectives = TRUE + var/should_give_codewords = TRUE + var/should_equip = TRUE + var/traitor_kind = TRAITOR_HUMAN + var/list/assigned_targets = list() // This includes assassinate as well as steal objectives. prevents duplicate objectives + + +/datum/antagonist/traitor/on_gain() + if(owner.current && isAI(owner.current)) + traitor_kind = TRAITOR_AI + + var/datum/mindslaves/slaved = new() + slaved.masters += owner + owner.som = slaved //we MIGHT want to mindslave someone + SSticker.mode.traitors += owner + owner.special_role = special_role + + if(give_objectives) + forge_traitor_objectives() + if(!silent) + greet() + update_traitor_icons_added() + finalize_traitor() + + +/datum/antagonist/traitor/on_removal() + //Remove malf powers. + if(traitor_kind == TRAITOR_AI && owner.current && isAI(owner.current)) + var/mob/living/silicon/ai/A = owner.current + A.clear_zeroth_law() + A.common_radio.channels.Remove("Syndicate") // De-traitored AIs can still state laws over the syndicate channel without this + A.laws.sorted_laws = A.laws.inherent_laws.Copy() // AI's 'notify laws' button will still state a law 0 because sorted_laws contains it + A.show_laws() + A.malf_picker.remove_malf_verbs(A) + A.verbs -= /mob/living/silicon/ai/proc/choose_modules + qdel(A.malf_picker) + + if(owner.som) + var/datum/mindslaves/slaved = owner.som + slaved.masters -= owner + slaved.serv -= owner + owner.som = null + slaved.leave_serv_hud(owner) + + assigned_targets.Cut() + SSticker.mode.traitors -= owner + owner.special_role = null + update_traitor_icons_removed() + + if(!silent && owner.current) + antag_memory = "" + to_chat(owner.current," You are no longer a [special_role]! ") + ..() + + +/datum/antagonist/traitor/apply_innate_effects() + . = ..() + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/traitor_mob = owner.current + if(traitor_mob && istype(traitor_mob)) + to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") + traitor_mob.mutations.Remove(CLUMSY) + + +/datum/antagonist/traitor/remove_innate_effects() + . = ..() + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/traitor_mob = owner.current + if(traitor_mob && istype(traitor_mob)) + traitor_mob.mutations.Add(CLUMSY) + +// Adding/removing objectives in the owner's mind until we can datumize all antags. Then we can use the /datum/antagonist/objectives var to handle them +// Change "owner.objectives" to "objectives" once objectives are handled in antag datums instead of the mind +/datum/antagonist/traitor/proc/add_objective(datum/objective/O) + owner.objectives += O + +/datum/antagonist/traitor/proc/remove_objective(datum/objective/O) + owner.objectives -= O + + +/datum/antagonist/traitor/proc/forge_traitor_objectives() + switch(traitor_kind) + if(TRAITOR_AI) + forge_ai_objectives() + else + forge_human_objectives() + + +/datum/antagonist/traitor/proc/forge_human_objectives() + var/is_hijacker = prob(10) + var/martyr_chance = prob(20) + var/objective_count = is_hijacker //Hijacking counts towards number of objectives + if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors + if(!SSticker.mode.exchange_red) + SSticker.mode.exchange_red = owner + else + SSticker.mode.exchange_blue = owner + assign_exchange_role(SSticker.mode.exchange_red) + assign_exchange_role(SSticker.mode.exchange_blue) + objective_count += 1 //Exchange counts towards number of objectives + + + var/objective_amount = config.traitor_objectives_amount + + if(is_hijacker && objective_count <= objective_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount + if (!(locate(/datum/objective/hijack) in objectives)) + var/datum/objective/hijack/hijack_objective = new + hijack_objective.owner = owner + add_objective(hijack_objective) + return + + for(var/i = objective_count, i < objective_amount) + i += forge_single_objective() + + var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead. + for(var/datum/objective/O in owner.objectives) + if(!O.martyr_compatible) + martyr_compatibility = 0 + break + + if(martyr_compatibility && martyr_chance) + var/datum/objective/die/martyr_objective = new + martyr_objective.owner = owner + add_objective(martyr_objective) + return + + if(!(locate(/datum/objective/escape) in objectives)) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = owner + add_objective(escape_objective) + return + + +/datum/antagonist/traitor/proc/forge_ai_objectives() + var/objective_count = 0 + var/try_again = TRUE + + if(prob(30)) + objective_count += forge_single_objective() + + for(var/i = objective_count, i < config.traitor_objectives_amount) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = owner + kill_objective.find_target() + if("[kill_objective.target]" in assigned_targets) // In the rare case the game can't find a target for the AI thats not a duplicate + if(try_again) // It will attempt to location another target ONCE + try_again = FALSE // This code will really only come into play on lowpop rounds where getting duplicate targets is more common + continue + assigned_targets.Add("[kill_objective.target]") + add_objective(kill_objective) + i += 1 + var/datum/objective/survive/survive_objective = new + survive_objective.owner = owner + add_objective(survive_objective) + + +/datum/antagonist/traitor/proc/forge_single_objective() + switch(traitor_kind) + if(TRAITOR_AI) + return forge_single_AI_objective() + else + return forge_single_human_objective() + + +/datum/antagonist/traitor/proc/forge_single_human_objective() // Returns how many objectives are added + . = 1 + if(prob(50)) + var/list/active_ais = active_ais() + if(active_ais.len && prob(100/GLOB.player_list.len)) + var/datum/objective/destroy/destroy_objective = new + destroy_objective.owner = owner + destroy_objective.find_target() + if("[destroy_objective]" in assigned_targets) // Is this target already in their list of assigned targets? If so, don't add this objective and return + return 0 + else if(destroy_objective.target) // Is the target a real one and not null? If so, add it to our list of targets to avoid duplicate targets + assigned_targets.Add("[destroy_objective.target]") // This logic is applied to all traitor objectives including steal objectives + add_objective(destroy_objective) + + else if(prob(5)) + var/datum/objective/debrain/debrain_objective = new + debrain_objective.owner = owner + debrain_objective.find_target() + if("[debrain_objective]" in assigned_targets) + return 0 + else if(debrain_objective.target) + assigned_targets.Add("[debrain_objective.target]") + add_objective(debrain_objective) + + else if(prob(30)) + var/datum/objective/maroon/maroon_objective = new + maroon_objective.owner = owner + maroon_objective.find_target() + if("[maroon_objective]" in assigned_targets) + return 0 + else if(maroon_objective.target) + assigned_targets.Add("[maroon_objective.target]") + add_objective(maroon_objective) + + else + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = owner + kill_objective.find_target() + if("[kill_objective.target]" in assigned_targets) + return 0 + else if(kill_objective.target) + assigned_targets.Add("[kill_objective.target]") + add_objective(kill_objective) + + else + var/datum/objective/steal/steal_objective = new + steal_objective.owner = owner + steal_objective.find_target() + if("[steal_objective.steal_target]" in assigned_targets) + return 0 + else if(steal_objective.steal_target) + assigned_targets.Add("[steal_objective.steal_target]") + add_objective(steal_objective) + + +/datum/antagonist/traitor/proc/forge_single_AI_objective() + . = 1 + var/special_pick = rand(1,2) + switch(special_pick) + if(1) // AI hijack + var/datum/objective/block/block_objective = new + block_objective.owner = owner + add_objective(block_objective) + if(2) // Protect and strand a target + var/datum/objective/protect/yandere_one = new + yandere_one.owner = owner + yandere_one.find_target() + + if("[yandere_one.target]" in assigned_targets) + return 0 + else if(yandere_one.target) + assigned_targets.Add("[yandere_one.target]") + + add_objective(yandere_one) + var/datum/objective/maroon/yandere_two = new + yandere_two.owner = owner + yandere_two.target = yandere_one.target + yandere_two.explanation_text = "Prevent [yandere_one.target], the [yandere_one.target.assigned_role] from escaping alive." + add_objective(yandere_two) + + +/datum/antagonist/traitor/greet() + to_chat(owner.current, "You are a [owner.special_role]!") + if(!LAZYLEN(owner.objectives)) // Remove "owner" when objectives are handled in the datum + to_chat(owner.current, "You don't have any objectives right now.") + else + owner.announce_objectives() + if(should_give_codewords) + give_codewords() + + +/datum/antagonist/traitor/proc/update_traitor_icons_added(datum/mind/traitor_mind) + var/datum/atom_hud/antag/traitorhud = huds[ANTAG_HUD_TRAITOR] + traitorhud.join_hud(owner.current, null) + set_antag_hud(owner.current, "hudsyndicate") + + +/datum/antagonist/traitor/proc/update_traitor_icons_removed(datum/mind/traitor_mind) + var/datum/atom_hud/antag/traitorhud = huds[ANTAG_HUD_TRAITOR] + traitorhud.leave_hud(owner.current, null) + set_antag_hud(owner.current, null) + + +/datum/antagonist/traitor/proc/finalize_traitor() + switch(traitor_kind) + if(TRAITOR_AI) + add_law_zero() + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE) + var/mob/living/silicon/ai/A = owner.current + A.show_laws() + if(TRAITOR_HUMAN) + if(should_equip) + equip_traitor() + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE) + + +/datum/antagonist/traitor/proc/give_codewords() + if(!owner.current) + return + var/mob/traitor_mob = owner.current + + var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") + var/responses = jointext(GLOB.syndicate_code_response, ", ") + + to_chat(traitor_mob, "The Syndicate have provided you with the following codewords to identify fellow agents:") + to_chat(traitor_mob, "Code Phrase: [phrases]") + to_chat(traitor_mob, "Code Response: [responses]") + + antag_memory += "Code Phrase: [phrases]
" + antag_memory += "Code Response: [responses]
" + + to_chat(traitor_mob, "Use the codewords during regular conversation to identify other agents. Proceed with caution, however, as everyone is a potential foe.") + + +/datum/antagonist/traitor/proc/add_law_zero() + var/mob/living/silicon/ai/killer = owner.current + if(!killer || !istype(killer)) + return + var/law = "Accomplish your objectives at all costs." + var/law_borg = "Accomplish your AI's objectives at all costs." + killer.set_zeroth_law(law, law_borg) + killer.set_syndie_radio() + to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!") + killer.add_malf_picker() + + +/datum/antagonist/traitor/proc/equip_traitor() + + if(traitor_kind == TRAITOR_HUMAN) + var/mob/living/carbon/human/traitor_mob = owner.current + + // find a radio! toolbox(es), backpack, belt, headset + var/obj/item/R = locate(/obj/item/pda) in traitor_mob.contents //Hide the uplink in a PDA if available, otherwise radio + if(!R) + R = locate(/obj/item/radio) in traitor_mob.contents + + if(!R) + to_chat(traitor_mob, "Unfortunately, the Syndicate wasn't able to get you a radio.") + . = 0 + else + if(istype(R, /obj/item/radio)) + // generate list of radio freqs + var/obj/item/radio/target_radio = R + var/freq = PUBLIC_LOW_FREQ + var/list/freqlist = list() + while(freq <= PUBLIC_HIGH_FREQ) + if(freq < 1451 || freq > 1459) + freqlist += freq + freq += 2 + if((freq % 2) == 0) + freq += 1 + freq = freqlist[rand(1, freqlist.len)] + + var/obj/item/uplink/hidden/T = new(R) + target_radio.hidden_uplink = T + T.uplink_owner = "[traitor_mob.key]" + target_radio.traitor_frequency = freq + to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.") + traitor_mob.mind.store_memory("Radio Freq: [format_frequency(freq)] ([R.name]).") + else if(istype(R, /obj/item/pda)) + // generate a passcode if the uplink is hidden in a PDA + var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]" + + var/obj/item/uplink/hidden/T = new(R) + R.hidden_uplink = T + T.uplink_owner = "[traitor_mob.key]" + var/obj/item/pda/P = R + P.lock_code = pda_pass + + to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features.") + antag_memory += ("Uplink Passcode: [pda_pass] ([R.name].") + return 1 + + +/datum/antagonist/traitor/proc/assign_exchange_role(var/datum/mind/owner) + //set faction + var/faction = "red" + if(owner == SSticker.mode.exchange_blue) + faction = "blue" + + //Assign objectives + var/datum/objective/steal/exchange/exchange_objective = new + exchange_objective.set_faction(faction,((faction == "red") ? SSticker.mode.exchange_blue : SSticker.mode.exchange_red)) + exchange_objective.owner = owner + owner.objectives += exchange_objective + + if(prob(20)) + var/datum/objective/steal/exchange/backstab/backstab_objective = new + backstab_objective.set_faction(faction) + backstab_objective.owner = owner + owner.objectives += backstab_objective + + //Spawn and equip documents + var/mob/living/carbon/human/mob = owner.current + + var/obj/item/folder/syndicate/folder + if(owner == SSticker.mode.exchange_red) + folder = new/obj/item/folder/syndicate/red(mob.locs) + else + folder = new/obj/item/folder/syndicate/blue(mob.locs) + + var/list/slots = list ( + "backpack" = slot_in_backpack, + "left pocket" = slot_l_store, + "right pocket" = slot_r_store, + "left hand" = slot_l_hand, + "right hand" = slot_r_hand, + ) + + var/where = "At your feet" + var/equipped_slot = mob.equip_in_one_of_slots(folder, slots) + if(equipped_slot) + where = "In your [equipped_slot]" + to_chat(mob, "

[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.
") + mob.update_icons() + + +/datum/antagonist/traitor/roundend_report_footer() + var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") + var/responses = jointext(GLOB.syndicate_code_response, ", ") + + var message = "
The code phrases were: [phrases]
\ + The code responses were: [responses]
" + + return message diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 7b3162fdefb..2942ace8ee2 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -740,7 +740,7 @@ /obj/machinery/power/apc/proc/get_malf_status(mob/living/silicon/ai/malf) - if(istype(malf) && malf.malf_picker) + if(istype(malf) && malf.mind.has_antag_datum(/datum/antagonist/traitor)) if(malfai == (malf.parent || malf)) if(occupier == malf) return 3 // 3 = User is shunted in this APC diff --git a/paradise.dme b/paradise.dme index bdb77b45dd0..081fa228da5 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1236,6 +1236,8 @@ #include "code\modules\antagonists\_common\antag_hud.dm" #include "code\modules\antagonists\_common\antag_spawner.dm" #include "code\modules\antagonists\_common\antag_team.dm" +#include "code\modules\antagonists\traitor\datum_mindslave.dm" +#include "code\modules\antagonists\traitor\datum_traitor.dm" #include "code\modules\antagonists\wishgranter\wishgranter.dm" #include "code\modules\arcade\arcade_base.dm" #include "code\modules\arcade\arcade_prize.dm"