From ebac066b2f003c0e37961db1a5226384cf910c4e Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 25 Feb 2020 16:10:23 -0800 Subject: [PATCH 01/17] lets add traitor classes --- code/datums/mind.dm | 14 +- .../modules/antagonists/traitor/classes/ai.dm | 70 ++++++++++ .../antagonists/traitor/classes/gorlex.dm | 25 ++++ .../antagonists/traitor/classes/human.dm | 131 ++++++++++++++++++ .../traitor/classes/traitor_class.dm | 35 +++++ .../antagonists/traitor/datum_traitor.dm | 90 +++++------- strings/flavor_objectives/ninja_helping.txt | 1 - strings/flavor_objectives/traitor.txt | 1 - 8 files changed, 306 insertions(+), 61 deletions(-) create mode 100644 code/modules/antagonists/traitor/classes/ai.dm create mode 100644 code/modules/antagonists/traitor/classes/gorlex.dm create mode 100644 code/modules/antagonists/traitor/classes/human.dm create mode 100644 code/modules/antagonists/traitor/classes/traitor_class.dm diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 61d467a20d..5cde9c5115 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -257,9 +257,11 @@ remove_rev() SSticker.mode.update_cult_icons_removed(src) -/datum/mind/proc/equip_traitor(employer = "The Syndicate", silent = FALSE, datum/antagonist/uplink_owner) +/datum/mind/proc/equip_traitor(traitor_class, silent = FALSE, datum/antagonist/uplink_owner) if(!current) return + if(!traitor_class) + traitor_class = GLOB.traitor_classes[BASIC_TRAITOR] var/mob/living/carbon/human/traitor_mob = current if (!istype(traitor_mob)) return @@ -307,21 +309,21 @@ if (!uplink_loc) if(!silent) - to_chat(traitor_mob, "Unfortunately, [employer] wasn't able to get you an Uplink.") + to_chat(traitor_mob, "Unfortunately, [traitor_class.employer] wasn't able to get you an Uplink.") . = 0 else . = uplink_loc - var/datum/component/uplink/U = uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key) + var/datum/component/uplink/U = uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key,traitor_class) if(!U) CRASH("Uplink creation failed.") U.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, "[traitor_class.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.") 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, "[traitor_class.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.") 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 [U.unlock_code] from its starting position to unlock its hidden features.") + to_chat(traitor_mob, "[traitor_class.employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [U.unlock_code] from its starting position to unlock its hidden features.") if(uplink_owner) uplink_owner.antag_memory += U.unlock_note + "
" diff --git a/code/modules/antagonists/traitor/classes/ai.dm b/code/modules/antagonists/traitor/classes/ai.dm new file mode 100644 index 0000000000..60d7dcdeba --- /dev/null +++ b/code/modules/antagonists/traitor/classes/ai.dm @@ -0,0 +1,70 @@ +#define TRAITOR_AI /datum/traitor_class/ai + +/datum/traitor_class/ai // this one is special, so has no weight + name = "Malfunctioning AI" + +/datum/traitor_class/ai/forge_objectives(/datum/antagonist/traitor/T) + var/objective_count = 0 + + if(prob(30)) + objective_count += forge_single_objective() + + for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = owner + kill_objective.find_target() + T.add_objective(kill_objective) + + var/datum/objective/survive/exist/exist_objective = new + exist_objective.owner = owner + T.add_objective(exist_objective) + +/datum/traitor_class/ai/forge_single_objective(/datum/antagonist/traitor/T) + .=1 + var/special_pick = rand(1,4) + switch(special_pick) + if(1) + var/datum/objective/block/block_objective = new + block_objective.owner = owner + T.add_objective(block_objective) + if(2) + var/datum/objective/purge/purge_objective = new + purge_objective.owner = owner + T.add_objective(purge_objective) + if(3) + var/datum/objective/robot_army/robot_objective = new + robot_objective.owner = owner + T.add_objective(robot_objective) + if(4) //Protect and strand a target + var/datum/objective/protect/yandere_one = new + yandere_one.owner = owner + T.add_objective(yandere_one) + yandere_one.find_target() + var/datum/objective/maroon/yandere_two = new + yandere_two.owner = owner + yandere_two.target = yandere_one.target + yandere_two.update_explanation_text() // normally called in find_target() + T.add_objective(yandere_two) + .=2 + +/datum/traitor_class/ai/on_removal(/datum/antagonist/traitor/T) + var/mob/living/silicon/ai/A = T.owner.current + A.set_zeroth_law("") + A.verbs -= /mob/living/silicon/ai/proc/choose_modules + A.malf_picker.remove_malf_verbs(A) + qdel(A.malf_picker) + + +/datum/traitor_class/ai/apply_innate_effects(mob/living/M) + var/mob/living/silicon/ai/A = M + A.hack_software = TRUE + +/datum/traitor_class/ai/remove_innate_effects(mob/living/M) + var/mob/living/silicon/ai/A = M + A.hack_software = FALSE + +/datum/traitor_class/ai/finalize_objectives(/datum/antagonist/traitor/T) + T.add_law_zero() + T.owner.current.playsound_local(get_turf(T.owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE) + T.owner.current.grant_language(/datum/language/codespeak) + return FALSE diff --git a/code/modules/antagonists/traitor/classes/gorlex.dm b/code/modules/antagonists/traitor/classes/gorlex.dm new file mode 100644 index 0000000000..1089d7ef50 --- /dev/null +++ b/code/modules/antagonists/traitor/classes/gorlex.dm @@ -0,0 +1,25 @@ +/datum/traitor_class/human/gorlex + name = "Gorlex Marauders" + employer = "Gorlex Marauders" + weight = 2 + chaos = 20 + TC = 30 + +/datum/traitor_class/proc/forge_objectives(/datum/antagonist/traitor/T) + // Like the old forge_human_objectives. Makes all the objectives for this traitor class. + +/datum/traitor_class/proc/forge_single_objective(/datum/antagonist/traitor/T) + // As forge_single_objective. + +/datum/traitor_class/proc/on_removal(/datum/antagonist/traitor/T) + // What this does to the antag datum on removal. Called before proper removal, obviously. + +/datum/traitor_class/proc/apply_innate_effects(mob/living/M) + // What innate effects it should have. See: AI. + +/datum/traitor_class/proc/remove_innate_effects(mob/living/M) + // Cleaning up the innate effects. + +/datum/traitor_class/proc/finalize_traitor(/datum/antagonist/traitor/T) + // Finalization. Return TRUE if should play standard traitor sound/equip, return FALSE if both are special case + return TRUE diff --git a/code/modules/antagonists/traitor/classes/human.dm b/code/modules/antagonists/traitor/classes/human.dm new file mode 100644 index 0000000000..1f7b64d4f5 --- /dev/null +++ b/code/modules/antagonists/traitor/classes/human.dm @@ -0,0 +1,131 @@ +#define BASIC_TRAITOR /datum/traitor_class/human + +/datum/traitor_class/human + name = "Traitor" + chaos = 1 + +/datum/traitor_class/human/forge_objectives(/datum/antagonist/traitor/T) + var/is_hijacker = FALSE + var/datum/game_mode/dynamic/mode + var/is_dynamic = FALSE + var/hijack_prob = 0 + if(istype(SSticker.mode,/datum/game_mode/dynamic)) + mode = SSticker.mode + is_dynamic = TRUE + if(mode.threat >= CONFIG_GET(number/dynamic_hijack_cost)) + hijack_prob = CLAMP(mode.threat_level-50,0,20) + if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit) + is_hijacker = (prob(hijack_prob) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement)) + else + var/indice_pop = min(10,round(GLOB.joined_player_list.len/mode.pop_per_requirement)+1) + is_hijacker = (prob(hijack_prob) && (mode.threat_level >= CONFIG_GET(number_list/dynamic_hijack_requirements)[indice_pop])) + if(mode.storyteller.flags & NO_ASSASSIN) + is_hijacker = FALSE + else if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks + hijack_prob = 10 + is_hijacker = prob(10) + var/martyr_chance = prob(hijack_prob*2) + 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 = T.owner + else + SSticker.mode.exchange_blue = T.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/toa = CONFIG_GET(number/traitor_objectives_amount) + for(var/i = objective_count, i < toa, i++) + forge_single_objective(T) + + if(is_hijacker && objective_count <= toa) //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 = T.owner + T.add_objective(hijack_objective) + if(is_dynamic) + var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost) + mode.spend_threat(threat_spent) + mode.log_threat("[owner.name] spent [threat_spent] on hijack.") + return + + + var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead. + for(var/datum/objective/O in objectives) + if(!O.martyr_compatible) + martyr_compatibility = 0 + break + + if(martyr_compatibility && martyr_chance) + var/datum/objective/martyr/martyr_objective = new + martyr_objective.owner = T.owner + T.add_objective(martyr_objective) + if(is_dynamic) + var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost) + mode.spend_threat(threat_spent) + mode.log_threat("[owner.name] spent [threat_spent] on glorious death.") + return + + else + if(!(locate(/datum/objective/escape) in objectives)) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = owner + T.add_objective(escape_objective) + return + +/datum/traitor_class/human/forge_single_objective(/datum/antagonist/traitor/T) + .=1 + var/assassin_prob = 50 + var/is_dynamic = FALSE + var/datum/game_mode/dynamic/mode + if(istype(SSticker.mode,/datum/game_mode/dynamic)) + mode = SSticker.mode + is_dynamic = TRUE + assassin_prob = max(0,mode.threat_level-20) + if(prob(assassin_prob)) + if(is_dynamic) + var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost) + mode.spend_threat(threat_spent) + mode.log_threat("[T.owner.name] spent [threat_spent] on an assassination target.") + var/list/active_ais = active_ais() + if(active_ais.len && prob(100/GLOB.joined_player_list.len)) + var/datum/objective/destroy/destroy_objective = new + destroy_objective.owner = T.owner + destroy_objective.find_target() + T.add_objective(destroy_objective) + else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN))) + var/datum/objective/maroon/maroon_objective = new + maroon_objective.owner = T.owner + maroon_objective.find_target() + T.add_objective(maroon_objective) + else if(prob(max(0,assassin_prob-20))) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = T.owner + kill_objective.find_target() + T.add_objective(kill_objective) + else + var/datum/objective/assassinate/once/kill_objective = new + kill_objective.owner = T.owner + kill_objective.find_target() + T.add_objective(kill_objective) + else + if(prob(15) && !(locate(/datum/objective/download) in objectives) && !(owner.assigned_role in list("Research Director", "Scientist", "Roboticist"))) + var/datum/objective/download/download_objective = new + download_objective.owner = T.owner + download_objective.gen_amount_goal() + T.add_objective(download_objective) + else if(prob(40)) // cum. not counting download: 40%. + var/datum/objective/steal/steal_objective = new + steal_objective.owner = T.owner + steal_objective.find_target() + T.add_objective(steal_objective) + else if(prob(100/3)) // cum. not counting download: 20%. + var/datum/objective/sabotage/sabotage_objective = new + sabotage_objective.owner = T.owner + sabotage_objective.find_target() + T.add_objective(sabotage_objective) + else // cum. not counting download: 40% + var/datum/objective/flavor/traitor/flavor_objective = new + flavor_objective.owner = T.owner + flavor_objective.forge_objective() + T.add_objective(flavor_objective) diff --git a/code/modules/antagonists/traitor/classes/traitor_class.dm b/code/modules/antagonists/traitor/classes/traitor_class.dm new file mode 100644 index 0000000000..8107fa5af9 --- /dev/null +++ b/code/modules/antagonists/traitor/classes/traitor_class.dm @@ -0,0 +1,35 @@ +GLOBAL_LIST_EMPTY(traitor_classes) + +/datum/traitor_class + var/name = "Bad Coders Ltd." + var/employer = "The Syndicate" + var/weight = 0 + var/chaos = 0 + var/TC = 20 + +/datum/traitor_class/New() + ..() + if(src.type in traitor_classes) + qdel(src) + else + traitor_classes += src.type + traitor_classes[src.type] = src + +/datum/traitor_class/proc/forge_objectives(/datum/antagonist/traitor/T) + // Like the old forge_human_objectives. Makes all the objectives for this traitor class. + +/datum/traitor_class/proc/forge_single_objective(/datum/antagonist/traitor/T) + // As forge_single_objective. + +/datum/traitor_class/proc/on_removal(/datum/antagonist/traitor/T) + // What this does to the antag datum on removal. Called before proper removal, obviously. + +/datum/traitor_class/proc/apply_innate_effects(mob/living/M) + // What innate effects it should have. See: AI. + +/datum/traitor_class/proc/remove_innate_effects(mob/living/M) + // Cleaning up the innate effects. + +/datum/traitor_class/proc/finalize_traitor(/datum/antagonist/traitor/T) + // Finalization. Return TRUE if should play standard traitor sound/equip, return FALSE if both are special case + return TRUE diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 1c7ee48f71..da35d1ffdc 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -1,5 +1,4 @@ #define TRAITOR_HUMAN "human" -#define TRAITOR_AI "AI" /datum/antagonist/traitor name = "Traitor" @@ -12,21 +11,42 @@ var/give_objectives = TRUE var/should_give_codewords = TRUE var/should_equip = TRUE - var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment + var/datum/traitor_class/traitor_kind = TRAITOR_HUMAN //Set on initial assignment can_hijack = HIJACK_HIJACKER +/datum/antagonist/traitor/New() + ..() + if(!GLOB.traitor_classes.len)//Only need to fill the list when it's needed. + for(var/I in subtypesof(/datum/traitor_class)) + new I + +/datum/antagonist/traitor/proc/set_traitor_kind(var/kind) + traitor_kind = traitor_classes[kind] + /datum/antagonist/traitor/on_gain() if(owner.current && isAI(owner.current)) - traitor_kind = TRAITOR_AI - + set_traitor_kind(TRAITOR_AI) + else + var/chaos_weight = 0 + if(istype(SSticker.mode,/datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + chaos_weight = (mode.threat - 50)/50 + var/list/weights = list() + for(var/C in traitor_classes) + var/datum/traitor_class/class = C + var/weight = class.weight/(1+NUM_E**(-chaos_weight*class.chaos)) // just a logistic function + weights[C] = weight + set_traitor_kind(pickweightAllowZero(weights)) + traitor_kind.weight /= 2 // less likely this round SSticker.mode.traitors += owner owner.special_role = special_role if(give_objectives) - forge_traitor_objectives() - finalize_traitor() + traitor_kind.forge_objectives(src) + traitor_kind.finalize_traitor(src) ..() /datum/antagonist/traitor/apply_innate_effects() + traitor_kind.apply_innate_effects(src) if(owner.assigned_role == "Clown") var/mob/living/carbon/human/traitor_mob = owner.current if(traitor_mob && istype(traitor_mob)) @@ -35,6 +55,7 @@ traitor_mob.dna.remove_mutation(CLOWNMUT) /datum/antagonist/traitor/remove_innate_effects() + traitor_kind.remove_innate_effects(src) if(owner.assigned_role == "Clown") var/mob/living/carbon/human/traitor_mob = owner.current if(traitor_mob && istype(traitor_mob)) @@ -42,12 +63,7 @@ /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.set_zeroth_law("") - A.verbs -= /mob/living/silicon/ai/proc/choose_modules - A.malf_picker.remove_malf_verbs(A) - qdel(A.malf_picker) + traitor_kind.on_removal(src) SSticker.mode.traitors -= owner if(!silent && owner.current) to_chat(owner.current," You are no longer the [special_role]! ") @@ -67,6 +83,7 @@ objectives -= O /datum/antagonist/traitor/proc/forge_traitor_objectives() + traitor_kind.forge_objectives(src) switch(traitor_kind) if(TRAITOR_AI) forge_ai_objectives() @@ -142,30 +159,6 @@ add_objective(escape_objective) return -/datum/antagonist/traitor/proc/forge_ai_objectives() - var/objective_count = 0 - - if(prob(30)) - objective_count += forge_single_objective() - - for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = owner - kill_objective.find_target() - add_objective(kill_objective) - - var/datum/objective/survive/exist/exist_objective = new - exist_objective.owner = owner - add_objective(exist_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 var/assassin_prob = 50 @@ -268,32 +261,24 @@ 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) - owner.current.grant_language(/datum/language/codespeak) - if(TRAITOR_HUMAN) - if(should_equip) - equip(silent) - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE) + var/should_base_finalize = traitor_kind.finalize_traitor(src) + if(should_base_finalize) + if(should_equip) + equip(silent) + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE) /datum/antagonist/traitor/apply_innate_effects(mob/living/mob_override) . = ..() update_traitor_icons_added() var/mob/M = mob_override || owner.current - if(isAI(M) && traitor_kind == TRAITOR_AI) - var/mob/living/silicon/ai/A = M - A.hack_software = TRUE + traitor_kind.apply_innate_effects(M) RegisterSignal(M, COMSIG_MOVABLE_HEAR, .proc/handle_hearing) /datum/antagonist/traitor/remove_innate_effects(mob/living/mob_override) . = ..() update_traitor_icons_removed() var/mob/M = mob_override || owner.current - if(isAI(M) && traitor_kind == TRAITOR_AI) - var/mob/living/silicon/ai/A = M - A.hack_software = FALSE + traitor_kind.remove_innate_effects(M) UnregisterSignal(M, COMSIG_MOVABLE_HEAR) /datum/antagonist/traitor/proc/give_codewords() @@ -324,8 +309,7 @@ killer.add_malf_picker() /datum/antagonist/traitor/proc/equip(var/silent = FALSE) - if(traitor_kind == TRAITOR_HUMAN) - owner.equip_traitor(employer, silent, src) + owner.equip_traitor(traitor_kind, silent, src) /datum/antagonist/traitor/proc/assign_exchange_role() //set faction diff --git a/strings/flavor_objectives/ninja_helping.txt b/strings/flavor_objectives/ninja_helping.txt index 1280939b5c..4cca9a2234 100644 --- a/strings/flavor_objectives/ninja_helping.txt +++ b/strings/flavor_objectives/ninja_helping.txt @@ -1,6 +1,5 @@ Nanotrasen want to make sure that their employees are on the up-and-up. Try to find any blackmail you can. Increase productivity however you can. -You are a security ninja. Answer to the Head of Security, and follow space law. You are a cargo ninja. Answer to the Quartermaster, and do what they say. Nanotrasen want you to ensure maximum morale. Protect the members of the crew who are on break. Ensure that all the paperwork is being done. \ No newline at end of file diff --git a/strings/flavor_objectives/traitor.txt b/strings/flavor_objectives/traitor.txt index 6d54c8ed9d..1a08b6cac1 100644 --- a/strings/flavor_objectives/traitor.txt +++ b/strings/flavor_objectives/traitor.txt @@ -2,7 +2,6 @@ The Gorlex Marauders want you to teach the heads of staff a lesson they will nev Show Nanotrasen the utility of a 40% oxygen atmosphere. Waffle Co. wants you To cause as much humorous terrorism against Nanotrasen as possible! How? We don’t care as long as it’s entertaining! Be as creative and exciting as possible when carrying out your dirty deeds. Have fun! Kill one of the station's beloved pets. Make a show of it, though you don't have to reveal yourself. -The Tiger Cooperative want you to get their illegal technology spread through the station. The Animal Rights Consortium needs you to save the innocent non-humanoid creatures aboard Citadel Station by any means necessary. Use your best judgement to decide whether an animal or xenobiological is abused, but if they are, ensure the abuser is punished. Avoid killing too many people if possible, and if you do harm any creatures, you will be terminated upon extraction. Donk Co. wants ransom money, and you are going to get it. Your goal is to kidnap and crewmember you can get your hands on and hold them hostage until you get something of significant value. Try to work out the best deal you can. Remember that Higher Value Targets are generally going to get a better deal so try to prioritize heads of staff if possible. We do not approve of mindless killing of Nanotrasen employees, so don’t do it. The Gorlex Marauders want you to steal as many shoes as possible. Lay broken glass everywhere. \ No newline at end of file From f344af633f69242a6e92b12aaeae2bfd66802d07 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 29 Feb 2020 23:29:24 -0800 Subject: [PATCH 02/17] finalized. --- code/__DEFINES/antagonists.dm | 3 + code/datums/components/uplink.dm | 8 +- code/datums/mind.dm | 4 +- .../traitor/IAA/internal_affairs.dm | 8 - .../modules/antagonists/traitor/classes/ai.dm | 24 ++- .../antagonists/traitor/classes/assassin.dm | 37 ++++ .../antagonists/traitor/classes/gimmick.dm | 12 ++ .../antagonists/traitor/classes/gorlex.dm | 25 --- .../antagonists/traitor/classes/hijack.dm | 15 ++ .../antagonists/traitor/classes/human.dm | 79 ++------ .../antagonists/traitor/classes/martyr.dm | 15 ++ .../antagonists/traitor/classes/subterfuge.dm | 40 ++++ .../traitor/classes/traitor_class.dm | 19 +- .../antagonists/traitor/datum_traitor.dm | 178 ++---------------- code/modules/uplink/uplink_items.dm | 5 +- tgstation.dme | 8 + 16 files changed, 192 insertions(+), 288 deletions(-) create mode 100644 code/modules/antagonists/traitor/classes/assassin.dm create mode 100644 code/modules/antagonists/traitor/classes/gimmick.dm delete mode 100644 code/modules/antagonists/traitor/classes/gorlex.dm create mode 100644 code/modules/antagonists/traitor/classes/hijack.dm create mode 100644 code/modules/antagonists/traitor/classes/martyr.dm create mode 100644 code/modules/antagonists/traitor/classes/subterfuge.dm diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index cabcc0a17d..9084e60ce2 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -1,3 +1,6 @@ +#define TRAITOR_HUMAN /datum/traitor_class/human +#define TRAITOR_AI /datum/traitor_class/ai + #define NUKE_RESULT_FLUKE 0 #define NUKE_RESULT_NUKE_WIN 1 #define NUKE_RESULT_CREW_WIN 2 diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index a8e03946b6..e73465d785 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -28,7 +28,7 @@ GLOBAL_LIST_EMPTY(uplinks) var/compact_mode = FALSE var/debug = FALSE -/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate) +/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20, datum/ui_state/_checkstate, datum/traitor_class/traitor_class) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -47,7 +47,11 @@ GLOBAL_LIST_EMPTY(uplinks) RegisterSignal(parent, COMSIG_PEN_ROTATED, .proc/pen_rotation) GLOB.uplinks += src - uplink_items = get_uplink_items(gamemode, TRUE, allow_restricted) + var/list/filters = list() + if(istype(traitor_class)) + filters = traitor_class.uplink_filters + starting_tc = traitor_class.TC + uplink_items = get_uplink_items(gamemode, TRUE, allow_restricted, filters) if(_owner) owner = _owner diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 5cde9c5115..16870b3f75 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -257,11 +257,11 @@ remove_rev() SSticker.mode.update_cult_icons_removed(src) -/datum/mind/proc/equip_traitor(traitor_class, silent = FALSE, datum/antagonist/uplink_owner) +/datum/mind/proc/equip_traitor(datum/traitor_class/traitor_class, silent = FALSE, datum/antagonist/uplink_owner) if(!current) return if(!traitor_class) - traitor_class = GLOB.traitor_classes[BASIC_TRAITOR] + traitor_class = GLOB.traitor_classes[TRAITOR_HUMAN] var/mob/living/carbon/human/traitor_mob = current if (!istype(traitor_mob)) return diff --git a/code/modules/antagonists/traitor/IAA/internal_affairs.dm b/code/modules/antagonists/traitor/IAA/internal_affairs.dm index caf2f644df..f6ee056865 100644 --- a/code/modules/antagonists/traitor/IAA/internal_affairs.dm +++ b/code/modules/antagonists/traitor/IAA/internal_affairs.dm @@ -215,14 +215,6 @@ kill_objective.target = target_mind kill_objective.update_explanation_text() add_objective(kill_objective) - - //Optional traitor objective - if(prob(PROB_ACTUAL_TRAITOR)) - employer = "The Syndicate" - owner.special_role = TRAITOR_AGENT_ROLE - special_role = TRAITOR_AGENT_ROLE - syndicate = TRUE - forge_single_objective() return /datum/antagonist/traitor/internal_affairs/forge_traitor_objectives() diff --git a/code/modules/antagonists/traitor/classes/ai.dm b/code/modules/antagonists/traitor/classes/ai.dm index 60d7dcdeba..fac1efeb49 100644 --- a/code/modules/antagonists/traitor/classes/ai.dm +++ b/code/modules/antagonists/traitor/classes/ai.dm @@ -1,9 +1,7 @@ -#define TRAITOR_AI /datum/traitor_class/ai - /datum/traitor_class/ai // this one is special, so has no weight name = "Malfunctioning AI" -/datum/traitor_class/ai/forge_objectives(/datum/antagonist/traitor/T) +/datum/traitor_class/ai/forge_objectives(datum/antagonist/traitor/T) var/objective_count = 0 if(prob(30)) @@ -11,43 +9,43 @@ for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++) var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = owner + kill_objective.owner = T.owner kill_objective.find_target() T.add_objective(kill_objective) var/datum/objective/survive/exist/exist_objective = new - exist_objective.owner = owner + exist_objective.owner = T.owner T.add_objective(exist_objective) -/datum/traitor_class/ai/forge_single_objective(/datum/antagonist/traitor/T) +/datum/traitor_class/ai/forge_single_objective(datum/antagonist/traitor/T) .=1 var/special_pick = rand(1,4) switch(special_pick) if(1) var/datum/objective/block/block_objective = new - block_objective.owner = owner + block_objective.owner = T.owner T.add_objective(block_objective) if(2) var/datum/objective/purge/purge_objective = new - purge_objective.owner = owner + purge_objective.owner = T.owner T.add_objective(purge_objective) if(3) var/datum/objective/robot_army/robot_objective = new - robot_objective.owner = owner + robot_objective.owner = T.owner T.add_objective(robot_objective) if(4) //Protect and strand a target var/datum/objective/protect/yandere_one = new - yandere_one.owner = owner + yandere_one.owner = T.owner T.add_objective(yandere_one) yandere_one.find_target() var/datum/objective/maroon/yandere_two = new - yandere_two.owner = owner + yandere_two.owner = T.owner yandere_two.target = yandere_one.target yandere_two.update_explanation_text() // normally called in find_target() T.add_objective(yandere_two) .=2 -/datum/traitor_class/ai/on_removal(/datum/antagonist/traitor/T) +/datum/traitor_class/ai/on_removal(datum/antagonist/traitor/T) var/mob/living/silicon/ai/A = T.owner.current A.set_zeroth_law("") A.verbs -= /mob/living/silicon/ai/proc/choose_modules @@ -63,7 +61,7 @@ var/mob/living/silicon/ai/A = M A.hack_software = FALSE -/datum/traitor_class/ai/finalize_objectives(/datum/antagonist/traitor/T) +/datum/traitor_class/ai/finalize_traitor(datum/antagonist/traitor/T) T.add_law_zero() T.owner.current.playsound_local(get_turf(T.owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE) T.owner.current.grant_language(/datum/language/codespeak) diff --git a/code/modules/antagonists/traitor/classes/assassin.dm b/code/modules/antagonists/traitor/classes/assassin.dm new file mode 100644 index 0000000000..ca192aff5a --- /dev/null +++ b/code/modules/antagonists/traitor/classes/assassin.dm @@ -0,0 +1,37 @@ +/datum/traitor_class/human/assassin + name = "Donk Co Operative" + employer = "Donk Corporation" + weight = 4 + chaos = 1 + cost = 2 + +/datum/traitor_class/human/assassin/forge_single_objective(datum/antagonist/traitor/T) + .=1 + var/permakill_prob = 20 + var/is_dynamic = FALSE + var/datum/game_mode/dynamic/mode + if(istype(SSticker.mode,/datum/game_mode/dynamic)) + mode = SSticker.mode + is_dynamic = TRUE + permakill_prob = max(0,mode.threat_level-50) + var/list/active_ais = active_ais() + if(active_ais.len && prob(100/GLOB.joined_player_list.len)) + var/datum/objective/destroy/destroy_objective = new + destroy_objective.owner = T.owner + destroy_objective.find_target() + T.add_objective(destroy_objective) + else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN))) + var/datum/objective/maroon/maroon_objective = new + maroon_objective.owner = T.owner + maroon_objective.find_target() + T.add_objective(maroon_objective) + else if(prob(permakill_prob)) + var/datum/objective/assassinate/kill_objective = new + kill_objective.owner = T.owner + kill_objective.find_target() + T.add_objective(kill_objective) + else + var/datum/objective/assassinate/once/kill_objective = new + kill_objective.owner = T.owner + kill_objective.find_target() + T.add_objective(kill_objective) diff --git a/code/modules/antagonists/traitor/classes/gimmick.dm b/code/modules/antagonists/traitor/classes/gimmick.dm new file mode 100644 index 0000000000..12f9674140 --- /dev/null +++ b/code/modules/antagonists/traitor/classes/gimmick.dm @@ -0,0 +1,12 @@ +/datum/traitor_class/human/gimmick + name = "Waffle Co Agent" + employer = "Waffle Company" + weight = 4 + chaos = 0 + +/datum/traitor_class/human/gimmick/forge_objectives(datum/antagonist/traitor/T) + var/datum/objective/escape/O = new + O.explanation_text = "You have no goals! Whatever you can do do antagonize Nanotrasen, do it! The gimmickier, the better! Make sure to escape alive, though!" + O.owner = T.owner + T.add_objective(O) + return diff --git a/code/modules/antagonists/traitor/classes/gorlex.dm b/code/modules/antagonists/traitor/classes/gorlex.dm deleted file mode 100644 index 1089d7ef50..0000000000 --- a/code/modules/antagonists/traitor/classes/gorlex.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/traitor_class/human/gorlex - name = "Gorlex Marauders" - employer = "Gorlex Marauders" - weight = 2 - chaos = 20 - TC = 30 - -/datum/traitor_class/proc/forge_objectives(/datum/antagonist/traitor/T) - // Like the old forge_human_objectives. Makes all the objectives for this traitor class. - -/datum/traitor_class/proc/forge_single_objective(/datum/antagonist/traitor/T) - // As forge_single_objective. - -/datum/traitor_class/proc/on_removal(/datum/antagonist/traitor/T) - // What this does to the antag datum on removal. Called before proper removal, obviously. - -/datum/traitor_class/proc/apply_innate_effects(mob/living/M) - // What innate effects it should have. See: AI. - -/datum/traitor_class/proc/remove_innate_effects(mob/living/M) - // Cleaning up the innate effects. - -/datum/traitor_class/proc/finalize_traitor(/datum/antagonist/traitor/T) - // Finalization. Return TRUE if should play standard traitor sound/equip, return FALSE if both are special case - return TRUE diff --git a/code/modules/antagonists/traitor/classes/hijack.dm b/code/modules/antagonists/traitor/classes/hijack.dm new file mode 100644 index 0000000000..0ed716c3cd --- /dev/null +++ b/code/modules/antagonists/traitor/classes/hijack.dm @@ -0,0 +1,15 @@ +/datum/traitor_class/human/martyr + name = "Gorlex Marauder" + employer = "The Gorlex Marauders" + weight = 2 + chaos = 5 + cost = 5 + TC = 30 + uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit) + +/datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T) + var/datum/objective/hijack/O = new + O.explanation_text = "The Gorlex Marauders are letting you do what you want, with one condition: the shuttle must be hijacked." + O.owner = T.owner + T.add_objective(O) + return diff --git a/code/modules/antagonists/traitor/classes/human.dm b/code/modules/antagonists/traitor/classes/human.dm index 1f7b64d4f5..4e096390c0 100644 --- a/code/modules/antagonists/traitor/classes/human.dm +++ b/code/modules/antagonists/traitor/classes/human.dm @@ -1,79 +1,27 @@ -#define BASIC_TRAITOR /datum/traitor_class/human - /datum/traitor_class/human - name = "Traitor" - chaos = 1 + name = "Syndicate Agent" + chaos = 0 -/datum/traitor_class/human/forge_objectives(/datum/antagonist/traitor/T) - var/is_hijacker = FALSE - var/datum/game_mode/dynamic/mode - var/is_dynamic = FALSE - var/hijack_prob = 0 - if(istype(SSticker.mode,/datum/game_mode/dynamic)) - mode = SSticker.mode - is_dynamic = TRUE - if(mode.threat >= CONFIG_GET(number/dynamic_hijack_cost)) - hijack_prob = CLAMP(mode.threat_level-50,0,20) - if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit) - is_hijacker = (prob(hijack_prob) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement)) - else - var/indice_pop = min(10,round(GLOB.joined_player_list.len/mode.pop_per_requirement)+1) - is_hijacker = (prob(hijack_prob) && (mode.threat_level >= CONFIG_GET(number_list/dynamic_hijack_requirements)[indice_pop])) - if(mode.storyteller.flags & NO_ASSASSIN) - is_hijacker = FALSE - else if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks - hijack_prob = 10 - is_hijacker = prob(10) - var/martyr_chance = prob(hijack_prob*2) - var/objective_count = is_hijacker //Hijacking counts towards number of objectives +/datum/traitor_class/human/forge_objectives(datum/antagonist/traitor/T) + var/objective_count = 0 //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 = T.owner else SSticker.mode.exchange_blue = T.owner - assign_exchange_role(SSticker.mode.exchange_red) - assign_exchange_role(SSticker.mode.exchange_blue) + T.assign_exchange_role(SSticker.mode.exchange_red) + T.assign_exchange_role(SSticker.mode.exchange_blue) objective_count += 1 //Exchange counts towards number of objectives var/toa = CONFIG_GET(number/traitor_objectives_amount) for(var/i = objective_count, i < toa, i++) forge_single_objective(T) - - if(is_hijacker && objective_count <= toa) //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 = T.owner - T.add_objective(hijack_objective) - if(is_dynamic) - var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost) - mode.spend_threat(threat_spent) - mode.log_threat("[owner.name] spent [threat_spent] on hijack.") - return - - - var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead. - for(var/datum/objective/O in objectives) - if(!O.martyr_compatible) - martyr_compatibility = 0 - break - - if(martyr_compatibility && martyr_chance) - var/datum/objective/martyr/martyr_objective = new - martyr_objective.owner = T.owner - T.add_objective(martyr_objective) - if(is_dynamic) - var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost) - mode.spend_threat(threat_spent) - mode.log_threat("[owner.name] spent [threat_spent] on glorious death.") + if(!(locate(/datum/objective/escape) in T.objectives)) + var/datum/objective/escape/escape_objective = new + escape_objective.owner = T.owner + T.add_objective(escape_objective) return - else - if(!(locate(/datum/objective/escape) in objectives)) - var/datum/objective/escape/escape_objective = new - escape_objective.owner = owner - T.add_objective(escape_objective) - return - -/datum/traitor_class/human/forge_single_objective(/datum/antagonist/traitor/T) +/datum/traitor_class/human/forge_single_objective(datum/antagonist/traitor/T) .=1 var/assassin_prob = 50 var/is_dynamic = FALSE @@ -109,7 +57,7 @@ kill_objective.find_target() T.add_objective(kill_objective) else - if(prob(15) && !(locate(/datum/objective/download) in objectives) && !(owner.assigned_role in list("Research Director", "Scientist", "Roboticist"))) + if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist"))) var/datum/objective/download/download_objective = new download_objective.owner = T.owner download_objective.gen_amount_goal() @@ -129,3 +77,6 @@ flavor_objective.owner = T.owner flavor_objective.forge_objective() T.add_objective(flavor_objective) + +/datum/traitor_class/human/greet(datum/antagonist/traitor/T) + to_chat(T.owner.current, "You are under contract with [employer]. They have given you your objectives.") diff --git a/code/modules/antagonists/traitor/classes/martyr.dm b/code/modules/antagonists/traitor/classes/martyr.dm new file mode 100644 index 0000000000..c934c38417 --- /dev/null +++ b/code/modules/antagonists/traitor/classes/martyr.dm @@ -0,0 +1,15 @@ +/datum/traitor_class/human/martyr + name = "Tiger Cooperative Agent" + employer = "The Tiger Cooperative" + weight = 2 + chaos = 5 + cost = 5 + TC = 30 + uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit) + +/datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T) + var/datum/objective/martyr/O = new + O.explanation_text = "The tiger cooperative have given you free reign. You may do as you wish, as long as you die a glorious death!" + O.owner = T.owner + T.add_objective(O) + return diff --git a/code/modules/antagonists/traitor/classes/subterfuge.dm b/code/modules/antagonists/traitor/classes/subterfuge.dm new file mode 100644 index 0000000000..2b4716e67e --- /dev/null +++ b/code/modules/antagonists/traitor/classes/subterfuge.dm @@ -0,0 +1,40 @@ +/datum/traitor_class/human/subterfuge + name = "MI13 Operative" + employer = "MI13" + weight = 4 + chaos = -5 + +/datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T) + .=1 + var/assassin_prob = 20 + var/is_dynamic = FALSE + var/datum/game_mode/dynamic/mode + if(istype(SSticker.mode,/datum/game_mode/dynamic)) + mode = SSticker.mode + is_dynamic = TRUE + assassin_prob = max(0,mode.threat_level-50) + if(prob(assassin_prob)) + if(is_dynamic) + var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost) + mode.spend_threat(threat_spent) + mode.log_threat("[T.owner.name] spent [threat_spent] on an assassination target.") + var/datum/objective/maroon/maroon_objective = new + maroon_objective.owner = T.owner + maroon_objective.find_target() + T.add_objective(maroon_objective) + else + if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist"))) + var/datum/objective/download/download_objective = new + download_objective.owner = T.owner + download_objective.gen_amount_goal() + T.add_objective(download_objective) + else if(prob(70)) // cum. not counting download: 40%. + var/datum/objective/steal/steal_objective = new + steal_objective.owner = T.owner + steal_objective.find_target() + T.add_objective(steal_objective) + else + var/datum/objective/sabotage/sabotage_objective = new + sabotage_objective.owner = T.owner + sabotage_objective.find_target() + T.add_objective(sabotage_objective) diff --git a/code/modules/antagonists/traitor/classes/traitor_class.dm b/code/modules/antagonists/traitor/classes/traitor_class.dm index 8107fa5af9..3df9dec929 100644 --- a/code/modules/antagonists/traitor/classes/traitor_class.dm +++ b/code/modules/antagonists/traitor/classes/traitor_class.dm @@ -5,23 +5,25 @@ GLOBAL_LIST_EMPTY(traitor_classes) var/employer = "The Syndicate" var/weight = 0 var/chaos = 0 + var/cost = 0 var/TC = 20 + var/list/uplink_filters /datum/traitor_class/New() ..() - if(src.type in traitor_classes) + if(src.type in GLOB.traitor_classes) qdel(src) else - traitor_classes += src.type - traitor_classes[src.type] = src + GLOB.traitor_classes += src.type + GLOB.traitor_classes[src.type] = src -/datum/traitor_class/proc/forge_objectives(/datum/antagonist/traitor/T) +/datum/traitor_class/proc/forge_objectives(datum/antagonist/traitor/T) // Like the old forge_human_objectives. Makes all the objectives for this traitor class. -/datum/traitor_class/proc/forge_single_objective(/datum/antagonist/traitor/T) +/datum/traitor_class/proc/forge_single_objective(datum/antagonist/traitor/T) // As forge_single_objective. -/datum/traitor_class/proc/on_removal(/datum/antagonist/traitor/T) +/datum/traitor_class/proc/on_removal(datum/antagonist/traitor/T) // What this does to the antag datum on removal. Called before proper removal, obviously. /datum/traitor_class/proc/apply_innate_effects(mob/living/M) @@ -30,6 +32,9 @@ GLOBAL_LIST_EMPTY(traitor_classes) /datum/traitor_class/proc/remove_innate_effects(mob/living/M) // Cleaning up the innate effects. -/datum/traitor_class/proc/finalize_traitor(/datum/antagonist/traitor/T) +/datum/traitor_class/proc/greet(datum/antagonist/traitor/T) + // Message upon creation. Not necessary, but can be useful. + +/datum/traitor_class/proc/finalize_traitor(datum/antagonist/traitor/T) // Finalization. Return TRUE if should play standard traitor sound/equip, return FALSE if both are special case return TRUE diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index da35d1ffdc..fcaa0f2211 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -1,5 +1,3 @@ -#define TRAITOR_HUMAN "human" - /datum/antagonist/traitor name = "Traitor" roundend_category = "traitors" @@ -11,7 +9,7 @@ var/give_objectives = TRUE var/should_give_codewords = TRUE var/should_equip = TRUE - var/datum/traitor_class/traitor_kind = TRAITOR_HUMAN //Set on initial assignment + var/datum/traitor_class/traitor_kind can_hijack = HIJACK_HIJACKER /datum/antagonist/traitor/New() @@ -21,7 +19,12 @@ new I /datum/antagonist/traitor/proc/set_traitor_kind(var/kind) - traitor_kind = traitor_classes[kind] + traitor_kind = GLOB.traitor_classes[kind] + if(istype(SSticker.mode, /datum/game_mode/dynamic)) + var/datum/game_mode/dynamic/mode = SSticker.mode + if(traitor_kind.cost) + mode.spend_threat(traitor_kind.cost) + mode.log_threat("[traitor_kind.cost] was spent due to [owner.name] being a [traitor_kind.name].") /datum/antagonist/traitor/on_gain() if(owner.current && isAI(owner.current)) @@ -32,10 +35,13 @@ var/datum/game_mode/dynamic/mode = SSticker.mode chaos_weight = (mode.threat - 50)/50 var/list/weights = list() - for(var/C in traitor_classes) - var/datum/traitor_class/class = C + for(var/C in GLOB.traitor_classes) + var/datum/traitor_class/class = GLOB.traitor_classes[C] var/weight = class.weight/(1+NUM_E**(-chaos_weight*class.chaos)) // just a logistic function weights[C] = weight + var/choice = pickweightAllowZero(weights) + if(!choice) + choice = GLOB.traitor_classes[TRAITOR_HUMAN] set_traitor_kind(pickweightAllowZero(weights)) traitor_kind.weight /= 2 // less likely this round SSticker.mode.traitors += owner @@ -84,168 +90,10 @@ /datum/antagonist/traitor/proc/forge_traitor_objectives() traitor_kind.forge_objectives(src) - switch(traitor_kind) - if(TRAITOR_AI) - forge_ai_objectives() - else - forge_human_objectives() - -/datum/antagonist/traitor/proc/forge_human_objectives() - var/is_hijacker = FALSE - var/datum/game_mode/dynamic/mode - var/is_dynamic = FALSE - var/hijack_prob = 0 - if(istype(SSticker.mode,/datum/game_mode/dynamic)) - mode = SSticker.mode - is_dynamic = TRUE - if(mode.threat >= CONFIG_GET(number/dynamic_hijack_cost)) - hijack_prob = CLAMP(mode.threat_level-50,0,20) - if(GLOB.joined_player_list.len>=GLOB.dynamic_high_pop_limit) - is_hijacker = (prob(hijack_prob) && mode.threat_level > CONFIG_GET(number/dynamic_hijack_high_population_requirement)) - else - var/indice_pop = min(10,round(GLOB.joined_player_list.len/mode.pop_per_requirement)+1) - is_hijacker = (prob(hijack_prob) && (mode.threat_level >= CONFIG_GET(number_list/dynamic_hijack_requirements)[indice_pop])) - if(mode.storyteller.flags & NO_ASSASSIN) - is_hijacker = FALSE - else if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks - hijack_prob = 10 - is_hijacker = prob(10) - var/martyr_chance = prob(hijack_prob*2) - 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/toa = CONFIG_GET(number/traitor_objectives_amount) - for(var/i = objective_count, i < toa, i++) - forge_single_objective() - - if(is_hijacker && objective_count <= toa) //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) - if(is_dynamic) - var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost) - mode.spend_threat(threat_spent) - mode.log_threat("[owner.name] spent [threat_spent] on hijack.") - return - - - var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead. - for(var/datum/objective/O in objectives) - if(!O.martyr_compatible) - martyr_compatibility = 0 - break - - if(martyr_compatibility && martyr_chance) - var/datum/objective/martyr/martyr_objective = new - martyr_objective.owner = owner - add_objective(martyr_objective) - if(is_dynamic) - var/threat_spent = CONFIG_GET(number/dynamic_hijack_cost) - mode.spend_threat(threat_spent) - mode.log_threat("[owner.name] spent [threat_spent] on glorious death.") - return - - else - 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_single_human_objective() //Returns how many objectives are added - .=1 - var/assassin_prob = 50 - var/is_dynamic = FALSE - var/datum/game_mode/dynamic/mode - if(istype(SSticker.mode,/datum/game_mode/dynamic)) - mode = SSticker.mode - is_dynamic = TRUE - assassin_prob = max(0,mode.threat_level-20) - if(prob(assassin_prob)) - if(is_dynamic) - var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost) - mode.spend_threat(threat_spent) - mode.log_threat("[owner.name] spent [threat_spent] on an assassination target.") - var/list/active_ais = active_ais() - if(active_ais.len && prob(100/GLOB.joined_player_list.len)) - var/datum/objective/destroy/destroy_objective = new - destroy_objective.owner = owner - destroy_objective.find_target() - add_objective(destroy_objective) - else if(prob(30) || (is_dynamic && (mode.storyteller.flags & NO_ASSASSIN))) - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = owner - maroon_objective.find_target() - add_objective(maroon_objective) - else if(prob(max(0,assassin_prob-20))) - var/datum/objective/assassinate/kill_objective = new - kill_objective.owner = owner - kill_objective.find_target() - add_objective(kill_objective) - else - var/datum/objective/assassinate/once/kill_objective = new - kill_objective.owner = owner - kill_objective.find_target() - add_objective(kill_objective) - else - if(prob(15) && !(locate(/datum/objective/download) in objectives) && !(owner.assigned_role in list("Research Director", "Scientist", "Roboticist"))) - var/datum/objective/download/download_objective = new - download_objective.owner = owner - download_objective.gen_amount_goal() - add_objective(download_objective) - else if(prob(40)) // cum. not counting download: 40%. - var/datum/objective/steal/steal_objective = new - steal_objective.owner = owner - steal_objective.find_target() - add_objective(steal_objective) - else if(prob(100/3)) // cum. not counting download: 20%. - var/datum/objective/sabotage/sabotage_objective = new - sabotage_objective.owner = owner - sabotage_objective.find_target() - add_objective(sabotage_objective) - else // cum. not counting download: 40% - var/datum/objective/flavor/traitor/flavor_objective = new - flavor_objective.owner = owner - flavor_objective.forge_objective() - add_objective(flavor_objective) - -/datum/antagonist/traitor/proc/forge_single_AI_objective() - .=1 - var/special_pick = rand(1,4) - switch(special_pick) - if(1) - var/datum/objective/block/block_objective = new - block_objective.owner = owner - add_objective(block_objective) - if(2) - var/datum/objective/purge/purge_objective = new - purge_objective.owner = owner - add_objective(purge_objective) - if(3) - var/datum/objective/robot_army/robot_objective = new - robot_objective.owner = owner - add_objective(robot_objective) - if(4) //Protect and strand a target - var/datum/objective/protect/yandere_one = new - yandere_one.owner = owner - add_objective(yandere_one) - yandere_one.find_target() - var/datum/objective/maroon/yandere_two = new - yandere_two.owner = owner - yandere_two.target = yandere_one.target - yandere_two.update_explanation_text() // normally called in find_target() - add_objective(yandere_two) - .=2 /datum/antagonist/traitor/greet() to_chat(owner.current, "You are the [owner.special_role].") + traitor_kind.greet(src) owner.announce_objectives() if(should_give_codewords) give_codewords() diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 52f6efd3df..bbfa186a48 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -1,4 +1,4 @@ -/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE) +/proc/get_uplink_items(datum/game_mode/gamemode, allow_sales = TRUE, allow_restricted = TRUE, other_filter = list()) var/list/filtered_uplink_items = GLOB.uplink_categories.Copy() // list of uplink categories without associated values. var/list/sale_items = list() @@ -18,7 +18,8 @@ continue if (I.restricted && !allow_restricted) continue - + if (I.type in other_filter) + continue LAZYSET(filtered_uplink_items[I.category], I.name, I) if(I.limited_stock < 0 && !I.cant_discount && I.item && I.cost > 1) diff --git a/tgstation.dme b/tgstation.dme index 0b7ad871c3..83ddb4d336 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -1453,6 +1453,14 @@ #include "code\modules\antagonists\swarmer\swarmer.dm" #include "code\modules\antagonists\swarmer\swarmer_event.dm" #include "code\modules\antagonists\traitor\datum_traitor.dm" +#include "code\modules\antagonists\traitor\classes\ai.dm" +#include "code\modules\antagonists\traitor\classes\assassin.dm" +#include "code\modules\antagonists\traitor\classes\gimmick.dm" +#include "code\modules\antagonists\traitor\classes\hijack.dm" +#include "code\modules\antagonists\traitor\classes\human.dm" +#include "code\modules\antagonists\traitor\classes\martyr.dm" +#include "code\modules\antagonists\traitor\classes\subterfuge.dm" +#include "code\modules\antagonists\traitor\classes\traitor_class.dm" #include "code\modules\antagonists\traitor\equipment\Malf_Modules.dm" #include "code\modules\antagonists\traitor\IAA\internal_affairs.dm" #include "code\modules\antagonists\valentines\heartbreaker.dm" From 56ab702fa542fb0f3b7ac0b4d4b0f20c36385762 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 1 Mar 2020 00:02:16 -0800 Subject: [PATCH 03/17] but how --- code/modules/antagonists/traitor/datum_traitor.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 576569b8ba..e2a5c0046a 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -10,7 +10,6 @@ var/should_give_codewords = TRUE var/should_equip = TRUE var/datum/traitor_class/traitor_kind - var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment can_hijack = HIJACK_HIJACKER hijack_speed = 0.5 //10 seconds per hijack stage by default From 6e7406a51a5f7cfa8f7efdaa70138259c940748d Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 1 Mar 2020 00:03:00 -0800 Subject: [PATCH 04/17] what --- code/modules/antagonists/traitor/datum_traitor.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index e2a5c0046a..16e7e71eac 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -10,7 +10,6 @@ var/should_give_codewords = TRUE var/should_equip = TRUE var/datum/traitor_class/traitor_kind - can_hijack = HIJACK_HIJACKER hijack_speed = 0.5 //10 seconds per hijack stage by default /datum/antagonist/traitor/New() From 7a5366f5dd1b0ddc4a2ef65a932e5a71a667f23d Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 1 Mar 2020 00:03:12 -0800 Subject: [PATCH 05/17] come to think of it a "cooperative", huh --- code/modules/antagonists/traitor/classes/martyr.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/classes/martyr.dm b/code/modules/antagonists/traitor/classes/martyr.dm index c934c38417..24da190057 100644 --- a/code/modules/antagonists/traitor/classes/martyr.dm +++ b/code/modules/antagonists/traitor/classes/martyr.dm @@ -1,5 +1,5 @@ /datum/traitor_class/human/martyr - name = "Tiger Cooperative Agent" + name = "Tiger Cooperator" employer = "The Tiger Cooperative" weight = 2 chaos = 5 From 3059e482785625b1f84618dae0ce1d15256e5d88 Mon Sep 17 00:00:00 2001 From: Putnam Date: Tue, 3 Mar 2020 16:46:41 -0800 Subject: [PATCH 06/17] Removed 30TC thing from martyr/hijack --- code/modules/antagonists/traitor/classes/hijack.dm | 3 +-- code/modules/antagonists/traitor/classes/martyr.dm | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/code/modules/antagonists/traitor/classes/hijack.dm b/code/modules/antagonists/traitor/classes/hijack.dm index 0ed716c3cd..d6b4fa3f26 100644 --- a/code/modules/antagonists/traitor/classes/hijack.dm +++ b/code/modules/antagonists/traitor/classes/hijack.dm @@ -1,10 +1,9 @@ -/datum/traitor_class/human/martyr +/datum/traitor_class/human/hijack name = "Gorlex Marauder" employer = "The Gorlex Marauders" weight = 2 chaos = 5 cost = 5 - TC = 30 uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit) /datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T) diff --git a/code/modules/antagonists/traitor/classes/martyr.dm b/code/modules/antagonists/traitor/classes/martyr.dm index 24da190057..13d0e73a41 100644 --- a/code/modules/antagonists/traitor/classes/martyr.dm +++ b/code/modules/antagonists/traitor/classes/martyr.dm @@ -4,7 +4,6 @@ weight = 2 chaos = 5 cost = 5 - TC = 30 uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit) /datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T) From 436e781ec94930e55cb9838dcdb18e424fb33eda Mon Sep 17 00:00:00 2001 From: Putnam Date: Fri, 6 Mar 2020 15:37:59 -0800 Subject: [PATCH 07/17] Removed assassin-only, made subterfuge more likely to assassinate --- .../antagonists/traitor/classes/assassin.dm | 2 +- .../antagonists/traitor/classes/subterfuge.dm | 22 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/code/modules/antagonists/traitor/classes/assassin.dm b/code/modules/antagonists/traitor/classes/assassin.dm index ca192aff5a..0c1d950f57 100644 --- a/code/modules/antagonists/traitor/classes/assassin.dm +++ b/code/modules/antagonists/traitor/classes/assassin.dm @@ -1,7 +1,7 @@ /datum/traitor_class/human/assassin name = "Donk Co Operative" employer = "Donk Corporation" - weight = 4 + weight = 0 chaos = 1 cost = 2 diff --git a/code/modules/antagonists/traitor/classes/subterfuge.dm b/code/modules/antagonists/traitor/classes/subterfuge.dm index 2b4716e67e..8e97a6a2ba 100644 --- a/code/modules/antagonists/traitor/classes/subterfuge.dm +++ b/code/modules/antagonists/traitor/classes/subterfuge.dm @@ -6,22 +6,24 @@ /datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T) .=1 - var/assassin_prob = 20 + var/assassin_prob = 30 var/is_dynamic = FALSE var/datum/game_mode/dynamic/mode if(istype(SSticker.mode,/datum/game_mode/dynamic)) mode = SSticker.mode is_dynamic = TRUE - assassin_prob = max(0,mode.threat_level-50) + assassin_prob = max(0,mode.threat_level-40) if(prob(assassin_prob)) - if(is_dynamic) - var/threat_spent = CONFIG_GET(number/dynamic_assassinate_cost) - mode.spend_threat(threat_spent) - mode.log_threat("[T.owner.name] spent [threat_spent] on an assassination target.") - var/datum/objective/maroon/maroon_objective = new - maroon_objective.owner = T.owner - maroon_objective.find_target() - T.add_objective(maroon_objective) + if(prob(assassin_prob)) + var/datum/objective/assassinate/once/kill_objective = new + kill_objective.owner = T.owner + kill_objective.find_target() + T.add_objective(kill_objective) + else + var/datum/objective/maroon/maroon_objective = new + maroon_objective.owner = T.owner + maroon_objective.find_target() + T.add_objective(maroon_objective) else if(prob(15) && !(locate(/datum/objective/download) in T.objectives) && !(T.owner.assigned_role in list("Research Director", "Scientist", "Roboticist"))) var/datum/objective/download/download_objective = new From 182e98192cd67ae9b63adb767dff5a13631cb280 Mon Sep 17 00:00:00 2001 From: Putnam Date: Fri, 6 Mar 2020 17:01:43 -0800 Subject: [PATCH 08/17] no longer uses that var --- code/modules/antagonists/traitor/classes/subterfuge.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/modules/antagonists/traitor/classes/subterfuge.dm b/code/modules/antagonists/traitor/classes/subterfuge.dm index 8e97a6a2ba..834ef72fe8 100644 --- a/code/modules/antagonists/traitor/classes/subterfuge.dm +++ b/code/modules/antagonists/traitor/classes/subterfuge.dm @@ -7,11 +7,9 @@ /datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T) .=1 var/assassin_prob = 30 - var/is_dynamic = FALSE var/datum/game_mode/dynamic/mode if(istype(SSticker.mode,/datum/game_mode/dynamic)) mode = SSticker.mode - is_dynamic = TRUE assassin_prob = max(0,mode.threat_level-40) if(prob(assassin_prob)) if(prob(assassin_prob)) From 1c37b95c0b749ae03940f53bec2de84768bc932c Mon Sep 17 00:00:00 2001 From: Putnam Date: Fri, 6 Mar 2020 17:21:30 -0800 Subject: [PATCH 09/17] renamed "gimmick" to "freeform" --- .../antagonists/traitor/classes/{gimmick.dm => freeform.dm} | 4 ++-- tgstation.dme | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename code/modules/antagonists/traitor/classes/{gimmick.dm => freeform.dm} (73%) diff --git a/code/modules/antagonists/traitor/classes/gimmick.dm b/code/modules/antagonists/traitor/classes/freeform.dm similarity index 73% rename from code/modules/antagonists/traitor/classes/gimmick.dm rename to code/modules/antagonists/traitor/classes/freeform.dm index 12f9674140..08fc7416bd 100644 --- a/code/modules/antagonists/traitor/classes/gimmick.dm +++ b/code/modules/antagonists/traitor/classes/freeform.dm @@ -1,10 +1,10 @@ -/datum/traitor_class/human/gimmick +/datum/traitor_class/human/freeform name = "Waffle Co Agent" employer = "Waffle Company" weight = 4 chaos = 0 -/datum/traitor_class/human/gimmick/forge_objectives(datum/antagonist/traitor/T) +/datum/traitor_class/human/freeform/forge_objectives(datum/antagonist/traitor/T) var/datum/objective/escape/O = new O.explanation_text = "You have no goals! Whatever you can do do antagonize Nanotrasen, do it! The gimmickier, the better! Make sure to escape alive, though!" O.owner = T.owner diff --git a/tgstation.dme b/tgstation.dme index f8d349720b..4d3439472a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1474,7 +1474,7 @@ #include "code\modules\antagonists\traitor\datum_traitor.dm" #include "code\modules\antagonists\traitor\classes\ai.dm" #include "code\modules\antagonists\traitor\classes\assassin.dm" -#include "code\modules\antagonists\traitor\classes\gimmick.dm" +#include "code\modules\antagonists\traitor\classes\freeform.dm" #include "code\modules\antagonists\traitor\classes\hijack.dm" #include "code\modules\antagonists\traitor\classes\human.dm" #include "code\modules\antagonists\traitor\classes\martyr.dm" From 39527ae4a73136c42bbd00c96b565efe578d64c8 Mon Sep 17 00:00:00 2001 From: Putnam Date: Fri, 6 Mar 2020 17:21:41 -0800 Subject: [PATCH 10/17] prevented hijack/martyr from being contractors --- code/modules/antagonists/traitor/classes/hijack.dm | 2 +- code/modules/antagonists/traitor/classes/martyr.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/antagonists/traitor/classes/hijack.dm b/code/modules/antagonists/traitor/classes/hijack.dm index d6b4fa3f26..5390bfca25 100644 --- a/code/modules/antagonists/traitor/classes/hijack.dm +++ b/code/modules/antagonists/traitor/classes/hijack.dm @@ -4,7 +4,7 @@ weight = 2 chaos = 5 cost = 5 - uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit) + uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit) /datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T) var/datum/objective/hijack/O = new diff --git a/code/modules/antagonists/traitor/classes/martyr.dm b/code/modules/antagonists/traitor/classes/martyr.dm index 13d0e73a41..78f8bf9b0c 100644 --- a/code/modules/antagonists/traitor/classes/martyr.dm +++ b/code/modules/antagonists/traitor/classes/martyr.dm @@ -4,7 +4,7 @@ weight = 2 chaos = 5 cost = 5 - uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit) + uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit) /datum/traitor_class/human/martyr/forge_objectives(datum/antagonist/traitor/T) var/datum/objective/martyr/O = new From f670d09a88dfa8e40978e609aa1ec287c141b602 Mon Sep 17 00:00:00 2001 From: Putnam Date: Fri, 6 Mar 2020 21:39:38 -0800 Subject: [PATCH 11/17] Made IAA work again (whoops) --- code/modules/antagonists/traitor/IAA/internal_affairs.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/antagonists/traitor/IAA/internal_affairs.dm b/code/modules/antagonists/traitor/IAA/internal_affairs.dm index f6ee056865..19144d67c9 100644 --- a/code/modules/antagonists/traitor/IAA/internal_affairs.dm +++ b/code/modules/antagonists/traitor/IAA/internal_affairs.dm @@ -120,7 +120,7 @@ /datum/antagonist/traitor/internal_affairs/reinstate_escape_objective() ..() - var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive + var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive var/datum/objective/escape_objective = new objtype escape_objective.owner = owner add_objective(escape_objective) @@ -220,7 +220,7 @@ /datum/antagonist/traitor/internal_affairs/forge_traitor_objectives() forge_iaa_objectives() - var/objtype = traitor_kind == TRAITOR_HUMAN ? /datum/objective/escape : /datum/objective/survive + var/objtype = !istype(traitor_kind,TRAITOR_AI) ? /datum/objective/escape : /datum/objective/survive var/datum/objective/escape_objective = new objtype escape_objective.owner = owner add_objective(escape_objective) From 023d1d6d979232f4609d139849f4a5956c04c0c3 Mon Sep 17 00:00:00 2001 From: Putnam Date: Fri, 6 Mar 2020 21:40:44 -0800 Subject: [PATCH 12/17] Tweaked weights a bunch --- code/__DEFINES/antagonists.dm | 2 +- code/modules/antagonists/traitor/classes/freeform.dm | 2 +- code/modules/antagonists/traitor/classes/hijack.dm | 2 +- code/modules/antagonists/traitor/classes/martyr.dm | 2 +- code/modules/antagonists/traitor/classes/subterfuge.dm | 2 +- code/modules/antagonists/traitor/datum_traitor.dm | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index ba1b509d2c..33472ba789 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -1,4 +1,4 @@ -#define TRAITOR_HUMAN /datum/traitor_class/human +#define TRAITOR_HUMAN /datum/traitor_class/human/freeform #define TRAITOR_AI /datum/traitor_class/ai #define NUKE_RESULT_FLUKE 0 diff --git a/code/modules/antagonists/traitor/classes/freeform.dm b/code/modules/antagonists/traitor/classes/freeform.dm index 08fc7416bd..f84eadb9f6 100644 --- a/code/modules/antagonists/traitor/classes/freeform.dm +++ b/code/modules/antagonists/traitor/classes/freeform.dm @@ -1,7 +1,7 @@ /datum/traitor_class/human/freeform name = "Waffle Co Agent" employer = "Waffle Company" - weight = 4 + weight = 16 chaos = 0 /datum/traitor_class/human/freeform/forge_objectives(datum/antagonist/traitor/T) diff --git a/code/modules/antagonists/traitor/classes/hijack.dm b/code/modules/antagonists/traitor/classes/hijack.dm index 5390bfca25..e61abae465 100644 --- a/code/modules/antagonists/traitor/classes/hijack.dm +++ b/code/modules/antagonists/traitor/classes/hijack.dm @@ -1,7 +1,7 @@ /datum/traitor_class/human/hijack name = "Gorlex Marauder" employer = "The Gorlex Marauders" - weight = 2 + weight = 1 chaos = 5 cost = 5 uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit) diff --git a/code/modules/antagonists/traitor/classes/martyr.dm b/code/modules/antagonists/traitor/classes/martyr.dm index 78f8bf9b0c..fa0ee600b4 100644 --- a/code/modules/antagonists/traitor/classes/martyr.dm +++ b/code/modules/antagonists/traitor/classes/martyr.dm @@ -1,7 +1,7 @@ /datum/traitor_class/human/martyr name = "Tiger Cooperator" employer = "The Tiger Cooperative" - weight = 2 + weight = 1 chaos = 5 cost = 5 uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit) diff --git a/code/modules/antagonists/traitor/classes/subterfuge.dm b/code/modules/antagonists/traitor/classes/subterfuge.dm index 834ef72fe8..ae43f11fe7 100644 --- a/code/modules/antagonists/traitor/classes/subterfuge.dm +++ b/code/modules/antagonists/traitor/classes/subterfuge.dm @@ -1,7 +1,7 @@ /datum/traitor_class/human/subterfuge name = "MI13 Operative" employer = "MI13" - weight = 4 + weight = 20 chaos = -5 /datum/traitor_class/human/subterfuge/forge_single_objective(datum/antagonist/traitor/T) diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 875a6c688c..8c41a31785 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -38,13 +38,13 @@ var/list/weights = list() for(var/C in GLOB.traitor_classes) var/datum/traitor_class/class = GLOB.traitor_classes[C] - var/weight = class.weight/(1+NUM_E**(-chaos_weight*class.chaos)) // just a logistic function + var/weight = (1.5*class.weight)/(0.5+NUM_E**(-chaos_weight*class.chaos)) // just a logistic function weights[C] = weight var/choice = pickweightAllowZero(weights) if(!choice) choice = GLOB.traitor_classes[TRAITOR_HUMAN] set_traitor_kind(pickweightAllowZero(weights)) - traitor_kind.weight /= 2 // less likely this round + traitor_kind.weight *= 0.8 // less likely this round SSticker.mode.traitors += owner owner.special_role = special_role if(give_objectives) From eacdc3b43821589d3bf8857297ac6c8ab724a256 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sun, 8 Mar 2020 14:05:04 -0700 Subject: [PATCH 13/17] Let gorlex marauders contract, and made them hijack 2x as fast as other traitors --- code/modules/antagonists/traitor/classes/hijack.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/classes/hijack.dm b/code/modules/antagonists/traitor/classes/hijack.dm index e61abae465..3f6b83a0ad 100644 --- a/code/modules/antagonists/traitor/classes/hijack.dm +++ b/code/modules/antagonists/traitor/classes/hijack.dm @@ -4,7 +4,7 @@ weight = 1 chaos = 5 cost = 5 - uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit) + uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit) /datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T) var/datum/objective/hijack/O = new @@ -12,3 +12,6 @@ O.owner = T.owner T.add_objective(O) return + +/datum/traitor_class/human/hijack/finalize_traitor(datum/antagonist/traitor/T) + T.hijack_speed=1 From f19647acc795dcd3b02894610f1ff50d549a617b Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 9 Mar 2020 18:47:06 -0700 Subject: [PATCH 14/17] Fixed uplinks not being given to traitors. Always remember to follow your code VERY CLOSELY or garbage like this happens. finalize_traitor calls traitor_kind.finalize_traitor(); that's how I intended it to happen. Instead, I foolishly wrote "traitor_kind.finalize_traitor()" in the on_gain() proc. I didn't notice for a LONG time, because... well, it's supposed to call finalize_traitor(), just not that one. The pitfalls of working with old code. --- code/modules/antagonists/traitor/classes/hijack.dm | 1 + code/modules/antagonists/traitor/datum_traitor.dm | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/classes/hijack.dm b/code/modules/antagonists/traitor/classes/hijack.dm index 3f6b83a0ad..89c3d60a12 100644 --- a/code/modules/antagonists/traitor/classes/hijack.dm +++ b/code/modules/antagonists/traitor/classes/hijack.dm @@ -15,3 +15,4 @@ /datum/traitor_class/human/hijack/finalize_traitor(datum/antagonist/traitor/T) T.hijack_speed=1 + return TRUE diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 8c41a31785..3324f1e756 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -49,7 +49,7 @@ owner.special_role = special_role if(give_objectives) traitor_kind.forge_objectives(src) - traitor_kind.finalize_traitor(src) + finalize_traitor() ..() /datum/antagonist/traitor/apply_innate_effects() From 5a18d143a92e2df6b2bd6c2877c51d9d3596de73 Mon Sep 17 00:00:00 2001 From: Putnam Date: Mon, 9 Mar 2020 18:47:42 -0700 Subject: [PATCH 15/17] Removed extraneous apply_innate_effects This one was caused by the hear proc overhaul. --- .../antagonists/traitor/datum_traitor.dm | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 3324f1e756..a9dee81a6c 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -52,22 +52,6 @@ finalize_traitor() ..() -/datum/antagonist/traitor/apply_innate_effects() - traitor_kind.apply_innate_effects(src) - if(owner.assigned_role == "Clown") - var/mob/living/carbon/human/traitor_mob = owner.current - if(traitor_mob && istype(traitor_mob)) - if(!silent) - to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") - traitor_mob.dna.remove_mutation(CLOWNMUT) - -/datum/antagonist/traitor/remove_innate_effects() - traitor_kind.remove_innate_effects(src) - if(owner.assigned_role == "Clown") - var/mob/living/carbon/human/traitor_mob = owner.current - if(traitor_mob && istype(traitor_mob)) - traitor_mob.dna.add_mutation(CLOWNMUT) - /datum/antagonist/traitor/on_removal() //Remove malf powers. traitor_kind.on_removal(src) @@ -111,8 +95,7 @@ set_antag_hud(owner.current, null) /datum/antagonist/traitor/proc/finalize_traitor() - var/should_base_finalize = traitor_kind.finalize_traitor(src) - if(should_base_finalize) + if(traitor_kind.finalize_traitor(src)) if(should_equip) equip(silent) owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE) @@ -122,6 +105,12 @@ update_traitor_icons_added() var/mob/M = mob_override || owner.current traitor_kind.apply_innate_effects(M) + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/H = M + if(istype(H)) + if(!silent) + to_chat(H, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") + H.dna.remove_mutation(CLOWNMUT) RegisterSignal(M, COMSIG_MOVABLE_HEAR, .proc/handle_hearing) /datum/antagonist/traitor/remove_innate_effects(mob/living/mob_override) @@ -129,6 +118,10 @@ update_traitor_icons_removed() var/mob/M = mob_override || owner.current traitor_kind.remove_innate_effects(M) + if(owner.assigned_role == "Clown") + var/mob/living/carbon/human/H = M + if(istype(H)) + H.dna.add_mutation(CLOWNMUT) UnregisterSignal(M, COMSIG_MOVABLE_HEAR) /datum/antagonist/traitor/proc/give_codewords() From ae94083dbeecfe97c8d4091ce2c32384f10bae5e Mon Sep 17 00:00:00 2001 From: Putnam Date: Thu, 12 Mar 2020 14:59:04 -0700 Subject: [PATCH 16/17] Added more explanation to hijack. --- code/modules/antagonists/traitor/classes/hijack.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/classes/hijack.dm b/code/modules/antagonists/traitor/classes/hijack.dm index 89c3d60a12..bee87f94b1 100644 --- a/code/modules/antagonists/traitor/classes/hijack.dm +++ b/code/modules/antagonists/traitor/classes/hijack.dm @@ -8,7 +8,7 @@ /datum/traitor_class/human/hijack/forge_objectives(datum/antagonist/traitor/T) var/datum/objective/hijack/O = new - O.explanation_text = "The Gorlex Marauders are letting you do what you want, with one condition: the shuttle must be hijacked." + O.explanation_text = "The Gorlex Marauders are letting you do what you want, with one condition: the shuttle must be hijacked by hacking its navigational protocols through the control console (alt click emergency shuttle console)." O.owner = T.owner T.add_objective(O) return From b1a94f7667eaa881513983fba31800a819bcd319 Mon Sep 17 00:00:00 2001 From: Putnam Date: Thu, 12 Mar 2020 15:05:53 -0700 Subject: [PATCH 17/17] Made hijack, martyr more common --- code/modules/antagonists/traitor/classes/hijack.dm | 2 +- code/modules/antagonists/traitor/classes/martyr.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/antagonists/traitor/classes/hijack.dm b/code/modules/antagonists/traitor/classes/hijack.dm index bee87f94b1..e89eda1dcf 100644 --- a/code/modules/antagonists/traitor/classes/hijack.dm +++ b/code/modules/antagonists/traitor/classes/hijack.dm @@ -1,7 +1,7 @@ /datum/traitor_class/human/hijack name = "Gorlex Marauder" employer = "The Gorlex Marauders" - weight = 1 + weight = 3 chaos = 5 cost = 5 uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit) diff --git a/code/modules/antagonists/traitor/classes/martyr.dm b/code/modules/antagonists/traitor/classes/martyr.dm index fa0ee600b4..78f8bf9b0c 100644 --- a/code/modules/antagonists/traitor/classes/martyr.dm +++ b/code/modules/antagonists/traitor/classes/martyr.dm @@ -1,7 +1,7 @@ /datum/traitor_class/human/martyr name = "Tiger Cooperator" employer = "The Tiger Cooperative" - weight = 1 + weight = 2 chaos = 5 cost = 5 uplink_filters = list(/datum/uplink_item/stealthy_weapons/romerol_kit,/datum/uplink_item/bundles_TC/contract_kit)