From f344af633f69242a6e92b12aaeae2bfd66802d07 Mon Sep 17 00:00:00 2001 From: Putnam Date: Sat, 29 Feb 2020 23:29:24 -0800 Subject: [PATCH] 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"