From 93ee5f617c6c139415768b0f0b1df174e5f9556e Mon Sep 17 00:00:00 2001
From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com>
Date: Wed, 22 Nov 2023 19:56:02 -0800
Subject: [PATCH] very nice
---
code/__DEFINES/~monkestation/uplink.dm | 2 +
code/datums/components/uplink.dm | 26 +-
code/game/objects/items/melee/baton.dm | 5 +-
.../antagonists/traitor/datum_traitor.dm | 13 +-
.../antagonists/traitor/objective_category.dm | 16 +-
.../traitor/objectives/kidnapping.dm | 3 +
.../antagonists/traitor/traitor_objective.dm | 5 +
.../antagonists/traitor/uplink_handler.dm | 16 +-
code/modules/uplink/uplink_items/special.dm | 1 +
monkestation/code/datums/components/uplink.dm | 17 +-
.../game/objects/items/storage/uplink_kits.dm | 10 +-
.../contractor/datums/contractor_datum.dm | 8 +-
.../contractor/datums/contractor_hub.dm | 4 -
.../contractor/datums/contractor_items.dm | 68 ++--
.../contractor/datums/contractor_support.dm | 1 -
.../antagonists/contractor/items/boxes.dm | 2 +-
.../contractor/items/modsuit/modsuit.dm | 11 +-
.../contractor/items/modsuit/theme.dm | 2 +-
.../antagonists/traitor/datum_traitor.dm | 3 -
.../final_objective/final_objective.dm | 2 +
.../traitor/objectives/kidnapping.dm | 309 ++++++++++++++++++
.../antagonists/traitor/traitor_objective.dm | 4 +-
.../antagonists/traitor/uplink_handler.dm | 20 ++
.../modules/uplink/uplink_items/bundle.dm | 16 +-
.../{contractor_modsuit.dmi => modsuit.dmi} | Bin
tgstation.dme | 5 +-
.../tgui/interfaces/Uplink/ContractorMenu.tsx | 64 ++++
.../tgui/interfaces/Uplink/ObjectiveMenu.tsx | 5 +
.../packages/tgui/interfaces/Uplink/index.tsx | 24 +-
29 files changed, 580 insertions(+), 82 deletions(-)
create mode 100644 code/__DEFINES/~monkestation/uplink.dm
delete mode 100644 monkestation/code/modules/antagonists/contractor/datums/contractor_hub.dm
delete mode 100644 monkestation/code/modules/antagonists/traitor/datum_traitor.dm
create mode 100644 monkestation/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm
create mode 100644 monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm
rename monkestation/icons/obj/clothing/modsuits/{contractor_modsuit.dmi => modsuit.dmi} (100%)
create mode 100644 tgui/packages/tgui/interfaces/Uplink/ContractorMenu.tsx
diff --git a/code/__DEFINES/~monkestation/uplink.dm b/code/__DEFINES/~monkestation/uplink.dm
new file mode 100644
index 000000000000..fc05b3f16e34
--- /dev/null
+++ b/code/__DEFINES/~monkestation/uplink.dm
@@ -0,0 +1,2 @@
+/// the uplink flag for contractors
+#define UPLINK_CONTRACTORS (1 << 6)
diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm
index e7fe90891cf1..aa04e64a0cae 100644
--- a/code/datums/components/uplink.dm
+++ b/code/datums/components/uplink.dm
@@ -253,7 +253,22 @@
data["current_stock"] = remaining_stock
data["shop_locked"] = uplink_handler.shop_locked
data["purchased_items"] = length(uplink_handler.purchase_log?.purchase_log)
- data["locked_entries"] = uplink_handler.locked_entries //monkestation edit
+//monkestation edit start
+ data["locked_entries"] = uplink_handler.locked_entries
+ data["is_contractor"] = (uplink_handler.uplink_flag == UPLINK_CONTRACTORS)
+ var/list/contractor_items = list()
+ for(var/datum/contractor_item/item in uplink_handler.contractor_market_items)
+ contractor_items += list(list(
+ "id" = item.type,
+ "name" = item.name,
+ "desc" = item.desc,
+ "cost" = item.cost,
+ "stock" = item.stock,
+ "item_icon" = item.item_icon,
+ ))
+ data["contractor_items"] = contractor_items
+ data["contractor_rep"] = uplink_handler.contractor_rep
+//monkestation edit end
return data
/datum/component/uplink/ui_static_data(mob/user)
@@ -302,6 +317,15 @@
if(uplink_handler.owner?.current != ui.user || !uplink_handler.can_take_objectives)
return TRUE
+//monkestation edit start
+ switch(action)
+ if("buy_contractor")
+ var/item = params["item"]
+ for(var/datum/contractor_item/hub_item in uplink_handler.contractor_market_items)
+ if(hub_item.name == item)
+ hub_item.handle_purchase(uplink_handler, ui.user)
+//monkestation edit end
+
switch(action)
if("regenerate_objectives")
uplink_handler.generate_objectives()
diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm
index 0b8c9b0a4da9..cbffeac6c620 100644
--- a/code/game/objects/items/melee/baton.dm
+++ b/code/game/objects/items/melee/baton.dm
@@ -322,9 +322,11 @@
)
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
+//monkestation edit start
/obj/item/melee/baton/telescopic/additional_effects_non_cyborg(mob/living/target, mob/living/user)
. = ..()
target.Disorient(6 SECONDS, 5, paralyze = 3 SECONDS, stack_status = FALSE)
+//monkestation edit end
/obj/item/melee/baton/telescopic/suicide_act(mob/living/user)
var/mob/living/carbon/human/human_user = user
@@ -375,7 +377,7 @@
force = 5
cooldown = 2.5 SECONDS
force_say_chance = 80 //very high force say chance because it's funny
- stamina_damage = 170
+ stamina_damage = 170 //monkestation edit: stam damage increased
clumsy_knockdown_time = 24 SECONDS
affect_cyborg = TRUE
on_stun_sound = 'sound/effects/contractorbatonhit.ogg'
@@ -390,6 +392,7 @@
/obj/item/melee/baton/telescopic/contractor_baton/additional_effects_non_cyborg(mob/living/target, mob/living/user)
target.set_jitter_if_lower(40 SECONDS)
target.set_stutter_if_lower(40 SECONDS)
+ target.Disorient(6 SECONDS, 5, paralyze = 3 SECONDS, stack_status = TRUE) //monkestation edit
/obj/item/melee/baton/security
name = "stun baton"
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index 4e40ab3efc60..18e7a0da65f6 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -79,6 +79,10 @@
if(give_secondary_objectives)
uplink_handler.has_objectives = TRUE
uplink_handler.generate_objectives()
+//monkestation edit start
+ else
+ uplink_handler.has_objectives = FALSE
+//monkestation edit end
if(uplink_handler.progression_points < SStraitor.current_global_progression)
uplink_handler.progression_points = SStraitor.current_global_progression * SStraitor.newjoin_progression_coeff
@@ -344,14 +348,15 @@
var/completed_objectives_text = "Completed Uplink Objectives: "
for(var/datum/traitor_objective/objective as anything in uplink_handler.completed_objectives)
if(objective.objective_state == OBJECTIVE_STATE_COMPLETED)
- completed_objectives_text += "
[objective.name] - ([objective.telecrystal_reward] TC, [DISPLAY_PROGRESSION(objective.progression_reward)] Reputation)"
+ completed_objectives_text += "
[objective.name] - ([objective.telecrystal_reward] TC, [DISPLAY_PROGRESSION(objective.progression_reward)] Threat Level)"
+//monkestation edit on previous line: replaced "Reputation" with "Threat Level"
result += completed_objectives_text
- result += "
The traitor had a total of [DISPLAY_PROGRESSION(uplink_handler.progression_points)] Reputation and [uplink_handler.telecrystals] Unused Telecrystals."
-
+ result += "
The traitor had a total of [DISPLAY_PROGRESSION(uplink_handler.progression_points)] Threat Level and [uplink_handler.telecrystals] Unused Telecrystals."
+//monkestation edit on previous line: replaced "Reputation" with "Threat Level"
var/special_role_text = lowertext(name)
//monkestation edit start
- if(contractor_hub)
+ if(uplink_handler?.purchased_contractor_items)
result += contractor_round_end()
//monkestation edit end
diff --git a/code/modules/antagonists/traitor/objective_category.dm b/code/modules/antagonists/traitor/objective_category.dm
index 5484d2937985..d4e38d70130c 100644
--- a/code/modules/antagonists/traitor/objective_category.dm
+++ b/code/modules/antagonists/traitor/objective_category.dm
@@ -12,27 +12,31 @@
// Category should just get autoGC'd here if they don't have any length, this may not be necessary
qdel(category)
-/datum/traitor_category_handler/proc/objective_valid(datum/traitor_objective/objective_path, progression_points)
+/datum/traitor_category_handler/proc/objective_valid(datum/traitor_objective/objective_path, progression_points, uplink_flag) //monkestation edit: adds uplink_flag
if(initial(objective_path.abstract_type) == objective_path)
return FALSE
if(progression_points < initial(objective_path.progression_minimum))
return FALSE
if(progression_points > initial(objective_path.progression_maximum))
return FALSE
+//monkestation edit start
+ if(!(initial(objective_path.valid_uplinks) & uplink_flag))
+ return FALSE
+//monkestation edit end
return TRUE
-/datum/traitor_category_handler/proc/get_possible_objectives(progression_points)
+/datum/traitor_category_handler/proc/get_possible_objectives(progression_points, uplink_flag) //monkestation edit: adds uplink_flag
var/list/valid_objectives = list()
for(var/datum/traitor_objective_category/category as anything in all_categories)
var/list/category_list = list()
for(var/value in category.objectives)
if(islist(value))
- var/list/objective_category = filter_invalid_objective_list(value, progression_points)
+ var/list/objective_category = filter_invalid_objective_list(value, progression_points, uplink_flag) //monkestation edit:: adds uplink_flag
if(!length(objective_category))
continue
category_list[objective_category] = category.objectives[value]
else
- if(!objective_valid(value, progression_points))
+ if(!objective_valid(value, progression_points, uplink_flag)) //monkestation edit: adds uplink_flag
continue
category_list[value] = category.objectives[value]
if(!length(category_list))
@@ -41,7 +45,7 @@
return valid_objectives
-/datum/traitor_category_handler/proc/filter_invalid_objective_list(list/objectives, progression_points)
+/datum/traitor_category_handler/proc/filter_invalid_objective_list(list/objectives, progression_points, uplink_flag) //monkestation edit: adds uplink_flag
var/list/filtered_objectives = list()
for(var/value in objectives)
if(islist(value))
@@ -50,7 +54,7 @@
continue
filtered_objectives[result] = objectives[value]
else
- if(!objective_valid(value, progression_points))
+ if(!objective_valid(value, progression_points, uplink_flag)) //monkestation edit: adds uplink_flag
continue
filtered_objectives[value] = objectives[value]
return filtered_objectives
diff --git a/code/modules/antagonists/traitor/objectives/kidnapping.dm b/code/modules/antagonists/traitor/objectives/kidnapping.dm
index 72551716a491..2ad4a74a57d1 100644
--- a/code/modules/antagonists/traitor/objectives/kidnapping.dm
+++ b/code/modules/antagonists/traitor/objectives/kidnapping.dm
@@ -1,3 +1,5 @@
+//MONKESTATIONFILE REMOVAL, CHECK THE FILE IN THE MODULAR DIRECTORY
+/*
/datum/traitor_objective/target_player/kidnapping
name = "Kidnap %TARGET% the %JOB TITLE% and deliver them to %AREA%"
description = "%TARGET% holds extremely important information regarding secret NT projects - and you'll need to kidnap and deliver them to %AREA%, where our transport pod will be waiting. \
@@ -321,3 +323,4 @@
for (var/obj/item/implant/storage/internal_bag in kidnapee.implants)
belongings += internal_bag.contents
return belongings
+*/
diff --git a/code/modules/antagonists/traitor/traitor_objective.dm b/code/modules/antagonists/traitor/traitor_objective.dm
index 30a8ba679441..b77bdd281c31 100644
--- a/code/modules/antagonists/traitor/traitor_objective.dm
+++ b/code/modules/antagonists/traitor/traitor_objective.dm
@@ -228,6 +228,10 @@
/datum/traitor_objective/proc/completion_payout()
handler.progression_points += progression_reward
handler.telecrystals += telecrystal_reward
+//monkestation edit start
+ if(given_contractor_rep)
+ handler.contractor_rep += given_contractor_rep
+//monkestation edit end
/// Used for sending data to the uplink UI
/datum/traitor_objective/proc/uplink_ui_data(mob/user)
@@ -241,6 +245,7 @@
"objective_state" = objective_state,
"original_progression" = original_progression,
"telecrystal_penalty" = telecrystal_penalty,
+ "contractor_rep" = given_contractor_rep, //monkestation edit
)
/datum/traitor_objective/proc/on_objective_taken(mob/user)
diff --git a/code/modules/antagonists/traitor/uplink_handler.dm b/code/modules/antagonists/traitor/uplink_handler.dm
index 40b5d97c0cff..4103f8f45176 100644
--- a/code/modules/antagonists/traitor/uplink_handler.dm
+++ b/code/modules/antagonists/traitor/uplink_handler.dm
@@ -114,14 +114,24 @@
on_update()
return TRUE
-/// Generates objectives for this uplink handler
-/datum/uplink_handler/proc/generate_objectives()
+/** Generates objectives for this uplink handler
+ * forced_types - an assoc list of objective types that when passed will always be generated first if possible to generate, value is how many of that type to generate
+ */
+/datum/uplink_handler/proc/generate_objectives(list/forced_types = list()) //monkestation edit: adds forced_types
var/potential_objectives_left = maximum_potential_objectives - (length(potential_objectives) + length(active_objectives))
- var/list/objectives = SStraitor.category_handler.get_possible_objectives(progression_points)
+ var/list/objectives = SStraitor.category_handler.get_possible_objectives(progression_points, uplink_flag) //monkestation edit: adds uplink_flag
if(!length(objectives))
return
while(length(objectives) && potential_objectives_left > 0)
var/objective_typepath = pick_weight(objectives)
+//monkestation edit start
+ if(length(forced_types))
+ var/picked_type = pick(forced_types)
+ forced_types[picked_type] -= 1
+ if(!forced_types[picked_type])
+ forced_types -= picked_type
+ objective_typepath = picked_type
+//monkestation edit end
var/list/target_list = objectives
while(islist(objective_typepath))
if(!length(objective_typepath))
diff --git a/code/modules/uplink/uplink_items/special.dm b/code/modules/uplink/uplink_items/special.dm
index 00425f2089a7..24d91ccd9341 100644
--- a/code/modules/uplink/uplink_items/special.dm
+++ b/code/modules/uplink/uplink_items/special.dm
@@ -18,3 +18,4 @@
..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_CYBERNETIC_REVOLUTION))
purchasable_from |= UPLINK_TRAITORS
+ purchasable_from |= UPLINK_CONTRACTORS //monkestation edit
diff --git a/monkestation/code/datums/components/uplink.dm b/monkestation/code/datums/components/uplink.dm
index 5477d2b5b667..e7c39c911559 100644
--- a/monkestation/code/datums/components/uplink.dm
+++ b/monkestation/code/datums/components/uplink.dm
@@ -1,2 +1,17 @@
-//this file contains extra stuff we have for uplink components like contractors
+#define STARTING_COMMON_CONTRACTS 3
+#define STARTING_UNCOMMON_CONTRACTS 2
+#define STARTING_RARE_CONTRACTS 1
+/datum/component/uplink/proc/become_contractor()
+ uplink_handler.uplink_flag = UPLINK_CONTRACTORS
+ uplink_handler.clear_secondaries()
+ uplink_handler.generate_objectives(list(
+ /datum/traitor_objective/target_player/kidnapping/common = STARTING_COMMON_CONTRACTS,
+ /datum/traitor_objective/target_player/kidnapping/uncommon = STARTING_UNCOMMON_CONTRACTS,
+ /datum/traitor_objective/target_player/kidnapping/rare = STARTING_RARE_CONTRACTS,
+ ))
+ for(var/item as anything in subtypesof(/datum/contractor_item))
+ uplink_handler.contractor_market_items += new item
+#undef STARTING_COMMON_CONTRACTS
+#undef STARTING_UNCOMMON_CONTRACTS
+#undef STARTING_RARE_CONTRACTS
diff --git a/monkestation/code/game/objects/items/storage/uplink_kits.dm b/monkestation/code/game/objects/items/storage/uplink_kits.dm
index 394aea4247db..d68a9559b3a4 100644
--- a/monkestation/code/game/objects/items/storage/uplink_kits.dm
+++ b/monkestation/code/game/objects/items/storage/uplink_kits.dm
@@ -24,7 +24,7 @@
/obj/item/clothing/under/syndicate/skirt/maid = 1,
/obj/item/clothing/gloves/combat/maid = 1,
/obj/item/clothing/accessory/maidapron/syndicate = 1,)
- generate_items_inside(items_inside,src)
+ generate_items_inside(items_inside, src)
/obj/item/storage/box/syndie_kit/contractor_loadout
name = "Standard Loadout"
@@ -41,7 +41,7 @@
new /obj/item/jammer(src)
/obj/item/storage/box/syndie_kit/contract_kit/PopulateContents()
- new /obj/item/storage/box/syndicate/contractor_loadout(src)
+ new /obj/item/storage/box/syndie_kit/contractor_loadout(src)
new /obj/item/melee/baton/telescopic/contractor_baton(src)
// You get one item from each sub list
@@ -84,9 +84,9 @@
)
var/list/items_to_give = list()
- items_to_give += pick(item_list[KIT_ITEM_CATEGORY_SUPPORT])
- items_to_give += pick(item_list[KIT_ITEM_CATEGORY_WEAPONS])
- items_to_give += pick(item_list[KIT_ITEM_CATEGORY_MISC])
+ items_to_give[pick(item_list[KIT_ITEM_CATEGORY_SUPPORT])] = 1
+ items_to_give[pick(item_list[KIT_ITEM_CATEGORY_WEAPONS])] = 1
+ items_to_give[pick(item_list[KIT_ITEM_CATEGORY_MISC])] = 1
generate_items_inside(items_to_give, src)
// Paper guide
diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm
index 68acfd7ee2e8..c83c7efa12ad 100644
--- a/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm
+++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm
@@ -7,17 +7,17 @@
var/contractor_support_unit = "" // Set if they had a support unit - and shows appended to their contracts completed
/// Get all the icons/total cost for all our items bought
- for (var/datum/contractor_item/contractor_purchase in contractor_hub.purchased_items)
+ for(var/datum/contractor_item/contractor_purchase in uplink_handler.purchased_contractor_items)
contractor_item_icons += "\[ [contractor_purchase.name] - [contractor_purchase.cost] Rep
[contractor_purchase.desc] \]"
-
+//TEST SPANS
total_spent_rep += contractor_purchase.cost
/// Special case for reinforcements, we want to show their ckey and name on round end.
- if (istype(contractor_purchase, /datum/contractor_item/contractor_partner))
+ if(istype(contractor_purchase, /datum/contractor_item/contractor_partner))
var/datum/contractor_item/contractor_partner/partner = contractor_purchase
contractor_support_unit += "
[partner.partner_mind.key] played [partner.partner_mind.current.name], their contractor support unit."
- if (contractor_hub.purchased_items.len)
+ if(length(uplink_handler.purchased_contractor_items))
result += "
(used [total_spent_rep] Rep) "
result += contractor_item_icons
result += "
"
diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_hub.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_hub.dm
deleted file mode 100644
index 6ac1f55aa061..000000000000
--- a/monkestation/code/modules/antagonists/contractor/datums/contractor_hub.dm
+++ /dev/null
@@ -1,4 +0,0 @@
-/datum/contractor_hub
- var/contract_rep = 0
- var/static/list/hub_items = list()
- var/list/purchased_items = list()
diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm
index 33f6de3a1933..6dc8adcdddac 100644
--- a/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm
+++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm
@@ -6,6 +6,21 @@
var/stock = -1 // Any number above 0 for how many times it can be bought in a round for a single traitor. -1 is unlimited.
var/cost // Cost of the item in contract rep.
+/datum/contractor_item/contract_reroll
+ name = "Contract Reroll"
+ desc = "Request a reroll of your current contract list. Will generate a new target, payment, and dropoff for the contracts you currently have available."
+ item_icon = "dice"
+ stock = 2
+ cost = 0
+
+/datum/contractor_item/contract_reroll/handle_purchase(datum/uplink_handler/handler, mob/living/user)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ handler.clear_secondaries()
+ handler.generate_objectives()
+
/datum/contractor_item/contractor_pinpointer
name = "Contractor Pinpointer"
desc = "A pinpointer that finds targets even without active suit sensors. Due to taking advantage of an exploit within the system, \
@@ -21,7 +36,7 @@
Activating the pack on your target will send them over to the beacon - make sure they're not just going to run away though!"
item = /obj/item/storage/box/contractor/fulton_extraction
item_icon = "parachute-box"
- stock = 1
+ stock = 2
cost = 1
/datum/contractor_item/contractor_partner
@@ -33,10 +48,10 @@
cost = 2
var/datum/mind/partner_mind = null
-/datum/contractor_item/contractor_partner/handle_purchase(datum/contractor_hub/hub, mob/living/user)
+/datum/contractor_item/contractor_partner/handle_purchase(datum/uplink_handler/handler, mob/living/user)
. = ..()
if(!.)
- return
+ return FALSE
to_chat(user, span_notice("The uplink vibrates quietly, connecting to nearby agents..."))
@@ -51,8 +66,8 @@
// refund and add the limit back.
stock += 1
- hub.contract_rep += cost
- hub.purchased_items -= src
+ handler.contractor_rep += cost
+ handler.purchased_contractor_items -= src
/datum/contractor_item/contractor_partner/proc/spawn_contractor_partner(mob/living/user, key)
var/mob/living/carbon/human/partner = new()
@@ -91,28 +106,29 @@
stock = 2
cost = 3
-/datum/contractor_item/blackout/handle_purchase(datum/contractor_hub/hub)
+/datum/contractor_item/blackout/handle_purchase(datum/uplink_handler/handler)
. = ..()
- if (.)
- power_fail(35, 50)
- priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", \
- "Critical Power Failure", ANNOUNCER_POWEROFF)
+ if(!.)
+ return FALSE
-// Subtract cost, and spawn if it's an item.
-/datum/contractor_item/proc/handle_purchase(datum/contractor_hub/hub, mob/living/user)
+ power_fail(35, 50)
+ priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", \
+ "Critical Power Failure", ANNOUNCER_POWEROFF)
- if (hub.contract_rep >= cost)
- hub.contract_rep -= cost
+// Subtract cost, and spawn if it's an item.
+/datum/contractor_item/proc/handle_purchase(datum/uplink_handler/handler, mob/living/user)
+ if(handler.contractor_rep >= cost)
+ handler.contractor_rep -= cost
else
return FALSE
- if (stock >= 1)
+ if(stock >= 1)
stock -= 1
- else if (stock == 0)
+ else if(stock == 0)
return FALSE
- hub.purchased_items.Add(src)
+ handler.purchased_contractor_items.Add(src)
user.playsound_local(user, 'sound/machines/uplinkpurchase.ogg', 100)
@@ -127,24 +143,6 @@
return item_to_create
return TRUE
-/obj/item/pinpointer/crew/contractor
- name = "contractor pinpointer"
- desc = "A handheld tracking device that locks onto certain signals. Ignores suit sensors, but is much less accurate."
- icon_state = "pinpointer_syndicate"
- worn_icon_state = "pinpointer_black"
- minimum_range = 25
- has_owner = TRUE
- ignore_suit_sensor_level = TRUE
-
-/obj/item/storage/box/contractor/fulton_extraction
- name = "Fulton Extraction Kit"
- icon_state = "syndiebox"
- illustration = "writing_syndie"
-
-/obj/item/storage/box/contractor/fulton_extraction/PopulateContents()
- new /obj/item/extraction_pack(src)
- new /obj/item/fulton_core(src)
-
/datum/contractor_item/baton_holster
name = "Baton Holster Module"
desc = "Never worry about dropping your baton again with this holster module! Simply insert your baton into the module, put it in your MODsuit, \
diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm
index 412839847373..b8f4e2edef20 100644
--- a/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm
+++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm
@@ -5,7 +5,6 @@
show_in_roundend = FALSE // We're already adding them in to the contractor's roundend.
give_objectives = TRUE // We give them their own custom objective.
show_in_antagpanel = FALSE // Not a proper/full antag.
- give_uplink = FALSE // Don't give them an uplink.
give_secondary_objectives = FALSE
/// Team datum that contains the contractor and the support unit
var/datum/team/contractor_team/contractor_team
diff --git a/monkestation/code/modules/antagonists/contractor/items/boxes.dm b/monkestation/code/modules/antagonists/contractor/items/boxes.dm
index 4f15be95e2fb..fdff852150e1 100644
--- a/monkestation/code/modules/antagonists/contractor/items/boxes.dm
+++ b/monkestation/code/modules/antagonists/contractor/items/boxes.dm
@@ -5,4 +5,4 @@
/obj/item/storage/box/contractor/fulton_extraction/PopulateContents()
new /obj/item/extraction_pack/contractor(src)
- new /obj/item/fulton_core(src)
+ generate_items_inside(list(/obj/item/fulton_core = 3), src)
diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm
index 31418e6c32c6..97cf27b3e1d1 100644
--- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm
+++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm
@@ -1,6 +1,7 @@
/obj/item/mod/control/pre_equipped/contractor
worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi'
- icon = 'monkestation/icons/obj/clothing/modsuits/contractor_modsuit.dmi'
+ icon = 'monkestation/icons/obj/clothing/modsuits/modsuit.dmi'
+ icon_state = "contractor-control"
theme = /datum/mod_theme/contractor
applied_cell = /obj/item/stock_parts/cell/hyper
applied_modules = list(
@@ -24,16 +25,16 @@
// I absolutely fuckin hate having to do this
/obj/item/clothing/head/mod/contractor
worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi'
- icon = 'monkestation/icons/obj/clothing/modsuits/contractor_modsuit.dmi'
+ icon = 'monkestation/icons/obj/clothing/modsuits/modsuit.dmi'
/obj/item/clothing/suit/mod/contractor
worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi'
- icon = 'monkestation/icons/obj/clothing/modsuits/contractor_modsuit.dmi'
+ icon = 'monkestation/icons/obj/clothing/modsuits/modsuit.dmi'
/obj/item/clothing/gloves/mod/contractor
worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi'
- icon = 'monkestation/icons/obj/clothing/modsuits/contractor_modsuit.dmi'
+ icon = 'monkestation/icons/obj/clothing/modsuits/modsuit.dmi'
/obj/item/clothing/shoes/mod/contractor
worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi'
- icon = 'monkestation/icons/obj/clothing/modsuits/contractor_modsuit.dmi'
+ icon = 'monkestation/icons/obj/clothing/modsuits/modsuit.dmi'
diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm
index fb71e85bbb56..530c18f2a442 100644
--- a/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm
+++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm
@@ -56,7 +56,7 @@
),
),
)
-
+//ICONS BORKED
/datum/armor/mod_contractor_armor
melee = 40
bullet = 50
diff --git a/monkestation/code/modules/antagonists/traitor/datum_traitor.dm b/monkestation/code/modules/antagonists/traitor/datum_traitor.dm
deleted file mode 100644
index 902fa6ef7c73..000000000000
--- a/monkestation/code/modules/antagonists/traitor/datum_traitor.dm
+++ /dev/null
@@ -1,3 +0,0 @@
-/datum/antagonist/traitor
- ///ref to our contractor hub datum, if we have one
- var/datum/contractor_hub/contractor_hub
diff --git a/monkestation/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm b/monkestation/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm
new file mode 100644
index 000000000000..fa64e26afccc
--- /dev/null
+++ b/monkestation/code/modules/antagonists/traitor/objectives/final_objective/final_objective.dm
@@ -0,0 +1,2 @@
+/datum/traitor_objective/ultimate
+ valid_uplinks = UPLINK_TRAITORS | UPLINK_CONTRACTORS
diff --git a/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm b/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm
new file mode 100644
index 000000000000..6b7ac9c9bbe7
--- /dev/null
+++ b/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm
@@ -0,0 +1,309 @@
+#define STARTING_COMMON_OBJECTIVES
+/datum/traitor_objective/target_player/kidnapping
+ name = "Kidnap %TARGET% the %JOB TITLE% and deliver them to %AREA%"
+ description = "%TARGET% holds extremely important information regarding secret NT projects - and you'll need to kidnap and deliver them to %AREA%, where our transport pod will be waiting. \
+ If %TARGET% is delivered alive, you will be rewarded with an additional %TC% telecrystals."
+
+ abstract_type = /datum/traitor_objective/target_player/kidnapping
+ valid_uplinks = UPLINK_CONTRACTORS
+ given_contractor_rep = 1
+ progression_minimum = 0 MINUTES
+
+ /// The jobs that this objective is targetting.
+ var/list/target_jobs
+ /// Area that the target needs to be delivered to
+ var/area/dropoff_area
+ /// Have we called the pod yet?
+ var/pod_called = FALSE
+ /// How much TC do we get from sending the target alive
+ var/alive_bonus = 0
+ /// All stripped targets belongings
+ var/list/target_belongings = list()
+
+/datum/traitor_objective/target_player/kidnapping/common
+ progression_reward = list(2 MINUTES, 4 MINUTES)
+ telecrystal_reward = list(2, 3)
+ target_jobs = list(
+ // Cargo
+ /datum/job/cargo_technician,
+ // Engineering
+ /datum/job/atmospheric_technician,
+ /datum/job/station_engineer,
+ // Medical
+ /datum/job/chemist,
+ /datum/job/doctor,
+ /datum/job/psychologist,
+ /datum/job/virologist,
+ // Science
+ /datum/job/geneticist,
+ /datum/job/roboticist,
+ /datum/job/scientist,
+ // Service
+ /datum/job/bartender,
+ /datum/job/botanist,
+ /datum/job/chaplain,
+ /datum/job/clown,
+ /datum/job/curator,
+ /datum/job/janitor,
+ /datum/job/lawyer,
+ /datum/job/mime,
+ )
+ alive_bonus = 3
+
+/datum/traitor_objective/target_player/kidnapping/common/assistant
+ target_jobs = list(
+ /datum/job/assistant
+ )
+ telecrystal_reward = 3 //go bully the assistants
+
+/datum/traitor_objective/target_player/kidnapping/uncommon //Hard to fish out targets
+ progression_reward = list(4 MINUTES, 8 MINUTES)
+ telecrystal_reward = list(3, 4)
+ given_contractor_rep = 2
+
+ target_jobs = list(
+ // Cargo
+ /datum/job/quartermaster,
+ /datum/job/shaft_miner,
+ // Medical
+ /datum/job/paramedic,
+ // Service
+ /datum/job/cook,
+ )
+ alive_bonus = 4
+
+/datum/traitor_objective/target_player/kidnapping/rare
+ progression_reward = list(8 MINUTES, 12 MINUTES)
+ telecrystal_reward = list(4, 5)
+ given_contractor_rep = 3
+
+ target_jobs = list(
+ // Heads of staff
+ /datum/job/chief_engineer,
+ /datum/job/chief_medical_officer,
+ /datum/job/head_of_personnel,
+ /datum/job/research_director,
+ // Security
+ /datum/job/detective,
+ /datum/job/security_officer,
+ /datum/job/warden,
+ )
+ alive_bonus = 5
+
+/datum/traitor_objective/target_player/kidnapping/captain
+ progression_reward = list(12 MINUTES, 16 MINUTES)
+ telecrystal_reward = list(5, 6)
+ given_contractor_rep = 4
+
+ target_jobs = list(
+ /datum/job/captain,
+ /datum/job/head_of_security,
+ )
+ alive_bonus = 6
+
+/datum/traitor_objective/target_player/kidnapping/generate_objective(datum/mind/generating_for, list/possible_duplicates)
+
+ var/list/already_targeting = list() //List of minds we're already targeting. The possible_duplicates is a list of objectives, so let's not mix things
+ for(var/datum/objective/task as anything in handler.primary_objectives)
+ if(!istype(task.target, /datum/mind))
+ continue
+ already_targeting += task.target //Removing primary objective kill targets from the list
+
+ var/list/possible_targets = list()
+ for(var/datum/mind/possible_target as anything in get_crewmember_minds())
+ if(possible_target == generating_for)
+ continue
+
+ if(possible_target in already_targeting)
+ continue
+
+ if(!ishuman(possible_target.current))
+ continue
+
+ if(possible_target.current.stat == DEAD)
+ continue
+
+ if(HAS_TRAIT(possible_target, TRAIT_HAS_BEEN_KIDNAPPED))
+ continue
+
+ if(possible_target.has_antag_datum(/datum/antagonist/traitor))
+ continue
+
+ if(!(possible_target.assigned_role.type in target_jobs))
+ continue
+
+ possible_targets += possible_target
+
+ for(var/datum/traitor_objective/target_player/objective as anything in possible_duplicates)
+ if(!objective.target) //the old objective was already completed.
+ continue
+ possible_targets -= objective.target.mind
+
+ if(!length(possible_targets))
+ return FALSE
+
+ var/datum/mind/target_mind = pick(possible_targets)
+ target = target_mind.current
+ AddComponent(/datum/component/traitor_objective_register, target, fail_signals = list(COMSIG_PARENT_QDELETING))
+ var/list/possible_areas = GLOB.the_station_areas.Copy()
+ for(var/area/possible_area as anything in possible_areas)
+ if(ispath(possible_area, /area/station/hallway) || ispath(possible_area, /area/station/security) || initial(possible_area.outdoors))
+ possible_areas -= possible_area
+
+ dropoff_area = pick(possible_areas)
+ replace_in_name("%TARGET%", target_mind.name)
+ replace_in_name("%JOB TITLE%", target_mind.assigned_role.title)
+ replace_in_name("%AREA%", initial(dropoff_area.name))
+ replace_in_name("%TC%", alive_bonus)
+ return TRUE
+
+/datum/traitor_objective/target_player/kidnapping/ungenerate_objective()
+ target = null
+ dropoff_area = null
+
+/datum/traitor_objective/target_player/kidnapping/on_objective_taken(mob/user)
+ . = ..()
+ INVOKE_ASYNC(src, PROC_REF(generate_holding_area))
+
+/datum/traitor_objective/target_player/kidnapping/proc/generate_holding_area()
+ // Let's load in the holding facility ahead of time
+ // even if they fail the objective it's better to get done now rather than later
+ SSmapping.lazy_load_template(LAZY_TEMPLATE_KEY_NINJA_HOLDING_FACILITY)
+
+/datum/traitor_objective/target_player/kidnapping/generate_ui_buttons(mob/user)
+ var/list/buttons = list()
+ if(!pod_called)
+ buttons += add_ui_button("Call Extraction Pod", "Pressing this will call down an extraction pod.", "rocket", "call_pod")
+ return buttons
+
+/datum/traitor_objective/target_player/kidnapping/ui_perform_action(mob/living/user, action)
+ . = ..()
+ switch(action)
+ if("call_pod")
+ if(pod_called)
+ return
+ var/area/user_area = get_area(user)
+ var/area/target_area = get_area(target)
+
+ if(user_area.type != dropoff_area)
+ to_chat(user, span_warning("You must be in [initial(dropoff_area.name)] to call the extraction pod."))
+ return
+
+ if(target_area.type != dropoff_area)
+ to_chat(user, span_warning("[target.real_name] must be in [initial(dropoff_area.name)] for you to call the extraction pod."))
+ return
+
+ call_pod(user)
+
+/datum/traitor_objective/target_player/kidnapping/proc/call_pod(mob/living/user)
+ pod_called = TRUE
+ var/obj/structure/closet/supplypod/extractionpod/new_pod = new()
+ RegisterSignal(new_pod, COMSIG_ATOM_ENTERED, PROC_REF(enter_check))
+ new /obj/effect/pod_landingzone(get_turf(user), new_pod)
+
+/datum/traitor_objective/target_player/kidnapping/proc/enter_check(obj/structure/closet/supplypod/extractionpod/source, entered_atom)
+ if(!istype(source))
+ CRASH("Kidnapping objective's enter_check called with source being not an extraction pod: [source ? source.type : "N/A"]")
+
+ if(!ishuman(entered_atom))
+ return
+
+ var/mob/living/carbon/human/sent_mob = entered_atom
+
+ if(sent_mob.mind)
+ ADD_TRAIT(sent_mob.mind, TRAIT_HAS_BEEN_KIDNAPPED, TRAIT_GENERIC)
+
+ for(var/obj/item/belonging in gather_belongings(sent_mob))
+ if(belonging == sent_mob.get_item_by_slot(ITEM_SLOT_ICLOTHING) || belonging == sent_mob.get_item_by_slot(ITEM_SLOT_FEET))
+ continue
+
+ var/unequipped = sent_mob.transferItemToLoc(belonging)
+ if (!unequipped)
+ continue
+ target_belongings.Add(belonging)
+
+ var/datum/bank_account/cargo_account = SSeconomy.get_dep_account(ACCOUNT_CAR)
+
+ if(cargo_account) //Just in case
+ cargo_account.adjust_money(-min(rand(1000, 3000), cargo_account.account_balance)) //Not so much, especially for competent cargo. Plus this can't be mass-triggered like it has been done with contractors
+
+ priority_announce("One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. As is policy we've taken a portion of the station's funds to offset the overall cost.", "Nanotrasen Asset Protection", has_important_message = TRUE)
+
+ addtimer(CALLBACK(src, PROC_REF(handle_target), sent_mob), 1.5 SECONDS)
+
+ if(sent_mob != target)
+ fail_objective(penalty_cost = telecrystal_penalty)
+ source.startExitSequence(source)
+ return
+
+ if(sent_mob.stat != DEAD)
+ telecrystal_reward += alive_bonus
+
+ succeed_objective()
+ source.startExitSequence(source)
+
+/datum/traitor_objective/target_player/kidnapping/proc/handle_target(mob/living/carbon/human/sent_mob)
+ addtimer(CALLBACK(src, PROC_REF(return_target), sent_mob), 3 MINUTES)
+ if(sent_mob.stat == DEAD)
+ return
+
+ sent_mob.flash_act()
+ sent_mob.adjust_confusion(10 SECONDS)
+ sent_mob.adjust_dizzy(10 SECONDS)
+ sent_mob.set_eye_blur_if_lower(100 SECONDS)
+ sent_mob.dna.species.give_important_for_life(sent_mob) // so plasmamen do not get left for dead
+ to_chat(sent_mob, span_hypnophrase(span_reallybig("A million voices echo in your head... \"Your mind held many valuable secrets - \
+ we thank you for providing them. Your value is expended, and you will be ransomed back to your station. We always get paid, \
+ so it's only a matter of time before we ship you back...\"")))
+
+/datum/traitor_objective/target_player/kidnapping/proc/return_target(mob/living/carbon/human/sent_mob)
+ if(!sent_mob || QDELETED(sent_mob)) //suicided and qdeleted themselves
+ return
+
+ var/list/possible_turfs = list()
+ for(var/turf/open/open_turf in dropoff_area)
+ if(open_turf.is_blocked_turf() || isspaceturf(open_turf))
+ continue
+ possible_turfs += open_turf
+
+ if(!LAZYLEN(possible_turfs))
+ var/turf/new_turf = get_safe_random_station_turf()
+ if(!new_turf) //SOMEHOW
+ to_chat(sent_mob, span_hypnophrase(span_reallybig("A million voices echo in your head... \"Seems where you got sent here from won't \
+ be able to handle our pod... You will die here instead.\"")))
+ if (sent_mob.can_heartattack())
+ sent_mob.set_heartattack(TRUE)
+ return
+
+ possible_turfs += new_turf
+
+ var/obj/structure/closet/supplypod/return_pod = new()
+ return_pod.bluespace = TRUE
+ return_pod.explosionSize = list(0,0,0,0)
+ return_pod.style = STYLE_SYNDICATE
+
+ do_sparks(8, FALSE, sent_mob)
+ sent_mob.visible_message(span_notice("[sent_mob] vanishes!"))
+ for(var/obj/item/belonging in gather_belongings(sent_mob))
+ if(belonging == sent_mob.get_item_by_slot(ITEM_SLOT_ICLOTHING) || belonging == sent_mob.get_item_by_slot(ITEM_SLOT_FEET))
+ continue
+ sent_mob.dropItemToGround(belonging) // No souvenirs, except shoes and t-shirts
+
+ for(var/obj/item/belonging in target_belongings)
+ belonging.forceMove(return_pod)
+
+ sent_mob.forceMove(return_pod)
+ sent_mob.flash_act()
+ sent_mob.adjust_confusion(10 SECONDS)
+ sent_mob.adjust_dizzy(10 SECONDS)
+ sent_mob.set_eye_blur_if_lower(100 SECONDS)
+ sent_mob.dna.species.give_important_for_life(sent_mob) // so plasmamen do not get left for dead
+
+ new /obj/effect/pod_landingzone(pick(possible_turfs), return_pod)
+
+/// Returns a list of things that the provided mob has which we would rather that they do not have
+/datum/traitor_objective/target_player/kidnapping/proc/gather_belongings(mob/living/carbon/human/kidnapee)
+ var/list/belongings = kidnapee.get_all_gear()
+ for (var/obj/item/implant/storage/internal_bag in kidnapee.implants)
+ belongings += internal_bag.contents
+ return belongings
diff --git a/monkestation/code/modules/antagonists/traitor/traitor_objective.dm b/monkestation/code/modules/antagonists/traitor/traitor_objective.dm
index f728ec22b2ff..9d0c0e802c2f 100644
--- a/monkestation/code/modules/antagonists/traitor/traitor_objective.dm
+++ b/monkestation/code/modules/antagonists/traitor/traitor_objective.dm
@@ -1,3 +1,5 @@
/datum/traitor_objective
///a bitfield for what types of uplinks can gain this objective
- var/valid_uplinks = ALL //this is a secret tool that will help us later
+ var/valid_uplinks = UPLINK_TRAITORS //this is a secret tool that will help us later
+ ///how much contractor rep this gives for completion
+ var/given_contractor_rep
diff --git a/monkestation/code/modules/antagonists/traitor/uplink_handler.dm b/monkestation/code/modules/antagonists/traitor/uplink_handler.dm
index 4848d52468e5..98f9657b6213 100644
--- a/monkestation/code/modules/antagonists/traitor/uplink_handler.dm
+++ b/monkestation/code/modules/antagonists/traitor/uplink_handler.dm
@@ -1,8 +1,28 @@
/datum/uplink_handler
/// Extra stuff that cannot be purchased by an uplink, regardless of flag.
var/list/locked_entries = list()
+ ///how much contractor rep we have
+ var/contractor_rep = 10 //SET THIS BACK TO 0
+ ///list of our contractor market items
+ var/list/contractor_market_items = list()
+ ///list of purchased contractor items
+ var/list/purchased_contractor_items = list()
///Add items to our locked_entries
/datum/uplink_handler/proc/add_locked_entries(list/items_to_add)
for(var/datum/uplink_item/item as anything in items_to_add)
locked_entries |= item
+
+///Clear a handler's potential_objectives
+/**
+ * fail_active - should we also call fail_objective() their active_objectives
+ * regenerate_objectives - should we let their objectives regenerate or not
+ */
+/datum/uplink_handler/proc/clear_secondaries(fail_active = FALSE, regenerate_objectives = FALSE)
+ var/original_max = maximum_potential_objectives
+ if(!regenerate_objectives)
+ maximum_potential_objectives = 0 //janky, but it needs the least new code and should work with what this proc does
+
+ for(var/datum/traitor_objective/possible_objective in potential_objectives + (fail_active ? active_objectives : list()))
+ possible_objective.fail_objective()
+ maximum_potential_objectives = original_max
diff --git a/monkestation/code/modules/uplink/uplink_items/bundle.dm b/monkestation/code/modules/uplink/uplink_items/bundle.dm
index 7687174e936e..86e2496adf42 100644
--- a/monkestation/code/modules/uplink/uplink_items/bundle.dm
+++ b/monkestation/code/modules/uplink/uplink_items/bundle.dm
@@ -1,6 +1,18 @@
/datum/uplink_item/bundles_tc/contract_kit
name = "Contractor Bundle"
desc = "A box containing everything you need to take contracts from the Syndicate. Kidnap people and drop them off at specified locations for rewards in the form of Telecrystals \
- (Usable in the provided uplink) and Contractor Points. Can not be bought if you have completed any secondary objectives."
- item = /obj/item/storage/box/syndicate/contract_kit
+ (Usable in the provided uplink) and Contractor Points. Can not be bought if you have taken any secondary objectives."
+ item = /obj/item/storage/box/syndie_kit/contract_kit
cost = 20
+ purchasable_from = UPLINK_TRAITORS
+
+/datum/uplink_item/bundles_tc/contract_kit/unique_checks(mob/user, datum/uplink_handler/handler, atom/movable/source)
+ if(length(handler.completed_objectives) || length(handler.active_objectives) || !handler.can_take_objectives || !handler.has_objectives)
+ return FALSE
+ return TRUE
+
+/datum/uplink_item/bundles_tc/contract_kit/purchase(mob/user, datum/uplink_handler/uplink_handler, atom/movable/source)
+ . = ..()
+ var/datum/component/uplink/our_uplink = source.GetComponent(/datum/component/uplink)
+ if(uplink_handler && our_uplink)
+ our_uplink.become_contractor()
diff --git a/monkestation/icons/obj/clothing/modsuits/contractor_modsuit.dmi b/monkestation/icons/obj/clothing/modsuits/modsuit.dmi
similarity index 100%
rename from monkestation/icons/obj/clothing/modsuits/contractor_modsuit.dmi
rename to monkestation/icons/obj/clothing/modsuits/modsuit.dmi
diff --git a/tgstation.dme b/tgstation.dme
index 9c8e2f1d3e32..37ef1e5acf45 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -393,6 +393,7 @@
#include "code\__DEFINES\~monkestation\status_effects.dm"
#include "code\__DEFINES\~monkestation\storytellers.dm"
#include "code\__DEFINES\~monkestation\traits.dm"
+#include "code\__DEFINES\~monkestation\uplink.dm"
#include "code\__DEFINES\~monkestation\dcs\signals\signals_atom.dm"
#include "code\__DEFINES\~monkestation\dcs\signals\signals_carbon.dm"
#include "code\__DEFINES\~monkestation\dcs\signals\signals_traitor.dm"
@@ -5670,7 +5671,6 @@
#include "monkestation\code\modules\antagonists\clock_cult\structures\traps\senders\lever.dm"
#include "monkestation\code\modules\antagonists\clock_cult\structures\traps\senders\pressure_sensor.dm"
#include "monkestation\code\modules\antagonists\contractor\datums\contractor_datum.dm"
-#include "monkestation\code\modules\antagonists\contractor\datums\contractor_hub.dm"
#include "monkestation\code\modules\antagonists\contractor\datums\contractor_items.dm"
#include "monkestation\code\modules\antagonists\contractor\datums\contractor_support.dm"
#include "monkestation\code\modules\antagonists\contractor\datums\mind_datum.dm"
@@ -5702,11 +5702,12 @@
#include "monkestation\code\modules\antagonists\slasher\slasher_outfit\slasher_footwear.dm"
#include "monkestation\code\modules\antagonists\slasher\slasher_outfit\slasher_headgear.dm"
#include "monkestation\code\modules\antagonists\slasher\slasher_outfit\slasher_middlewear.dm"
-#include "monkestation\code\modules\antagonists\traitor\datum_traitor.dm"
#include "monkestation\code\modules\antagonists\traitor\traitor_objective.dm"
#include "monkestation\code\modules\antagonists\traitor\uplink_handler.dm"
+#include "monkestation\code\modules\antagonists\traitor\objectives\kidnapping.dm"
#include "monkestation\code\modules\antagonists\traitor\objectives\tide_bug_department.dm"
#include "monkestation\code\modules\antagonists\traitor\objectives\final_objective\become_wizard.dm"
+#include "monkestation\code\modules\antagonists\traitor\objectives\final_objective\final_objective.dm"
#include "monkestation\code\modules\antagonists\wizard\equipment\artefact.dm"
#include "monkestation\code\modules\antagonists\wizard\equipment\spellbook_entries\defensive.dm"
#include "monkestation\code\modules\antagonists\wizard\equipment\spellbook_entries\mobility.dm"
diff --git a/tgui/packages/tgui/interfaces/Uplink/ContractorMenu.tsx b/tgui/packages/tgui/interfaces/Uplink/ContractorMenu.tsx
new file mode 100644
index 000000000000..6d7bd74ecc03
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Uplink/ContractorMenu.tsx
@@ -0,0 +1,64 @@
+import { useBackend } from '../../backend';
+import { Box, Button, Icon, Section, Table } from '../../components';
+
+export type ContractorItem = {
+ id: string;
+ name: string;
+ desc: string;
+ cost: number;
+ stock: number;
+ item_icon: string;
+};
+
+type ContractorMenuProps = {
+ items: ContractorItem[];
+ rep: number;
+};
+
+export const ContractorMenu = (props: ContractorMenuProps, context) => {
+ const { act, data } = useBackend(context);
+ const contractor_hub_items = props.items || [];
+ return (
+
+ Reputation: {props.rep}
+ {contractor_hub_items.map((item) => {
+ const repInfo = item.cost ? item.cost + ' Rep' : 'FREE';
+ const stock = item.stock !== -1;
+ return (
+
+ {stock && (
+
+ {item.stock} remaining
+
+ )}
+
+ );
+ })}
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Uplink/ObjectiveMenu.tsx b/tgui/packages/tgui/interfaces/Uplink/ObjectiveMenu.tsx
index 8e932cf10934..ecc1b439e691 100644
--- a/tgui/packages/tgui/interfaces/Uplink/ObjectiveMenu.tsx
+++ b/tgui/packages/tgui/interfaces/Uplink/ObjectiveMenu.tsx
@@ -13,6 +13,7 @@ export type Objective = {
progression_reward: number;
telecrystal_reward: number;
telecrystal_penalty: number;
+ contractor_rep?: number;
ui_buttons?: ObjectiveUiButton[];
objective_state: ObjectiveState;
original_progression: number;
@@ -290,6 +291,7 @@ const ObjectiveFunction = (
telecrystalReward={objective.telecrystal_reward}
telecrystalPenalty={objective.telecrystal_penalty}
progressionReward={objective.progression_reward}
+ contractorRep={objective.contractor_rep}
objectiveState={objective.objective_state}
originalProgression={objective.original_progression}
hideTcRep={objective.final_objective}
@@ -339,6 +341,7 @@ type ObjectiveElementProps = {
description: string;
telecrystalReward: number;
progressionReward: number;
+ contractorRep?: number;
uiButtons?: InfernoNode;
objectiveState?: ObjectiveState;
originalProgression: number;
@@ -360,6 +363,7 @@ export const ObjectiveElement = (props: ObjectiveElementProps, context) => {
uiButtons = null,
telecrystalReward,
progressionReward,
+ contractorRep,
objectiveState,
telecrystalPenalty,
handleCompletion,
@@ -457,6 +461,7 @@ export const ObjectiveElement = (props: ObjectiveElementProps, context) => {
width="100%"
textAlign="center">
{telecrystalReward} TC,
+ {!!contractorRep ? ' ' + contractorRep + ' REP,' : ''}
{calculateProgression(progressionReward)} Threat Level
{Math.abs(progressionDiff) > 10 && (
diff --git a/tgui/packages/tgui/interfaces/Uplink/index.tsx b/tgui/packages/tgui/interfaces/Uplink/index.tsx
index fe2aa6b0d08b..3d35b56e4281 100644
--- a/tgui/packages/tgui/interfaces/Uplink/index.tsx
+++ b/tgui/packages/tgui/interfaces/Uplink/index.tsx
@@ -8,6 +8,7 @@ import { BooleanLike } from 'common/react';
import { Box, Tabs, Button, Stack, Section, Tooltip, Dimmer } from '../../components';
import { PrimaryObjectiveMenu } from './PrimaryObjectiveMenu';
import { Objective, ObjectiveMenu } from './ObjectiveMenu';
+import { ContractorItem, ContractorMenu } from './ContractorMenu';
import { calculateProgression, calculateDangerLevel, dangerDefault, dangerLevelsTooltip } from './calculateDangerLevel';
type UplinkItem = {
@@ -60,6 +61,9 @@ type UplinkData = {
purchased_items: number;
shop_locked: BooleanLike;
locked_entries: string[];
+ is_contractor: BooleanLike;
+ contractor_items: ContractorItem[];
+ contractor_rep: number;
};
type UplinkState = {
@@ -178,6 +182,9 @@ export class Uplink extends Component<{}, UplinkState> {
purchased_items,
shop_locked,
locked_entries,
+ is_contractor,
+ contractor_items,
+ contractor_rep,
} = data;
const { allItems, allCategories, currentTab } = this.state as UplinkState;
@@ -359,9 +366,16 @@ export class Uplink extends Component<{}, UplinkState> {
)}
+ {!!is_contractor && (
+ this.setState({ currentTab: 2 })}>
+ Contractor Market
+
+ )}
this.setState({ currentTab: 2 })}>
+ selected={currentTab === 3 || !has_objectives}
+ onClick={() => this.setState({ currentTab: 3 })}>
Market
@@ -419,6 +433,12 @@ export class Uplink extends Component<{}, UplinkState> {
}
handleRequestObjectives={() => act('regenerate_objectives')}
/>
+ )) ||
+ (currentTab === 2 && is_contractor && (
+
)) || (