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"