From e0671107c1ecac9dbaa55ad686e8be6b6c2ef1a4 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:36:25 -0800 Subject: [PATCH 01/60] cool --- code/__DEFINES/admin.dm | 3 - code/__DEFINES/~monkestation/admin.dm | 12 +++ code/__DEFINES/{ => ~monkestation}/patreon.dm | 0 code/modules/admin/topic.dm | 9 +- code/modules/mob/login.dm | 4 +- monkestation/code/datums/antag_tokens.dm | 2 +- monkestation/code/datums/patreon_data.dm | 1 + .../code/modules/admin/antag_tokens.dm | 9 +- .../code/modules/admin/event_tokens.dm | 17 ++++ .../{ggg => smites}/where_are_your_fingers.dm | 0 .../modules/cassettes/cassette_approval.dm | 12 +-- .../code/modules/client/event_tokens.dm | 1 + .../code/modules/client/preferences.dm | 6 ++ monkestation/code/modules/client/verbs.dm | 98 +++++++++++++------ .../modules/code_redemption/code_redeemer.dm | 2 +- .../events/{base_event.dm => _base_event.dm} | 2 + tgstation.dme | 9 +- 17 files changed, 128 insertions(+), 59 deletions(-) create mode 100644 code/__DEFINES/~monkestation/admin.dm rename code/__DEFINES/{ => ~monkestation}/patreon.dm (100%) create mode 100644 monkestation/code/modules/admin/event_tokens.dm rename monkestation/code/modules/admin/{ggg => smites}/where_are_your_fingers.dm (100%) create mode 100644 monkestation/code/modules/client/event_tokens.dm rename monkestation/code/modules/twitch_bits/events/{base_event.dm => _base_event.dm} (93%) diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 2d29562e1ebb..6c65c1ae747d 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -73,9 +73,6 @@ #define ADMIN_SHOW_PAPER(atom) "(SHOW)" /// Displays "(PLAY)" in the chat, when clicked it tries to play internet sounds from the request. #define ADMIN_PLAY_INTERNET(text) "(PLAY)" -#define ADMIN_APPROVE_TOKEN(user) "(Yes)" -#define ADMIN_REJECT_TOKEN(user) "(No)" -#define ADMIN_OPEN_REVIEW(id) "(Open Review)" /atom/proc/Admin_Coordinates_Readable(area_name, admin_jump_ref) var/turf/T = Safe_COORD_Location() diff --git a/code/__DEFINES/~monkestation/admin.dm b/code/__DEFINES/~monkestation/admin.dm new file mode 100644 index 000000000000..584dad8665aa --- /dev/null +++ b/code/__DEFINES/~monkestation/admin.dm @@ -0,0 +1,12 @@ +#define ADMIN_APPROVE_TOKEN(user) "(Yes)" +#define ADMIN_REJECT_TOKEN(user) "(No)" +#define ADMIN_OPEN_REVIEW(id) "(Open Review)" +#define ADMIN_APPROVE_TOKEN_EVENT(user) "(Yes)" +#define ADMIN_REJECT_TOKEN_EVENT(user) "(No)" + +///Sends all admins the chosen sound +#define SEND_ADMINS_NOTFICATION_SOUND(sound) for(var/client/X in GLOB.admins){X << sound;} +///Sends a message in adminchat +#define SEND_ADMINCHAT_MESSAGE(message) to_chat(GLOB.admins, type = MESSAGE_TYPE_ADMINCHAT, html = message, confidential = TRUE) +///Sends a message in adminchat with the chosen notfication sound +#define SEND_NOTFIED_ADMIN_MESSAGE(sound, message) SEND_ADMINS_NOTFICATION_SOUND(sound); SEND_ADMINCHAT_MESSAGE(message) diff --git a/code/__DEFINES/patreon.dm b/code/__DEFINES/~monkestation/patreon.dm similarity index 100% rename from code/__DEFINES/patreon.dm rename to code/__DEFINES/~monkestation/patreon.dm diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index b3600978a9a6..807cc82af0bc 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1758,7 +1758,7 @@ return web_sound(usr, link_url) - +//monkestation edit start else if(href_list["approve_token"]) if(!check_rights(R_ADMIN)) return @@ -1766,7 +1766,7 @@ if(!IS_CLIENT_OR_MOCK(target)) return var/client/user_client = target - user_client.saved_tokens.approve_token() + user_client.client_saved_tokens.approve_token() message_admins("[user_client]'s token has been approved, by [owner]") else if(href_list["reject_token"]) @@ -1776,7 +1776,7 @@ if(!IS_CLIENT_OR_MOCK(target)) return var/client/user_client = target - user_client.saved_tokens.reject_token() + user_client.client_saved_tokens.reject_token() message_admins("[user_client]'s token has been rejected, by [owner]") else if(href_list["open_music_review"]) @@ -1787,3 +1787,6 @@ if(!istype(cassette_review)) return cassette_review.ui_interact(usr) + + else if() +//monkestation edit end diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index d7300dcbabbc..a3d0262f4960 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -131,8 +131,8 @@ if(!client.patreon) client.patreon = new(client) - if(!client.saved_tokens) - client.saved_tokens = new(client) + if(!client.client_saved_tokens) + client.client_saved_tokens = new(client) return TRUE diff --git a/monkestation/code/datums/antag_tokens.dm b/monkestation/code/datums/antag_tokens.dm index 0654ffb30693..ec5df443fe4b 100644 --- a/monkestation/code/datums/antag_tokens.dm +++ b/monkestation/code/datums/antag_tokens.dm @@ -1,7 +1,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) /client - var/datum/antag_token_holder/saved_tokens + var/datum/antag_token_holder/client_saved_tokens /datum/antag_token_holder var/client/owner diff --git a/monkestation/code/datums/patreon_data.dm b/monkestation/code/datums/patreon_data.dm index f64889c11f66..6c8629fc3c41 100644 --- a/monkestation/code/datums/patreon_data.dm +++ b/monkestation/code/datums/patreon_data.dm @@ -1,5 +1,6 @@ /client var/datum/patreon_data/patreon + /datum/patreon_data ///the client that owns this data var/client/owner diff --git a/monkestation/code/modules/admin/antag_tokens.dm b/monkestation/code/modules/admin/antag_tokens.dm index 9698d8d93151..4947d1a13756 100644 --- a/monkestation/code/modules/admin/antag_tokens.dm +++ b/monkestation/code/modules/admin/antag_tokens.dm @@ -4,17 +4,16 @@ set name = "Adjust Antag Tokens" set desc = "You can modifiy a targets metacoin balance by adding or subtracting." - var/mob/chosen_player - chosen_player = tgui_input_list(src, "Choose a Player", "Player List", GLOB.player_list) + var/mob/chosen_player = tgui_input_list(src, "Choose a Player", "Player List", GLOB.player_list) if(!chosen_player) return - var/client/chosen_client = chosen_player.client + var/client/chosen_client = chosen_player.client var/adjustment_amount = tgui_input_number(src, "How much should we adjust this users antag tokens by?", "Input Value", TRUE, 10, -10) - if(!adjustment_amount) + if(!adjustment_amount || !chosen_client) return var/tier = tgui_input_list(src, "Choose a tier for the token", "Tier list", list(HIGH_THREAT, MEDIUM_THREAT, LOW_THREAT)) if(!tier) return - chosen_client.saved_tokens.adjust_tokens(tier, adjustment_amount) + chosen_client.client_saved_tokens.adjust_tokens(tier, adjustment_amount) diff --git a/monkestation/code/modules/admin/event_tokens.dm b/monkestation/code/modules/admin/event_tokens.dm new file mode 100644 index 000000000000..1c633ebde0fd --- /dev/null +++ b/monkestation/code/modules/admin/event_tokens.dm @@ -0,0 +1,17 @@ +/client/proc/set_players_event_tokens() + set category = "Admin.Fun" +//due to the fact that these reset each month im just making this directly this this value instead of add or subtract + set name = "Set Event Tokens" + set desc = "Set how many event tokens someone has." + + var/mob/chosen_player = tgui_input_list(src, "Choose a Player", "Player List", GLOB.player_list) + if(!chosen_player) + return + + var/client/chosen_client = chosen_player.client + var/adjustment_amount = tgui_input_number(src, "What should we set this users tokens to?", "Input Value", TRUE) + if(!adjustment_amount || !chosen_client || !chosen_client.patreon) + return + + check_event_tokens(chosen_client) + chosen_client.prefs.event_tokens = adjustment_amount diff --git a/monkestation/code/modules/admin/ggg/where_are_your_fingers.dm b/monkestation/code/modules/admin/smites/where_are_your_fingers.dm similarity index 100% rename from monkestation/code/modules/admin/ggg/where_are_your_fingers.dm rename to monkestation/code/modules/admin/smites/where_are_your_fingers.dm diff --git a/monkestation/code/modules/cassettes/cassette_approval.dm b/monkestation/code/modules/cassettes/cassette_approval.dm index 6bae8ae8a81b..c758bb1dc658 100644 --- a/monkestation/code/modules/cassettes/cassette_approval.dm +++ b/monkestation/code/modules/cassettes/cassette_approval.dm @@ -20,16 +20,8 @@ GLOBAL_LIST_INIT(cassette_reviews, list()) new_review.submitted_tape = submitted GLOB.cassette_reviews["[new_review.id]"] = new_review - - var/message = "[span_big(span_admin("[span_prefix("MUSIC APPROVAL:")] [key_name(user)] [ADMIN_OPEN_REVIEW(new_review.id)] has requested a review on their cassette."))]" - - for(var/client/X in GLOB.admins) - X << 'sound/items/bikehorn.ogg' - - to_chat(GLOB.admins, - type = MESSAGE_TYPE_ADMINCHAT, - html = message, - confidential = TRUE) + SEND_NOTIFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_big(span_admin("[span_prefix("MUSIC APPROVAL:")] [key_name(user)] [ADMIN_OPEN_REVIEW(new_review.id)] \ + has requested a review on their cassette."))]") to_chat(user, span_notice("Your Cassette has been sent to the Space Board of Music for review, you will be notified when an outcome has been made.")) /obj/item/device/cassette_tape/proc/generate_cassette_json() diff --git a/monkestation/code/modules/client/event_tokens.dm b/monkestation/code/modules/client/event_tokens.dm new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/monkestation/code/modules/client/event_tokens.dm @@ -0,0 +1 @@ + diff --git a/monkestation/code/modules/client/preferences.dm b/monkestation/code/modules/client/preferences.dm index a266c0a24036..226aae63cf2b 100644 --- a/monkestation/code/modules/client/preferences.dm +++ b/monkestation/code/modules/client/preferences.dm @@ -30,3 +30,9 @@ var/list/alt_job_titles = list() /// the month we used our last donator token on var/token_month = 0 + + ///how many event tokens we currently have + var/event_tokens = 0 + ///the month we last used event tokens on + var/event_token_month = 0 + ///what token event do we currently have queued diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index 40fbcc906dc9..7e5780f1a99c 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -16,7 +16,16 @@ GLOBAL_LIST_INIT(low_threat_antags, list( /datum/antagonist/paradox_clone, )) - +//PLACEHOLDER VALUES(1 to 1 cent to token conversion, also you get a free token if you dont pay yeah totally) +///assoc list of how many event tokens each role gets each month +GLOBAL_LIST_INIT(patreon_etoken_values, list( + NO_RANK = 0, + RANK_TANKS = 100, + ASSISTANT_RANK = 500, + COMMAND_RANK = 1000, + TRAITOR_RANK = 2500, + NUKIE_RANK = 5000, +)) /client/verb/spend_antag_tokens() set category = "IC" @@ -31,15 +40,18 @@ GLOBAL_LIST_INIT(low_threat_antags, list( if(isobserver(mob)) to_chat(src, span_notice("NOTE: You will be spawned where ever your ghost is when approved, so becareful where you are.")) - if(!saved_tokens) - saved_tokens = new(src) + if(!client_saved_tokens) + client_saved_tokens = new(src) - var/tier = tgui_input_list(src, "High:[saved_tokens.total_high_threat_tokens] | Med: [saved_tokens.total_medium_threat_tokens] | Low: [saved_tokens.total_low_threat_tokens] | Donator:[saved_tokens.donator_token]", "Choose A Tier To Spend", list(HIGH_THREAT, MEDIUM_THREAT, LOW_THREAT)) + var/tier = tgui_input_list(src, "High:[client_saved_tokens.total_high_threat_tokens] | \ + Med: [client_saved_tokens.total_medium_threat_tokens] | \ + Low: [client_saved_tokens.total_low_threat_tokens] | \ + Donator:[client_saved_tokens.donator_token]", "Choose A Tier To Spend", list(HIGH_THREAT, MEDIUM_THREAT, LOW_THREAT)) if(!tier) return var/using_donor = FALSE - if(saved_tokens.donator_token) + if(client_saved_tokens.donator_token) var/choice = tgui_alert(src, "Use Donator Token?" , "Spend Tokens", list("Yes", "No")) if(choice == "Yes") using_donor = TRUE @@ -47,41 +59,65 @@ GLOBAL_LIST_INIT(low_threat_antags, list( if(!using_donor) switch(tier) if(HIGH_THREAT) - if(saved_tokens.total_high_threat_tokens <= 0) + if(client_saved_tokens.total_high_threat_tokens <= 0) return if(MEDIUM_THREAT) - if(saved_tokens.total_medium_threat_tokens <= 0) + if(client_saved_tokens.total_medium_threat_tokens <= 0) return if(LOW_THREAT) - if(saved_tokens.total_low_threat_tokens <= 0) + if(client_saved_tokens.total_low_threat_tokens <= 0) return var/datum/antagonist/chosen_antagonist - switch(tier) - if(HIGH_THREAT) - chosen_antagonist = tgui_input_list(src, "Choose an Antagonist", "Spend Tokens", GLOB.high_threat_antags) - if(MEDIUM_THREAT) - chosen_antagonist = tgui_input_list(src, "Choose an Antagonist", "Spend Tokens", GLOB.medium_threat_antags) - if(LOW_THREAT) - chosen_antagonist = tgui_input_list(src, "Choose an Antagonist", "Spend Tokens", GLOB.low_threat_antags) + var/static/list/token_values = list( + HIGH_THREAT = GLOB.high_threat_antags, + MEDIUM_THREAT = GLOB.medium_threat_antags, + LOW_THREAT = GLOB.low_threat_antags, + ) + chosen_antagonist = tgui_input_list(src, "Choose an Antagonist", "Spend Tokens", token_values[tier]) if(!chosen_antagonist) return - saved_tokens.queued_donor = using_donor - saved_tokens.in_queued_tier = tier - saved_tokens.in_queue = new chosen_antagonist + client_saved_tokens.queued_donor = using_donor + client_saved_tokens.in_queued_tier = tier + client_saved_tokens.in_queue = new chosen_antagonist to_chat(src, "Your request has been sent to the admins.") - wait_for_approval(src, chosen_antagonist) - - -/proc/wait_for_approval(client/requestor, datum/antagonist/requested_antag) - var/msg = "[span_admin("[span_prefix("ANTAG TOKEN:")] [key_name(requestor)] [ADMIN_APPROVE_TOKEN(requestor)] [ADMIN_REJECT_TOKEN(requestor)] | [requestor] has requested to use their antag token to be a [requested_antag].")]" - - for(var/client/X in GLOB.admins) - X << 'sound/items/bikehorn.ogg' - - to_chat(GLOB.admins, - type = MESSAGE_TYPE_ADMINCHAT, - html = msg, - confidential = TRUE) + SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_admin("[span_prefix("ANTAG TOKEN:")] [key_name(src)] [ADMIN_APPROVE_TOKEN(src)] [ADMIN_REJECT_TOKEN(src)] | \ + [src] has requested to use their antag token to be a [chosen_antagonist].")]") + +/client/proc/trigger_token_event() + set category = "Ghost" + set name = "Trigger Token Event" + set desc = "Opens a ui to spend event tokens on" + + if(!isobserver(mob)) + to_chat(src, "You can only trigger events as a ghost.") + + var/static/list/event_list + if(!event_list) + event_list = subtypesof(/datum/twitch_event) + for(var/datum/twitch_event/event as anything in event_list) + if(!event.token_cost) + event_list -= event + + check_event_tokens(src) + + var/datum/twitch_event/selected_event = tgui_input_list(src, "Event tokens: [prefs.event_tokens]", "Choose an event to trigger", event_list) + var/confirm = tgui_alert(src, "Are you sure you want to trigger [selected_event.event_name]? It will cost [selected_event.token_cost] event tokens.", "Trigger token event", \ + list("Yes", "No")) + if(confirm == "Yes") + if(prefs.event_tokens >= selected_event.token_cost) + SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "MESSAGE") + return + to_chat(src, "You dont have enough tokens to trigger this event.") + +/proc/approve_token_event() + +/proc/reject_token_event() + +/proc/check_event_tokens(client/checked_client) + var/month_number = text2num(time2text(world.time, "MM")) + if(checked_client.prefs.event_token_month != month_number) + checked_client.prefs.event_token_month = month_number + checked_client.prefs.event_tokens = GLOB.patreon_etoken_values[checked_client.patreon.owned_rank] diff --git a/monkestation/code/modules/code_redemption/code_redeemer.dm b/monkestation/code/modules/code_redemption/code_redeemer.dm index d02aeaa14ea8..cf0e7941e8ef 100644 --- a/monkestation/code/modules/code_redemption/code_redeemer.dm +++ b/monkestation/code/modules/code_redemption/code_redeemer.dm @@ -26,7 +26,7 @@ GLOBAL_LIST_INIT(redeemed_codes, list()) if(isnum(path)) usr.client.prefs.adjust_metacoins(usr.ckey, path, "Redeemed a Giveaway Code", donator_multipler = FALSE) else if(path == HIGH_THREAT || path == MEDIUM_THREAT || path == LOW_THREAT) - usr.client.saved_tokens.adjust_tokens(path, 1) + usr.client.client_saved_tokens.adjust_tokens(path, 1) to_chat(usr, span_boldnotice("You have successfully redeemed a giveaway code for: [path] Antag Token.")) else var/pathedstring = text2path(path) diff --git a/monkestation/code/modules/twitch_bits/events/base_event.dm b/monkestation/code/modules/twitch_bits/events/_base_event.dm similarity index 93% rename from monkestation/code/modules/twitch_bits/events/base_event.dm rename to monkestation/code/modules/twitch_bits/events/_base_event.dm index b38ecfb8691f..ead023a1c4f6 100644 --- a/monkestation/code/modules/twitch_bits/events/base_event.dm +++ b/monkestation/code/modules/twitch_bits/events/_base_event.dm @@ -13,6 +13,8 @@ var/id_tag ///should we announce this event var/announce = TRUE + ///how many event tokens does this cost to trigger + var/token_cost = 0 /datum/twitch_event/proc/run_event(name) if(event_flags & TWITCH_AFFECTS_STREAMER) diff --git a/tgstation.dme b/tgstation.dme index d3bc1729f965..70a2d47a85eb 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -175,7 +175,6 @@ #include "code\__DEFINES\paper.dm" #include "code\__DEFINES\particles.dm" #include "code\__DEFINES\path.dm" -#include "code\__DEFINES\patreon.dm" #include "code\__DEFINES\perf_test.dm" #include "code\__DEFINES\pinpointers.dm" #include "code\__DEFINES\pipe_construction.dm" @@ -371,6 +370,7 @@ #include "code\__DEFINES\research\anomalies.dm" #include "code\__DEFINES\research\research_categories.dm" #include "code\__DEFINES\~monkestation\access.dm" +#include "code\__DEFINES\~monkestation\admin.dm" #include "code\__DEFINES\~monkestation\ai.dm" #include "code\__DEFINES\~monkestation\antagonists.dm" #include "code\__DEFINES\~monkestation\clock_cult.dm" @@ -386,6 +386,7 @@ #include "code\__DEFINES\~monkestation\mecha.dm" #include "code\__DEFINES\~monkestation\misc.dm" #include "code\__DEFINES\~monkestation\mobs.dm" +#include "code\__DEFINES\~monkestation\patreon.dm" #include "code\__DEFINES\~monkestation\robots.dm" #include "code\__DEFINES\~monkestation\smoothing.dm" #include "code\__DEFINES\~monkestation\span.dm" @@ -5552,9 +5553,10 @@ #include "monkestation\code\game\turfs\open\water.dm" #include "monkestation\code\modules\admin\antag_tokens.dm" #include "monkestation\code\modules\admin\camera_view.dm" -#include "monkestation\code\modules\admin\ggg\where_are_your_fingers.dm" +#include "monkestation\code\modules\admin\event_tokens.dm" #include "monkestation\code\modules\admin\smites\dagothkillsmite.dm" #include "monkestation\code\modules\admin\smites\dagothstripsmite.dm" +#include "monkestation\code\modules\admin\smites\where_are_your_fingers.dm" #include "monkestation\code\modules\aesthetics\airlock\airlock.dm" #include "monkestation\code\modules\aesthetics\items\clothing.dm" #include "monkestation\code\modules\aesthetics\mapping\tilecoloring.dm" @@ -5812,6 +5814,7 @@ #include "monkestation\code\modules\cassettes\machines\media\track.dm" #include "monkestation\code\modules\cassettes\machines\media\subsystem\media_track_manager.dm" #include "monkestation\code\modules\cassettes\walkman\_walkmen.dm" +#include "monkestation\code\modules\client\event_tokens.dm" #include "monkestation\code\modules\client\preference_savefile.dm" #include "monkestation\code\modules\client\preferences.dm" #include "monkestation\code\modules\client\verbs.dm" @@ -6349,10 +6352,10 @@ #include "monkestation\code\modules\surgery\organs\internal\tongue.dm" #include "monkestation\code\modules\twitch_bits\admin_command.dm" #include "monkestation\code\modules\twitch_bits\twitch_system.dm" +#include "monkestation\code\modules\twitch_bits\events\_base_event.dm" #include "monkestation\code\modules\twitch_bits\events\amongus.dm" #include "monkestation\code\modules\twitch_bits\events\anime_ook.dm" #include "monkestation\code\modules\twitch_bits\events\australia_mode.dm" -#include "monkestation\code\modules\twitch_bits\events\base_event.dm" #include "monkestation\code\modules\twitch_bits\events\buff.dm" #include "monkestation\code\modules\twitch_bits\events\chuckle_nut.dm" #include "monkestation\code\modules\twitch_bits\events\die_fate.dm" From f8ca0c542128192855a8dfcf0af921158d57885e Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:48:45 -0800 Subject: [PATCH 02/60] meta tokens --- code/modules/admin/topic.dm | 2 +- .../{antag_tokens.dm => meta_tokens.dm} | 20 +++++++++---------- .../modules/cassettes/cassette_approval.dm | 2 +- .../code/modules/client/preferences.dm | 1 + tgstation.dme | 2 +- 5 files changed, 14 insertions(+), 13 deletions(-) rename monkestation/code/datums/{antag_tokens.dm => meta_tokens.dm} (83%) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 807cc82af0bc..22800494bfef 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1788,5 +1788,5 @@ return cassette_review.ui_interact(usr) - else if() +// else if() //monkestation edit end diff --git a/monkestation/code/datums/antag_tokens.dm b/monkestation/code/datums/meta_tokens.dm similarity index 83% rename from monkestation/code/datums/antag_tokens.dm rename to monkestation/code/datums/meta_tokens.dm index ec5df443fe4b..454ee33c7126 100644 --- a/monkestation/code/datums/antag_tokens.dm +++ b/monkestation/code/datums/meta_tokens.dm @@ -1,9 +1,9 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) /client - var/datum/antag_token_holder/client_saved_tokens + var/datum/meta_token_holder/client_saved_tokens -/datum/antag_token_holder +/datum/meta_token_holder var/client/owner ///are they a donator? and do they have their free token? var/donator_token = FALSE @@ -20,7 +20,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) var/in_queued_tier var/queued_donor = FALSE -/datum/antag_token_holder/New(client/creator) +/datum/meta_token_holder/New(client/creator) . = ..() if(!creator) return @@ -30,7 +30,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) convert_list_to_tokens(owners_prefs.saved_tokens) donator_token = check_for_donator_token() -/datum/antag_token_holder/proc/convert_list_to_tokens(list/saved_tokens) +/datum/meta_token_holder/proc/convert_list_to_tokens(list/saved_tokens) if(!length(saved_tokens)) return total_low_threat_tokens = saved_tokens["low_threat"] @@ -39,7 +39,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) total_antag_tokens = total_low_threat_tokens + total_medium_threat_tokens + total_high_threat_tokens -/datum/antag_token_holder/proc/convert_tokens_to_list() +/datum/meta_token_holder/proc/convert_tokens_to_list() owner.prefs.saved_tokens = list( "low_threat" = total_low_threat_tokens, "medium_threat" = total_medium_threat_tokens, @@ -47,7 +47,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) ) owner.prefs.save_preferences() -/datum/antag_token_holder/proc/check_for_donator_token() +/datum/meta_token_holder/proc/check_for_donator_token() if(!owner.patreon) return FALSE if(!owner.patreon.has_access(ACCESS_TRAITOR_RANK)) @@ -57,7 +57,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) return FALSE return TRUE -/datum/antag_token_holder/proc/spend_token(tier, use_donor = FALSE) +/datum/meta_token_holder/proc/spend_token(tier, use_donor = FALSE) if(use_donor) if(donator_token) donator_token = FALSE @@ -76,7 +76,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) convert_tokens_to_list() ///adjusts the users tokens, yes they can be in antag token debt -/datum/antag_token_holder/proc/adjust_tokens(tier, amount) +/datum/meta_token_holder/proc/adjust_tokens(tier, amount) switch(tier) if(HIGH_THREAT) total_high_threat_tokens += amount @@ -88,7 +88,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) convert_tokens_to_list() -/datum/antag_token_holder/proc/approve_token() +/datum/meta_token_holder/proc/approve_token() if(!in_queue) return to_chat(owner, "Your request to play as [in_queue] has been approved.") @@ -103,7 +103,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) in_queued_tier = null queued_donor = FALSE -/datum/antag_token_holder/proc/reject_token() +/datum/meta_token_holder/proc/reject_token() to_chat(owner, "Your request to play as [in_queue] has been denied.") in_queue = null in_queued_tier = null diff --git a/monkestation/code/modules/cassettes/cassette_approval.dm b/monkestation/code/modules/cassettes/cassette_approval.dm index c758bb1dc658..d658372c26c4 100644 --- a/monkestation/code/modules/cassettes/cassette_approval.dm +++ b/monkestation/code/modules/cassettes/cassette_approval.dm @@ -20,7 +20,7 @@ GLOBAL_LIST_INIT(cassette_reviews, list()) new_review.submitted_tape = submitted GLOB.cassette_reviews["[new_review.id]"] = new_review - SEND_NOTIFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_big(span_admin("[span_prefix("MUSIC APPROVAL:")] [key_name(user)] [ADMIN_OPEN_REVIEW(new_review.id)] \ + SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_big(span_admin("[span_prefix("MUSIC APPROVAL:")] [key_name(user)] [ADMIN_OPEN_REVIEW(new_review.id)] \ has requested a review on their cassette."))]") to_chat(user, span_notice("Your Cassette has been sent to the Space Board of Music for review, you will be notified when an outcome has been made.")) diff --git a/monkestation/code/modules/client/preferences.dm b/monkestation/code/modules/client/preferences.dm index 226aae63cf2b..8086108e086f 100644 --- a/monkestation/code/modules/client/preferences.dm +++ b/monkestation/code/modules/client/preferences.dm @@ -36,3 +36,4 @@ ///the month we last used event tokens on var/event_token_month = 0 ///what token event do we currently have queued + var/datum/twitch_event/queued_token_event diff --git a/tgstation.dme b/tgstation.dme index 70a2d47a85eb..dcc757bda72c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5474,9 +5474,9 @@ #include "monkestation\code\__HELPERS\turfs.dm" #include "monkestation\code\_onclick\hud\alert.dm" #include "monkestation\code\datums\action.dm" -#include "monkestation\code\datums\antag_tokens.dm" #include "monkestation\code\datums\emotes.dm" #include "monkestation\code\datums\interaction_particle.dm" +#include "monkestation\code\datums\meta_tokens.dm" #include "monkestation\code\datums\patreon_data.dm" #include "monkestation\code\datums\stamina_container.dm" #include "monkestation\code\datums\ai\idle_behaviors\idle_dukeman.dm" From 34a339d9898a71917071eb1b99a6046cb5560d2b Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:50:57 -0800 Subject: [PATCH 03/60] client token holder --- code/modules/admin/topic.dm | 4 +-- code/modules/mob/login.dm | 4 +-- monkestation/code/datums/meta_tokens.dm | 2 +- .../code/modules/admin/antag_tokens.dm | 2 +- monkestation/code/modules/client/verbs.dm | 26 +++++++++---------- .../modules/code_redemption/code_redeemer.dm | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 22800494bfef..b1a08181f125 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1766,7 +1766,7 @@ if(!IS_CLIENT_OR_MOCK(target)) return var/client/user_client = target - user_client.client_saved_tokens.approve_token() + user_client.client_token_holder.approve_token() message_admins("[user_client]'s token has been approved, by [owner]") else if(href_list["reject_token"]) @@ -1776,7 +1776,7 @@ if(!IS_CLIENT_OR_MOCK(target)) return var/client/user_client = target - user_client.client_saved_tokens.reject_token() + user_client.client_token_holder.reject_token() message_admins("[user_client]'s token has been rejected, by [owner]") else if(href_list["open_music_review"]) diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index a3d0262f4960..a1e9324a535c 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -131,8 +131,8 @@ if(!client.patreon) client.patreon = new(client) - if(!client.client_saved_tokens) - client.client_saved_tokens = new(client) + if(!client.client_token_holder) + client.client_token_holder = new(client) return TRUE diff --git a/monkestation/code/datums/meta_tokens.dm b/monkestation/code/datums/meta_tokens.dm index 454ee33c7126..aa0d32cc6c6c 100644 --- a/monkestation/code/datums/meta_tokens.dm +++ b/monkestation/code/datums/meta_tokens.dm @@ -1,7 +1,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) /client - var/datum/meta_token_holder/client_saved_tokens + var/datum/meta_token_holder/client_token_holder /datum/meta_token_holder var/client/owner diff --git a/monkestation/code/modules/admin/antag_tokens.dm b/monkestation/code/modules/admin/antag_tokens.dm index 4947d1a13756..def24b5fdea1 100644 --- a/monkestation/code/modules/admin/antag_tokens.dm +++ b/monkestation/code/modules/admin/antag_tokens.dm @@ -16,4 +16,4 @@ if(!tier) return - chosen_client.client_saved_tokens.adjust_tokens(tier, adjustment_amount) + chosen_client.client_token_holder.adjust_tokens(tier, adjustment_amount) diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index 7e5780f1a99c..a62bfebb884d 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -40,18 +40,18 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( if(isobserver(mob)) to_chat(src, span_notice("NOTE: You will be spawned where ever your ghost is when approved, so becareful where you are.")) - if(!client_saved_tokens) - client_saved_tokens = new(src) + if(!client_token_holder) + client_token_holder = new(src) - var/tier = tgui_input_list(src, "High:[client_saved_tokens.total_high_threat_tokens] | \ - Med: [client_saved_tokens.total_medium_threat_tokens] | \ - Low: [client_saved_tokens.total_low_threat_tokens] | \ - Donator:[client_saved_tokens.donator_token]", "Choose A Tier To Spend", list(HIGH_THREAT, MEDIUM_THREAT, LOW_THREAT)) + var/tier = tgui_input_list(src, "High:[client_token_holder.total_high_threat_tokens] | \ + Med: [client_token_holder.total_medium_threat_tokens] | \ + Low: [client_token_holder.total_low_threat_tokens] | \ + Donator:[client_token_holder.donator_token]", "Choose A Tier To Spend", list(HIGH_THREAT, MEDIUM_THREAT, LOW_THREAT)) if(!tier) return var/using_donor = FALSE - if(client_saved_tokens.donator_token) + if(client_token_holder.donator_token) var/choice = tgui_alert(src, "Use Donator Token?" , "Spend Tokens", list("Yes", "No")) if(choice == "Yes") using_donor = TRUE @@ -59,13 +59,13 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( if(!using_donor) switch(tier) if(HIGH_THREAT) - if(client_saved_tokens.total_high_threat_tokens <= 0) + if(client_token_holder.total_high_threat_tokens <= 0) return if(MEDIUM_THREAT) - if(client_saved_tokens.total_medium_threat_tokens <= 0) + if(client_token_holder.total_medium_threat_tokens <= 0) return if(LOW_THREAT) - if(client_saved_tokens.total_low_threat_tokens <= 0) + if(client_token_holder.total_low_threat_tokens <= 0) return var/datum/antagonist/chosen_antagonist @@ -78,9 +78,9 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( if(!chosen_antagonist) return - client_saved_tokens.queued_donor = using_donor - client_saved_tokens.in_queued_tier = tier - client_saved_tokens.in_queue = new chosen_antagonist + client_token_holder.queued_donor = using_donor + client_token_holder.in_queued_tier = tier + client_token_holder.in_queue = new chosen_antagonist to_chat(src, "Your request has been sent to the admins.") SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_admin("[span_prefix("ANTAG TOKEN:")] [key_name(src)] [ADMIN_APPROVE_TOKEN(src)] [ADMIN_REJECT_TOKEN(src)] | \ diff --git a/monkestation/code/modules/code_redemption/code_redeemer.dm b/monkestation/code/modules/code_redemption/code_redeemer.dm index cf0e7941e8ef..7e394286b0d4 100644 --- a/monkestation/code/modules/code_redemption/code_redeemer.dm +++ b/monkestation/code/modules/code_redemption/code_redeemer.dm @@ -26,7 +26,7 @@ GLOBAL_LIST_INIT(redeemed_codes, list()) if(isnum(path)) usr.client.prefs.adjust_metacoins(usr.ckey, path, "Redeemed a Giveaway Code", donator_multipler = FALSE) else if(path == HIGH_THREAT || path == MEDIUM_THREAT || path == LOW_THREAT) - usr.client.client_saved_tokens.adjust_tokens(path, 1) + usr.client.client_token_holder.adjust_tokens(path, 1) to_chat(usr, span_boldnotice("You have successfully redeemed a giveaway code for: [path] Antag Token.")) else var/pathedstring = text2path(path) From f74ee9a7bba79382548626e7c184d3ae838bf657 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:08:33 -0800 Subject: [PATCH 04/60] well --- code/__DEFINES/~monkestation/admin.dm | 4 ++-- code/modules/admin/topic.dm | 4 ++-- monkestation/code/datums/meta_tokens.dm | 17 ++++++++++++++--- monkestation/code/modules/client/preferences.dm | 9 ++------- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/code/__DEFINES/~monkestation/admin.dm b/code/__DEFINES/~monkestation/admin.dm index 584dad8665aa..bf7b9207aa53 100644 --- a/code/__DEFINES/~monkestation/admin.dm +++ b/code/__DEFINES/~monkestation/admin.dm @@ -1,5 +1,5 @@ -#define ADMIN_APPROVE_TOKEN(user) "(Yes)" -#define ADMIN_REJECT_TOKEN(user) "(No)" +#define ADMIN_APPROVE_TOKEN(user) "(Yes)" +#define ADMIN_REJECT_TOKEN(user) "(No)" #define ADMIN_OPEN_REVIEW(id) "(Open Review)" #define ADMIN_APPROVE_TOKEN_EVENT(user) "(Yes)" #define ADMIN_REJECT_TOKEN_EVENT(user) "(No)" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index b1a08181f125..c436d382d3a5 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1759,7 +1759,7 @@ web_sound(usr, link_url) //monkestation edit start - else if(href_list["approve_token"]) + else if(href_list["approve_antag_token"]) if(!check_rights(R_ADMIN)) return var/atom/movable/target = locate(href_list["approve_token"]) @@ -1769,7 +1769,7 @@ user_client.client_token_holder.approve_token() message_admins("[user_client]'s token has been approved, by [owner]") - else if(href_list["reject_token"]) + else if(href_list["reject_antag_token"]) if(!check_rights(R_ADMIN)) return var/atom/movable/target = locate(href_list["reject_token"]) diff --git a/monkestation/code/datums/meta_tokens.dm b/monkestation/code/datums/meta_tokens.dm index aa0d32cc6c6c..29ad1493723e 100644 --- a/monkestation/code/datums/meta_tokens.dm +++ b/monkestation/code/datums/meta_tokens.dm @@ -4,6 +4,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) var/datum/meta_token_holder/client_token_holder /datum/meta_token_holder + ///the client that owns this holder var/client/owner ///are they a donator? and do they have their free token? var/donator_token = FALSE @@ -18,7 +19,14 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) ///the antagonist we are currently waiting for a reply on whether we can use var/datum/antagonist/in_queue var/in_queued_tier + ///is the queued token a donor token var/queued_donor = FALSE + ///how many event tokens we currently have + var/event_tokens = 0 + ///the month we last used event tokens on + var/event_token_month = 0 + ///what token event do we currently have queued + var/datum/twitch_event/queued_token_event /datum/meta_token_holder/New(client/creator) . = ..() @@ -36,6 +44,8 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) total_low_threat_tokens = saved_tokens["low_threat"] total_medium_threat_tokens = saved_tokens["medium_threat"] total_high_threat_tokens = saved_tokens["high_threat"] + event_tokens = saved_tokens["event_tokens"] + event_token_month = saved_tokens["event_token_month"] total_antag_tokens = total_low_threat_tokens + total_medium_threat_tokens + total_high_threat_tokens @@ -44,6 +54,8 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) "low_threat" = total_low_threat_tokens, "medium_threat" = total_medium_threat_tokens, "high_threat" = total_high_threat_tokens, + "event_tokens" = event_tokens, + "event_token_month" = event_token_month, ) owner.prefs.save_preferences() @@ -87,8 +99,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) convert_tokens_to_list() - -/datum/meta_token_holder/proc/approve_token() +/datum/meta_token_holder/proc/approve_token(thing_to_approve) if(!in_queue) return to_chat(owner, "Your request to play as [in_queue] has been approved.") @@ -103,7 +114,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) in_queued_tier = null queued_donor = FALSE -/datum/meta_token_holder/proc/reject_token() +/datum/meta_token_holder/proc/reject_token(thing_to_reject) to_chat(owner, "Your request to play as [in_queue] has been denied.") in_queue = null in_queued_tier = null diff --git a/monkestation/code/modules/client/preferences.dm b/monkestation/code/modules/client/preferences.dm index 8086108e086f..a93b287440ce 100644 --- a/monkestation/code/modules/client/preferences.dm +++ b/monkestation/code/modules/client/preferences.dm @@ -21,6 +21,8 @@ "high_threat" = 0, "medium_threat" = 0, "low_threat" = 0, + "event_tokens" = 0, + "event_token_month" = 0, ) ///amount of metaconis you can earn per shift @@ -30,10 +32,3 @@ var/list/alt_job_titles = list() /// the month we used our last donator token on var/token_month = 0 - - ///how many event tokens we currently have - var/event_tokens = 0 - ///the month we last used event tokens on - var/event_token_month = 0 - ///what token event do we currently have queued - var/datum/twitch_event/queued_token_event From 41696e038d8f538f3ce27eb347331fe98d748eb5 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 16 Nov 2023 01:27:14 -0800 Subject: [PATCH 05/60] workstm --- code/__DEFINES/~monkestation/admin.dm | 4 +- code/modules/admin/admin_verbs.dm | 5 +- code/modules/admin/topic.dm | 36 ++++++++--- monkestation/code/datums/meta_tokens.dm | 60 ++++++++++++++++--- .../code/modules/admin/antag_tokens.dm | 3 +- .../code/modules/admin/event_tokens.dm | 16 ++--- .../code/modules/client/event_tokens.dm | 1 - monkestation/code/modules/client/verbs.dm | 53 +++++++--------- .../modules/code_redemption/code_redeemer.dm | 2 +- .../modules/twitch_bits/events/amongus.dm | 3 +- .../modules/twitch_bits/events/anime_ook.dm | 1 + .../twitch_bits/events/australia_mode.dm | 1 + .../code/modules/twitch_bits/events/buff.dm | 1 + .../modules/twitch_bits/events/chuckle_nut.dm | 1 + .../modules/twitch_bits/events/die_fate.dm | 2 + .../modules/twitch_bits/events/random_item.dm | 1 + .../code/modules/twitch_bits/events/rod.dm | 1 + .../code/modules/twitch_bits/events/skinny.dm | 1 + .../code/modules/twitch_bits/twitch_system.dm | 14 ++++- tgstation.dme | 1 - 20 files changed, 141 insertions(+), 66 deletions(-) delete mode 100644 monkestation/code/modules/client/event_tokens.dm diff --git a/code/__DEFINES/~monkestation/admin.dm b/code/__DEFINES/~monkestation/admin.dm index bf7b9207aa53..f705fdb26b2b 100644 --- a/code/__DEFINES/~monkestation/admin.dm +++ b/code/__DEFINES/~monkestation/admin.dm @@ -1,5 +1,5 @@ -#define ADMIN_APPROVE_TOKEN(user) "(Yes)" -#define ADMIN_REJECT_TOKEN(user) "(No)" +#define ADMIN_APPROVE_ANTAG_TOKEN(user) "(Yes)" +#define ADMIN_REJECT_ANTAG_TOKEN(user) "(No)" #define ADMIN_OPEN_REVIEW(id) "(Open Review)" #define ADMIN_APPROVE_TOKEN_EVENT(user) "(Yes)" #define ADMIN_REJECT_TOKEN_EVENT(user) "(No)" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index c01ab9e5b21d..dd3d514254e9 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -104,8 +104,9 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list( // Client procs /client/proc/admin_away, /client/proc/add_mob_ability, - /client/proc/adjust_players_antag_tokens, - /client/proc/adjust_players_metacoins, + /client/proc/adjust_players_antag_tokens, //monkestation edit + /client/proc/adjust_players_event_tokens, //monkestation edit + /client/proc/adjust_players_metacoins, //monkestation edit /client/proc/admin_change_sec_level, /client/proc/change_ocean, //monkestation addition /client/proc/cinematic, diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index c436d382d3a5..fc36a8e8a8ba 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1762,22 +1762,24 @@ else if(href_list["approve_antag_token"]) if(!check_rights(R_ADMIN)) return - var/atom/movable/target = locate(href_list["approve_token"]) + var/atom/movable/target = locate(href_list["approve_antag_token"]) if(!IS_CLIENT_OR_MOCK(target)) return var/client/user_client = target - user_client.client_token_holder.approve_token() - message_admins("[user_client]'s token has been approved, by [owner]") + user_client.client_token_holder.approve_antag_token() + message_admins("[user_client]'s token has been approved by [owner].") + log_admin("[user_client]'s token has been approved by [owner].") else if(href_list["reject_antag_token"]) if(!check_rights(R_ADMIN)) return - var/atom/movable/target = locate(href_list["reject_token"]) + var/atom/movable/target = locate(href_list["reject_antag_token"]) if(!IS_CLIENT_OR_MOCK(target)) return var/client/user_client = target - user_client.client_token_holder.reject_token() - message_admins("[user_client]'s token has been rejected, by [owner]") + user_client.client_token_holder.reject_antag_token() + message_admins("[user_client]'s token has been rejected by [owner].") + log_admin("[user_client]'s token has been rejected by [owner].") else if(href_list["open_music_review"]) if(!check_rights(R_ADMIN)) @@ -1788,5 +1790,25 @@ return cassette_review.ui_interact(usr) -// else if() + else if(href_list["approve_token_event"]) + if(!check_rights(R_ADMIN)) + return + var/atom/movable/target = locate(href_list["approve_token_event"]) + if(!IS_CLIENT_OR_MOCK(target)) + return + var/client/user_client = target + user_client.client_token_holder.approve_token_event() + message_admins("[user_client]'s token event has been approved by [owner].") + log_admin("[user_client]'s token event has been approved by [owner].") + + else if(href_list["reject_token_event"]) + if(!check_rights(R_ADMIN)) + return + var/atom/movable/target = locate(href_list["reject_token_event"]) + if(!IS_CLIENT_OR_MOCK(target)) + return + var/client/user_client = target + user_client.client_token_holder.reject_token_event() + message_admins("[user_client]'s token event has been rejected by [owner].") + log_admin("[user_client]'s token event has been rejected by [owner].") //monkestation edit end diff --git a/monkestation/code/datums/meta_tokens.dm b/monkestation/code/datums/meta_tokens.dm index 29ad1493723e..12031c8c2d3e 100644 --- a/monkestation/code/datums/meta_tokens.dm +++ b/monkestation/code/datums/meta_tokens.dm @@ -1,5 +1,15 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) +///assoc list of how many event tokens each role gets each month +GLOBAL_LIST_INIT(patreon_etoken_values, list( + NO_RANK = 0, + RANK_TANKS = 100, + ASSISTANT_RANK = 500, + COMMAND_RANK = 1000, + TRAITOR_RANK = 2500, + NUKIE_RANK = 5000, +)) + /client var/datum/meta_token_holder/client_token_holder @@ -69,7 +79,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) return FALSE return TRUE -/datum/meta_token_holder/proc/spend_token(tier, use_donor = FALSE) +/datum/meta_token_holder/proc/spend_antag_token(tier, use_donor = FALSE) if(use_donor) if(donator_token) donator_token = FALSE @@ -88,7 +98,8 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) convert_tokens_to_list() ///adjusts the users tokens, yes they can be in antag token debt -/datum/meta_token_holder/proc/adjust_tokens(tier, amount) +/datum/meta_token_holder/proc/adjust_antag_tokens(tier, amount) + var/list/old_token_values = list(HIGH_THREAT = total_high_threat_tokens, MEDIUM_THREAT = total_medium_threat_tokens, LOW_THREAT = total_low_threat_tokens) switch(tier) if(HIGH_THREAT) total_high_threat_tokens += amount @@ -97,25 +108,60 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) if(LOW_THREAT) total_low_threat_tokens += amount + log_admin("[key_name(owner)] had their antag tokens adjusted from high: [old_token_values[HIGH_THREAT]], medium: [old_token_values[MEDIUM_THREAT]], \ + low: [old_token_values[LOW_THREAT]], to, high: [total_high_threat_tokens], medium: [total_medium_threat_tokens], low: [total_low_threat_tokens]") convert_tokens_to_list() -/datum/meta_token_holder/proc/approve_token(thing_to_approve) +/datum/meta_token_holder/proc/approve_antag_token() if(!in_queue) return - to_chat(owner, "Your request to play as [in_queue] has been approved.") - spend_token(in_queued_tier, queued_donor) + to_chat(owner, "Your request to play as [in_queue] has been approved.") + spend_antag_token(in_queued_tier, queued_donor) if(!owner.mob.mind) owner.mob.mind_initialize() - in_queue.antag_token(owner.mob.mind, owner.mob) + in_queue.antag_token(owner.mob.mind, owner.mob) //might not be in queue qdel(in_queue) in_queue = null in_queued_tier = null queued_donor = FALSE -/datum/meta_token_holder/proc/reject_token(thing_to_reject) +/datum/meta_token_holder/proc/reject_antag_token() + if(!in_queue) + return + to_chat(owner, "Your request to play as [in_queue] has been denied.") in_queue = null in_queued_tier = null queued_donor = FALSE + +/datum/meta_token_holder/proc/adjust_event_tokens(amount) + check_event_tokens(owner) + var/old_value = event_tokens + event_tokens += amount + log_admin("[key_name(owner)] had their event tokens adjusted from [old_value] to, [event_tokens].") + convert_tokens_to_list() + +/datum/meta_token_holder/proc/check_event_tokens(client/checked_client) + var/month_number = text2num(time2text(world.time, "MM")) + if(event_token_month != month_number) + event_token_month = month_number + event_tokens = GLOB.patreon_etoken_values[checked_client.patreon.owned_rank] + convert_tokens_to_list() + +/datum/meta_token_holder/proc/approve_token_event() + if(!queued_token_event) + return + + to_chat(owner, "Your request to trigger [queued_token_event] has been approved.") + adjust_event_tokens(-queued_token_event.token_cost) + SStwitch.add_to_queue(initial(queued_token_event.id_tag)) + queued_token_event = null + +/datum/meta_token_holder/proc/reject_token_event() + if(!queued_token_event) + return + + to_chat(owner, "Your request to trigger [queued_token_event] has been denied.") + queued_token_event = null diff --git a/monkestation/code/modules/admin/antag_tokens.dm b/monkestation/code/modules/admin/antag_tokens.dm index def24b5fdea1..67754d61f5a4 100644 --- a/monkestation/code/modules/admin/antag_tokens.dm +++ b/monkestation/code/modules/admin/antag_tokens.dm @@ -16,4 +16,5 @@ if(!tier) return - chosen_client.client_token_holder.adjust_tokens(tier, adjustment_amount) + log_admin("[key_name(src)] adjusted the [tier] antag tokens of [key_name(chosen_client)] by [adjustment_amount].") + chosen_client.client_token_holder.adjust_antag_tokens(tier, adjustment_amount) diff --git a/monkestation/code/modules/admin/event_tokens.dm b/monkestation/code/modules/admin/event_tokens.dm index 1c633ebde0fd..8e89c4960cbd 100644 --- a/monkestation/code/modules/admin/event_tokens.dm +++ b/monkestation/code/modules/admin/event_tokens.dm @@ -1,17 +1,17 @@ -/client/proc/set_players_event_tokens() +/client/proc/adjust_players_event_tokens() set category = "Admin.Fun" -//due to the fact that these reset each month im just making this directly this this value instead of add or subtract - set name = "Set Event Tokens" - set desc = "Set how many event tokens someone has." + + set name = "Adjust Event Tokens" + set desc = "Adjust how many event tokens someone has." var/mob/chosen_player = tgui_input_list(src, "Choose a Player", "Player List", GLOB.player_list) if(!chosen_player) return var/client/chosen_client = chosen_player.client - var/adjustment_amount = tgui_input_number(src, "What should we set this users tokens to?", "Input Value", TRUE) - if(!adjustment_amount || !chosen_client || !chosen_client.patreon) + var/adjustment_amount = tgui_input_number(src, "How much should we adjust this users tokens by?", "Input Value", TRUE) + if(!adjustment_amount || !chosen_client) return - check_event_tokens(chosen_client) - chosen_client.prefs.event_tokens = adjustment_amount + log_admin("[key_name(src)] adjusted the event tokens of [key_name(chosen_client)] by [adjustment_amount].") + chosen_client.client_token_holder.adjust_event_tokens(adjustment_amount) diff --git a/monkestation/code/modules/client/event_tokens.dm b/monkestation/code/modules/client/event_tokens.dm deleted file mode 100644 index 8b137891791f..000000000000 --- a/monkestation/code/modules/client/event_tokens.dm +++ /dev/null @@ -1 +0,0 @@ - diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index a62bfebb884d..b6ec997e08d8 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -16,17 +16,6 @@ GLOBAL_LIST_INIT(low_threat_antags, list( /datum/antagonist/paradox_clone, )) -//PLACEHOLDER VALUES(1 to 1 cent to token conversion, also you get a free token if you dont pay yeah totally) -///assoc list of how many event tokens each role gets each month -GLOBAL_LIST_INIT(patreon_etoken_values, list( - NO_RANK = 0, - RANK_TANKS = 100, - ASSISTANT_RANK = 500, - COMMAND_RANK = 1000, - TRAITOR_RANK = 2500, - NUKIE_RANK = 5000, -)) - /client/verb/spend_antag_tokens() set category = "IC" set name = "Spend Antag Tokens" @@ -83,11 +72,12 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( client_token_holder.in_queue = new chosen_antagonist to_chat(src, "Your request has been sent to the admins.") - SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_admin("[span_prefix("ANTAG TOKEN:")] [key_name(src)] [ADMIN_APPROVE_TOKEN(src)] [ADMIN_REJECT_TOKEN(src)] | \ + SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_admin("[span_prefix("ANTAG TOKEN:")] [key_name(src)] \ + [ADMIN_APPROVE_ANTAG_TOKEN(src)] [ADMIN_REJECT_ANTAG_TOKEN(src)] | \ [src] has requested to use their antag token to be a [chosen_antagonist].")]") -/client/proc/trigger_token_event() - set category = "Ghost" +/client/verb/trigger_token_event() + set category = "IC" set name = "Trigger Token Event" set desc = "Opens a ui to spend event tokens on" @@ -96,28 +86,27 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( var/static/list/event_list if(!event_list) - event_list = subtypesof(/datum/twitch_event) - for(var/datum/twitch_event/event as anything in event_list) - if(!event.token_cost) - event_list -= event + event_list = list() + for(var/event as anything in GLOB.twitch_events_by_type) + var/datum/twitch_event/event_instance = GLOB.twitch_events_by_type[event] + if(!event_instance.token_cost) + continue + event_list += event_instance + + client_token_holder.check_event_tokens(src) - check_event_tokens(src) + var/datum/twitch_event/selected_event = tgui_input_list(src, "Event tokens: [client_token_holder.event_tokens]", "Choose an event to trigger", event_list) + if(!selected_event) + return - var/datum/twitch_event/selected_event = tgui_input_list(src, "Event tokens: [prefs.event_tokens]", "Choose an event to trigger", event_list) var/confirm = tgui_alert(src, "Are you sure you want to trigger [selected_event.event_name]? It will cost [selected_event.token_cost] event tokens.", "Trigger token event", \ list("Yes", "No")) if(confirm == "Yes") - if(prefs.event_tokens >= selected_event.token_cost) - SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "MESSAGE") + if(client_token_holder.event_tokens >= selected_event.token_cost) + client_token_holder.queued_token_event = selected_event + to_chat(src, "Your request has been sent.") + SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_admin("[span_prefix("TOKEN EVENT:")] [key_name(src)] \ + [ADMIN_APPROVE_TOKEN_EVENT(src)] [ADMIN_REJECT_TOKEN_EVENT(src)] | \ + [src] has requested use their event tokens to trigger [selected_event].")]") return to_chat(src, "You dont have enough tokens to trigger this event.") - -/proc/approve_token_event() - -/proc/reject_token_event() - -/proc/check_event_tokens(client/checked_client) - var/month_number = text2num(time2text(world.time, "MM")) - if(checked_client.prefs.event_token_month != month_number) - checked_client.prefs.event_token_month = month_number - checked_client.prefs.event_tokens = GLOB.patreon_etoken_values[checked_client.patreon.owned_rank] diff --git a/monkestation/code/modules/code_redemption/code_redeemer.dm b/monkestation/code/modules/code_redemption/code_redeemer.dm index 7e394286b0d4..208b1618cbfa 100644 --- a/monkestation/code/modules/code_redemption/code_redeemer.dm +++ b/monkestation/code/modules/code_redemption/code_redeemer.dm @@ -26,7 +26,7 @@ GLOBAL_LIST_INIT(redeemed_codes, list()) if(isnum(path)) usr.client.prefs.adjust_metacoins(usr.ckey, path, "Redeemed a Giveaway Code", donator_multipler = FALSE) else if(path == HIGH_THREAT || path == MEDIUM_THREAT || path == LOW_THREAT) - usr.client.client_token_holder.adjust_tokens(path, 1) + usr.client.client_token_holder.adjust_antag_tokens(path, 1) to_chat(usr, span_boldnotice("You have successfully redeemed a giveaway code for: [path] Antag Token.")) else var/pathedstring = text2path(path) diff --git a/monkestation/code/modules/twitch_bits/events/amongus.dm b/monkestation/code/modules/twitch_bits/events/amongus.dm index d0739aefbff1..871ea5095193 100644 --- a/monkestation/code/modules/twitch_bits/events/amongus.dm +++ b/monkestation/code/modules/twitch_bits/events/amongus.dm @@ -3,13 +3,14 @@ event_duration = 15 MINUTES event_flags = TWITCH_AFFECTS_ALL id_tag = "amongus-all15" + token_cost = 500 /datum/twitch_event/amongus/ook event_name = "Amongus Ook" event_duration = 30 MINUTES event_flags = TWITCH_AFFECTS_STREAMER id_tag = "amongus-ook10" - + token_cost = 500 /datum/twitch_event/amongus/run_event(name) . = ..() diff --git a/monkestation/code/modules/twitch_bits/events/anime_ook.dm b/monkestation/code/modules/twitch_bits/events/anime_ook.dm index 1237e91d18cb..70e9573dce98 100644 --- a/monkestation/code/modules/twitch_bits/events/anime_ook.dm +++ b/monkestation/code/modules/twitch_bits/events/anime_ook.dm @@ -3,6 +3,7 @@ event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER id_tag = "anime-ook" + token_cost = 100 /datum/twitch_event/anime_ook/run_event(name) . = ..() diff --git a/monkestation/code/modules/twitch_bits/events/australia_mode.dm b/monkestation/code/modules/twitch_bits/events/australia_mode.dm index 9204c81c2ae1..2bf42cc3eee2 100644 --- a/monkestation/code/modules/twitch_bits/events/australia_mode.dm +++ b/monkestation/code/modules/twitch_bits/events/australia_mode.dm @@ -3,6 +3,7 @@ event_duration = 15 MINUTES //effect is very minor so it lasts for a while event_flags = TWITCH_AFFECTS_ALL id_tag = "australia-mode" + token_cost = 500 /datum/twitch_event/australia_mode/run_event(name) . = ..() diff --git a/monkestation/code/modules/twitch_bits/events/buff.dm b/monkestation/code/modules/twitch_bits/events/buff.dm index 97c10978ad3d..fd92367a5aac 100644 --- a/monkestation/code/modules/twitch_bits/events/buff.dm +++ b/monkestation/code/modules/twitch_bits/events/buff.dm @@ -3,6 +3,7 @@ event_duration = 5 MINUTES event_flags = TWITCH_AFFECTS_ALL id_tag = "buff-5" + token_cost = 500 /datum/twitch_event/buff/run_event(name) . = ..() diff --git a/monkestation/code/modules/twitch_bits/events/chuckle_nut.dm b/monkestation/code/modules/twitch_bits/events/chuckle_nut.dm index 9608cf4e5a2f..d462f440400e 100644 --- a/monkestation/code/modules/twitch_bits/events/chuckle_nut.dm +++ b/monkestation/code/modules/twitch_bits/events/chuckle_nut.dm @@ -3,6 +3,7 @@ event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER id_tag = "chucklenuts-ook" + token_cost = 800 /datum/twitch_event/chucklenuts/random event_name = "Think Fast" diff --git a/monkestation/code/modules/twitch_bits/events/die_fate.dm b/monkestation/code/modules/twitch_bits/events/die_fate.dm index 9bb6dabfa845..30934772ec20 100644 --- a/monkestation/code/modules/twitch_bits/events/die_fate.dm +++ b/monkestation/code/modules/twitch_bits/events/die_fate.dm @@ -3,6 +3,7 @@ event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER id_tag = "ook-die-fate" + token_cost = 2500 /datum/twitch_event/free_wiz/run_event(name) . = ..() @@ -19,3 +20,4 @@ event_name = "Change Everyone's Fate" event_flags = TWITCH_AFFECTS_ALL id_tag = "everyone-die-fate" + token_cost = 5002 // :) diff --git a/monkestation/code/modules/twitch_bits/events/random_item.dm b/monkestation/code/modules/twitch_bits/events/random_item.dm index 0bcc67025703..de5de7c6d2a7 100644 --- a/monkestation/code/modules/twitch_bits/events/random_item.dm +++ b/monkestation/code/modules/twitch_bits/events/random_item.dm @@ -3,6 +3,7 @@ event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER id_tag = "give-ook-item" + token_cost = 1000 /datum/twitch_event/give_smsword/run_event(name) . = ..() diff --git a/monkestation/code/modules/twitch_bits/events/rod.dm b/monkestation/code/modules/twitch_bits/events/rod.dm index 7de830e3cbca..235988add906 100644 --- a/monkestation/code/modules/twitch_bits/events/rod.dm +++ b/monkestation/code/modules/twitch_bits/events/rod.dm @@ -4,6 +4,7 @@ event_flags = TWITCH_AFFECTS_STREAMER id_tag = "rod-ook" announce = FALSE //takes a while to reach its target so dont announce it + token_cost = 3000 /datum/twitch_event/clang/run_event(name) . = ..() diff --git a/monkestation/code/modules/twitch_bits/events/skinny.dm b/monkestation/code/modules/twitch_bits/events/skinny.dm index 1a670135e2da..b0d7a5865825 100644 --- a/monkestation/code/modules/twitch_bits/events/skinny.dm +++ b/monkestation/code/modules/twitch_bits/events/skinny.dm @@ -3,6 +3,7 @@ event_duration = 5 MINUTES event_flags = TWITCH_AFFECTS_ALL id_tag = "skinny-5" + token_cost = 500 /datum/twitch_event/skinny/run_event(name) . = ..() diff --git a/monkestation/code/modules/twitch_bits/twitch_system.dm b/monkestation/code/modules/twitch_bits/twitch_system.dm index 56f90afce6d1..465f89da211a 100644 --- a/monkestation/code/modules/twitch_bits/twitch_system.dm +++ b/monkestation/code/modules/twitch_bits/twitch_system.dm @@ -1,10 +1,13 @@ +///assoc list of instances of all twitch events keyed by their type +GLOBAL_LIST_EMPTY(twitch_events_by_type) + /datum/config_entry/string/twitch_key default = "changethisplease" SUBSYSTEM_DEF(twitch) name = "Twitch Events" wait = 0.5 SECONDS - flags = SS_KEEP_TIMING | SS_NO_INIT + flags = SS_KEEP_TIMING runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME priority = FIRE_PRIORITY_TWITCH init_order = INIT_ORDER_TWITCH @@ -19,6 +22,11 @@ SUBSYSTEM_DEF(twitch) var/last_event_execution = 0 var/last_executor +/datum/controller/subsystem/twitch/Initialize() + for(var/event as anything in subtypesof(/datum/twitch_event)) + GLOB.twitch_events_by_type[event] = new event + return SS_INIT_SUCCESS + /datum/controller/subsystem/twitch/stat_entry(msg) msg += "Running Events:[running_events.len]" return ..() @@ -44,7 +52,7 @@ SUBSYSTEM_DEF(twitch) for(var/datum/twitch_event/listed_events as anything in subtypesof(/datum/twitch_event)) if(incoming[3] != initial(listed_events.id_tag)) continue - chosen_one = new listed_events + chosen_one = GLOB.twitch_events_by_type[listed_events] if(!chosen_one) return @@ -76,7 +84,7 @@ SUBSYSTEM_DEF(twitch) for(var/datum/twitch_event/listed_events as anything in subtypesof(/datum/twitch_event)) if(listed_item != initial(listed_events.id_tag)) continue - chosen_one = new listed_events + chosen_one = GLOB.twitch_events_by_type[listed_events] if(!chosen_one) return chosen_one.run_event() diff --git a/tgstation.dme b/tgstation.dme index dcc757bda72c..bf23f2499a5b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5814,7 +5814,6 @@ #include "monkestation\code\modules\cassettes\machines\media\track.dm" #include "monkestation\code\modules\cassettes\machines\media\subsystem\media_track_manager.dm" #include "monkestation\code\modules\cassettes\walkman\_walkmen.dm" -#include "monkestation\code\modules\client\event_tokens.dm" #include "monkestation\code\modules\client\preference_savefile.dm" #include "monkestation\code\modules\client\preferences.dm" #include "monkestation\code\modules\client\verbs.dm" From 914ad1f33d6f561ad410cebe53db0f5c244cb50c Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 16 Nov 2023 17:35:08 -0800 Subject: [PATCH 06/60] defines and modular --- code/__DEFINES/twitch.dm | 3 --- code/__DEFINES/~monkestation/admin.dm | 6 ------ code/__DEFINES/~monkestation/twitch.dm | 18 ++++++++++++++++++ .../modules/cassettes/cassette_approval.dm | 3 +++ monkestation/code/modules/client/verbs.dm | 9 +++++++++ .../modules/twitch_bits/events/_base_event.dm | 2 +- .../code/modules/twitch_bits/events/amongus.dm | 4 ++-- .../modules/twitch_bits/events/anime_ook.dm | 2 +- .../twitch_bits/events/australia_mode.dm | 2 +- .../code/modules/twitch_bits/events/buff.dm | 2 +- .../modules/twitch_bits/events/chuckle_nut.dm | 5 +++-- .../modules/twitch_bits/events/die_fate.dm | 8 ++++---- .../modules/twitch_bits/events/random_item.dm | 8 +++++++- .../code/modules/twitch_bits/events/rod.dm | 4 ++-- .../code/modules/twitch_bits/events/skinny.dm | 2 +- tgstation.dme | 2 +- 16 files changed, 54 insertions(+), 26 deletions(-) delete mode 100644 code/__DEFINES/twitch.dm create mode 100644 code/__DEFINES/~monkestation/twitch.dm diff --git a/code/__DEFINES/twitch.dm b/code/__DEFINES/twitch.dm deleted file mode 100644 index 5d408fede4e9..000000000000 --- a/code/__DEFINES/twitch.dm +++ /dev/null @@ -1,3 +0,0 @@ -#define TWITCH_AFFECTS_STREAMER (1 << 0) -#define TWITCH_AFFECTS_ALL (1 << 1) -#define TWITCH_AFFECTS_RANDOM (1 << 2) diff --git a/code/__DEFINES/~monkestation/admin.dm b/code/__DEFINES/~monkestation/admin.dm index f705fdb26b2b..198511a23db1 100644 --- a/code/__DEFINES/~monkestation/admin.dm +++ b/code/__DEFINES/~monkestation/admin.dm @@ -1,9 +1,3 @@ -#define ADMIN_APPROVE_ANTAG_TOKEN(user) "(Yes)" -#define ADMIN_REJECT_ANTAG_TOKEN(user) "(No)" -#define ADMIN_OPEN_REVIEW(id) "(Open Review)" -#define ADMIN_APPROVE_TOKEN_EVENT(user) "(Yes)" -#define ADMIN_REJECT_TOKEN_EVENT(user) "(No)" - ///Sends all admins the chosen sound #define SEND_ADMINS_NOTFICATION_SOUND(sound) for(var/client/X in GLOB.admins){X << sound;} ///Sends a message in adminchat diff --git a/code/__DEFINES/~monkestation/twitch.dm b/code/__DEFINES/~monkestation/twitch.dm new file mode 100644 index 000000000000..ccf5c48238ca --- /dev/null +++ b/code/__DEFINES/~monkestation/twitch.dm @@ -0,0 +1,18 @@ +#define TWITCH_AFFECTS_STREAMER (1 << 0) +#define TWITCH_AFFECTS_ALL (1 << 1) +#define TWITCH_AFFECTS_RANDOM (1 << 2) + +// twitch event IDs +#define T_EVENT_AMONGUS_ALL_15 "amongus-all15" +#define T_EVENT_AMONGUS_OOK_10 "amongus-ook10" +#define T_EVENT_ANIME_OOK "anime-ook" +#define T_EVENT_AUSTRALIA_MODE "australia-mode" +#define T_EVENT_BUFF_5 "buff-5" +#define T_EVENT_CHUCKLENUTS_OOK "chucklenuts-ook" +#define T_EVENT_CHUCKLENUTS_RANDOM "chucklenuts-random" +#define T_EVENT_OOK_DIE_FATE "ook-die-fate" +#define T_EVENT_EVERYONE_DIE_FATE "everyone-die-fate" +#define T_EVENT_GIVE_OOK_ITEM "give-ook-item" +#define T_EVENT_GIVE_EVERYONE_ITEM "give-everyone-item" +#define T_EVENT_ROD_OOK "rod-ook" +#define T_EVENT_SKINNY_5 "skinny-5" diff --git a/monkestation/code/modules/cassettes/cassette_approval.dm b/monkestation/code/modules/cassettes/cassette_approval.dm index d658372c26c4..3ba2f63b7be8 100644 --- a/monkestation/code/modules/cassettes/cassette_approval.dm +++ b/monkestation/code/modules/cassettes/cassette_approval.dm @@ -1,5 +1,6 @@ GLOBAL_LIST_INIT(cassette_reviews, list()) +#define ADMIN_OPEN_REVIEW(id) "(Open Review)" /proc/submit_cassette_for_review(obj/item/device/cassette_tape/submitted, mob/user) if(!user.client) return @@ -131,3 +132,5 @@ GLOBAL_LIST_INIT(cassette_reviews, list()) /proc/fetch_review(id) return GLOB.cassette_reviews[id] + +#undef ADMIN_OPEN_REVIEW diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index b6ec997e08d8..d9f00c008753 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -16,6 +16,10 @@ GLOBAL_LIST_INIT(low_threat_antags, list( /datum/antagonist/paradox_clone, )) +#define ADMIN_APPROVE_ANTAG_TOKEN(user) "(Yes)" +#define ADMIN_REJECT_ANTAG_TOKEN(user) "(No)" +#define ADMIN_APPROVE_TOKEN_EVENT(user) "(Yes)" +#define ADMIN_REJECT_TOKEN_EVENT(user) "(No)" /client/verb/spend_antag_tokens() set category = "IC" set name = "Spend Antag Tokens" @@ -110,3 +114,8 @@ GLOBAL_LIST_INIT(low_threat_antags, list( [src] has requested use their event tokens to trigger [selected_event].")]") return to_chat(src, "You dont have enough tokens to trigger this event.") + +#undef ADMIN_APPROVE_ANTAG_TOKEN +#undef ADMIN_REJECT_ANTAG_TOKEN +#undef ADMIN_APPROVE_TOKEN_EVENT +#undef ADMIN_REJECT_TOKEN_EVENT diff --git a/monkestation/code/modules/twitch_bits/events/_base_event.dm b/monkestation/code/modules/twitch_bits/events/_base_event.dm index ead023a1c4f6..015ef7e3ee28 100644 --- a/monkestation/code/modules/twitch_bits/events/_base_event.dm +++ b/monkestation/code/modules/twitch_bits/events/_base_event.dm @@ -9,7 +9,7 @@ var/random_count = 0 ///list of targets var/list/targets = list() - ///the tag tied to this event, should make these be defines at some point + ///the tag tied to this event var/id_tag ///should we announce this event var/announce = TRUE diff --git a/monkestation/code/modules/twitch_bits/events/amongus.dm b/monkestation/code/modules/twitch_bits/events/amongus.dm index 871ea5095193..4a842ba7beaf 100644 --- a/monkestation/code/modules/twitch_bits/events/amongus.dm +++ b/monkestation/code/modules/twitch_bits/events/amongus.dm @@ -2,14 +2,14 @@ event_name = "Amongus Everyone" event_duration = 15 MINUTES event_flags = TWITCH_AFFECTS_ALL - id_tag = "amongus-all15" + id_tag = T_EVENT_AMONGUS_ALL_15 token_cost = 500 /datum/twitch_event/amongus/ook event_name = "Amongus Ook" event_duration = 30 MINUTES event_flags = TWITCH_AFFECTS_STREAMER - id_tag = "amongus-ook10" + id_tag = T_EVENT_AMONGUS_OOK_10 token_cost = 500 /datum/twitch_event/amongus/run_event(name) diff --git a/monkestation/code/modules/twitch_bits/events/anime_ook.dm b/monkestation/code/modules/twitch_bits/events/anime_ook.dm index 70e9573dce98..b7ccb229deec 100644 --- a/monkestation/code/modules/twitch_bits/events/anime_ook.dm +++ b/monkestation/code/modules/twitch_bits/events/anime_ook.dm @@ -2,7 +2,7 @@ event_name = "Anime Ook" event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER - id_tag = "anime-ook" + id_tag = T_EVENT_ANIME_OOK token_cost = 100 /datum/twitch_event/anime_ook/run_event(name) diff --git a/monkestation/code/modules/twitch_bits/events/australia_mode.dm b/monkestation/code/modules/twitch_bits/events/australia_mode.dm index 2bf42cc3eee2..50c4843b77f4 100644 --- a/monkestation/code/modules/twitch_bits/events/australia_mode.dm +++ b/monkestation/code/modules/twitch_bits/events/australia_mode.dm @@ -2,7 +2,7 @@ event_name = "Australia Mode" event_duration = 15 MINUTES //effect is very minor so it lasts for a while event_flags = TWITCH_AFFECTS_ALL - id_tag = "australia-mode" + id_tag = T_EVENT_AUSTRALIA_MODE token_cost = 500 /datum/twitch_event/australia_mode/run_event(name) diff --git a/monkestation/code/modules/twitch_bits/events/buff.dm b/monkestation/code/modules/twitch_bits/events/buff.dm index fd92367a5aac..46c6e361b64b 100644 --- a/monkestation/code/modules/twitch_bits/events/buff.dm +++ b/monkestation/code/modules/twitch_bits/events/buff.dm @@ -2,7 +2,7 @@ event_name = "Bodybuilder Mode" event_duration = 5 MINUTES event_flags = TWITCH_AFFECTS_ALL - id_tag = "buff-5" + id_tag = T_EVENT_BUFF_5 token_cost = 500 /datum/twitch_event/buff/run_event(name) diff --git a/monkestation/code/modules/twitch_bits/events/chuckle_nut.dm b/monkestation/code/modules/twitch_bits/events/chuckle_nut.dm index d462f440400e..4fad6aea1dde 100644 --- a/monkestation/code/modules/twitch_bits/events/chuckle_nut.dm +++ b/monkestation/code/modules/twitch_bits/events/chuckle_nut.dm @@ -2,14 +2,15 @@ event_name = "Think Fast Ook" event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER - id_tag = "chucklenuts-ook" + id_tag = T_EVENT_CHUCKLENUTS_OOK token_cost = 800 /datum/twitch_event/chucklenuts/random event_name = "Think Fast" event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_RANDOM - id_tag = "chucklenuts-random" + id_tag = T_EVENT_CHUCKLENUTS_RANDOM + token_cost = null /datum/twitch_event/chucklenuts/run_event(name) . = ..() diff --git a/monkestation/code/modules/twitch_bits/events/die_fate.dm b/monkestation/code/modules/twitch_bits/events/die_fate.dm index 30934772ec20..9487260add50 100644 --- a/monkestation/code/modules/twitch_bits/events/die_fate.dm +++ b/monkestation/code/modules/twitch_bits/events/die_fate.dm @@ -2,7 +2,7 @@ event_name = "Change Ook's Fate" event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER - id_tag = "ook-die-fate" + id_tag = T_EVENT_OOK_DIE_FATE token_cost = 2500 /datum/twitch_event/free_wiz/run_event(name) @@ -12,12 +12,12 @@ var/mob/living/future_wiz = target var/obj/item/dice/d20/fate/one_use/the_die = new(get_turf(future_wiz)) future_wiz.put_in_hands(the_die) - to_chat(future_wiz, span_warning("Something apears in your hand and- oh no you fumbled it. That can't be good.")) - the_die.diceroll(future_wiz) + to_chat(future_wiz, span_userdanger("Something apears in your hand and- oh no you fumbled it. That can't be good.")) + addtimer(CALLBACK(the_die, TYPE_PROC_REF(/obj/item/dice, diceroll), future_wiz), 0.5 SECONDS) //this is more of a joke, could maybe cost 100k bits or something /datum/twitch_event/free_wiz/everyone event_name = "Change Everyone's Fate" event_flags = TWITCH_AFFECTS_ALL - id_tag = "everyone-die-fate" + id_tag = T_EVENT_EVERYONE_DIE_FATE token_cost = 5002 // :) diff --git a/monkestation/code/modules/twitch_bits/events/random_item.dm b/monkestation/code/modules/twitch_bits/events/random_item.dm index de5de7c6d2a7..981a54c37a2b 100644 --- a/monkestation/code/modules/twitch_bits/events/random_item.dm +++ b/monkestation/code/modules/twitch_bits/events/random_item.dm @@ -2,7 +2,7 @@ event_name = "Give Ook Random Item" event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER - id_tag = "give-ook-item" + id_tag = T_EVENT_GIVE_OOK_ITEM token_cost = 1000 /datum/twitch_event/give_smsword/run_event(name) @@ -13,3 +13,9 @@ var/obj/item/gamer_item = pick(subtypesof(/obj/item)) gamer_item = new gamer_item() debug_uplink_reciever.put_in_hands(gamer_item) + +/datum/twitch_event/give_smsword/everyone + event_name = "Give Everyone Random Item" + event_flags = TWITCH_AFFECTS_ALL + id_tag = T_EVENT_GIVE_EVERYONE_ITEM + token_cost = null diff --git a/monkestation/code/modules/twitch_bits/events/rod.dm b/monkestation/code/modules/twitch_bits/events/rod.dm index 235988add906..b82c7d10eff1 100644 --- a/monkestation/code/modules/twitch_bits/events/rod.dm +++ b/monkestation/code/modules/twitch_bits/events/rod.dm @@ -2,9 +2,9 @@ event_name = "Immovable Rod Ook" event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER - id_tag = "rod-ook" + id_tag = T_EVENT_ROD_OOK announce = FALSE //takes a while to reach its target so dont announce it - token_cost = 3000 + token_cost = 3500 /datum/twitch_event/clang/run_event(name) . = ..() diff --git a/monkestation/code/modules/twitch_bits/events/skinny.dm b/monkestation/code/modules/twitch_bits/events/skinny.dm index b0d7a5865825..27dbdce76fe6 100644 --- a/monkestation/code/modules/twitch_bits/events/skinny.dm +++ b/monkestation/code/modules/twitch_bits/events/skinny.dm @@ -2,7 +2,7 @@ event_name = "Thinned Out Mode" event_duration = 5 MINUTES event_flags = TWITCH_AFFECTS_ALL - id_tag = "skinny-5" + id_tag = T_EVENT_SKINNY_5 token_cost = 500 /datum/twitch_event/skinny/run_event(name) diff --git a/tgstation.dme b/tgstation.dme index bf23f2499a5b..7a1d604c350f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -246,7 +246,6 @@ #include "code\__DEFINES\tram.dm" #include "code\__DEFINES\turbine_defines.dm" #include "code\__DEFINES\turfs.dm" -#include "code\__DEFINES\twitch.dm" #include "code\__DEFINES\typeids.dm" #include "code\__DEFINES\unit_tests.dm" #include "code\__DEFINES\uplink.dm" @@ -393,6 +392,7 @@ #include "code\__DEFINES\~monkestation\status_effects.dm" #include "code\__DEFINES\~monkestation\storytellers.dm" #include "code\__DEFINES\~monkestation\traits.dm" +#include "code\__DEFINES\~monkestation\twitch.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" From 62b27763c2b185e7a4035dc03deeb9f256ee54c9 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Sun, 19 Nov 2023 15:08:42 -0800 Subject: [PATCH 07/60] should commit --- .../__DEFINES/~monkestation/baton_upgrades.dm | 3 + .../antagonists/traitor/datum_traitor.dm | 5 + monkestation/code/datums/components/uplink.dm | 2 + .../game/objects/items/storage/uplink_kits.dm | 77 +++++++- .../contractor/datums/contractor_datum.dm | 25 +++ .../contractor/datums/contractor_hub.dm | 4 + .../contractor/datums/contractor_items.dm | 172 ++++++++++++++++++ .../contractor/datums/contractor_support.dm | 54 ++++++ .../contractor/datums/mind_datum.dm | 4 + .../antagonists/contractor/items/baton.dm | 85 +++++++++ .../antagonists/contractor/items/boxes.dm | 8 + .../antagonists/contractor/items/misc.dm | 14 ++ .../contractor/items/modsuit/modsuit.dm | 39 ++++ .../contractor/items/modsuit/modules.dm | 87 +++++++++ .../contractor/items/modsuit/theme.dm | 68 +++++++ .../antagonists/traitor/datum_traitor.dm | 3 + .../antagonists/traitor/traitor_objective.dm | 3 + .../antagonists/traitor/uplink_handler.dm | 1 + .../code/modules/paperwork/paper_premade.dm | 39 ++++ .../modules/uplink/uplink_items/bundle.dm | 6 + .../icons/mob/clothing/worn_modsuit.dmi | Bin 0 -> 1829 bytes .../clothing/modsuits/contractor_modsuit.dmi | Bin 0 -> 1230 bytes .../icons/obj/items/baton_upgrades.dmi | Bin 0 -> 354 bytes monkestation/icons/obj/items/fulton.dmi | Bin 0 -> 1352 bytes .../icons/obj/items/modsuit_modules.dmi | Bin 0 -> 382 bytes tgstation.dme | 18 ++ 26 files changed, 714 insertions(+), 3 deletions(-) create mode 100644 code/__DEFINES/~monkestation/baton_upgrades.dm create mode 100644 monkestation/code/datums/components/uplink.dm create mode 100644 monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm create mode 100644 monkestation/code/modules/antagonists/contractor/datums/contractor_hub.dm create mode 100644 monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm create mode 100644 monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm create mode 100644 monkestation/code/modules/antagonists/contractor/datums/mind_datum.dm create mode 100644 monkestation/code/modules/antagonists/contractor/items/baton.dm create mode 100644 monkestation/code/modules/antagonists/contractor/items/boxes.dm create mode 100644 monkestation/code/modules/antagonists/contractor/items/misc.dm create mode 100644 monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm create mode 100644 monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm create mode 100644 monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm create mode 100644 monkestation/code/modules/antagonists/traitor/datum_traitor.dm create mode 100644 monkestation/code/modules/antagonists/traitor/traitor_objective.dm create mode 100644 monkestation/code/modules/antagonists/traitor/uplink_handler.dm create mode 100644 monkestation/code/modules/paperwork/paper_premade.dm create mode 100644 monkestation/code/modules/uplink/uplink_items/bundle.dm create mode 100644 monkestation/icons/mob/clothing/worn_modsuit.dmi create mode 100644 monkestation/icons/obj/clothing/modsuits/contractor_modsuit.dmi create mode 100644 monkestation/icons/obj/items/baton_upgrades.dmi create mode 100644 monkestation/icons/obj/items/fulton.dmi create mode 100644 monkestation/icons/obj/items/modsuit_modules.dmi diff --git a/code/__DEFINES/~monkestation/baton_upgrades.dm b/code/__DEFINES/~monkestation/baton_upgrades.dm new file mode 100644 index 000000000000..dcfbfbabe45c --- /dev/null +++ b/code/__DEFINES/~monkestation/baton_upgrades.dm @@ -0,0 +1,3 @@ +#define BATON_ALL_UPGRADE (1<<0) +#define BATON_CUFF_UPGRADE (1<<1) +#define BATON_MUTE_UPGRADE (1<<2) diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index b150289f2e4d..4e40ab3efc60 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -350,6 +350,11 @@ var/special_role_text = lowertext(name) +//monkestation edit start + if(contractor_hub) + result += contractor_round_end() +//monkestation edit end + if(traitor_won) result += span_greentext("The [special_role_text] was successful!") else diff --git a/monkestation/code/datums/components/uplink.dm b/monkestation/code/datums/components/uplink.dm new file mode 100644 index 000000000000..5477d2b5b667 --- /dev/null +++ b/monkestation/code/datums/components/uplink.dm @@ -0,0 +1,2 @@ +//this file contains extra stuff we have for uplink components like contractors + diff --git a/monkestation/code/game/objects/items/storage/uplink_kits.dm b/monkestation/code/game/objects/items/storage/uplink_kits.dm index aabb3983d513..48b654a2341f 100644 --- a/monkestation/code/game/objects/items/storage/uplink_kits.dm +++ b/monkestation/code/game/objects/items/storage/uplink_kits.dm @@ -1,11 +1,12 @@ +#define KIT_ITEM_CATEGORY_SUPPORT "support" +#define KIT_ITEM_CATEGORY_WEAPONS "weapons" +#define KIT_ITEM_CATEGORY_MISC "misc" /obj/item/storage/box/syndie_kit/imp_hard_spear name = "hardlight spear implant box" /obj/item/storage/box/syndie_kit/imp_hard_spear/PopulateContents() new /obj/item/implanter/hard_spear(src) - - /obj/item/storage/box/syndimaid name = "Syndicate maid outfit" desc = "A box containing a 'tactical' and 'practical' maid outfit." @@ -17,4 +18,74 @@ /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" + desc = "Supplied to Syndicate contractors, providing their specialised space suit and chameleon uniform." + icon_state = "syndiebox" + illustration = "writing_syndie" + +/obj/item/storage/box/syndie_kit/contractor_loadout/PopulateContents() + new /obj/item/mod/control/pre_equipped/contractor(src) + new /obj/item/storage/box/syndie_kit/chameleon(src) + new /obj/item/storage/fancy/cigarettes/cigpack_syndicate(src) + new /obj/item/card/id/advanced/chameleon(src) + new /obj/item/lighter(src) + 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/melee/baton/telescopic/contractor_baton(src) + + // You get one item from each sub list + var/static/list/item_list = list( + KIT_ITEM_CATEGORY_SUPPORT = list( + /obj/item/pen/sleepy, + /obj/item/storage/medkit/tactical, + /obj/item/pen/sleepy, + /obj/item/gun/syringe/syndicate, + /obj/item/storage/backpack/duffelbag/syndie/x4, + /obj/item/clothing/shoes/chameleon/noslip, + /obj/item/clothing/glasses/thermal/syndi, + /obj/item/storage/box/syndie_kit/imp_freedom, + /obj/item/reagent_containers/hypospray/medipen/stimulants, + /obj/item/card/emag/doorjack, + ), + + KIT_ITEM_CATEGORY_WEAPONS = list( + /obj/item/melee/powerfist, //over value but its never used + /obj/item/storage/box/syndie_kit/origami_bundle, + /obj/item/clothing/gloves/krav_maga/combatglovesplus, + /obj/item/gun/ballistic/automatic/c20r/toy/unrestricted/riot, + /obj/item/storage/box/syndie_kit/throwing_weapons, + /obj/item/storage/box/syndie_kit/chemical, //technically over value but it cant be used on its own + /obj/item/autosurgeon/syndicate/anti_stun, //way over value but you dont get a real weapon, might have to remove this one + ), + + KIT_ITEM_CATEGORY_MISC = list( + /obj/item/syndie_glue, + /obj/item/slimepotion/slime/sentience/nuclear, + /obj/item/storage/box/syndie_kit/imp_uplink, + /obj/item/grenade/clusterbuster/soap, + /obj/item/flashlight/emp, + /obj/item/encryptionkey/syndicate, + /obj/item/multitool/ai_detect, + /obj/item/storage/toolbox/syndicate, + /obj/item/card/emag, + /obj/item/ai_module/syndicate, + ) + ) + + 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]) + generate_items_inside(items_to_give, src) + + // Paper guide + new /obj/item/paper/contractor_guide(src) + +#undef KIT_ITEM_CATEGORY_SUPPORT +#undef KIT_ITEM_CATEGORY_WEAPONS +#undef KIT_ITEM_CATEGORY_MISC diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm new file mode 100644 index 000000000000..68acfd7ee2e8 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm @@ -0,0 +1,25 @@ +// Proc detailing contract kit buys/completed contracts/additional info +/datum/antagonist/traitor/proc/contractor_round_end() + var/result = "" + var/total_spent_rep = 0 + + var/contractor_item_icons = "" // Icons of purchases + 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) + contractor_item_icons += "\[ [contractor_purchase.name] - [contractor_purchase.cost] Rep

[contractor_purchase.desc]
\]
" + + 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)) + 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) + result += "
(used [total_spent_rep] Rep) " + result += contractor_item_icons + result += "
" + + return result diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_hub.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_hub.dm new file mode 100644 index 000000000000..6ac1f55aa061 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_hub.dm @@ -0,0 +1,4 @@ +/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 new file mode 100644 index 000000000000..33f6de3a1933 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm @@ -0,0 +1,172 @@ +/datum/contractor_item + var/name // Name of item + var/desc // description of item + var/item // item path, no item path means the purchase needs it's own handle_purchase() + var/item_icon = "broadcast-tower" // fontawesome icon to use inside the hub - https://fontawesome.com/icons/ + 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/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, \ + it can't pinpoint to the same accuracy as the traditional models. Becomes permanently locked to the user that first activates it." + item = /obj/item/pinpointer/crew/contractor + item_icon = "search-location" + stock = 2 + cost = 1 + +/datum/contractor_item/fulton_extraction_kit + name = "Fulton Extraction Kit" + desc = "For getting your target across the station to those difficult dropoffs. Place the beacon somewhere secure, and link the pack. \ + 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 + cost = 1 + +/datum/contractor_item/contractor_partner + name = "Reinforcements" + desc = "Upon purchase we'll contact available units in the area. Should there be an agent free, we'll send them down to assist you immediately. \ + If no units are free, we give a full refund." + item_icon = "user-friends" + stock = 1 + cost = 2 + var/datum/mind/partner_mind = null + +/datum/contractor_item/contractor_partner/handle_purchase(datum/contractor_hub/hub, mob/living/user) + . = ..() + if(!.) + return + + to_chat(user, span_notice("The uplink vibrates quietly, connecting to nearby agents...")) + + var/list/mob/dead/observer/candidates = poll_ghost_candidates("Do you want to play as the Contractor Support Unit for [user.real_name]?", ROLE_TRAITOR, FALSE, 100, \ + POLL_IGNORE_CONTRACTOR_SUPPORT) + + if(LAZYLEN(candidates)) + var/mob/dead/observer/candidate = pick(candidates) + spawn_contractor_partner(user, candidate.key) + else + to_chat(user, span_notice("No available agents at this time, please try again later.")) + + // refund and add the limit back. + stock += 1 + hub.contract_rep += cost + hub.purchased_items -= src + +/datum/contractor_item/contractor_partner/proc/spawn_contractor_partner(mob/living/user, key) + var/mob/living/carbon/human/partner = new() + var/datum/outfit/contractor_partner/partner_outfit = new() + + partner_outfit.equip(partner) + + var/obj/structure/closet/supplypod/arrival_pod = new(null, STYLE_SYNDICATE) + arrival_pod.explosionSize = list(0,0,0,0) + arrival_pod.bluespace = TRUE + + var/turf/free_location = find_obstruction_free_location(2, user) + + // We really want to send them - if we can't find a nice location just land it on top of them. + if(!free_location) + free_location = get_turf(user) + + partner.forceMove(arrival_pod) + partner.ckey = key + + /// We give a reference to the mind that'll be the support unit + partner_mind = partner.mind + partner_mind.make_contractor_support() + + to_chat(partner_mind.current, "\n[span_alertwarning("[user.real_name] is your superior. Follow any, and all orders given by them. You're here to support their mission only.")]") + to_chat(partner_mind.current, "[span_alertwarning("Should they perish, or be otherwise unavailable, \ + you're to assist other active agents in this mission area to the best of your ability.")]\n\n") + + new /obj/effect/pod_landingzone(free_location, arrival_pod) + +//this can be bought for TC, might have to be removed/replaced +/datum/contractor_item/blackout + name = "Blackout" + desc = "Request Syndicate Command to distrupt the station's powernet. Disables power across the station for a short duration." + item_icon = "bolt" + stock = 2 + cost = 3 + +/datum/contractor_item/blackout/handle_purchase(datum/contractor_hub/hub) + . = ..() + + 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) + +// Subtract cost, and spawn if it's an item. +/datum/contractor_item/proc/handle_purchase(datum/contractor_hub/hub, mob/living/user) + + if (hub.contract_rep >= cost) + hub.contract_rep -= cost + else + return FALSE + + if (stock >= 1) + stock -= 1 + else if (stock == 0) + return FALSE + + hub.purchased_items.Add(src) + + user.playsound_local(user, 'sound/machines/uplinkpurchase.ogg', 100) + + if (item && ispath(item)) + var/atom/item_to_create = new item(get_turf(user)) + + if(user.put_in_hands(item_to_create)) + to_chat(user, span_notice("Your purchase materializes into your hands!")) + else + to_chat(user, span_notice("Your purchase materializes onto the floor.")) + + 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, \ + and the baton will retract whenever dropped." + item = /obj/item/mod/module/baton_holster + item_icon = "arrow-up-from-arc" //I cannot find anything better, replace if you find something more fitting + stock = 1 + cost = 1 + +/datum/contractor_item/baton_upgrade_cuff + name = "Baton Cuff Upgrade" + desc = "Using technology reverse-engineered from some alien batons we had lying around, you can now cuff people using your baton with the secondary attack. \ + Due to technical limitations, only cable cuffs and zipties work, and they need to be loaded into the baton manually." + item = /obj/item/baton_upgrade/cuff + item_icon = "handcuff" + stock = 1 + cost = 1 + +/datum/contractor_item/baton_upgrade_mute + name = "Baton Mute Upgrade" + desc = "A relatively new advancement in completely proprietary baton technology, this baton upgrade will mute anyone hit for ten seconds, maximizing at twenty seconds." + item = /obj/item/baton_upgrade/mute + item_icon = "comment-slash" + stock = 1 + cost = 2 diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm new file mode 100644 index 000000000000..412839847373 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm @@ -0,0 +1,54 @@ +/datum/antagonist/traitor/contractor_support + name = "Contractor Support Unit" + antag_moodlet = /datum/mood_event/focused + + 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 + +/// Team for storing both the contractor and their support unit - only really for the HUD and admin logging. +/datum/team/contractor_team + show_roundend_report = FALSE + +/datum/antagonist/traitor/contractor_support/forge_traitor_objectives() + var/datum/objective/generic_objective = new + + generic_objective.name = "Follow the Contractor's Orders" + generic_objective.explanation_text = "Follow your orders. Assist agents in this mission area." + + generic_objective.completed = TRUE + + objectives += generic_objective + +/datum/outfit/contractor_partner + name = "Contractor Support Unit" + + uniform = /obj/item/clothing/under/chameleon + suit = /obj/item/clothing/suit/chameleon + back = /obj/item/storage/backpack + belt = /obj/item/modular_computer/pda/chameleon + mask = /obj/item/clothing/mask/cigarette/syndicate + shoes = /obj/item/clothing/shoes/chameleon/noslip + ears = /obj/item/radio/headset/chameleon + id = /obj/item/card/id/advanced/chameleon + r_hand = /obj/item/storage/toolbox/syndicate + id_trim = /datum/id_trim/chameleon/operative + + backpack_contents = list( + /obj/item/storage/box/survival, + /obj/item/implanter/uplink, + /obj/item/clothing/mask/chameleon, + /obj/item/storage/fancy/cigarettes/cigpack_syndicate, + /obj/item/lighter + ) + +/datum/outfit/contractor_partner/post_equip(mob/living/carbon/human/partner, visualsOnly) + . = ..() + var/obj/item/clothing/mask/cigarette/syndicate/cig = partner.get_item_by_slot(ITEM_SLOT_MASK) + + // pre-light their cig + cig.light() diff --git a/monkestation/code/modules/antagonists/contractor/datums/mind_datum.dm b/monkestation/code/modules/antagonists/contractor/datums/mind_datum.dm new file mode 100644 index 000000000000..91cb9a5ac69b --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/datums/mind_datum.dm @@ -0,0 +1,4 @@ +/datum/mind/proc/make_contractor_support() + if(has_antag_datum(/datum/antagonist/traitor/contractor_support)) + return + add_antag_datum(/datum/antagonist/traitor/contractor_support) diff --git a/monkestation/code/modules/antagonists/contractor/items/baton.dm b/monkestation/code/modules/antagonists/contractor/items/baton.dm new file mode 100644 index 000000000000..b23f5dc2b5d9 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/items/baton.dm @@ -0,0 +1,85 @@ +#define CUFF_MAXIMUM 3 +#define MUTE_CYCLES 5 + +/obj/item/melee/baton/telescopic/contractor_baton + /// Ref to the baton holster, should the baton have one. + var/obj/item/mod/module/baton_holster/holster + /// Bitflags for what upgrades the baton has + var/upgrade_flags + +/obj/item/melee/baton/telescopic/contractor_baton/dropped(mob/user, silent) + . = ..() + if(!holster) + return + holster.undeploy(user) + +/obj/item/melee/baton/telescopic/contractor_baton/attack_secondary(mob/living/victim, mob/living/user, params) + if(!(upgrade_flags & BATON_CUFF_UPGRADE) || !active) + return + for(var/obj/item/restraints/handcuffs/cuff in src.contents) + cuff.attack(victim, user) + break + +/obj/item/melee/baton/telescopic/contractor_baton/attackby(obj/item/attacking_item, mob/user, params) + . = ..() + if(istype(attacking_item, /obj/item/baton_upgrade)) + var/obj/item/baton_upgrade/upgrade = attacking_item + if(!(upgrade_flags & upgrade.upgrade_flag)) + upgrade_flags |= upgrade.upgrade_flag + upgrade.desc_update(src) + attacking_item.forceMove(src) + balloon_alert(user, "[attacking_item] attached") + if(!(upgrade_flags & BATON_CUFF_UPGRADE) && !(upgrade_flags & BATON_ALL_UPGRADE)) + return + if(!istype(attacking_item, /obj/item/restraints/handcuffs/cable)) + return + var/cuffcount = 0 + for(var/obj/item/restraints/handcuffs/cuff in src.contents) + cuffcount++ + if(cuffcount >= CUFF_MAXIMUM) + balloon_alert(user, "baton at maximum cuffs") + return + attacking_item.forceMove(src) + balloon_alert(user, "[attacking_item] inserted") + +/obj/item/melee/baton/telescopic/contractor_baton/wrench_act(mob/living/user, obj/item/tool) + . = ..() + for(var/obj/item/baton_upgrade/upgrade in src.contents) + upgrade.forceMove(get_turf(src)) + upgrade_flags &= ~upgrade.upgrade_flag + tool.play_tool_sound(src) + desc = initial(desc) + +/obj/item/melee/baton/telescopic/contractor_baton/additional_effects_non_cyborg(mob/living/carbon/target, mob/living/user) + . = ..() + if(!((upgrade_flags & BATON_MUTE_UPGRADE) && !(upgrade_flags & BATON_ALL_UPGRADE))|| !istype(target)) + return + target.adjust_silence_up_to(10 SECONDS, 20 SECONDS) + +/obj/item/melee/baton/telescopic/contractor_baton/upgraded + upgrade_flags = BATON_ALL_UPGRADE + desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets. This one seems to be fully upgraded with unremovable parts." + +/obj/item/baton_upgrade + icon = 'monkestation/icons/obj/items/baton_upgrades.dmi' + var/upgrade_flag + +/obj/item/baton_upgrade/proc/desc_update(obj/item/melee/baton/telescopic/contractor_baton/batong) + if(!batong.upgrade_flags) + desc += "

[span_boldnotice("[batong] has the following upgrades attached:")]" + desc += "
[span_notice("[src].")]" + +/obj/item/baton_upgrade/cuff + name = "handcuff baton upgrade" + desc = "Allows the user to apply restraints to a target via baton, requires to be loaded with up to three prior." + icon_state = "cuff_upgrade" + upgrade_flag = BATON_CUFF_UPGRADE + +/obj/item/baton_upgrade/mute + name = "mute baton upgrade" + desc = "Use of the baton on a target will mute them for a short period." + icon_state = "mute_upgrade" + upgrade_flag = BATON_MUTE_UPGRADE + +#undef CUFF_MAXIMUM +#undef MUTE_CYCLES diff --git a/monkestation/code/modules/antagonists/contractor/items/boxes.dm b/monkestation/code/modules/antagonists/contractor/items/boxes.dm new file mode 100644 index 000000000000..4f15be95e2fb --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/items/boxes.dm @@ -0,0 +1,8 @@ +/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/contractor(src) + new /obj/item/fulton_core(src) diff --git a/monkestation/code/modules/antagonists/contractor/items/misc.dm b/monkestation/code/modules/antagonists/contractor/items/misc.dm new file mode 100644 index 000000000000..12f4db60ecf3 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/items/misc.dm @@ -0,0 +1,14 @@ +/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 = 15 + has_owner = TRUE + ignore_suit_sensor_level = TRUE + +/obj/item/extraction_pack/contractor + name = "black fulton extraction pack" + desc = "A modified fulton pack that can be used indoors thanks to Bluespace technology. Favored by Syndicate Contractors." + icon = 'monkestation/icons/obj/items/fulton.dmi' + can_use_indoors = TRUE diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm new file mode 100644 index 000000000000..31418e6c32c6 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm @@ -0,0 +1,39 @@ +/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' + theme = /datum/mod_theme/contractor + applied_cell = /obj/item/stock_parts/cell/hyper + applied_modules = list( + /obj/item/mod/module/storage/syndicate, + /obj/item/mod/module/tether, + /obj/item/mod/module/flashlight, + /obj/item/mod/module/dna_lock, + /obj/item/mod/module/holster, + ) + +/obj/item/mod/control/pre_equipped/contractor/upgraded + applied_cell = /obj/item/stock_parts/cell/bluespace + applied_modules = list( + /obj/item/mod/module/storage/syndicate, + /obj/item/mod/module/jetpack, + /obj/item/mod/module/dna_lock, + /obj/item/mod/module/holster, + /obj/item/mod/module/baton_holster/preloaded, + ) + +// 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' + +/obj/item/clothing/suit/mod/contractor + worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi' + icon = 'monkestation/icons/obj/clothing/modsuits/contractor_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' + +/obj/item/clothing/shoes/mod/contractor + worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi' + icon = 'monkestation/icons/obj/clothing/modsuits/contractor_modsuit.dmi' diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm new file mode 100644 index 000000000000..45fe4d1f1894 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm @@ -0,0 +1,87 @@ +/obj/item/mod/module/baton_holster + name = "MOD baton holster module" + desc = "A module installed into the chest of a MODSuit, this allows you \ + to retrieve an inserted baton from the suit at will. Insert a baton \ + by using the module with the baton in hand. \ + Remove an inserted baton by using a wrench on the module while it is removed from the suit." + icon_state = "holster" + icon = 'monkestation/icons/obj/items/modsuit_modules.dmi' + complexity = 3 + incompatible_modules = list(/obj/item/mod/module/baton_holster) + module_type = MODULE_USABLE + /// Ref to the baton + var/obj/item/melee/baton/telescopic/contractor_baton/stored_batong + /// If the baton is out or not + var/deployed = FALSE + +// doesn't give a shit if it's deployed or not +/obj/item/mod/module/baton_holster/on_select() + on_use() + SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED, src) + +/obj/item/mod/module/baton_holster/wrench_act(mob/living/user, obj/item/tool) + . = ..() + if(!stored_batong) + return + balloon_alert(user, "[stored_batong] removed") + stored_batong.forceMove(get_turf(src)) + stored_batong.holster = null + stored_batong = null + tool.play_tool_sound(src) + +/obj/item/mod/module/baton_holster/Destroy() + if(stored_batong) + stored_batong.forceMove(get_turf(src)) + stored_batong.holster = null + stored_batong = null + . = ..() + +/obj/item/mod/module/baton_holster/on_use() + var/obj/item/held_item = mod.wearer.get_active_held_item() + if(istype(held_item, /obj/item/melee/baton/telescopic/contractor_baton) && !stored_batong) + balloon_alert(mod.wearer, "[held_item] inserted") + held_item.forceMove(src) + stored_batong = held_item + stored_batong.holster = src + return + + if(!deployed) + deploy(mod.wearer) + else + undeploy(mod.wearer) + +/obj/item/mod/module/baton_holster/proc/deploy(mob/living/user) + if(!(stored_batong in src)) + return + if(!user.put_in_hands(stored_batong)) + to_chat(user, span_warning("You need a free hand to hold [stored_batong]!")) + return + deployed = TRUE + balloon_alert(user, "[stored_batong] deployed") + +/obj/item/mod/module/baton_holster/proc/undeploy(mob/living/user) + if(QDELETED(stored_batong)) + return + stored_batong.forceMove(src) + deployed = FALSE + balloon_alert(user, "[stored_batong] retracted") + +/obj/item/mod/module/baton_holster/preloaded + +/obj/item/mod/module/baton_holster/preloaded/Initialize(mapload) + . = ..() + stored_batong = new/obj/item/melee/baton/telescopic/contractor_baton/upgraded(src) + stored_batong.holster = src +//making this slow you down this will most likely not get used, might rework this +/obj/item/mod/module/armor_booster/contractor // Much flatter distribution because contractor suit gets a shitton of armor already + armor_mod = /datum/armor/mod_module_armor_booster_contractor + speed_added = -0.3 + desc = "An embedded set of armor plates, allowing the suit's already extremely high protection \ + to be increased further. However, the plating, while deployed, will slow down the user \ + and make the suit unable to vacuum seal so this extra armor provides zero ability for extravehicular activity while deployed." + +/datum/armor/mod_module_armor_booster_contractor + melee = 20 + bullet = 20 + laser = 20 + energy = 20 diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm new file mode 100644 index 000000000000..fb71e85bbb56 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm @@ -0,0 +1,68 @@ +/datum/mod_theme/contractor + name = "contractor" + desc = "A top-tier MODSuit developed with cooperation of Cybersun Industries and the Gorlex Marauders, a favorite of Syndicate Contractors." + extended_desc = "A rare depart from the Syndicate's usual color scheme, the Contractor MODsuit is produced and manufactured \ + for specialty contractors. The build is a streamlined layering consisting of shaped Plastitanium, \ + and composite ceramic, while the under suit is lined with a lightweight Kevlar and durathread hybrid weave \ + to provide ample protection to the user where the plating doesn't, with an illegal onboard electric powered \ + ablative shield module to provide resistance against conventional energy firearms. \ + In addition, it has an in-built chameleon system, allowing you to disguise the suit while undeployed. \ + A small tag hangs off of it reading; 'Property of the Gorlex Marauders, with assistance from Cybersun Industries. \ + All rights reserved, tampering with suit will void warranty." + default_skin = "contractor" + armor_type = /datum/armor/mod_contractor_armor + atom_flags = PREVENT_CONTENTS_EXPLOSION_1 + resistance_flags = FIRE_PROOF | ACID_PROOF + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + siemens_coefficient = 0 + slowdown_inactive = 1 + slowdown_active = 0.5 + ui_theme = "syndicate" + inbuilt_modules = list(/obj/item/mod/module/armor_booster/contractor, /obj/item/mod/module/chameleon) + allowed_suit_storage = list( + /obj/item/flashlight, + /obj/item/tank/internals, + /obj/item/ammo_box, + /obj/item/ammo_casing, + /obj/item/restraints/handcuffs, + /obj/item/assembly/flash, + /obj/item/melee/baton, + /obj/item/melee/energy/sword, + /obj/item/shield/energy, + /obj/item/gun/ballistic, + /obj/item/gun/energy, + ) + skins = list( + "contractor" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/armor/mod_contractor_armor + melee = 40 + bullet = 50 + laser = 30 + energy = 40 + bomb = 30 + bio = 40 + fire = 80 + acid = 85 diff --git a/monkestation/code/modules/antagonists/traitor/datum_traitor.dm b/monkestation/code/modules/antagonists/traitor/datum_traitor.dm new file mode 100644 index 000000000000..902fa6ef7c73 --- /dev/null +++ b/monkestation/code/modules/antagonists/traitor/datum_traitor.dm @@ -0,0 +1,3 @@ +/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/traitor_objective.dm b/monkestation/code/modules/antagonists/traitor/traitor_objective.dm new file mode 100644 index 000000000000..f728ec22b2ff --- /dev/null +++ b/monkestation/code/modules/antagonists/traitor/traitor_objective.dm @@ -0,0 +1,3 @@ +/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 diff --git a/monkestation/code/modules/antagonists/traitor/uplink_handler.dm b/monkestation/code/modules/antagonists/traitor/uplink_handler.dm new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/monkestation/code/modules/antagonists/traitor/uplink_handler.dm @@ -0,0 +1 @@ + diff --git a/monkestation/code/modules/paperwork/paper_premade.dm b/monkestation/code/modules/paperwork/paper_premade.dm new file mode 100644 index 000000000000..7ac48dd6302b --- /dev/null +++ b/monkestation/code/modules/paperwork/paper_premade.dm @@ -0,0 +1,39 @@ +/obj/item/paper/contractor_guide + name = "Contractor Guide" + +/obj/item/paper/contractor_guide/Initialize(mapload) + default_raw_text = {"

Welcome agent, congratulations on your new position as contractor. On top of your already assigned objectives, + this kit will provide you contracts to take on for TC payments.

+

Provided within, we give your specialist contractor space suit. It's even more compact, being able to fit into a pocket, and faster than the + Syndicate space suit available to you on the uplink. We also provide your chameleon jumpsuit and mask, both of which can be changed + to any form you need for the moment. The cigarettes are a special blend - it'll heal your injuries slowly overtime.

+

Your standard issue contractor baton hits harder than the ones you might be used to, and likely be your go to weapon for kidnapping your + targets. The three additional items have been randomly selected from what we had available. We hope they're useful to you for your mission.

+

The contractor hub, available at the top right of the uplink, will provide you unique items and abilities. These are bought using Contractor Rep, + with two Rep being provided each time you complete a contract.

+

Using the tablet

+
    +
  1. Open the Syndicate Contract Uplink program.
  2. +
  3. Here, you can accept a contract, and redeem your TC payments from completed contracts.
  4. +
  5. The payment number shown in brackets is the bonus you'll receive when bringing your target alive. You receive the + other number regardless of if they were alive or dead.
  6. +
  7. Contracts are completed by bringing the target to designated dropoff, calling for extraction, and putting them + inside the pod.
  8. +
+

Be careful when accepting a contract. While you'll be able to see the location of the dropoff point, cancelling will make it + unavailable to take on again.

+

The tablet can also be recharged at any cell charger.

+

Extracting

+
    +
  1. Make sure both yourself and your target are at the dropoff.
  2. +
  3. Call the extraction, and stand back from the drop point.
  4. +
  5. If it fails, make sure your target is inside, and there's a free space for the pod to land.
  6. +
  7. Grab your target, and drag them into the pod.
  8. +
+

Ransoms

+

We need your target for our own reasons, but we ransom them back to your mission area once their use is served. They will return back + from where you sent them off from in several minutes time. Don't worry, we give you a cut of what we get paid. We pay this into whatever + ID card you have equipped, on top of the TC payment we give.

+

Good luck agent. You can burn this document with the supplied lighter.

"} + + return ..() diff --git a/monkestation/code/modules/uplink/uplink_items/bundle.dm b/monkestation/code/modules/uplink/uplink_items/bundle.dm new file mode 100644 index 000000000000..7687174e936e --- /dev/null +++ b/monkestation/code/modules/uplink/uplink_items/bundle.dm @@ -0,0 +1,6 @@ +/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 + cost = 20 diff --git a/monkestation/icons/mob/clothing/worn_modsuit.dmi b/monkestation/icons/mob/clothing/worn_modsuit.dmi new file mode 100644 index 0000000000000000000000000000000000000000..5bb12b10c05eed0fb2704ef1da23401bed1c9829 GIT binary patch literal 1829 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 literal 0 HcmV?d00001 diff --git a/monkestation/icons/obj/items/fulton.dmi b/monkestation/icons/obj/items/fulton.dmi new file mode 100644 index 0000000000000000000000000000000000000000..424c0e82e4f5b07619c26269a08437d38052fa83 GIT binary patch literal 1352 zcmV-O1-JT%P)V=-0C=1w$FT~7Fc1ddIrkJlx|dqJW|4?w&{vS4S96rAB!~L=9o)XJMALSD zfa^USoU&{yEZ&bNnNwzsu&7^TBFhr>PS&6di-IprVN%)FaSzkCATvwKu&Bs)7|a1Y@xs{3AkVp3Z@Vr z43wCHBnEwuCm_CwF~lcI2qoA=p)mm?5~(jn68w2+;!mQ25lA7SRS1efqon+lEiN>L z+7{YvFMGSY_s;lG_R9XW-4damWV3h9oH^&aXXc#Q6|JqUOr>a38vXwO;C|SJwSyzd z8E68eqAlbTj|HICU#eLC3=GDgH~>KE+hf#Rk1Nkh&(qe^T`!t>%KbZ~wiX02`7P+X3kXmW>x=KOzCQ_oD4&iNo{OtOC-w2?cwT-1NKWW(QW-eEbBo}s zBhH}%z_t;kK}aUCPqu+e1Is3L_IyD;Cw&IY&M3GvL`g9S0m&p z|GVqa0G!{sMQDB>Vn!Jv;77Pz$SWPlu5RS@zea;cJBW5(E6CqNm0@#tlx4kso?cds z8i=8VN>M^!|8|ky8#jpB1}7@~yz;037VO$4hJogH52|GzKXc8Q#B7_NWSj-tw}~=f zR?9akSgdU`?#YAW`4WX*M*H`@l`g9|5P0C5`ZwRn+jy!L&sQxceqe5R$(W64T!1|d zb;`2s1YmD2)&r+!2N6QxFY;g}QYfV`&A1)bXSja({bIuHat-X++fsS>#x83RBhO_*_q3!f_;tk$}kKzu3t^u)@Z*F$q1Gm9N^f|A8Ef3A#Q7I zT)$d341;}*^#ygp41ngt2b66~)~s62@iXm|+`njmylB4-jb7N)qf!z&ts&c_RBG+#^x{_(raC(#c(Xf%0*S2yLy@Q`o_IY6aF;In}OjwCMy^HTk~FzCnIS3lRba#>Sb0g zs$%$#IZ<3k@?J(}GDW1nhZ)mDqY7!^5&~P~n!A*ZQp&N7^!Lyg8z>kcCj*Upo5YYg zNM*T>rfF!Jh7bZIWam@Bs9p%iwz6Dz{1gH(=4G_Ip-xQ;gt*_6l%^p>k=sHOZqj{9 zDN7|Rx0EO#DFj8a_+Y`o#|2136zV7~lLD88kFP-nKnrDZ4oU z0004WQchCV=-0C=2JR&a84_w-Y6@%7{?OD!tS z%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+(=$pSoZ^zil2jm5DI-6pxFoemiHkEOv#1y- zV#vjrR+N~V3SlcNxca$(4F&*xLmLbo9NH}a004qXL_t(IjqQ*@4#OY}1Y<7=!J(%A ze{JmuAwfcW>Zu*UX@|wIEI$h|-sa4})d=7 cHP64m3mt?Cb5oEwy8r+H07*qoM6N<$f*d-QQ2+n{ literal 0 HcmV?d00001 diff --git a/tgstation.dme b/tgstation.dme index d3bc1729f965..204d3780ff05 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -373,6 +373,7 @@ #include "code\__DEFINES\~monkestation\access.dm" #include "code\__DEFINES\~monkestation\ai.dm" #include "code\__DEFINES\~monkestation\antagonists.dm" +#include "code\__DEFINES\~monkestation\baton_upgrades.dm" #include "code\__DEFINES\~monkestation\clock_cult.dm" #include "code\__DEFINES\~monkestation\colors.dm" #include "code\__DEFINES\~monkestation\combat.dm" @@ -5487,6 +5488,7 @@ #include "monkestation\code\datums\components\multi_hit.dm" #include "monkestation\code\datums\components\throw_bounce.dm" #include "monkestation\code\datums\components\turf_healing.dm" +#include "monkestation\code\datums\components\uplink.dm" #include "monkestation\code\datums\diseases\advance\symptoms\clockwork.dm" #include "monkestation\code\datums\keybinding\carbon.dm" #include "monkestation\code\datums\keybinding\living.dm" @@ -5667,6 +5669,17 @@ #include "monkestation\code\modules\antagonists\clock_cult\structures\traps\senders\delay.dm" #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" +#include "monkestation\code\modules\antagonists\contractor\items\baton.dm" +#include "monkestation\code\modules\antagonists\contractor\items\boxes.dm" +#include "monkestation\code\modules\antagonists\contractor\items\misc.dm" +#include "monkestation\code\modules\antagonists\contractor\items\modsuit\modsuit.dm" +#include "monkestation\code\modules\antagonists\contractor\items\modsuit\modules.dm" +#include "monkestation\code\modules\antagonists\contractor\items\modsuit\theme.dm" #include "monkestation\code\modules\antagonists\florida_man\__outfits.dm" #include "monkestation\code\modules\antagonists\florida_man\_defines.dm" #include "monkestation\code\modules\antagonists\florida_man\_florida_man.dm" @@ -5689,6 +5702,9 @@ #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\tide_bug_department.dm" #include "monkestation\code\modules\antagonists\traitor\objectives\final_objective\become_wizard.dm" #include "monkestation\code\modules\antagonists\uplink_items\bundles.dm" @@ -6132,6 +6148,7 @@ #include "monkestation\code\modules\outdoors\code\datum\particle_weathers\weather_types\snow.dm" #include "monkestation\code\modules\outdoors\code\screen_alerts\alert.dm" #include "monkestation\code\modules\outdoors\code\sunlight\sunlight_object.dm" +#include "monkestation\code\modules\paperwork\paper_premade.dm" #include "monkestation\code\modules\pissing\bladder.dm" #include "monkestation\code\modules\pissing\emote.dm" #include "monkestation\code\modules\pissing\piss_effect.dm" @@ -6360,6 +6377,7 @@ #include "monkestation\code\modules\twitch_bits\events\rod.dm" #include "monkestation\code\modules\twitch_bits\events\skinny.dm" #include "monkestation\code\modules\uplink\uplink_items\badass.dm" +#include "monkestation\code\modules\uplink\uplink_items\bundle.dm" #include "monkestation\code\modules\uplink\uplink_items\job.dm" #include "monkestation\code\modules\uplink\uplink_items\species.dm" #include "monkestation\code\modules\vehicles\monkey_ball.dm" From 153a25ca2f11d9eed100aa9d5f2136fb1200d7dc Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:42:35 -0800 Subject: [PATCH 08/60] Update topic.dm --- code/modules/admin/topic.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index fc36a8e8a8ba..5f6deb22b56c 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1767,7 +1767,6 @@ return var/client/user_client = target user_client.client_token_holder.approve_antag_token() - message_admins("[user_client]'s token has been approved by [owner].") log_admin("[user_client]'s token has been approved by [owner].") else if(href_list["reject_antag_token"]) @@ -1778,7 +1777,6 @@ return var/client/user_client = target user_client.client_token_holder.reject_antag_token() - message_admins("[user_client]'s token has been rejected by [owner].") log_admin("[user_client]'s token has been rejected by [owner].") else if(href_list["open_music_review"]) From 58d73b092e6a4ebbc90f9f309f6402aea8eeff47 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:43:37 -0800 Subject: [PATCH 09/60] Update topic.dm --- code/modules/admin/topic.dm | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 5f6deb22b56c..f5c15035d43c 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1796,7 +1796,6 @@ return var/client/user_client = target user_client.client_token_holder.approve_token_event() - message_admins("[user_client]'s token event has been approved by [owner].") log_admin("[user_client]'s token event has been approved by [owner].") else if(href_list["reject_token_event"]) @@ -1807,6 +1806,5 @@ return var/client/user_client = target user_client.client_token_holder.reject_token_event() - message_admins("[user_client]'s token event has been rejected by [owner].") log_admin("[user_client]'s token event has been rejected by [owner].") //monkestation edit end 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 10/60] 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 && ( + )) || (
Date: Wed, 22 Nov 2023 21:20:46 -0800 Subject: [PATCH 11/60] see this is why you check things --- monkestation/code/modules/antagonists/traitor/uplink_handler.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/modules/antagonists/traitor/uplink_handler.dm b/monkestation/code/modules/antagonists/traitor/uplink_handler.dm index 98f9657b6213..4ab0aa7d4aac 100644 --- a/monkestation/code/modules/antagonists/traitor/uplink_handler.dm +++ b/monkestation/code/modules/antagonists/traitor/uplink_handler.dm @@ -2,7 +2,7 @@ /// 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 + var/contractor_rep = 0 ///list of our contractor market items var/list/contractor_market_items = list() ///list of purchased contractor items From 4e0b75679e759b5943e92e28533e701860848b42 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:19:06 -0800 Subject: [PATCH 12/60] m --- code/__DEFINES/role_preferences.dm | 6 +++++- tgui/packages/tgui/interfaces/Uplink/ObjectiveMenu.tsx | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index af75661790d2..64a4ccdc0772 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -16,7 +16,7 @@ #define ROLE_OPERATIVE "Operative" #define ROLE_TRAITOR "Traitor" #define ROLE_WIZARD "Wizard" -#define ROLE_CLOCK_CULTIST "Clock Cultist" +#define ROLE_CLOCK_CULTIST "Clock Cultist" //monkestation edit // Midround roles #define ROLE_ABDUCTOR "Abductor" @@ -39,6 +39,7 @@ #define ROLE_SPACE_DRAGON "Space Dragon" #define ROLE_SPIDER "Spider" #define ROLE_WIZARD_MIDROUND "Wizard (Midround)" +#define ROLE_DRIFTING_CONTRACTOR "Drifting Contractor" //monkestation edit // Latejoin roles #define ROLE_HERETIC_SMUGGLER "Heretic Smuggler" @@ -148,8 +149,11 @@ GLOBAL_LIST_INIT(special_roles, list( ROLE_SPACE_DRAGON = 0, ROLE_SPIDER = 0, ROLE_WIZARD_MIDROUND = 14, +//monkestation edit start + ROLE_DRIFTING_CONTRACTOR = 0, ROLE_VAMPIRICACCIDENT = 0, ROLE_MONSTERHUNTER = 0, +//monkestation edit end // Latejoin ROLE_HERETIC_SMUGGLER = 0, diff --git a/tgui/packages/tgui/interfaces/Uplink/ObjectiveMenu.tsx b/tgui/packages/tgui/interfaces/Uplink/ObjectiveMenu.tsx index ecc1b439e691..91977ee14e1d 100644 --- a/tgui/packages/tgui/interfaces/Uplink/ObjectiveMenu.tsx +++ b/tgui/packages/tgui/interfaces/Uplink/ObjectiveMenu.tsx @@ -461,7 +461,7 @@ export const ObjectiveElement = (props: ObjectiveElementProps, context) => { width="100%" textAlign="center"> {telecrystalReward} TC, - {!!contractorRep ? ' ' + contractorRep + ' REP,' : ''} + {contractorRep ? ' ' + contractorRep + ' REP,' : ''} {calculateProgression(progressionReward)} Threat Level {Math.abs(progressionDiff) > 10 && ( From 74b4a7a3c59a6394a4c2eb73592bfb554e331b55 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 23 Nov 2023 03:02:40 -0800 Subject: [PATCH 13/60] actually does the zonespace one --- .../__DEFINES/~monkestation/baton_upgrades.dm | 3 - code/game/objects/items/melee/baton.dm | 7 +- code/modules/admin/antag_panel.dm | 1 + .../client/preferences/middleware/antags.dm | 1 + .../projectiles/guns/special/meat_hook.dm | 2 +- icons/effects/beam.dmi | Bin 130345 -> 130491 bytes icons/obj/card.dmi | Bin 15839 -> 16660 bytes icons/obj/lavaland/artefacts.dmi | Bin 41730 -> 40807 bytes .../game/objects/items/storage/uplink_kits.dm | 2 +- .../contractor/datums/contractor_datum.dm | 59 ++++++++ .../contractor/datums/contractor_items.dm | 113 ++++++++++----- .../antagonists/contractor/datums/outfit.dm | 44 ++++++ .../antagonists/contractor/items/baton.dm | 133 ++++++++++++++---- .../contractor/items/modsuit/modsuit.dm | 26 +++- .../contractor/items/modsuit/modules.dm | 113 +++++++-------- .../traitor/objectives/kidnapping.dm | 16 ++- .../events/ghost_role/drifting_contractor.dm | 44 ++++++ monkestation/code/modules/mod/mod_control.dm | 0 .../projectiles/guns/special/meat_hook.dm | 26 ++++ monkestation/icons/obj/guns/magic.dmi | Bin 0 -> 346 bytes tgstation.dme | 1 - .../antagonists/driftingcontractor.ts | 16 +++ 22 files changed, 468 insertions(+), 139 deletions(-) delete mode 100644 code/__DEFINES/~monkestation/baton_upgrades.dm create mode 100644 monkestation/code/modules/antagonists/contractor/datums/outfit.dm create mode 100644 monkestation/code/modules/events/ghost_role/drifting_contractor.dm create mode 100644 monkestation/code/modules/mod/mod_control.dm create mode 100644 monkestation/code/modules/projectiles/guns/special/meat_hook.dm create mode 100644 monkestation/icons/obj/guns/magic.dmi create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/antagonists/antagonists/driftingcontractor.ts diff --git a/code/__DEFINES/~monkestation/baton_upgrades.dm b/code/__DEFINES/~monkestation/baton_upgrades.dm deleted file mode 100644 index dcfbfbabe45c..000000000000 --- a/code/__DEFINES/~monkestation/baton_upgrades.dm +++ /dev/null @@ -1,3 +0,0 @@ -#define BATON_ALL_UPGRADE (1<<0) -#define BATON_CUFF_UPGRADE (1<<1) -#define BATON_MUTE_UPGRADE (1<<2) diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index cbffeac6c620..b47e3c720f31 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -363,7 +363,8 @@ playsound(src, on_sound, 50, TRUE) return COMPONENT_NO_DEFAULT_MESSAGE -/obj/item/melee/baton/telescopic/contractor_baton +//monkestation removal start +/*/obj/item/melee/baton/telescopic/contractor_baton name = "contractor baton" desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets." icon = 'icons/obj/weapons/baton.dmi' @@ -391,8 +392,8 @@ /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 + target.set_stutter_if_lower(40 SECONDS)*/ +//monkestation removal end /obj/item/melee/baton/security name = "stun baton" diff --git a/code/modules/admin/antag_panel.dm b/code/modules/admin/antag_panel.dm index 2aad9a7cbcf7..04fb8ef88566 100644 --- a/code/modules/admin/antag_panel.dm +++ b/code/modules/admin/antag_panel.dm @@ -112,6 +112,7 @@ GLOBAL_VAR(antag_prototypes) GLOB.antag_prototypes[cat_id] = list(A) else GLOB.antag_prototypes[cat_id] += A + sortTim(GLOB.antag_prototypes, GLOBAL_PROC_REF(cmp_text_asc)) //monkestation edit sortTim(GLOB.antag_prototypes, GLOBAL_PROC_REF(cmp_text_asc),associative=TRUE) var/list/sections = list() diff --git a/code/modules/client/preferences/middleware/antags.dm b/code/modules/client/preferences/middleware/antags.dm index e13167ba7347..2d8282174266 100644 --- a/code/modules/client/preferences/middleware/antags.dm +++ b/code/modules/client/preferences/middleware/antags.dm @@ -120,6 +120,7 @@ ROLE_FUGITIVE = /datum/antagonist/fugitive, ROLE_LONE_OPERATIVE = /datum/antagonist/nukeop/lone, ROLE_SENTIENCE = /datum/antagonist/sentient_creature, + ROLE_DRIFTING_CONTRACTOR = /datum/antagonist/contractor, //monkestation edit ) var/list/antagonists = non_ruleset_antagonists.Copy() diff --git a/code/modules/projectiles/guns/special/meat_hook.dm b/code/modules/projectiles/guns/special/meat_hook.dm index ac9e5361999e..ca654c0cf8ff 100644 --- a/code/modules/projectiles/guns/special/meat_hook.dm +++ b/code/modules/projectiles/guns/special/meat_hook.dm @@ -46,7 +46,7 @@ /obj/projectile/hook/fire(setAngle) if(firer) - chain = firer.Beam(src, icon_state = "chain", emissive = FALSE) + chain = firer.Beam(src, icon_state = chain_iconstate, emissive = FALSE) //monkestation edit: replaced "chain" with chain_iconstate ..() //TODO: root the firer until the chain returns diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index c7d3d8951e2ef48c476afec70c03413053c68e3e..aebbebecf5a7e2f68ccea29a0ff51544a04136e0 100644 GIT binary patch delta 10423 zcmYj%1ymdF6D{r#+}+*Xf|dfsr8vQ%xDXk}o@V=ibcB?q^%`fZqLxp300Uk;cLc;3K+}jX-e4bsn#SmVUg`h}2N5IKd*| zm=A{G@TY=14!16xZX?=fx}WF=)XH>{3=`}MX;}PdYIUNo>WNxT)*AU1b=b6%+$P

Wx{_qK$7^)61<5}G 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 F{|Ao4_~`%u delta 10275 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 diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index 7f171fa8d275b6d300858a86345eb6fddcaf0912..2ca77df90c25d1767aff12f71b016c00b90b87e9 100644 GIT binary patch literal 16660 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 DX>H+d literal 15839 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 pWUIeE1(YY^^ZyNnZn4gp1ANF~Hk>6#%#x{;KQ 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 literal 41730 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 vq_eGGK~FsgnS= contracts_needed //only given to contractors so we can assume any completed objectives are contracts + +/datum/job/drifting_contractor + title = ROLE_DRIFTING_CONTRACTOR diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm index 6dc8adcdddac..b574b250da8e 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm @@ -1,16 +1,47 @@ /datum/contractor_item - var/name // Name of item - var/desc // description of item - var/item // item path, no item path means the purchase needs it's own handle_purchase() - var/item_icon = "broadcast-tower" // fontawesome icon to use inside the hub - https://fontawesome.com/icons/ - 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. + /// Name of the item datum + var/name + /// Description of the item datum + var/desc + /// Item path to spawn, no item path means you need to override `handle_purchase()` + var/item + /// fontawesome icon to use inside the hub - https://fontawesome.com/icons/ + var/item_icon = "broadcast-tower" + /// Any number above 0 for how many times it can be bought in a round for a single traitor. -1 is unlimited. + var/stock = -1 + /// Cost of the item in contract rep. + var/cost + +/// Subtract cost, and spawn if it's an item. +/datum/contractor_item/proc/handle_purchase(datum/contractor_hub/hub, mob/living/user) + if(hub.contract_rep >= cost) + hub.contract_rep -= cost + else + return FALSE + + if(limited >= 1) + limited -= 1 + else + return FALSE + + hub.purchased_items.Add(src) + + user.playsound_local(user, 'sound/machines/uplinkpurchase.ogg', 100) + + if(item) + var/atom/item_to_create = new item(get_turf(user)) + if(user.put_in_hands(item_to_create)) + to_chat(user, span_notice("Your purchase materializes into your hands!")) + else + to_chat(user, span_notice("Your purchase materializes onto the floor.")) + return item_to_create + return TRUE /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 + stock = 3 cost = 0 /datum/contractor_item/contract_reroll/handle_purchase(datum/uplink_handler/handler, mob/living/user) @@ -104,7 +135,7 @@ desc = "Request Syndicate Command to distrupt the station's powernet. Disables power across the station for a short duration." item_icon = "bolt" stock = 2 - cost = 3 + cost = 2 /datum/contractor_item/blackout/handle_purchase(datum/uplink_handler/handler) . = ..() @@ -116,39 +147,27 @@ 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) -// 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) - stock -= 1 - else if(stock == 0) - return FALSE - - handler.purchased_contractor_items.Add(src) - - user.playsound_local(user, 'sound/machines/uplinkpurchase.ogg', 100) +/datum/contractor_item/comms_blackout + name = "Comms Outage" + desc = "Request Syndicate Command to disable station Telecommunications. Disables telecommunications across the station for a medium duration." + item_icon = "phone-slash" + limited = 2 + cost = 2 - if (item && ispath(item)) - var/atom/item_to_create = new item(get_turf(user)) +/datum/contractor_item/comms_blackout/handle_purchase(datum/contractor_hub/hub) + . = ..() + if(!.) + return - if(user.put_in_hands(item_to_create)) - to_chat(user, span_notice("Your purchase materializes into your hands!")) - else - to_chat(user, span_notice("Your purchase materializes onto the floor.")) + var/datum/round_event_control/event = locate(/datum/round_event_control/communications_blackout) in SSevents.control + event.runEvent() - return item_to_create - return TRUE - -/datum/contractor_item/baton_holster +/datum/contractor_item/mod_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, \ and the baton will retract whenever dropped." item = /obj/item/mod/module/baton_holster - item_icon = "arrow-up-from-arc" //I cannot find anything better, replace if you find something more fitting + item_icon = "wrench" //I cannot find anything better, replace if you find something more fitting stock = 1 cost = 1 @@ -157,7 +176,7 @@ desc = "Using technology reverse-engineered from some alien batons we had lying around, you can now cuff people using your baton with the secondary attack. \ Due to technical limitations, only cable cuffs and zipties work, and they need to be loaded into the baton manually." item = /obj/item/baton_upgrade/cuff - item_icon = "handcuff" + item_icon = "bacon" //ditto stock = 1 cost = 1 @@ -168,3 +187,27 @@ item_icon = "comment-slash" stock = 1 cost = 2 + +/datum/contractor_item/baton_upgrade_focus + name = "Baton Focus Upgrade" + desc = "When applied to a baton, it will exhaust the target even more, should they be the target of your current contract." + item = /obj/item/baton_upgrade/focus + item_icon = "eye" + stock = 1 + cost = 2 + +/datum/contractor_item/mod_magnetic_suit + name = "Magnetic Deployment Module" + desc = "A module that utilizes magnets to largely reduce the time needed to deploy and retract your MODsuit." + item = /obj/item/mod/module/springlock/contractor + item_icon = "magnet" + stock = 1 + cost = 2 + +/datum/contractor_item/mod_scorpion_hook + name = "SCORPION Hook Module" + desc = "A module that allows you to launch a hardlight hook from your MODsuit, pulling a target into range of your baton." + item = /obj/item/mod/module/scorpion_hook + item_icon = "arrow-left" //replace if fontawesome gets an actual hook icon + stock = 1 + cost = 3 diff --git a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm new file mode 100644 index 000000000000..175f20da6358 --- /dev/null +++ b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm @@ -0,0 +1,44 @@ +/datum/outfit/contractor + name = "Syndicate Contractor - Full Kit" + + glasses = /obj/item/clothing/glasses/night + mask = /obj/item/clothing/mask/gas/syndicate + back = /obj/item/mod/control/pre_equipped/contractor/upgraded + r_pocket = /obj/item/tank/internals/emergency_oxygen/engi + internals_slot = ITEM_SLOT_RPOCKET + belt = /obj/item/storage/belt/military + + uniform = /obj/item/clothing/under/syndicate/coldres + shoes = /obj/item/clothing/shoes/combat/swat + gloves = /obj/item/clothing/gloves/combat + ears = /obj/item/radio/headset/syndicate/alt + l_pocket = /obj/item/modular_computer/tablet/syndicate_contract_uplink + id = /obj/item/card/id/advanced/chameleon + backpack_contents = list( + /obj/item/storage/box/survival/syndie, + /obj/item/storage/box/syndie_kit/contract_kit, + /obj/item/knife/combat/survival, + /obj/item/pinpointer/crew/contractor + ) + + implants = list( + /obj/item/implant/uplink/precharged, + /obj/item/implant/explosive, + ) + + id_trim = /datum/id_trim/chameleon/contractor + +/datum/outfit/contractor_preview + name = "Syndicate Contractor (Preview only)" + + back = /obj/item/mod/control/pre_equipped/syndicate_empty/contractor + uniform = /obj/item/clothing/under/syndicate + glasses = /obj/item/clothing/glasses/night + +/datum/outfit/contractor/fully_upgraded + name = "Syndicate Contractor - Fully Upgraded" + back = /obj/item/mod/control/pre_equipped/contractor/upgraded/adminbus + +/datum/id_trim/chameleon/contractor + assignment = "Syndicate Contractor" + trim_state = "trim_contractor" diff --git a/monkestation/code/modules/antagonists/contractor/items/baton.dm b/monkestation/code/modules/antagonists/contractor/items/baton.dm index b23f5dc2b5d9..76e6db8a2633 100644 --- a/monkestation/code/modules/antagonists/contractor/items/baton.dm +++ b/monkestation/code/modules/antagonists/contractor/items/baton.dm @@ -1,12 +1,64 @@ #define CUFF_MAXIMUM 3 #define MUTE_CYCLES 5 +#define MUTE_MAX_MOD 2 +#define BONUS_STAMINA_DAM 25 +#define BONUS_STUTTER 10 SECONDS +#define BATON_CUFF_UPGRADE (1<<0) +#define BATON_MUTE_UPGRADE (1<<1) +#define BATON_FOCUS_UPGRADE (1<<2) /obj/item/melee/baton/telescopic/contractor_baton + name = "contractor baton" + desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets." + icon = 'icons/obj/weapons/baton.dmi' + icon_state = "contractor_baton" + worn_icon_state = "contractor_baton" + lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' + righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi' + slot_flags = ITEM_SLOT_BELT + w_class = WEIGHT_CLASS_SMALL + item_flags = NONE + force = 5 + cooldown = 2.5 SECONDS + force_say_chance = 80 //very high force say chance because it's funny + stamina_damage = 170 + clumsy_knockdown_time = 24 SECONDS + affect_cyborg = TRUE + on_stun_sound = 'sound/effects/contractorbatonhit.ogg' + + on_inhand_icon_state = "contractor_baton_on" + on_sound = 'sound/weapons/contractorbatonextend.ogg' + active_force = 16 + /// Ref to the baton holster, should the baton have one. var/obj/item/mod/module/baton_holster/holster /// Bitflags for what upgrades the baton has var/upgrade_flags +/obj/item/melee/baton/telescopic/contractor_baton/get_wait_description() + return span_danger("The baton is still charging!") + +/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) + if(!iscarbon(target)) + return + + var/mob/living/carbon/carbon_target = target + if(upgrade_flags & BATON_MUTE_UPGRADE) + if(carbon_target.silent < (MUTE_CYCLES * MUTE_MAX_MOD)) + carbon_target.silent = min((carbon_target.silent + MUTE_CYCLES), (MUTE_CYCLES * MUTE_MAX_MOD)) + + if(upgrade_flags & BATON_FOCUS_UPGRADE) + var/datum/antagonist/traitor/traitor_datum = IS_TRAITOR(user) + var/datum/uplink_handler/handler = traitor_datum?.uplink_handler + if(handler) + for(var/datum/traitor_objective/target_player/kidnapping/objective in handler.active_objectives) + if(carbon_target == objective.target) + carbon_target.stamina.adjust(-BONUS_STAMINA_DAM) + carbon_target.adjust_timed_status_effect(BONUS_STUTTER, /datum/status_effect/speech/stutter) + /obj/item/melee/baton/telescopic/contractor_baton/dropped(mob/user, silent) . = ..() if(!holster) @@ -16,31 +68,30 @@ /obj/item/melee/baton/telescopic/contractor_baton/attack_secondary(mob/living/victim, mob/living/user, params) if(!(upgrade_flags & BATON_CUFF_UPGRADE) || !active) return - for(var/obj/item/restraints/handcuffs/cuff in src.contents) + + for(var/obj/item/restraints/handcuffs/cuff in contents) cuff.attack(victim, user) break + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/item/melee/baton/telescopic/contractor_baton/attackby(obj/item/attacking_item, mob/user, params) . = ..() if(istype(attacking_item, /obj/item/baton_upgrade)) - var/obj/item/baton_upgrade/upgrade = attacking_item - if(!(upgrade_flags & upgrade.upgrade_flag)) - upgrade_flags |= upgrade.upgrade_flag - upgrade.desc_update(src) - attacking_item.forceMove(src) - balloon_alert(user, "[attacking_item] attached") - if(!(upgrade_flags & BATON_CUFF_UPGRADE) && !(upgrade_flags & BATON_ALL_UPGRADE)) - return - if(!istype(attacking_item, /obj/item/restraints/handcuffs/cable)) + add_upgrade(attacking_item, user) + + if(!(upgrade_flags & BATON_CUFF_UPGRADE) || !istype(attacking_item, /obj/item/restraints/handcuffs/cable)) return + var/cuffcount = 0 - for(var/obj/item/restraints/handcuffs/cuff in src.contents) + for(var/obj/item/restraints/handcuffs/cuff in contents) cuffcount++ + if(cuffcount >= CUFF_MAXIMUM) - balloon_alert(user, "baton at maximum cuffs") + to_chat(user, span_warning("[src] is at maximum capacity for handcuffs!")) return + attacking_item.forceMove(src) - balloon_alert(user, "[attacking_item] inserted") + to_chat(user, span_notice("You insert [attacking_item] into [src].")) /obj/item/melee/baton/telescopic/contractor_baton/wrench_act(mob/living/user, obj/item/tool) . = ..() @@ -48,38 +99,64 @@ upgrade.forceMove(get_turf(src)) upgrade_flags &= ~upgrade.upgrade_flag tool.play_tool_sound(src) - desc = initial(desc) -/obj/item/melee/baton/telescopic/contractor_baton/additional_effects_non_cyborg(mob/living/carbon/target, mob/living/user) +/obj/item/melee/baton/telescopic/contractor_baton/examine(mob/user) . = ..() - if(!((upgrade_flags & BATON_MUTE_UPGRADE) && !(upgrade_flags & BATON_ALL_UPGRADE))|| !istype(target)) - return - target.adjust_silence_up_to(10 SECONDS, 20 SECONDS) + if(upgrade_flags) + . += "

[span_boldnotice("[src] has the following upgrades attached:")]" + for(var/obj/item/baton_upgrade/upgrade in contents) + . += "
[span_notice("[upgrade].")]" + +/obj/item/melee/baton/telescopic/contractor_baton/proc/add_upgrade(obj/item/baton_upgrade/upgrade, mob/user) + if(!(upgrade_flags & upgrade.upgrade_flag)) + upgrade_flags |= upgrade.upgrade_flag + upgrade.forceMove(src) + if(user) + user.visible_message(span_notice("[user] inserts the [upgrade] into [src]."), span_notice("You insert [upgrade] into [src]."), span_hear("You hear a faint click.")) + return TRUE + return FALSE /obj/item/melee/baton/telescopic/contractor_baton/upgraded - upgrade_flags = BATON_ALL_UPGRADE - desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets. This one seems to be fully upgraded with unremovable parts." + desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets. This one seems to have unremovable parts." + +/obj/item/melee/baton/telescopic/contractor_baton/upgraded/Initialize(mapload) + . = ..() + for(var/upgrade in subtypesof(/obj/item/baton_upgrade)) + var/obj/item/baton_upgrade/the_upgrade = new upgrade() + add_upgrade(the_upgrade) + for(var/i in 1 to CUFF_MAXIMUM) + new/obj/item/restraints/handcuffs/cable(src) + +/obj/item/melee/baton/telescopic/contractor_baton/upgraded/wrench_act(mob/living/user, obj/item/tool) + return /obj/item/baton_upgrade - icon = 'monkestation/icons/obj/items/baton_upgrades.dmi' + icon = 'icons/obj/items_and_weapons.dmi' var/upgrade_flag -/obj/item/baton_upgrade/proc/desc_update(obj/item/melee/baton/telescopic/contractor_baton/batong) - if(!batong.upgrade_flags) - desc += "

[span_boldnotice("[batong] has the following upgrades attached:")]" - desc += "
[span_notice("[src].")]" - /obj/item/baton_upgrade/cuff name = "handcuff baton upgrade" desc = "Allows the user to apply restraints to a target via baton, requires to be loaded with up to three prior." - icon_state = "cuff_upgrade" + icon_state = "contractor_cuff_upgrade" upgrade_flag = BATON_CUFF_UPGRADE /obj/item/baton_upgrade/mute name = "mute baton upgrade" desc = "Use of the baton on a target will mute them for a short period." - icon_state = "mute_upgrade" + icon_state = "contractor_mute_upgrade" upgrade_flag = BATON_MUTE_UPGRADE +/obj/item/baton_upgrade/focus + name = "focus baton upgrade" + desc = "Use of the baton on a target, should they be the subject of your contract, will be extra exhausted." + icon_state = "contractor_focus_upgrade" + upgrade_flag = BATON_FOCUS_UPGRADE + #undef CUFF_MAXIMUM #undef MUTE_CYCLES +#undef MUTE_MAX_MOD +#undef BONUS_STAMINA_DAM +#undef BONUS_STUTTER +#undef BATON_CUFF_UPGRADE +#undef BATON_MUTE_UPGRADE +#undef BATON_FOCUS_UPGRADE diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm index 97cf27b3e1d1..b5e41fe9782e 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm @@ -1,27 +1,39 @@ /obj/item/mod/control/pre_equipped/contractor - worn_icon = 'monkestation/icons/mob/clothing/worn_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( + initial_modules = list( /obj/item/mod/module/storage/syndicate, /obj/item/mod/module/tether, /obj/item/mod/module/flashlight, /obj/item/mod/module/dna_lock, - /obj/item/mod/module/holster, + /obj/item/mod/module/magnetic_harness, + /obj/item/mod/module/emp_shield, ) /obj/item/mod/control/pre_equipped/contractor/upgraded applied_cell = /obj/item/stock_parts/cell/bluespace - applied_modules = list( + initial_modules = list( /obj/item/mod/module/storage/syndicate, /obj/item/mod/module/jetpack, /obj/item/mod/module/dna_lock, - /obj/item/mod/module/holster, + /obj/item/mod/module/magnetic_harness, + /obj/item/mod/module/baton_holster/preloaded, + /obj/item/mod/module/emp_shield, + ) + +/obj/item/mod/control/pre_equipped/contractor/upgraded/adminbus + initial_modules = list( + /obj/item/mod/module/storage/syndicate, + /obj/item/mod/module/jetpack/advanced, + /obj/item/mod/module/springlock/contractor/no_complexity, /obj/item/mod/module/baton_holster/preloaded, + /obj/item/mod/module/scorpion_hook, + /obj/item/mod/module/emp_shield, ) +/obj/item/mod/control/pre_equipped/syndicate_empty/contractor + theme = /datum/mod_theme/contractor + // I absolutely fuckin hate having to do this /obj/item/clothing/head/mod/contractor worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi' diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm index 45fe4d1f1894..503c6a27ab6f 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm @@ -6,72 +6,40 @@ Remove an inserted baton by using a wrench on the module while it is removed from the suit." icon_state = "holster" icon = 'monkestation/icons/obj/items/modsuit_modules.dmi' + module_type = MODULE_ACTIVE complexity = 3 + active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 + device = /obj/item/melee/baton/telescopic/contractor_baton incompatible_modules = list(/obj/item/mod/module/baton_holster) - module_type = MODULE_USABLE - /// Ref to the baton - var/obj/item/melee/baton/telescopic/contractor_baton/stored_batong - /// If the baton is out or not - var/deployed = FALSE + cooldown_time = 0.5 SECONDS + allow_flags = MODULE_ALLOW_INACTIVE + /// Have they sacrificed a baton to actually be able to use this? + var/eaten_baton = FALSE -// doesn't give a shit if it's deployed or not -/obj/item/mod/module/baton_holster/on_select() - on_use() - SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED, src) - -/obj/item/mod/module/baton_holster/wrench_act(mob/living/user, obj/item/tool) - . = ..() - if(!stored_batong) - return - balloon_alert(user, "[stored_batong] removed") - stored_batong.forceMove(get_turf(src)) - stored_batong.holster = null - stored_batong = null - tool.play_tool_sound(src) - -/obj/item/mod/module/baton_holster/Destroy() - if(stored_batong) - stored_batong.forceMove(get_turf(src)) - stored_batong.holster = null - stored_batong = null +/obj/item/mod/module/baton_holster/attackby(obj/item/attacking_item, mob/user, params) . = ..() - -/obj/item/mod/module/baton_holster/on_use() - var/obj/item/held_item = mod.wearer.get_active_held_item() - if(istype(held_item, /obj/item/melee/baton/telescopic/contractor_baton) && !stored_batong) - balloon_alert(mod.wearer, "[held_item] inserted") - held_item.forceMove(src) - stored_batong = held_item - stored_batong.holster = src - return - - if(!deployed) - deploy(mod.wearer) - else - undeploy(mod.wearer) - -/obj/item/mod/module/baton_holster/proc/deploy(mob/living/user) - if(!(stored_batong in src)) + if(!istype(attacking_item, /obj/item/melee/baton/telescopic/contractor_baton) || eaten_baton) return - if(!user.put_in_hands(stored_batong)) - to_chat(user, span_warning("You need a free hand to hold [stored_batong]!")) - return - deployed = TRUE - balloon_alert(user, "[stored_batong] deployed") + balloon_alert(user, "[attacking_item] inserted") + eaten_baton = TRUE + for(var/obj/item/melee/baton/telescopic/contractor_baton/device_baton as anything in src) + for(var/obj/item/item_contents as anything in attacking_item) + if(istype(item_contents, /obj/item/baton_upgrade)) + device_baton.add_upgrade(item_contents) + else + item_contents.forceMove(device_baton) + qdel(attacking_item) -/obj/item/mod/module/baton_holster/proc/undeploy(mob/living/user) - if(QDELETED(stored_batong)) +/obj/item/mod/module/baton_holster/on_activation() + if(!eaten_baton) + balloon_alert(mod.wearer, "no baton inserted") return - stored_batong.forceMove(src) - deployed = FALSE - balloon_alert(user, "[stored_batong] retracted") + return ..() /obj/item/mod/module/baton_holster/preloaded + eaten_baton = TRUE + device = /obj/item/melee/baton/telescopic/contractor_baton/upgraded -/obj/item/mod/module/baton_holster/preloaded/Initialize(mapload) - . = ..() - stored_batong = new/obj/item/melee/baton/telescopic/contractor_baton/upgraded(src) - stored_batong.holster = src //making this slow you down this will most likely not get used, might rework this /obj/item/mod/module/armor_booster/contractor // Much flatter distribution because contractor suit gets a shitton of armor already armor_mod = /datum/armor/mod_module_armor_booster_contractor @@ -85,3 +53,36 @@ bullet = 20 laser = 20 energy = 20 + +/// Non-deathtrap contractor springlock module +/obj/item/mod/module/springlock/contractor + name = "MOD magnetic deployment module" + desc = "A much more modern version of a springlock system. \ + This is a module that uses magnets to speed up the deployment and retraction time of your MODsuit." + icon_state = "magnet_springlock" + +/obj/item/mod/module/springlock/contractor/on_suit_activation() // This module is actually *not* a death trap + return + +/obj/item/mod/module/springlock/contractor/on_suit_deactivation(deleting = FALSE) + return + +/// This exists for the adminbus contractor modsuit. Do not use otherwise +/obj/item/mod/module/springlock/contractor/no_complexity + complexity = 0 + +/// SCORPION - hook a target into baton range quickly and non-lethally +/obj/item/mod/module/scorpion_hook + name = "MOD SCORPION hook module" + desc = "A module installed in the wrist of a MODSuit, this highly \ + illegal module uses a hardlight hook to forcefully pull \ + a target towards you at high speed, knocking them down and \ + partially exhausting them." + icon_state = "hook" + incompatible_modules = list(/obj/item/mod/module/scorpion_hook) + module_type = MODULE_ACTIVE + complexity = 3 + active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 + device = /obj/item/gun/magic/hook/contractor + cooldown_time = 0.5 SECONDS + allowed_inactive = TRUE diff --git a/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm b/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm index 6b7ac9c9bbe7..a52d8bb92f31 100644 --- a/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm +++ b/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm @@ -1,7 +1,7 @@ #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. \ + description = "%TARGET% %CRIMES% - 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 @@ -147,7 +147,8 @@ 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)) + if(ispath(possible_area, /area/station/hallway) || ispath(possible_area, /area/station/security) || initial(possible_area.outdoors) \ + || ispath(possible_area, /area/station/science/ordnance)) possible_areas -= possible_area dropoff_area = pick(possible_areas) @@ -155,6 +156,11 @@ replace_in_name("%JOB TITLE%", target_mind.assigned_role.title) replace_in_name("%AREA%", initial(dropoff_area.name)) replace_in_name("%TC%", alive_bonus) + var/base = pick_list(WANTED_FILE, "basemessage") + var/verb_string = pick_list(WANTED_FILE, "verb") + var/noun = pick_list_weighted(WANTED_FILE, "noun") + var/location = pick_list_weighted(WANTED_FILE, "location") + replace_in_name("%CRIMES%", "[base] [verb_string] [noun] [location].") return TRUE /datum/traitor_objective/target_player/kidnapping/ungenerate_objective() @@ -225,9 +231,10 @@ 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 + cargo_account.adjust_money(-min(rand(1000, 3000), cargo_account.account_balance)) //Not so much, especially for competent cargo. - 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) + 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) @@ -252,6 +259,7 @@ 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 + sent_mob.reagents?.add_reagent(/datum/reagent/medicine/omnizine, 20) 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...\""))) diff --git a/monkestation/code/modules/events/ghost_role/drifting_contractor.dm b/monkestation/code/modules/events/ghost_role/drifting_contractor.dm new file mode 100644 index 000000000000..47151e1cbfe5 --- /dev/null +++ b/monkestation/code/modules/events/ghost_role/drifting_contractor.dm @@ -0,0 +1,44 @@ +/datum/round_event_control/contractor + name = "Drifting Contractor" + typepath = /datum/round_event/ghost_role/contractor + weight = 8 + max_occurrences = 2 + min_players = 20 + + category = EVENT_CATEGORY_SPACE + description = "Spawns a contractor in space near the station." + track = EVENT_TRACK_MAJOR + tags = list(TAG_OUTSIDER_ANTAG, TAG_SPACE, TAG_COMBAT) + checks_antag_cap = TRUE + +/datum/round_event/ghost_role/contractor + minimum_required = 1 + role_name = "Drifting Contractor" + +/datum/round_event/ghost_role/contractor/spawn_role() + var/list/candidates = get_candidates(ROLE_DRIFTING_CONTRACTOR) + if(!length(candidates)) + return NOT_ENOUGH_PLAYERS + + var/mob/dead/selected = pick(candidates) + + var/list/spawn_locs = list() + for(var/obj/effect/landmark/carpspawn/carp in GLOB.landmarks_list) + spawn_locs += carp.loc + if(!length(spawn_locs)) + return MAP_ERROR + + var/mob/living/carbon/human/operative = new(pick(spawn_locs)) + operative.randomize_human_appearance(~RANDOMIZE_SPECIES) + operative.dna.update_dna_identity() + var/datum/mind/mind = new /datum/mind(selected.key) + mind.set_assigned_role(SSjob.GetJobType(/datum/job/drifting_contractor)) + mind.special_role = ROLE_DRIFTING_CONTRACTOR + mind.active = TRUE + mind.transfer_to(operative) + mind.add_antag_datum(/datum/antagonist/traitor/contractor) + + message_admins("[ADMIN_LOOKUPFLW(operative)] has been made into a [src] by an event.") + log_game("[key_name(operative)] was spawned as a [src] by an event.") + spawned_mobs += operative + return SUCCESSFUL_SPAWN diff --git a/monkestation/code/modules/mod/mod_control.dm b/monkestation/code/modules/mod/mod_control.dm new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/monkestation/code/modules/projectiles/guns/special/meat_hook.dm b/monkestation/code/modules/projectiles/guns/special/meat_hook.dm new file mode 100644 index 000000000000..a48002162137 --- /dev/null +++ b/monkestation/code/modules/projectiles/guns/special/meat_hook.dm @@ -0,0 +1,26 @@ +/obj/item/gun/magic/hook + ///what iconstate do we use for our chain + var/chain_iconstate = "chain" + +/// non-damaging version for contractor MODsuits +/obj/item/gun/magic/hook/contractor + name = "SCORPION hook" + desc = "A hardlight hook used to non-lethally pull targets much closer to the user." + icon = 'monkestation/icon/obj/guns/magic.dmi' + icon_state = "contractor_hook" + inhand_icon_state = "" //nah + ammo_type = /obj/item/ammo_casing/magic/hook/contractor + +/obj/item/ammo_casing/magic/hook/contractor + projectile_type = /obj/projectile/hook/contractor + +/obj/projectile/hook/contractor + icon_state = "contractor_hook" + damage = 0 + stamina = 25 + chain_iconstate = "contractor_chain" + +/obj/item/gun/magic/hook/contractor/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread) + if(prob(1)) + user.say("+GET OVER HERE!+", forced = "scorpion hook") + return ..() diff --git a/monkestation/icons/obj/guns/magic.dmi b/monkestation/icons/obj/guns/magic.dmi new file mode 100644 index 0000000000000000000000000000000000000000..0a82a69b391e8ed99de93690516976921d8da2ed GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv^#Gp`R|bava&kr{CQhE7G1n>? zczGnbxDa0(WE1jLKK2EE$!DY(JEaloF)=wo!pb2aKp@oN#0`O1hd_oi35{GVty;5G z8(3u&m>%{zwapQ3D7Yrl;ZVMK!Gh~T>s9SmhdE6N5nsu*XvKsZaawIjZ4=5gSLr%k p?OpM%!II|H Date: Thu, 23 Nov 2023 17:46:34 -0800 Subject: [PATCH 14/60] pain --- .../client/preferences/middleware/antags.dm | 2 +- .../contractor/datums/contractor_items.dm | 20 +++++++++--------- .../contractor/datums/contractor_support.dm | 7 ++++-- .../antagonists/contractor/datums/outfit.dm | 6 +++--- .../antagonists/contractor/items/baton.dm | 19 ++++++----------- .../contractor/items/modsuit/modsuit.dm | 6 +++--- .../contractor/items/modsuit/modules.dm | 14 ++++++------ .../contractor/items/modsuit/theme.dm | 12 +++++------ .../projectiles/guns/special/meat_hook.dm | 6 +++--- .../icons/obj/items/baton_upgrades.dmi | Bin 354 -> 435 bytes tgstation.dme | 3 +++ 11 files changed, 47 insertions(+), 48 deletions(-) diff --git a/code/modules/client/preferences/middleware/antags.dm b/code/modules/client/preferences/middleware/antags.dm index 2d8282174266..ef70b62cd5c4 100644 --- a/code/modules/client/preferences/middleware/antags.dm +++ b/code/modules/client/preferences/middleware/antags.dm @@ -120,7 +120,7 @@ ROLE_FUGITIVE = /datum/antagonist/fugitive, ROLE_LONE_OPERATIVE = /datum/antagonist/nukeop/lone, ROLE_SENTIENCE = /datum/antagonist/sentient_creature, - ROLE_DRIFTING_CONTRACTOR = /datum/antagonist/contractor, //monkestation edit + ROLE_DRIFTING_CONTRACTOR = /datum/antagonist/traitor/contractor, //monkestation edit ) var/list/antagonists = non_ruleset_antagonists.Copy() diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm index b574b250da8e..bdbfcd99bc51 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm @@ -13,18 +13,18 @@ var/cost /// Subtract cost, and spawn if it's an item. -/datum/contractor_item/proc/handle_purchase(datum/contractor_hub/hub, mob/living/user) - if(hub.contract_rep >= cost) - hub.contract_rep -= cost +/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(limited >= 1) - limited -= 1 - else + if(stock >= 1) + stock -= 1 + else if(stock != -1) return FALSE - hub.purchased_items.Add(src) + handler.purchased_contractor_items.Add(src) user.playsound_local(user, 'sound/machines/uplinkpurchase.ogg', 100) @@ -34,7 +34,7 @@ to_chat(user, span_notice("Your purchase materializes into your hands!")) else to_chat(user, span_notice("Your purchase materializes onto the floor.")) - return item_to_create + return TRUE /datum/contractor_item/contract_reroll @@ -151,10 +151,10 @@ name = "Comms Outage" desc = "Request Syndicate Command to disable station Telecommunications. Disables telecommunications across the station for a medium duration." item_icon = "phone-slash" - limited = 2 + stock = 2 cost = 2 -/datum/contractor_item/comms_blackout/handle_purchase(datum/contractor_hub/hub) +/datum/contractor_item/comms_blackout/handle_purchase(datum/uplink_handler/handler) . = ..() if(!.) return diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm index b8f4e2edef20..cc5b04da5657 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm @@ -4,7 +4,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_secondary_objectives = FALSE /// Team datum that contains the contractor and the support unit var/datum/team/contractor_team/contractor_team @@ -39,12 +38,16 @@ backpack_contents = list( /obj/item/storage/box/survival, - /obj/item/implanter/uplink, +// /obj/item/implanter/uplink, /obj/item/clothing/mask/chameleon, /obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/lighter ) + implants = list( + /obj/item/implant/uplink/precharged, //may need to make this not be precharged, we will see + ) + /datum/outfit/contractor_partner/post_equip(mob/living/carbon/human/partner, visualsOnly) . = ..() var/obj/item/clothing/mask/cigarette/syndicate/cig = partner.get_item_by_slot(ITEM_SLOT_MASK) diff --git a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm index 175f20da6358..ab1b5911c948 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm @@ -12,7 +12,7 @@ shoes = /obj/item/clothing/shoes/combat/swat gloves = /obj/item/clothing/gloves/combat ears = /obj/item/radio/headset/syndicate/alt - l_pocket = /obj/item/modular_computer/tablet/syndicate_contract_uplink + l_pocket = /obj/item/pinpointer/crew/contractor id = /obj/item/card/id/advanced/chameleon backpack_contents = list( /obj/item/storage/box/survival/syndie, @@ -35,8 +35,8 @@ uniform = /obj/item/clothing/under/syndicate glasses = /obj/item/clothing/glasses/night -/datum/outfit/contractor/fully_upgraded - name = "Syndicate Contractor - Fully Upgraded" +/datum/outfit/contractor/upgraded + name = "Syndicate Contractor (Upgraded)" back = /obj/item/mod/control/pre_equipped/contractor/upgraded/adminbus /datum/id_trim/chameleon/contractor diff --git a/monkestation/code/modules/antagonists/contractor/items/baton.dm b/monkestation/code/modules/antagonists/contractor/items/baton.dm index 76e6db8a2633..17bf6f0db2bd 100644 --- a/monkestation/code/modules/antagonists/contractor/items/baton.dm +++ b/monkestation/code/modules/antagonists/contractor/items/baton.dm @@ -1,6 +1,6 @@ #define CUFF_MAXIMUM 3 -#define MUTE_CYCLES 5 -#define MUTE_MAX_MOD 2 +#define MUTE_APPLIED 10 SECONDS +#define MUTE_MAX 30 SECONDS #define BONUS_STAMINA_DAM 25 #define BONUS_STUTTER 10 SECONDS #define BATON_CUFF_UPGRADE (1<<0) @@ -47,8 +47,7 @@ var/mob/living/carbon/carbon_target = target if(upgrade_flags & BATON_MUTE_UPGRADE) - if(carbon_target.silent < (MUTE_CYCLES * MUTE_MAX_MOD)) - carbon_target.silent = min((carbon_target.silent + MUTE_CYCLES), (MUTE_CYCLES * MUTE_MAX_MOD)) + carbon_target.adjust_silence_up_to(MUTE_APPLIED, MUTE_MAX) if(upgrade_flags & BATON_FOCUS_UPGRADE) var/datum/antagonist/traitor/traitor_datum = IS_TRAITOR(user) @@ -59,12 +58,6 @@ carbon_target.stamina.adjust(-BONUS_STAMINA_DAM) carbon_target.adjust_timed_status_effect(BONUS_STUTTER, /datum/status_effect/speech/stutter) -/obj/item/melee/baton/telescopic/contractor_baton/dropped(mob/user, silent) - . = ..() - if(!holster) - return - holster.undeploy(user) - /obj/item/melee/baton/telescopic/contractor_baton/attack_secondary(mob/living/victim, mob/living/user, params) if(!(upgrade_flags & BATON_CUFF_UPGRADE) || !active) return @@ -131,7 +124,7 @@ return /obj/item/baton_upgrade - icon = 'icons/obj/items_and_weapons.dmi' + icon = 'monkestation/icons/obj/items/baton_upgrades.dmi' var/upgrade_flag /obj/item/baton_upgrade/cuff @@ -153,8 +146,8 @@ upgrade_flag = BATON_FOCUS_UPGRADE #undef CUFF_MAXIMUM -#undef MUTE_CYCLES -#undef MUTE_MAX_MOD +#undef MUTE_APPLIED +#undef MUTE_MAX #undef BONUS_STAMINA_DAM #undef BONUS_STUTTER #undef BATON_CUFF_UPGRADE diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm index b5e41fe9782e..31e64387010a 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm @@ -1,7 +1,7 @@ /obj/item/mod/control/pre_equipped/contractor theme = /datum/mod_theme/contractor applied_cell = /obj/item/stock_parts/cell/hyper - initial_modules = list( + applied_modules = list( /obj/item/mod/module/storage/syndicate, /obj/item/mod/module/tether, /obj/item/mod/module/flashlight, @@ -12,7 +12,7 @@ /obj/item/mod/control/pre_equipped/contractor/upgraded applied_cell = /obj/item/stock_parts/cell/bluespace - initial_modules = list( + applied_modules = list( /obj/item/mod/module/storage/syndicate, /obj/item/mod/module/jetpack, /obj/item/mod/module/dna_lock, @@ -22,7 +22,7 @@ ) /obj/item/mod/control/pre_equipped/contractor/upgraded/adminbus - initial_modules = list( + applied_modules = list( /obj/item/mod/module/storage/syndicate, /obj/item/mod/module/jetpack/advanced, /obj/item/mod/module/springlock/contractor/no_complexity, diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm index 503c6a27ab6f..b882adfef33d 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm @@ -23,12 +23,12 @@ balloon_alert(user, "[attacking_item] inserted") eaten_baton = TRUE for(var/obj/item/melee/baton/telescopic/contractor_baton/device_baton as anything in src) - for(var/obj/item/item_contents as anything in attacking_item) - if(istype(item_contents, /obj/item/baton_upgrade)) - device_baton.add_upgrade(item_contents) - else - item_contents.forceMove(device_baton) - qdel(attacking_item) + for(var/obj/item/baton_upgrade/original_upgrade in attacking_item) + var/obj/item/baton_upgrade/new_upgrade = new original_upgrade.type(device_baton) + device_baton.add_upgrade(new_upgrade) + for(var/obj/item/restraints/handcuffs/cable/baton_cuffs in attacking_item) + baton_cuffs.forceMove(device_baton) + qdel(attacking_item) //TEST CUFFS /obj/item/mod/module/baton_holster/on_activation() if(!eaten_baton) @@ -85,4 +85,4 @@ active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 device = /obj/item/gun/magic/hook/contractor cooldown_time = 0.5 SECONDS - allowed_inactive = TRUE + allow_flags = MODULE_ALLOW_INACTIVE diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm index 530c18f2a442..c6b33c6d33a6 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm @@ -15,8 +15,8 @@ resistance_flags = FIRE_PROOF | ACID_PROOF max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT siemens_coefficient = 0 - slowdown_inactive = 1 - slowdown_active = 0.5 + slowdown_inactive = 0.5 + slowdown_active = 0 ui_theme = "syndicate" inbuilt_modules = list(/obj/item/mod/module/armor_booster/contractor, /obj/item/mod/module/chameleon) allowed_suit_storage = list( @@ -58,10 +58,10 @@ ) //ICONS BORKED /datum/armor/mod_contractor_armor - melee = 40 - bullet = 50 - laser = 30 - energy = 40 + melee = 30 + bullet = 40 + laser = 20 + energy = 30 bomb = 30 bio = 40 fire = 80 diff --git a/monkestation/code/modules/projectiles/guns/special/meat_hook.dm b/monkestation/code/modules/projectiles/guns/special/meat_hook.dm index a48002162137..af5a23198f6b 100644 --- a/monkestation/code/modules/projectiles/guns/special/meat_hook.dm +++ b/monkestation/code/modules/projectiles/guns/special/meat_hook.dm @@ -1,4 +1,4 @@ -/obj/item/gun/magic/hook +/obj/projectile/hook ///what iconstate do we use for our chain var/chain_iconstate = "chain" @@ -6,7 +6,7 @@ /obj/item/gun/magic/hook/contractor name = "SCORPION hook" desc = "A hardlight hook used to non-lethally pull targets much closer to the user." - icon = 'monkestation/icon/obj/guns/magic.dmi' + icon = 'monkestation/icons/obj/guns/magic.dmi' icon_state = "contractor_hook" inhand_icon_state = "" //nah ammo_type = /obj/item/ammo_casing/magic/hook/contractor @@ -17,7 +17,7 @@ /obj/projectile/hook/contractor icon_state = "contractor_hook" damage = 0 - stamina = 25 + stamina = 30 chain_iconstate = "contractor_chain" /obj/item/gun/magic/hook/contractor/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread) diff --git a/monkestation/icons/obj/items/baton_upgrades.dmi b/monkestation/icons/obj/items/baton_upgrades.dmi index 2cde174cb9ad5f1c54d7bfdbf9b17dd4a5f4e979..2b7a971dd6c9d16d826875b50c839b826386e860 100644 GIT binary patch delta 186 zcmaFFw3&H=IG+OxGXn!dgnQ0gAf-4_RbKkQfdl^;jC=BZvw@7ywDLRKnkxV`v>!;GICEoN_9pkoMBu+`JWF~p;D;^U0yKm#7e&4!Gu zYI Date: Fri, 24 Nov 2023 02:57:59 -0800 Subject: [PATCH 15/60] did I do a funny --- .../game/objects/items/storage/uplink_kits.dm | 52 ++++++++++++++++++ .../contractor/datums/contractor_datum.dm | 14 ++--- .../contractor/datums/contractor_support.dm | 2 +- .../antagonists/contractor/datums/outfit.dm | 10 ++-- .../contractor/items/modsuit/modsuit.dm | 30 +++++------ .../contractor/items/modsuit/modules.dm | 11 ++-- .../contractor/items/modsuit/theme.dm | 18 ++++--- .../traitor/objectives/kidnapping.dm | 22 ++++++-- .../code/modules/paperwork/paper_premade.dm | 37 +++++++++++-- .../modules/uplink/uplink_items/bundle.dm | 54 +++++++++++++++++++ .../modules/uplink/uplink_items/bundles.dm | 52 ------------------ tgstation.dme | 1 - 12 files changed, 203 insertions(+), 100 deletions(-) delete mode 100644 monkestation/code/modules/uplink/uplink_items/bundles.dm diff --git a/monkestation/code/game/objects/items/storage/uplink_kits.dm b/monkestation/code/game/objects/items/storage/uplink_kits.dm index c0206bae7d33..db51fd460d4c 100644 --- a/monkestation/code/game/objects/items/storage/uplink_kits.dm +++ b/monkestation/code/game/objects/items/storage/uplink_kits.dm @@ -92,6 +92,58 @@ // Paper guide new /obj/item/paper/contractor_guide(src) +/obj/item/storage/box/syndie_kit/contract_kit/midround/PopulateContents() + // You get one item from each sub list + var/static/list/item_list = list( + KIT_ITEM_CATEGORY_SUPPORT = list( + /obj/item/pen/sleepy, + /obj/item/storage/medkit/tactical, + /obj/item/pen/sleepy, + /obj/item/gun/syringe/syndicate, + /obj/item/storage/backpack/duffelbag/syndie/x4, + /obj/item/clothing/shoes/chameleon/noslip, + /obj/item/clothing/glasses/thermal/syndi, + /obj/item/storage/box/syndie_kit/imp_freedom, + /obj/item/reagent_containers/hypospray/medipen/stimulants, + /obj/item/card/emag/doorjack, + ), + + KIT_ITEM_CATEGORY_WEAPONS = list( + /obj/item/melee/powerfist, //over value but its never used + /obj/item/storage/box/syndie_kit/origami_bundle, + /obj/item/clothing/gloves/krav_maga/combatglovesplus, + /obj/item/gun/ballistic/automatic/c20r/toy/unrestricted/riot, + /obj/item/storage/box/syndie_kit/throwing_weapons, + /obj/item/storage/box/syndie_kit/chemical, //technically over value but it cant be used on its own + /obj/item/autosurgeon/syndicate/anti_stun, //way over value but you dont get a real weapon, might have to remove this one + ), + + KIT_ITEM_CATEGORY_MISC = list( + /obj/item/syndie_glue, + /obj/item/slimepotion/slime/sentience/nuclear, + /obj/item/storage/box/syndie_kit/imp_uplink, + /obj/item/grenade/clusterbuster/soap, + /obj/item/flashlight/emp, + /obj/item/encryptionkey/syndicate, + /obj/item/multitool/ai_detect, + /obj/item/storage/toolbox/syndicate, + /obj/item/card/emag, + /obj/item/ai_module/syndicate, + ) + ) + + var/list/items_to_give = list() + 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 + new /obj/item/paper/contractor_guide/midround(src) + new /obj/item/storage/fancy/cigarettes/cigpack_syndicate(src) + new /obj/item/lighter(src) + new /obj/item/jammer(src) + #undef KIT_ITEM_CATEGORY_SUPPORT #undef KIT_ITEM_CATEGORY_WEAPONS #undef KIT_ITEM_CATEGORY_MISC diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm index 74894c931ede..70ef424c42c6 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm @@ -33,6 +33,7 @@ antag_hud_name = "contractor" antag_moodlet = /datum/mood_event/focused show_to_ghosts = TRUE + give_uplink = FALSE suicide_cry = "FOR THE CONTRACTS!!" /// The outfit the contractor is equipped with var/contractor_outfit = /datum/outfit/contractor @@ -43,22 +44,23 @@ var/mob/living/carbon/human/person = owner.current person.equipOutfit(contractor_outfit) + return TRUE + +/datum/antagonist/traitor/contractor/on_gain() + equip_guy() + . = ..() + var/datum/component/uplink/found_uplink = owner.find_syndicate_uplink() if(!found_uplink) CRASH("Unable to find uplink for contractor [owner].") found_uplink.become_contractor() - return TRUE - -/datum/antagonist/traitor/contractor/on_gain() - . = ..() - equip_guy() /datum/antagonist/traitor/contractor/forge_traitor_objectives() var/datum/objective/contractor_total/contract_objective = new contract_objective.owner = owner objectives += contract_objective - . = ..() + objectives += forge_single_generic_objective() /// Used by drifting contractors /datum/objective/contractor_total diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm index cc5b04da5657..1ffbb889b070 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_support.dm @@ -3,6 +3,7 @@ antag_moodlet = /datum/mood_event/focused show_in_roundend = FALSE // We're already adding them in to the contractor's roundend. + give_uplink = FALSE give_objectives = TRUE // We give them their own custom objective. give_secondary_objectives = FALSE /// Team datum that contains the contractor and the support unit @@ -38,7 +39,6 @@ backpack_contents = list( /obj/item/storage/box/survival, -// /obj/item/implanter/uplink, /obj/item/clothing/mask/chameleon, /obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/lighter diff --git a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm index ab1b5911c948..fa41faebe1bb 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm @@ -9,14 +9,14 @@ belt = /obj/item/storage/belt/military uniform = /obj/item/clothing/under/syndicate/coldres - shoes = /obj/item/clothing/shoes/combat/swat + shoes = /obj/item/clothing/shoes/combat/swat //might need to make these not be swat gloves = /obj/item/clothing/gloves/combat ears = /obj/item/radio/headset/syndicate/alt - l_pocket = /obj/item/pinpointer/crew/contractor + l_pocket = /obj/item/restraints/handcuffs/cable/red id = /obj/item/card/id/advanced/chameleon backpack_contents = list( /obj/item/storage/box/survival/syndie, - /obj/item/storage/box/syndie_kit/contract_kit, + /obj/item/storage/box/syndie_kit/contract_kit/midround, /obj/item/knife/combat/survival, /obj/item/pinpointer/crew/contractor ) @@ -35,10 +35,6 @@ uniform = /obj/item/clothing/under/syndicate glasses = /obj/item/clothing/glasses/night -/datum/outfit/contractor/upgraded - name = "Syndicate Contractor (Upgraded)" - back = /obj/item/mod/control/pre_equipped/contractor/upgraded/adminbus - /datum/id_trim/chameleon/contractor assignment = "Syndicate Contractor" trim_state = "trim_contractor" diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm index 31e64387010a..c35591a520c3 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm @@ -2,33 +2,31 @@ theme = /datum/mod_theme/contractor applied_cell = /obj/item/stock_parts/cell/hyper applied_modules = list( - /obj/item/mod/module/storage/syndicate, - /obj/item/mod/module/tether, - /obj/item/mod/module/flashlight, /obj/item/mod/module/dna_lock, - /obj/item/mod/module/magnetic_harness, /obj/item/mod/module/emp_shield, + /obj/item/mod/module/flashlight, + /obj/item/mod/module/magnetic_harness, + /obj/item/mod/module/storage/syndicate, + /obj/item/mod/module/tether, + ) + default_pins = list( + /obj/item/mod/module/armor_booster/contractor, ) /obj/item/mod/control/pre_equipped/contractor/upgraded applied_cell = /obj/item/stock_parts/cell/bluespace applied_modules = list( - /obj/item/mod/module/storage/syndicate, - /obj/item/mod/module/jetpack, - /obj/item/mod/module/dna_lock, - /obj/item/mod/module/magnetic_harness, /obj/item/mod/module/baton_holster/preloaded, + /obj/item/mod/module/dna_lock, /obj/item/mod/module/emp_shield, - ) - -/obj/item/mod/control/pre_equipped/contractor/upgraded/adminbus - applied_modules = list( + /obj/item/mod/module/jetpack, + /obj/item/mod/module/magnetic_harness, /obj/item/mod/module/storage/syndicate, - /obj/item/mod/module/jetpack/advanced, - /obj/item/mod/module/springlock/contractor/no_complexity, + ) + default_pins = list( + /obj/item/mod/module/armor_booster/contractor, /obj/item/mod/module/baton_holster/preloaded, - /obj/item/mod/module/scorpion_hook, - /obj/item/mod/module/emp_shield, + /obj/item/mod/module/jetpack, ) /obj/item/mod/control/pre_equipped/syndicate_empty/contractor diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm index b882adfef33d..e2bccdb4bac6 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm @@ -38,8 +38,14 @@ /obj/item/mod/module/baton_holster/preloaded eaten_baton = TRUE + device = /obj/item/melee/baton/telescopic/contractor_baton + +/obj/item/mod/module/baton_holster/preloaded/upgraded device = /obj/item/melee/baton/telescopic/contractor_baton/upgraded +/obj/item/mod/module/chameleon/contractor // zero complexity module to match pre-TGification + complexity = 0 + //making this slow you down this will most likely not get used, might rework this /obj/item/mod/module/armor_booster/contractor // Much flatter distribution because contractor suit gets a shitton of armor already armor_mod = /datum/armor/mod_module_armor_booster_contractor @@ -60,6 +66,7 @@ desc = "A much more modern version of a springlock system. \ This is a module that uses magnets to speed up the deployment and retraction time of your MODsuit." icon_state = "magnet_springlock" + complexity = 0 //we have fast deploy already, we dont need this to cost anything /obj/item/mod/module/springlock/contractor/on_suit_activation() // This module is actually *not* a death trap return @@ -67,10 +74,6 @@ /obj/item/mod/module/springlock/contractor/on_suit_deactivation(deleting = FALSE) return -/// This exists for the adminbus contractor modsuit. Do not use otherwise -/obj/item/mod/module/springlock/contractor/no_complexity - complexity = 0 - /// SCORPION - hook a target into baton range quickly and non-lethally /obj/item/mod/module/scorpion_hook name = "MOD SCORPION hook module" diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm index c6b33c6d33a6..805f91d78eea 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/theme.dm @@ -18,7 +18,7 @@ slowdown_inactive = 0.5 slowdown_active = 0 ui_theme = "syndicate" - inbuilt_modules = list(/obj/item/mod/module/armor_booster/contractor, /obj/item/mod/module/chameleon) + inbuilt_modules = list(/obj/item/mod/module/armor_booster/contractor, /obj/item/mod/module/chameleon/contractor) allowed_suit_storage = list( /obj/item/flashlight, /obj/item/tank/internals, @@ -34,10 +34,12 @@ ) skins = list( "contractor" = list( + MOD_ICON_OVERRIDE = 'monkestation/icons/obj/clothing/modsuits/modsuit.dmi', + MOD_WORN_ICON_OVERRIDE = 'monkestation/icons/mob/clothing/worn_modsuit.dmi', HELMET_LAYER = NECK_LAYER, HELMET_FLAGS = list( UNSEALED_CLOTHING = SNUG_FIT, - SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|HEADINTERNALS, UNSEALED_INVISIBILITY = HIDEFACIALHAIR, SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, @@ -45,24 +47,28 @@ CHESTPLATE_FLAGS = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, ), GAUNTLETS_FLAGS = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + CAN_OVERSLOT = TRUE, ), BOOTS_FLAGS = list( UNSEALED_CLOTHING = THICKMATERIAL, SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + CAN_OVERSLOT = TRUE, ), ), ) //ICONS BORKED /datum/armor/mod_contractor_armor melee = 30 - bullet = 40 - laser = 20 - energy = 30 + bullet = 35 + laser = 15 + energy = 15 bomb = 30 bio = 40 fire = 80 - acid = 85 + acid = 90 + wound = 30 diff --git a/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm b/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm index a52d8bb92f31..612d6d0a44ad 100644 --- a/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm +++ b/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm @@ -1,7 +1,7 @@ -#define STARTING_COMMON_OBJECTIVES +#define CONTRACTOR_RANSOM_CUT 0.35 /datum/traitor_objective/target_player/kidnapping name = "Kidnap %TARGET% the %JOB TITLE% and deliver them to %AREA%" - description = "%TARGET% %CRIMES% - and you'll need to kidnap and deliver them to %AREA%, where our transport pod will be waiting. \ + description = "%TARGET% %CRIMES% 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 @@ -231,7 +231,19 @@ 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. + var/ransom = rand(5000, 10000) //technically the contractor can get overpayed even if cargo cant pay, but lets just say CC covers the tab, we will see if this is too much + cargo_account.adjust_money(-min(ransom, cargo_account.account_balance)) + var/obj/item/card/id/owner_id = handler.owner.current?.get_idcard(TRUE) + if(owner_id?.registered_account.account_id) //why do we check for account id? because apparently unset agent IDs have existing bank accounts that can't be accessed. this is suboptimal + owner_id.registered_account.adjust_money(ransom * CONTRACTOR_RANSOM_CUT) + + owner_id.registered_account.bank_card_talk("We've processed the ransom, agent. Here's your cut - your balance is now \ + [owner_id.registered_account.account_balance] credits.", TRUE) + else + to_chat(handler.owner.current, span_notice("A briefcase appears at your feet!")) + var/obj/item/storage/secure/briefcase/case = new(get_turf(handler.owner.current)) + for(var/i in 1 to (round((ransom * CONTRACTOR_RANSOM_CUT) / 1000))) // Gets slightly less/more but whatever + new /obj/item/stack/spacecash/c1000(case) 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) @@ -259,7 +271,7 @@ 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 - sent_mob.reagents?.add_reagent(/datum/reagent/medicine/omnizine, 20) + sent_mob.reagents?.add_reagent(/datum/reagent/medicine/omnizine, 20) //if people end up going with contractors too often(I doubt they will) we can port skyrats wounding stuff 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...\""))) @@ -315,3 +327,5 @@ for (var/obj/item/implant/storage/internal_bag in kidnapee.implants) belongings += internal_bag.contents return belongings + +#undef CONTRACTOR_RANSOM_CUT diff --git a/monkestation/code/modules/paperwork/paper_premade.dm b/monkestation/code/modules/paperwork/paper_premade.dm index 7ac48dd6302b..dec7f2f5e94c 100644 --- a/monkestation/code/modules/paperwork/paper_premade.dm +++ b/monkestation/code/modules/paperwork/paper_premade.dm @@ -1,7 +1,5 @@ /obj/item/paper/contractor_guide name = "Contractor Guide" - -/obj/item/paper/contractor_guide/Initialize(mapload) default_raw_text = {"

Welcome agent, congratulations on your new position as contractor. On top of your already assigned objectives, this kit will provide you contracts to take on for TC payments.

Provided within, we give your specialist contractor space suit. It's even more compact, being able to fit into a pocket, and faster than the @@ -36,4 +34,37 @@ ID card you have equipped, on top of the TC payment we give.

Good luck agent. You can burn this document with the supplied lighter.

"} - return ..() +/obj/item/paper/contractor_guide/midround + default_raw_text = {"

Welcome agent, congratulations on successfully getting in range of the station.

+

You likely already have your Contractor MODSuit equipped. It has a built in chameleon module, which only works when the MODSuit is undeployed, + but is highly useful for on-station infiltrations. We also provide your chameleon jumpsuit and mask, both of which can be changed + to any form you need for the moment. The cigarettes are a special blend - it'll heal your injuries slowly overtime.

+

Your standard issue contractor baton can be found in the baton holster MODSuit module, it hits harder than the ones you might be used to, + and will likely be your go to weapon for kidnapping your targets. The three additional items have been randomly selected from what we had available. + We hope they're useful to you for your mission.

+

The contractor hub, available at the top right of the uplink, will provide you unique items and abilities. These are bought using Contractor Rep, + with two Rep being provided each time you complete a contract.

+

Using the tablet

+
    +
  1. Open the Syndicate Contract Uplink program.
  2. +
  3. Here, you can accept a contract, and redeem your TC payments from completed contracts.
  4. +
  5. The payment number shown in brackets is the bonus you'll receive when bringing your target alive. You receive the + other number regardless of if they were alive or dead.
  6. +
  7. Contracts are completed by bringing the target to designated dropoff, calling for extraction, and putting them + inside the pod.
  8. +
+

Be careful when accepting a contract. While you'll be able to see the location of the dropoff point, cancelling will make it + unavailable to take on again.

+

The tablet can also be recharged at any cell charger.

+

Extracting

+
    +
  1. Make sure both yourself and your target are at the dropoff.
  2. +
  3. Call the extraction, and stand back from the drop point.
  4. +
  5. If it fails, make sure your target is inside, and there's a free space for the pod to land.
  6. +
  7. Grab your target, and drag them into the pod.
  8. +
+

Ransoms

+

We need your target for our own reasons, but we ransom them back to your mission area once their use is served. They will return back + from where you sent them off from in several minutes time. Don't worry, we give you a cut of what we get paid. We pay this into whatever + ID card you have equipped, on top of the TC payment we give.

+

Good luck agent. You can burn this document with the supplied lighter.

"} diff --git a/monkestation/code/modules/uplink/uplink_items/bundle.dm b/monkestation/code/modules/uplink/uplink_items/bundle.dm index 86e2496adf42..6ee0941d5daa 100644 --- a/monkestation/code/modules/uplink/uplink_items/bundle.dm +++ b/monkestation/code/modules/uplink/uplink_items/bundle.dm @@ -16,3 +16,57 @@ var/datum/component/uplink/our_uplink = source.GetComponent(/datum/component/uplink) if(uplink_handler && our_uplink) our_uplink.become_contractor() + +/datum/uplink_item/bundles_tc/surplus/lootbox + name = "Syndicate Lootbox Crate" + desc = "A dusty crate from the back of the Syndicate warehouse. Rumored to contain a valuable assortment of items, \ + With their all new kit, codenamed 'scam' the syndicate attempted to extract the energy of the die of fate to \ + make a loot-box style system but failed, so instead just fake their randomness using ook's evil twin brother to sniff out the items to shove in it. \ + Item price not guaranteed. Can contain normally unobtainable items. Purchasing this will prevent you from purchasing any non-random item. \ + Cannot be purchased if you have already bought another item." + +/datum/uplink_item/bundles_tc/surplus/lootbox/unique_checks(mob/user, datum/uplink_handler/handler, atom/movable/source) + //we dont acually have the var that makes this get checked so do it manually + if(length(handler.purchase_log.purchase_log) > 0) + return FALSE + return TRUE + +/datum/uplink_item/bundles_tc/surplus/lootbox/spawn_item(spawn_path, mob/user, datum/uplink_handler/handler, atom/movable/source) + crate_tc_value = rand(1,20) * 5 // randomise how much in TC it gives, from 5 to 100 TC + if(crate_tc_value == 5) //horrible luck, welcome to gambling + crate_tc_value = 0 + to_chat(user, span_warning("You feel an overwhelming sense of pride and accomplishment.")) + if(crate_tc_value == 100) // Jackpot, how lucky + crate_tc_value *= 2 + print_command_report("Congratulations to [user] for being the [rand(2, 9)]th lucky winner of the syndicate lottery! \ + Dread Admiral Sabertooth has authorised the beaming of your special equipment immediately! Happy hunting operative.", + "Syndicate Gambling Division High Command", TRUE) + if(ishuman(user) && !(locate(/obj/item/implant/weapons_auth) in user)) //jackpot winners dont have to find firing pins for any guns they get + var/obj/item/implant/weapons_auth/auth = new + auth.implant(user) + to_chat(user, span_notice("You feel as though the syndicate have given you the ability to use weapons beyond your normal access level.")) + var/obj/structure/closet/crate/surplus_crate = new crate_type() + if(!istype(surplus_crate)) + CRASH("crate_type is not a crate") + + var/list/possible_items = generate_possible_items(user, handler, TRUE) + if(!possible_items || !length(possible_items)) + handler.telecrystals += cost + to_chat(user, span_warning("You get the feeling something went wrong and that you should inform syndicate command.")) + qdel(surplus_crate) + CRASH("lootbox crate failed to generate possible items") + + fill_crate(surplus_crate, possible_items) + + podspawn(list( // unlike other chests, lets give them the chest with STYLE + "target" = get_turf(user), + "style" = STYLE_SYNDICATE, + "spawn" = surplus_crate, + )) + handler.add_locked_entries(subtypesof(/datum/uplink_item) - /datum/uplink_item/bundles_tc/random) + +//pain +///Check if we should ignore handler locked_entries or not +/datum/uplink_item/bundles_tc/random/proc/check_ignore_locked(datum/uplink_handler/handler) + return (length(handler.locked_entries) == (length(subtypesof(/datum/uplink_item)) - 1)) && !(src.type in handler.locked_entries) + diff --git a/monkestation/code/modules/uplink/uplink_items/bundles.dm b/monkestation/code/modules/uplink/uplink_items/bundles.dm deleted file mode 100644 index 4b5b73d01e44..000000000000 --- a/monkestation/code/modules/uplink/uplink_items/bundles.dm +++ /dev/null @@ -1,52 +0,0 @@ -/datum/uplink_item/bundles_tc/surplus/lootbox - name = "Syndicate Lootbox Crate" - desc = "A dusty crate from the back of the Syndicate warehouse. Rumored to contain a valuable assortment of items, \ - With their all new kit, codenamed 'scam' the syndicate attempted to extract the energy of the die of fate to \ - make a loot-box style system but failed, so instead just fake their randomness using ook's evil twin brother to sniff out the items to shove in it. \ - Item price not guaranteed. Can contain normally unobtainable items. Purchasing this will prevent you from purchasing any non-random item. \ - Cannot be purchased if you have already bought another item." - -/datum/uplink_item/bundles_tc/surplus/lootbox/unique_checks(mob/user, datum/uplink_handler/handler, atom/movable/source) - //we dont acually have the var that makes this get checked so do it manually - if(length(handler.purchase_log.purchase_log) > 0) - return FALSE - return TRUE - -/datum/uplink_item/bundles_tc/surplus/lootbox/spawn_item(spawn_path, mob/user, datum/uplink_handler/handler, atom/movable/source) - crate_tc_value = rand(1,20) * 5 // randomise how much in TC it gives, from 5 to 100 TC - if(crate_tc_value == 5) //horrible luck, welcome to gambling - crate_tc_value = 0 - to_chat(user, span_warning("You feel an overwhelming sense of pride and accomplishment.")) - if(crate_tc_value == 100) // Jackpot, how lucky - crate_tc_value *= 2 - print_command_report("Congratulations to [user] for being the [rand(2, 9)]th lucky winner of the syndicate lottery! \ - Dread Admiral Sabertooth has authorised the beaming of your special equipment immediately! Happy hunting operative.", - "Syndicate Gambling Division High Command", TRUE) - if(ishuman(user) && !(locate(/obj/item/implant/weapons_auth) in user)) //jackpot winners dont have to find firing pins for any guns they get - var/obj/item/implant/weapons_auth/auth = new - auth.implant(user) - to_chat(user, span_notice("You feel as though the syndicate have given you the ability to use weapons beyond your normal access level.")) - var/obj/structure/closet/crate/surplus_crate = new crate_type() - if(!istype(surplus_crate)) - CRASH("crate_type is not a crate") - - var/list/possible_items = generate_possible_items(user, handler, TRUE) - if(!possible_items || !length(possible_items)) - handler.telecrystals += cost - to_chat(user, span_warning("You get the feeling something went wrong and that you should inform syndicate command.")) - qdel(surplus_crate) - CRASH("lootbox crate failed to generate possible items") - - fill_crate(surplus_crate, possible_items) - - podspawn(list( // unlike other chests, lets give them the chest with STYLE - "target" = get_turf(user), - "style" = STYLE_SYNDICATE, - "spawn" = surplus_crate, - )) - handler.add_locked_entries(subtypesof(/datum/uplink_item) - /datum/uplink_item/bundles_tc/random) - -//pain -///Check if we should ignore handler locked_entries or not -/datum/uplink_item/bundles_tc/random/proc/check_ignore_locked(datum/uplink_handler/handler) - return (length(handler.locked_entries) == (length(subtypesof(/datum/uplink_item)) - 1)) && !(src.type in handler.locked_entries) diff --git a/tgstation.dme b/tgstation.dme index adb1a5f5b217..fe7dedb9d2c2 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6520,7 +6520,6 @@ #include "monkestation\code\modules\uplink\uplink_items.dm" #include "monkestation\code\modules\uplink\uplink_items\badass.dm" #include "monkestation\code\modules\uplink\uplink_items\bundle.dm" -#include "monkestation\code\modules\uplink\uplink_items\bundles.dm" #include "monkestation\code\modules\uplink\uplink_items\device_tools.dm" #include "monkestation\code\modules\uplink\uplink_items\explosive.dm" #include "monkestation\code\modules\uplink\uplink_items\job.dm" From c1efd93d1b827842c0e854bf348b0df58ee64906 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:27:45 -0800 Subject: [PATCH 16/60] STOP YELLING AT ME : ( --- .../antagonists/contractor/items/modsuit/modsuit.dm | 8 -------- 1 file changed, 8 deletions(-) diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm index c35591a520c3..c925c35f1ee2 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm @@ -34,17 +34,9 @@ // 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/modsuit.dmi' /obj/item/clothing/suit/mod/contractor - worn_icon = 'monkestation/icons/mob/clothing/worn_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/modsuit.dmi' /obj/item/clothing/shoes/mod/contractor - worn_icon = 'monkestation/icons/mob/clothing/worn_modsuit.dmi' - icon = 'monkestation/icons/obj/clothing/modsuits/modsuit.dmi' From 714972b6d0f9b3efd3b9a13bb136b3e4eb7db579 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:45:58 -0800 Subject: [PATCH 17/60] still yell --- .../code/modules/antagonists/contractor/items/baton.dm | 6 +++--- .../modules/antagonists/contractor/items/modsuit/modules.dm | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/monkestation/code/modules/antagonists/contractor/items/baton.dm b/monkestation/code/modules/antagonists/contractor/items/baton.dm index 17bf6f0db2bd..b5f54a6048ad 100644 --- a/monkestation/code/modules/antagonists/contractor/items/baton.dm +++ b/monkestation/code/modules/antagonists/contractor/items/baton.dm @@ -130,19 +130,19 @@ /obj/item/baton_upgrade/cuff name = "handcuff baton upgrade" desc = "Allows the user to apply restraints to a target via baton, requires to be loaded with up to three prior." - icon_state = "contractor_cuff_upgrade" + icon_state = "cuff_upgrade" upgrade_flag = BATON_CUFF_UPGRADE /obj/item/baton_upgrade/mute name = "mute baton upgrade" desc = "Use of the baton on a target will mute them for a short period." - icon_state = "contractor_mute_upgrade" + icon_state = "mute_upgrade" upgrade_flag = BATON_MUTE_UPGRADE /obj/item/baton_upgrade/focus name = "focus baton upgrade" desc = "Use of the baton on a target, should they be the subject of your contract, will be extra exhausted." - icon_state = "contractor_focus_upgrade" + icon_state = "focus_upgrade" upgrade_flag = BATON_FOCUS_UPGRADE #undef CUFF_MAXIMUM diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm index e2bccdb4bac6..4ae6a86435f8 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm @@ -81,6 +81,7 @@ illegal module uses a hardlight hook to forcefully pull \ a target towards you at high speed, knocking them down and \ partially exhausting them." + icon = 'monkestation/icons/obj/guns/magic.dmi' icon_state = "hook" incompatible_modules = list(/obj/item/mod/module/scorpion_hook) module_type = MODULE_ACTIVE From b3f9b1eab73d0ff360a7e765095cbb6c9fdd67e7 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:57:04 -0800 Subject: [PATCH 18/60] ye --- .../modules/antagonists/contractor/items/modsuit/modules.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm index 4ae6a86435f8..52750e00abfa 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm @@ -65,7 +65,6 @@ name = "MOD magnetic deployment module" desc = "A much more modern version of a springlock system. \ This is a module that uses magnets to speed up the deployment and retraction time of your MODsuit." - icon_state = "magnet_springlock" complexity = 0 //we have fast deploy already, we dont need this to cost anything /obj/item/mod/module/springlock/contractor/on_suit_activation() // This module is actually *not* a death trap @@ -82,7 +81,7 @@ a target towards you at high speed, knocking them down and \ partially exhausting them." icon = 'monkestation/icons/obj/guns/magic.dmi' - icon_state = "hook" + icon_state = "contractor_hook" incompatible_modules = list(/obj/item/mod/module/scorpion_hook) module_type = MODULE_ACTIVE complexity = 3 From a0ae373603107518682a9896c090b5c3117cb043 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 14:34:10 -0800 Subject: [PATCH 19/60] ok sure champ --- .../modules/antagonists/contractor/items/modsuit/modules.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm index 52750e00abfa..da423a58ea99 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm @@ -66,7 +66,7 @@ desc = "A much more modern version of a springlock system. \ This is a module that uses magnets to speed up the deployment and retraction time of your MODsuit." complexity = 0 //we have fast deploy already, we dont need this to cost anything - +//a /obj/item/mod/module/springlock/contractor/on_suit_activation() // This module is actually *not* a death trap return From 6c239ea8c7e873d89d8552f2afa4ca07421ab6bf Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 14:34:21 -0800 Subject: [PATCH 20/60] thats really cool --- .../modules/antagonists/contractor/items/modsuit/modules.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm index da423a58ea99..52750e00abfa 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modules.dm @@ -66,7 +66,7 @@ desc = "A much more modern version of a springlock system. \ This is a module that uses magnets to speed up the deployment and retraction time of your MODsuit." complexity = 0 //we have fast deploy already, we dont need this to cost anything -//a + /obj/item/mod/module/springlock/contractor/on_suit_activation() // This module is actually *not* a death trap return From 8918745910213ba7508701e7b03d78b35365e004 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 17:00:33 -0800 Subject: [PATCH 21/60] a --- .../screenshot_antag_icons_driftingcontractor.png | Bin 0 -> 601 bytes .../contractor/items/modsuit/modsuit.dm | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png new file mode 100644 index 0000000000000000000000000000000000000000..3dbbf1ee66ae7e2deb45d0711ce7ccdeb2e1c6f4 GIT binary patch literal 601 zcmV-f0;c_mP)h~!J}oUX6crlkzqBM3 z6-h8BSwJ!{9vE%%4YmLP00DGTPE!Ct=GbNc003lqR9JLGWpiV4X>fFDZ*Bkpc$`yK zaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainGEX}w$Gg33tGfE(w;*!LYR3KAH ziHkEOv#1!zH00t;D@x2wg|L+sT>V_YCISGS$rvAshC*oo00C7=L_t(&f$f;>QiCuM zMXM=_p^~cj{;%4*le-gIoFOP}2Yb(-%?H`TbW519+X*3r5JKFVr-B4`5Ij$iU`z;M z51OVyE4+Y^k>DnRSHP@rFmYfLa}r!%U^`FSwtTwY0Gk+W*VvV|FEC<^magkM28$Ss zt7Mm;hC`++a6|%6{+>A$%7_Hl6TfxVP_*8NkhC78|b=}K0oxcXm9wk@y~ zqhEXy`bkL391_$DtekuneimSkC4VeIPHqWCfBbWgXC_qEJ`NJh!W9VY9r>Q*uH(B; zmiRTi9|_hHTr6e*&jox#jBes_1m%oj2f#T24~c#{kzf@8R(t@S^X3GRCq%5M{oc8K z0avgFpP+2nzHx8_b6$f5Cua#N9g!9L0>dzv2Q3DR7#z^DYfQ52%Y_8Bd>81kCNqyF nmuLPr0%jdb@EYWvhr0?+W`mNLJUA2U00000NkvXXu0mjf-2(Lc literal 0 HcmV?d00001 diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm index c925c35f1ee2..25cf7d1a07a0 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm @@ -29,7 +29,7 @@ /obj/item/mod/module/jetpack, ) -/obj/item/mod/control/pre_equipped/syndicate_empty/contractor +/obj/item/mod/control/pre_equipped/syndicate_empty/contractor //for some reason this is acting weird in the screenshots, can fix it later theme = /datum/mod_theme/contractor // I absolutely fuckin hate having to do this From d12d0f63769026ff8617a0edee7b7b09ecc73a86 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 18:14:35 -0800 Subject: [PATCH 22/60] me when broken code --- .../code/modules/antagonists/contractor/datums/outfit.dm | 2 +- .../modules/antagonists/contractor/items/modsuit/modsuit.dm | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm index fa41faebe1bb..caf4aba23b03 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm @@ -31,7 +31,7 @@ /datum/outfit/contractor_preview name = "Syndicate Contractor (Preview only)" - back = /obj/item/mod/control/pre_equipped/syndicate_empty/contractor + back = /obj/item/mod/control/pre_equipped/contractor/upgraded uniform = /obj/item/clothing/under/syndicate glasses = /obj/item/clothing/glasses/night diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm index 25cf7d1a07a0..975fad3774b3 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm @@ -29,9 +29,6 @@ /obj/item/mod/module/jetpack, ) -/obj/item/mod/control/pre_equipped/syndicate_empty/contractor //for some reason this is acting weird in the screenshots, can fix it later - theme = /datum/mod_theme/contractor - // I absolutely fuckin hate having to do this /obj/item/clothing/head/mod/contractor From 7a1d4da14aa4f973cf7a4c42825fad3276885077 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 18:32:20 -0800 Subject: [PATCH 23/60] test --- .../code/modules/antagonists/contractor/datums/outfit.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm index caf4aba23b03..eb8386e9c608 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm @@ -31,7 +31,7 @@ /datum/outfit/contractor_preview name = "Syndicate Contractor (Preview only)" - back = /obj/item/mod/control/pre_equipped/contractor/upgraded +// back = /obj/item/mod/control/pre_equipped/contractor/upgraded uniform = /obj/item/clothing/under/syndicate glasses = /obj/item/clothing/glasses/night From fc7f37c88292677631b61d4d52d2474b6f500a4d Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 19:02:23 -0800 Subject: [PATCH 24/60] the pain --- .../code/modules/antagonists/contractor/datums/outfit.dm | 2 +- .../modules/antagonists/contractor/items/modsuit/modsuit.dm | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm index eb8386e9c608..bc4bc2811bd6 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm @@ -31,7 +31,7 @@ /datum/outfit/contractor_preview name = "Syndicate Contractor (Preview only)" -// back = /obj/item/mod/control/pre_equipped/contractor/upgraded + back = /obj/item/mod/control/pre_equipped/empty/contractor uniform = /obj/item/clothing/under/syndicate glasses = /obj/item/clothing/glasses/night diff --git a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm index 975fad3774b3..83fa0f214c26 100644 --- a/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm +++ b/monkestation/code/modules/antagonists/contractor/items/modsuit/modsuit.dm @@ -29,6 +29,9 @@ /obj/item/mod/module/jetpack, ) +/obj/item/mod/control/pre_equipped/empty/contractor + theme = /datum/mod_theme/contractor + // I absolutely fuckin hate having to do this /obj/item/clothing/head/mod/contractor From fe1344206dfaacb85c5c39e6950a11edf8a945c8 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 24 Nov 2023 21:31:36 -0800 Subject: [PATCH 25/60] now it looks good too --- ...creenshot_antag_icons_driftingcontractor.png | Bin 601 -> 635 bytes .../antagonists/contractor/datums/outfit.dm | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png index 3dbbf1ee66ae7e2deb45d0711ce7ccdeb2e1c6f4..d75bf8fffecca36ce16bb7b36b4687633cd2352d 100644 GIT binary patch delta 497 zcmVOhHA}bgd88|>vUS*f*k#B&1j7da6R9J=Wma$62KoEwbXzw64 zDk8D7x-cH1r-HinN{BBYq!)|TH#j@nD{Ze*EcY6*bYI~r?Swpo|4i<{LOnswWbytc zyGcIS$;|wdD4J-Z|0|*(f$4aSMe!;&%ryXb!yIKIbI6S#0U~Z@r@1IgIiXqrG|vMi zBnlCKu-0C-MOd5%2_V)@d({!y3v6lt5TS&&6hKj(jP{Hg0zekKwV!qc97{*R3#S43noV}t)zIpW| nuK~Fk+0BuIoAmix`ZnWS5|ZL#8Wme?$UL{+>A$%7_Hl6TfxVP_*8Nkh zC78|b=}K0oxcXm9wk@y~qhEXy`bkL391_$DtekuneimSkC4VeIPHqWCfBbWgXC_qE zJ`NJh!W9VY9r>Q*uH(B;miRTi9|_hHTr6e*&jox#jBes_1m%oj2f#T24~c#{Y>{9U z0aknfp7Z7ektal~sQuo#eF0an2A`m8*}idb1an@41t(_-Djks(`vSu-mi_@%07*qoM6N<$ Eg5 Date: Sat, 25 Nov 2023 00:20:59 -0800 Subject: [PATCH 26/60] barely visible but its something --- .../modules/antagonists/contractor/datums/outfit.dm | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm index ab9b555c6d33..bfa4b00994a5 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/outfit.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/outfit.dm @@ -34,6 +34,19 @@ back = /obj/item/mod/control/pre_equipped/empty/contractor uniform = /obj/item/clothing/under/syndicate glasses = /obj/item/clothing/glasses/night + l_hand = /obj/item/melee/baton/telescopic/contractor_baton + +/datum/outfit/contractor_preview/post_equip(mob/living/carbon/human/H, visualsOnly) + var/obj/item/melee/baton/telescopic/contractor_baton/baton = locate() in H.held_items + if(baton.flags_1 & INITIALIZED_1) + baton.attack_self() + else + baton.icon_state = "contractor_baton_on" + baton.inhand_icon_state = "contractor_baton_on" + baton.worn_icon_state = "contractor_baton_on" + + H.update_held_items() + /datum/id_trim/chameleon/contractor assignment = "Syndicate Contractor" From ea9b3b1bc40d2951f680451c46d2f65f85e2ce0a Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Sat, 25 Nov 2023 03:18:04 -0800 Subject: [PATCH 27/60] batong --- ...creenshot_antag_icons_driftingcontractor.png | Bin 635 -> 641 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_driftingcontractor.png index d75bf8fffecca36ce16bb7b36b4687633cd2352d..9004b18b756b4d4df25a95f161b38b96c75a40b4 100644 GIT binary patch delta 462 zcmV;<0Wtpj1c3#R7!3#m0002hMu!Rj001+QB`6aO4Gk$NDI6jz7#A5hKvEj_X`hi= zg@0&)?U?OugD?z5$te3MQ1<>$J6k!KO()b8L8XE3pVpAxQ{mW2Xqr$c6bhX|NfdyW z0NzBcNg{4&6aY23h&q!*I0s;VfX;LAP}g^pMCzRH1t7t=Q!)i$f51o9r->^8cnN@% zs@<1KBA4rv1Jr=d;{bH0Ep`+EsD)fbw11?O!!7rW{}-T(qi!dxWp}n#k{ne4b^?fT z0f=KSa*L!yEj*9`*ax7;8cVR(Ec5Ld0X*AeCf!^dKvtJS0IC3PTOuFVxuih2S(5x0 zFbu;uj)w$TQ@DwE#&>lf1;Qd)#^nCdo4LA6ssgYEaQl@;BstB++oP0sE}Twu%YSF) z3+@4^0bH_pEk_cmB|bWk{0VpbG4loYLjaiS(=?S@uswtW=&Yv(WauPUZ1OLg2cQbT z0w}-u7J;K2S_}DB#ypz*hXTxV0Lyh{*DBa~kOS32_W;xYn%tvV|6IQF#Mi3m4WMH< zom83!;8{^t)RO`zFP4pUu7?7U4j-ILOClAkAN+=ZAGB#lbN-#!=>Px#07*qoM6N<$ Eg5~+h4gdfE delta 456 zcmV;(0XP1E1^Wb$7!3pi0000GwrUFi001qKB`6IXA}bgd88|>vUS*f*kzj>?ScUDD zu}Z{15Qd{@?;tiRBC)f&Fdm|(g1Yufh%X?d7mL+5I6K=bZLd-+_ZqQuU*Rh4ggk@) zOzyx!JweW7@%|>eNj})g%>0umnrNc`E21EQ>3EGr@hUdVH2`?S9AzSN$c-QYB5r1< zxhP9Hp;`bm&jTeS3K6i@UbaPlSeyq5Al6NL)e+eXY-#`yp@g;+KvA8H_KX?=Ko+~V zB+=qB_k;Jx4CJ{nTHskG2ra-o!UATD0Nir-+MDhHnGiB8AdWxSjM>LV7L@_BIIkRC z4?Y+u;(b^hhXbT)E46gp92=e^?1AstQu^sf72zSj^K#!f56 y3ww{8y`o3HdG)UVjOU&oe-aaC{|q<$HSi93a15_qXrkBv0000 Date: Sat, 25 Nov 2023 17:07:14 -0800 Subject: [PATCH 28/60] modular and fewer globals yee --- code/__DEFINES/twitch.dm | 15 --------------- code/__DEFINES/~monkestation/twitch.dm | 10 ++++++++++ monkestation/code/modules/client/verbs.dm | 4 ++-- monkestation/code/modules/trading/lootbox_odds.dm | 6 +++--- .../code/modules/twitch_bits/twitch_system.dm | 11 +++++------ 5 files changed, 20 insertions(+), 26 deletions(-) delete mode 100644 code/__DEFINES/twitch.dm diff --git a/code/__DEFINES/twitch.dm b/code/__DEFINES/twitch.dm deleted file mode 100644 index 75521f11bba9..000000000000 --- a/code/__DEFINES/twitch.dm +++ /dev/null @@ -1,15 +0,0 @@ -//For the twitch extension -#define TWITCH_AFFECTS_STREAMER (1 << 0) -#define TWITCH_AFFECTS_ALL (1 << 1) -#define TWITCH_AFFECTS_RANDOM (1 << 2) - - -//For linking twitch account to ss13 -#define NO_TWITCH_SUB "" //these are the possible values for the twitch subs -#define TWITCH_SUB_TIER_1 "1000" -#define TWITCH_SUB_TIER_2 "2000" -#define TWITCH_SUB_TIER_3 "3000" - -#define ACCESS_TWITCH_SUB_TIER_1 1 -#define ACCESS_TWITCH_SUB_TIER_2 2 -#define ACCESS_TWITCH_SUB_TIER_3 3 diff --git a/code/__DEFINES/~monkestation/twitch.dm b/code/__DEFINES/~monkestation/twitch.dm index ccf5c48238ca..8c013681fa95 100644 --- a/code/__DEFINES/~monkestation/twitch.dm +++ b/code/__DEFINES/~monkestation/twitch.dm @@ -16,3 +16,13 @@ #define T_EVENT_GIVE_EVERYONE_ITEM "give-everyone-item" #define T_EVENT_ROD_OOK "rod-ook" #define T_EVENT_SKINNY_5 "skinny-5" + +//For linking twitch account to ss13 +#define NO_TWITCH_SUB "" //these are the possible values for the twitch subs +#define TWITCH_SUB_TIER_1 "1000" +#define TWITCH_SUB_TIER_2 "2000" +#define TWITCH_SUB_TIER_3 "3000" + +#define ACCESS_TWITCH_SUB_TIER_1 1 +#define ACCESS_TWITCH_SUB_TIER_2 2 +#define ACCESS_TWITCH_SUB_TIER_3 3 diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index d9f00c008753..c2e6f50688c1 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -91,8 +91,8 @@ GLOBAL_LIST_INIT(low_threat_antags, list( var/static/list/event_list if(!event_list) event_list = list() - for(var/event as anything in GLOB.twitch_events_by_type) - var/datum/twitch_event/event_instance = GLOB.twitch_events_by_type[event] + for(var/event as anything in SStwitch.twitch_events_by_type) + var/datum/twitch_event/event_instance = SStwitch.twitch_events_by_type[event] if(!event_instance.token_cost) continue event_list += event_instance diff --git a/monkestation/code/modules/trading/lootbox_odds.dm b/monkestation/code/modules/trading/lootbox_odds.dm index 23103913df67..9567c7d56ee2 100644 --- a/monkestation/code/modules/trading/lootbox_odds.dm +++ b/monkestation/code/modules/trading/lootbox_odds.dm @@ -29,15 +29,15 @@ if("High Tier") temp = new /obj/item/coin/antagtoken temp.name = "High Tier Antag Token" - user.client.saved_tokens.adjust_tokens(HIGH_THREAT, 1) + user.client.client_token_holder.adjust_antag_tokens(HIGH_THREAT, 1) if("Medium Tier") temp = new /obj/item/coin/antagtoken temp.name = "Medium Tier Antag Token" - user.client.saved_tokens.adjust_tokens(MEDIUM_THREAT, 1) + user.client.client_token_holder.adjust_antag_tokens(MEDIUM_THREAT, 1) if("Low Tier") temp = new /obj/item/coin/antagtoken temp.name = "Low Tier Antag Token" - user.client.saved_tokens.adjust_tokens(LOW_THREAT, 1) + user.client.client_token_holder.adjust_antag_tokens(LOW_THREAT, 1) if("Loadout Item") var/static/list/viable_types = list() diff --git a/monkestation/code/modules/twitch_bits/twitch_system.dm b/monkestation/code/modules/twitch_bits/twitch_system.dm index 465f89da211a..0bd694b1b22f 100644 --- a/monkestation/code/modules/twitch_bits/twitch_system.dm +++ b/monkestation/code/modules/twitch_bits/twitch_system.dm @@ -1,6 +1,3 @@ -///assoc list of instances of all twitch events keyed by their type -GLOBAL_LIST_EMPTY(twitch_events_by_type) - /datum/config_entry/string/twitch_key default = "changethisplease" @@ -17,6 +14,8 @@ SUBSYSTEM_DEF(twitch) var/list/running_events = list() ///list of deferred handlers var/list/deferred_handlers = list() + ///assoc list of instances of all twitch events keyed by their type + var/list/twitch_events_by_type = list() var/datum/twitch_event/last_event var/last_event_execution = 0 @@ -24,7 +23,7 @@ SUBSYSTEM_DEF(twitch) /datum/controller/subsystem/twitch/Initialize() for(var/event as anything in subtypesof(/datum/twitch_event)) - GLOB.twitch_events_by_type[event] = new event + twitch_events_by_type[event] = new event return SS_INIT_SUCCESS /datum/controller/subsystem/twitch/stat_entry(msg) @@ -52,7 +51,7 @@ SUBSYSTEM_DEF(twitch) for(var/datum/twitch_event/listed_events as anything in subtypesof(/datum/twitch_event)) if(incoming[3] != initial(listed_events.id_tag)) continue - chosen_one = GLOB.twitch_events_by_type[listed_events] + chosen_one = twitch_events_by_type[listed_events] if(!chosen_one) return @@ -84,7 +83,7 @@ SUBSYSTEM_DEF(twitch) for(var/datum/twitch_event/listed_events as anything in subtypesof(/datum/twitch_event)) if(listed_item != initial(listed_events.id_tag)) continue - chosen_one = GLOB.twitch_events_by_type[listed_events] + chosen_one = twitch_events_by_type[listed_events] if(!chosen_one) return chosen_one.run_event() From 16c6cd199fbc521303ab1f8328e2ca7a7c59c728 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 7 Dec 2023 16:34:42 -0800 Subject: [PATCH 29/60] lint --- tgstation.dme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgstation.dme b/tgstation.dme index 804dd5e13e1d..e0c09836250b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6093,8 +6093,8 @@ #include "monkestation\code\modules\donator\code\item\effects.dm" #include "monkestation\code\modules\donator\code\item\plush.dm" #include "monkestation\code\modules\donator\code\mob\pets.dm" -#include "monkestation\code\modules\events\ghost_role\drifting_contractor.dm" #include "monkestation\code\modules\events\summon_wizard_event.dm" +#include "monkestation\code\modules\events\ghost_role\drifting_contractor.dm" #include "monkestation\code\modules\events\wizard\summon_gifts.dm" #include "monkestation\code\modules\food_and_drinks\recipes\boiling.dm" #include "monkestation\code\modules\ghost_players\area_changes.dm" From 478ff24fb7a1df1308ad8110c5c288b21d8f9582 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:28:00 -0800 Subject: [PATCH 30/60] more conflict resolution --- code/__DEFINES/~monkestation/virology.dm | 44 ++++++++++++++++++++++++ tgstation.dme | 1 + 2 files changed, 45 insertions(+) create mode 100644 code/__DEFINES/~monkestation/virology.dm diff --git a/code/__DEFINES/~monkestation/virology.dm b/code/__DEFINES/~monkestation/virology.dm new file mode 100644 index 000000000000..c4fc5e1d80f1 --- /dev/null +++ b/code/__DEFINES/~monkestation/virology.dm @@ -0,0 +1,44 @@ +#define EFFECT_DANGER_HELPFUL "0" +#define EFFECT_DANGER_FLAVOR "1" +#define EFFECT_DANGER_ANNOYING "2" +#define EFFECT_DANGER_HINDRANCE "3" +#define EFFECT_DANGER_HARMFUL "4" +#define EFFECT_DANGER_DEADLY "5" + +#define ANTIGEN_BLOOD "blood" +#define ANTIGEN_COMMON "common" +#define ANTIGEN_RARE "rare" +#define ANTIGEN_ALIEN "alien" + +//blood antigens +#define ANTIGEN_O "O" +#define ANTIGEN_A "A" +#define ANTIGEN_B "B" +#define ANTIGEN_RH "Rh" +//common antigens +#define ANTIGEN_Q "Q" +#define ANTIGEN_U "U" +#define ANTIGEN_V "V" +//rare antigens +#define ANTIGEN_M "M" +#define ANTIGEN_N "N" +#define ANTIGEN_P "P" +//alien antigens +#define ANTIGEN_X "X" +#define ANTIGEN_Y "Y" +#define ANTIGEN_Z "Z" + + +#define DISEASE_BUMP "bump" +#define DISEASE_TOUCH "touch" + +#define DISEASE_NORMAL "normal" +#define DISEASE_TRANSFORMATION "transformation" +#define DISEASE_GONDOLA "gondola" +#define DISEASE_GONDOLA_DIGITAL "digital_gondola" +#define DISEASE_XENO "xeno" +#define DISEASE_CORGI "corgi" +#define DISEASE_SLIME "slime" +#define DISEASE_MORPH "morph" +#define DISEASE_ROBOT "robot" +#define DISEASE_COLD "cold" diff --git a/tgstation.dme b/tgstation.dme index e0c09836250b..277facc84cdd 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -404,6 +404,7 @@ #include "code\__DEFINES\~monkestation\status_effects.dm" #include "code\__DEFINES\~monkestation\storytellers.dm" #include "code\__DEFINES\~monkestation\traits.dm" +#include "code\__DEFINES\~monkestation\virology.dm" //out of order for conflict reasons, swap this and the line below #include "code\__DEFINES\~monkestation\uplink.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_atom.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_carbon.dm" From c84ee5a5ee696146f8aafbfeac430097c2229573 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:39:03 -0800 Subject: [PATCH 31/60] Revert "more conflict resolution" This reverts commit 478ff24fb7a1df1308ad8110c5c288b21d8f9582. --- code/__DEFINES/~monkestation/virology.dm | 44 ------------------------ tgstation.dme | 1 - 2 files changed, 45 deletions(-) delete mode 100644 code/__DEFINES/~monkestation/virology.dm diff --git a/code/__DEFINES/~monkestation/virology.dm b/code/__DEFINES/~monkestation/virology.dm deleted file mode 100644 index c4fc5e1d80f1..000000000000 --- a/code/__DEFINES/~monkestation/virology.dm +++ /dev/null @@ -1,44 +0,0 @@ -#define EFFECT_DANGER_HELPFUL "0" -#define EFFECT_DANGER_FLAVOR "1" -#define EFFECT_DANGER_ANNOYING "2" -#define EFFECT_DANGER_HINDRANCE "3" -#define EFFECT_DANGER_HARMFUL "4" -#define EFFECT_DANGER_DEADLY "5" - -#define ANTIGEN_BLOOD "blood" -#define ANTIGEN_COMMON "common" -#define ANTIGEN_RARE "rare" -#define ANTIGEN_ALIEN "alien" - -//blood antigens -#define ANTIGEN_O "O" -#define ANTIGEN_A "A" -#define ANTIGEN_B "B" -#define ANTIGEN_RH "Rh" -//common antigens -#define ANTIGEN_Q "Q" -#define ANTIGEN_U "U" -#define ANTIGEN_V "V" -//rare antigens -#define ANTIGEN_M "M" -#define ANTIGEN_N "N" -#define ANTIGEN_P "P" -//alien antigens -#define ANTIGEN_X "X" -#define ANTIGEN_Y "Y" -#define ANTIGEN_Z "Z" - - -#define DISEASE_BUMP "bump" -#define DISEASE_TOUCH "touch" - -#define DISEASE_NORMAL "normal" -#define DISEASE_TRANSFORMATION "transformation" -#define DISEASE_GONDOLA "gondola" -#define DISEASE_GONDOLA_DIGITAL "digital_gondola" -#define DISEASE_XENO "xeno" -#define DISEASE_CORGI "corgi" -#define DISEASE_SLIME "slime" -#define DISEASE_MORPH "morph" -#define DISEASE_ROBOT "robot" -#define DISEASE_COLD "cold" diff --git a/tgstation.dme b/tgstation.dme index 277facc84cdd..e0c09836250b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -404,7 +404,6 @@ #include "code\__DEFINES\~monkestation\status_effects.dm" #include "code\__DEFINES\~monkestation\storytellers.dm" #include "code\__DEFINES\~monkestation\traits.dm" -#include "code\__DEFINES\~monkestation\virology.dm" //out of order for conflict reasons, swap this and the line below #include "code\__DEFINES\~monkestation\uplink.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_atom.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_carbon.dm" From 7c15727326055eaa9f4456994d2d5ca0072c493e Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:43:16 -0800 Subject: [PATCH 32/60] conflicts try 2 --- code/__DEFINES/~monkestation/{uplink.dm => _uplink.dm} | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename code/__DEFINES/~monkestation/{uplink.dm => _uplink.dm} (100%) diff --git a/code/__DEFINES/~monkestation/uplink.dm b/code/__DEFINES/~monkestation/_uplink.dm similarity index 100% rename from code/__DEFINES/~monkestation/uplink.dm rename to code/__DEFINES/~monkestation/_uplink.dm diff --git a/tgstation.dme b/tgstation.dme index e0c09836250b..3a5943236b98 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -380,6 +380,7 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_spawner.dm" #include "code\__DEFINES\research\anomalies.dm" #include "code\__DEFINES\research\research_categories.dm" +#include "code\__DEFINES\~monkestation\_uplink.dm" //_ is to avoid conflicts, remove once no longer needed #include "code\__DEFINES\~monkestation\access.dm" #include "code\__DEFINES\~monkestation\ai.dm" #include "code\__DEFINES\~monkestation\antagonists.dm" @@ -404,7 +405,6 @@ #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" From 334bb0598d64b9c0ad9e40ccfacbb23ebbf711c3 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:54:21 -0800 Subject: [PATCH 33/60] pain --- .../code/modules/uplink/uplink_items/{bundle.dm => bundles.dm} | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename monkestation/code/modules/uplink/uplink_items/{bundle.dm => bundles.dm} (100%) diff --git a/monkestation/code/modules/uplink/uplink_items/bundle.dm b/monkestation/code/modules/uplink/uplink_items/bundles.dm similarity index 100% rename from monkestation/code/modules/uplink/uplink_items/bundle.dm rename to monkestation/code/modules/uplink/uplink_items/bundles.dm diff --git a/tgstation.dme b/tgstation.dme index 3a5943236b98..80cc386143a0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6596,7 +6596,7 @@ #include "monkestation\code\modules\twitch_bits\events\skinny.dm" #include "monkestation\code\modules\uplink\uplink_items.dm" #include "monkestation\code\modules\uplink\uplink_items\badass.dm" -#include "monkestation\code\modules\uplink\uplink_items\bundle.dm" +#include "monkestation\code\modules\uplink\uplink_items\bundles.dm" #include "monkestation\code\modules\uplink\uplink_items\device_tools.dm" #include "monkestation\code\modules\uplink\uplink_items\explosive.dm" #include "monkestation\code\modules\uplink\uplink_items\job.dm" From c8176d072208ad0aa80011bc5bc87c7640f71bae Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 7 Dec 2023 18:05:05 -0800 Subject: [PATCH 34/60] pain --- tgstation.dme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgstation.dme b/tgstation.dme index 80cc386143a0..a6b396cbd98e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -380,7 +380,7 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_spawner.dm" #include "code\__DEFINES\research\anomalies.dm" #include "code\__DEFINES\research\research_categories.dm" -#include "code\__DEFINES\~monkestation\_uplink.dm" //_ is to avoid conflicts, remove once no longer needed +#include "code\__DEFINES\~monkestation\_uplink.dm" //_ is to avoid conflicts, remove once no longer needed// #include "code\__DEFINES\~monkestation\access.dm" #include "code\__DEFINES\~monkestation\ai.dm" #include "code\__DEFINES\~monkestation\antagonists.dm" From 52c5c24f5cf505b1c2850856d323f6deb922b0ee Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 8 Dec 2023 19:19:32 -0800 Subject: [PATCH 35/60] contractor fix --- monkestation/code/modules/uplink/uplink_items/bundles.dm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/monkestation/code/modules/uplink/uplink_items/bundles.dm b/monkestation/code/modules/uplink/uplink_items/bundles.dm index 6ee0941d5daa..1b7441fdf429 100644 --- a/monkestation/code/modules/uplink/uplink_items/bundles.dm +++ b/monkestation/code/modules/uplink/uplink_items/bundles.dm @@ -7,8 +7,13 @@ 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) + if(length(handler.active_objectives) || !handler.can_take_objectives || !handler.has_objectives) return FALSE + + for(var/datum/traitor_objective/objective in handler.completed_objectives) + if(objective.objective_state != OBJECTIVE_STATE_INACTIVE) + return FALSE + return TRUE /datum/uplink_item/bundles_tc/contract_kit/purchase(mob/user, datum/uplink_handler/uplink_handler, atom/movable/source) From fd93651d04c688997a9f707a9277c0bb2f3edb29 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:49:14 -0800 Subject: [PATCH 36/60] fix --- .../modules/antagonists/contractor/datums/contractor_items.dm | 2 +- .../code/modules/antagonists/traitor/objectives/kidnapping.dm | 2 +- monkestation/code/modules/events/summon_wizard_event.dm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm index bdbfcd99bc51..09a9401e0287 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_items.dm @@ -160,7 +160,7 @@ return var/datum/round_event_control/event = locate(/datum/round_event_control/communications_blackout) in SSevents.control - event.runEvent() + event.run_event() /datum/contractor_item/mod_baton_holster name = "Baton Holster Module" diff --git a/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm b/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm index 612d6d0a44ad..79f94d8df977 100644 --- a/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm +++ b/monkestation/code/modules/antagonists/traitor/objectives/kidnapping.dm @@ -144,7 +144,7 @@ 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)) + AddComponent(/datum/component/traitor_objective_register, target, fail_signals = list(COMSIG_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) \ diff --git a/monkestation/code/modules/events/summon_wizard_event.dm b/monkestation/code/modules/events/summon_wizard_event.dm index c6d391488ff7..eebde2200466 100644 --- a/monkestation/code/modules/events/summon_wizard_event.dm +++ b/monkestation/code/modules/events/summon_wizard_event.dm @@ -28,4 +28,4 @@ setup = TRUE /datum/round_event/summon_wizard_event/start() - triggered_event.runEvent() + triggered_event.run_event() From fa283f7bd2aa6f31d26ec7bda0a809deb9b9022d Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:09:09 -0800 Subject: [PATCH 37/60] try --- tgstation.dme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgstation.dme b/tgstation.dme index a6f92277838b..94942ec8c03e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -380,7 +380,7 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_spawner.dm" #include "code\__DEFINES\research\anomalies.dm" #include "code\__DEFINES\research\research_categories.dm" -#include "code\__DEFINES\~monkestation\_uplink.dm" //_ is to avoid conflicts, remove once no longer needed// +#include "code\__DEFINES\~monkestation\_uplink.dm" #include "code\__DEFINES\~monkestation\access.dm" #include "code\__DEFINES\~monkestation\ai.dm" #include "code\__DEFINES\~monkestation\antagonists.dm" From 4deca287b69351d9b483816bb39191d30b1474ad Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:18:29 -0800 Subject: [PATCH 38/60] fixed objective --- .../antagonists/contractor/datums/contractor_datum.dm | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm b/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm index 70ef424c42c6..9f7b40a45743 100644 --- a/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm +++ b/monkestation/code/modules/antagonists/contractor/datums/contractor_datum.dm @@ -77,10 +77,14 @@ /datum/objective/contractor_total/check_completion() var/datum/antagonist/traitor/antag_datum = owner.has_antag_datum(/datum/antagonist/traitor) var/datum/uplink_handler/handler = antag_datum?.uplink_handler - if(!handler) - return FALSE + var/completed_contracts = 0 + for(var/datum/traitor_objective/objective in handler?.completed_objectives) + if(objective.objective_state != OBJECTIVE_STATE_COMPLETED) + continue - return length(handler.completed_objectives) >= contracts_needed //only given to contractors so we can assume any completed objectives are contracts + completed_contracts++ + + return completed_contracts >= contracts_needed || completed //only given to contractors so we can assume any completed objectives are contracts /datum/job/drifting_contractor title = ROLE_DRIFTING_CONTRACTOR From 8c6cc51d54ed7ec66b10b6fb4ff26ee8e2f0ca98 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 15 Dec 2023 02:28:31 -0800 Subject: [PATCH 39/60] I think good --- .../modules/code_redemption/code_generator.dm | 97 ++++++++---- .../modules/code_redemption/code_redeemer.dm | 14 ++ .../code/modules/trading/box_rolling.dm | 6 +- .../code/modules/trading/lootbox_clothing.dm | 131 ++++++++++++++++ .../code/modules/trading/lootbox_odds.dm | 141 +++++++++++++++--- tgstation.dme | 1 + 6 files changed, 346 insertions(+), 44 deletions(-) create mode 100644 monkestation/code/modules/trading/lootbox_clothing.dm diff --git a/monkestation/code/modules/code_redemption/code_generator.dm b/monkestation/code/modules/code_redemption/code_generator.dm index bd389347c9af..ef1feffbbc17 100644 --- a/monkestation/code/modules/code_redemption/code_generator.dm +++ b/monkestation/code/modules/code_redemption/code_generator.dm @@ -6,17 +6,20 @@ GLOBAL_LIST_INIT(stored_codes, list()) /proc/generate_redemption_code() if(!check_rights(R_FUN)) return - var/choice = tgui_input_list(usr, "Please choose a code type", "Code generation", list("Coins", "Loadout Items", "Antag Tokens")) + var/choice = tgui_input_list(usr, "Please choose a code type", "Code generation", list("Coins", "Loadout Items", "Antag Tokens", "Unusual")) if(!choice) return - if(choice == "Coins") - generate_coin_code() - else if(choice == "Loadout Items") - generate_loadout_code() - else - generate_antag_token_code() + switch(choice) + if("Coins") + generate_coin_code() + if("Loadout Items") + generate_loadout_code() + if("Antag Tokens") + generate_antag_token_code() + if("Unusual") + generate_unsual_code() /proc/generate_coin_code(no_logs = FALSE) if(!check_rights(R_FUN)) @@ -73,23 +76,6 @@ GLOBAL_LIST_INIT(stored_codes, list()) to_chat(usr, span_big("Your generated code is: [string]")) return string -/proc/generate_code_string() - var/list/sections = list() - for(var/num in 1 to 5) - sections += random_string(5, GLOB.hex_characters) - - var/string = sections.Join("-") - return string - -/proc/reload_global_stored_codes() - GLOB.stored_codes = list() - var/json_file = file(CODE_STORAGE_PATH) - - if(!fexists(json_file)) - return - GLOB.stored_codes = json_decode(file2text(json_file)) - - /proc/generate_antag_token_code(no_logs = FALSE) if(!check_rights(R_FUN)) return @@ -118,11 +104,72 @@ GLOBAL_LIST_INIT(stored_codes, list()) to_chat(usr, span_big("Your generated code is: [string]")) return string +/proc/generate_unsual_code(no_logs = FALSE) + if(!check_rights(R_FUN)) + return + var/item_choice = tgui_alert(usr, "Should it be a random item?", "Loadout Choice", list("Yes", "No")) + if(!item_choice) + return + if(item_choice == "Yes") + item_choice = pick(GLOB.possible_lootbox_clothing) + else + item_choice = tgui_input_list(usr, "Please choose a loadout item to award", "Loadout Choice", GLOB.possible_lootbox_clothing) + if(!item_choice || !ispath(item_choice)) + return + + var/effect_choice = tgui_alert(usr, "Should it be a random effect?", "Loadout Choice", list("Yes", "No")) + if(!effect_choice) + return + var/static/list/possible_effects = subtypesof(/datum/component/particle_spewer) - /datum/component/particle_spewer/movement + if(effect_choice == "Yes") + effect_choice = pick(possible_effects) + else + effect_choice = tgui_input_list(usr, "Please choose an effect to give the item.", "Loadout Choice", possible_effects) + if(!effect_choice || !ispath(effect_choice)) + return + + reload_global_stored_codes() + var/string = generate_code_string() + + var/json_file = file(CODE_STORAGE_PATH) + + var/list/collated_data = list() + if(fexists(json_file)) + var/list/old_data = json_decode(file2text(json_file)) + collated_data += old_data + + collated_data["[string]"] = "unusual_path=[item_choice]&effect_path=[effect_choice]" //the BYOND code demons come for you + + var/payload = json_encode(collated_data) + fdel(json_file) + WRITE_FILE(json_file, payload) + reload_global_stored_codes() + if(!no_logs) + log_game("[usr] generated a new redemption code giving a [item_choice] with the unusual effect [effect_choice].") + message_admins("[usr] generated a new redemption code giving a [item_choice] with the unusual effect [effect_choice].") + to_chat(usr, span_big("Your generated code is: [string]")) + return string + +/proc/generate_code_string() + var/list/sections = list() + for(var/num in 1 to 5) + sections += random_string(5, GLOB.hex_characters) + + var/string = sections.Join("-") + return string + +/proc/reload_global_stored_codes() + GLOB.stored_codes = list() + var/json_file = file(CODE_STORAGE_PATH) + + if(!fexists(json_file)) + return + GLOB.stored_codes = json_decode(file2text(json_file)) /proc/generate_bulk_redemption_code() if(!check_rights(R_FUN)) return - var/choice = tgui_input_list(usr, "Please choose a code type", "Code generation", list("Coins", "Loadout Items", "Antag Tokens")) + var/choice = tgui_input_list(usr, "Please choose a code type", "Code generation", list("Coins", "Loadout Items", "Antag Tokens")) //no bulk unusuals if(!choice) return diff --git a/monkestation/code/modules/code_redemption/code_redeemer.dm b/monkestation/code/modules/code_redemption/code_redeemer.dm index d02aeaa14ea8..71bf96f9bfc5 100644 --- a/monkestation/code/modules/code_redemption/code_redeemer.dm +++ b/monkestation/code/modules/code_redemption/code_redeemer.dm @@ -22,12 +22,26 @@ GLOBAL_LIST_INIT(redeemed_codes, list()) return var/path = GLOB.stored_codes[code] + var/list/list_path = params2list(path) if(isnum(path)) usr.client.prefs.adjust_metacoins(usr.ckey, path, "Redeemed a Giveaway Code", donator_multipler = FALSE) else if(path == HIGH_THREAT || path == MEDIUM_THREAT || path == LOW_THREAT) usr.client.saved_tokens.adjust_tokens(path, 1) to_chat(usr, span_boldnotice("You have successfully redeemed a giveaway code for: [path] Antag Token.")) + else if(list_path["unusual_path"]) + var/obj/item/unusual = text2path(list_path["unusual_path"]) + unusual = new + var/pulled_key = usr.ckey + if(!pulled_key) + pulled_key = "MissingNo." // have fun trying to get this one lol + unusual.AddComponent(/datum/component/unusual_handler, particle_path = text2path(list_path["effect_path"]), fresh_unusual = TRUE, client_ckey = pulled_key) + usr.client.prefs.save_new_unusual(unusual) + to_chat(usr, span_greenannounce("You have successfully redeemed a giveaway code for: [unusual]")) + if(isliving(usr)) + unusual.forceMove(get_turf(usr)) + else + qdel(unusual) else var/pathedstring = text2path(path) var/datum/store_item/given_item = new pathedstring diff --git a/monkestation/code/modules/trading/box_rolling.dm b/monkestation/code/modules/trading/box_rolling.dm index 0a11c23127e8..585531fc61eb 100644 --- a/monkestation/code/modules/trading/box_rolling.dm +++ b/monkestation/code/modules/trading/box_rolling.dm @@ -105,8 +105,10 @@ qdel(src) -/proc/testing_trigger_lootbox() - var/mob/user = usr +/proc/testing_trigger_lootbox(mob/user = usr) + if(!user || !user.client) + return + user.overlay_fullscreen("lb_main", /atom/movable/screen/fullscreen/lootbox_overlay/main/guaranteed) /mob/proc/trigger_lootbox_on_self() diff --git a/monkestation/code/modules/trading/lootbox_clothing.dm b/monkestation/code/modules/trading/lootbox_clothing.dm new file mode 100644 index 000000000000..a38e596deeb5 --- /dev/null +++ b/monkestation/code/modules/trading/lootbox_clothing.dm @@ -0,0 +1,131 @@ +/datum/armor/lootbox_clothing + melee = 0 + bullet = 0 + laser = 0 + energy = 0 + bomb = 0 + bio = 10 //these are all pretty standard so they should be fine + fire = 30 + acid = 30 + wound = 0 + +//versions of clothing with low armor to get given by lootboxes +/obj/item/clothing/head/beanie/durathread/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/beret/durathread/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/beret/sec/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/caphat/beret/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/cowboy/black/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/cowboy/bounty/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/cowboy/brown/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/cowboy/grey/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/cowboy/red/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/cowboy/white/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/caphat/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/caphat/parade/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/centcom_cap/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/centhat/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/coordinator/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/hopcap/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/hos/beret/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/hos/cap/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/hos/shako/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/warden/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/warden/drill/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/hats/warden/red/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/nanotrasen_consultant/hubert/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/recruiter_cap/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/soft/sec/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/utility/hardhat/pumpkinhead/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/utility/hardhat/pumpkinhead/blumpkin/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/wizard/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/wizard/black/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) + +/obj/item/clothing/head/wizard/marisa/lootbox/Initialize(mapload) + . = ..() + set_armor(/datum/armor/lootbox_clothing) diff --git a/monkestation/code/modules/trading/lootbox_odds.dm b/monkestation/code/modules/trading/lootbox_odds.dm index 23103913df67..ea69f45f6510 100644 --- a/monkestation/code/modules/trading/lootbox_odds.dm +++ b/monkestation/code/modules/trading/lootbox_odds.dm @@ -1,4 +1,3 @@ - //global because its easier long term //also its own file to make it super easy //to find and adjust odds of lootbox rolls @@ -6,14 +5,7 @@ var/obj/item/temp switch(type_string) if("Unusual") - var/list/viable_hats = list( - /obj/item/clothing/head/caphat, - /obj/item/clothing/head/beanie, - /obj/item/clothing/head/beret, - ) - viable_hats += subtypesof(/obj/item/clothing/head/hats) - typesof(/obj/item/clothing/head/hats/hos) - /obj/item/clothing/head/hats/centcom_cap - /obj/item/clothing/head/hats/hopcap - /obj/item/clothing/head/hats/centhat - /obj/item/clothing/head/hats/warden - viable_hats += subtypesof(/obj/item/clothing/head/costume) - var/path = pick(viable_hats) + var/path = pick(GLOB.possible_lootbox_clothing) temp = new path var/list/viable_unusuals = subtypesof(/datum/component/particle_spewer) - /datum/component/particle_spewer/movement var/picked_path = pick(viable_unusuals) @@ -103,15 +95,130 @@ var/turf/turf = get_turf(usr) for(var/i = 1 to 20) - var/list/viable_hats = list( - /obj/item/clothing/head/caphat, - /obj/item/clothing/head/beanie, - /obj/item/clothing/head/beret, - ) - viable_hats += subtypesof(/obj/item/clothing/head/hats) - typesof(/obj/item/clothing/head/hats/hos) - /obj/item/clothing/head/hats/centcom_cap - /obj/item/clothing/head/hats/hopcap - /obj/item/clothing/head/hats/centhat - /obj/item/clothing/head/hats/warden - viable_hats += subtypesof(/obj/item/clothing/head/costume) - /obj/item/clothing/head/costume/nightcap - var/path = pick(viable_hats) + var/path = pick(GLOB.possible_lootbox_clothing) var/obj/item/temp = new path(turf) var/list/viable_unusuals = subtypesof(/datum/component/particle_spewer) - /datum/component/particle_spewer/movement var/picked_path = pick(viable_unusuals) temp.AddComponent(/datum/component/unusual_handler, particle_path = picked_path) + +///list of all clothing that can be rolled by lootboxes +GLOBAL_LIST_INIT(possible_lootbox_clothing, list( + /obj/item/clothing/head/avipilot, + /obj/item/clothing/head/beanie, + /obj/item/clothing/head/beanie/black, + /obj/item/clothing/head/beanie/christmas, + /obj/item/clothing/head/beanie/durathread/lootbox, + /obj/item/clothing/head/bee, + /obj/item/clothing/head/beret, + /obj/item/clothing/head/beret/durathread/lootbox, + /obj/item/clothing/head/beret/sec/lootbox, + /obj/item/clothing/head/caphat/beret/lootbox, + /obj/item/clothing/head/chameleon/broken, + /obj/item/clothing/head/chaplain/clownmitre, + /obj/item/clothing/head/cone, + /obj/item/clothing/head/costume/allies, + /obj/item/clothing/head/costume/bearpelt, + /obj/item/clothing/head/costume/bronze, + /obj/item/clothing/head/costume/bunnyhead, + /obj/item/clothing/head/costume/canada, + /obj/item/clothing/head/costume/cardborg, + /obj/item/clothing/head/costume/chicken, + /obj/item/clothing/head/costume/cirno, + /obj/item/clothing/head/costume/constable, + /obj/item/clothing/head/costume/crown, + /obj/item/clothing/head/costume/crown/fancy, + /obj/item/clothing/head/costume/cueball, + /obj/item/clothing/head/costume/dark_hos, + /obj/item/clothing/head/costume/deckers, + /obj/item/clothing/head/costume/delinquent, + /obj/item/clothing/head/costume/drfreezehat, + /obj/item/clothing/head/costume/festive, + /obj/item/clothing/head/costume/foilhat, + /obj/item/clothing/head/costume/football_helmet, + /obj/item/clothing/head/costume/garland, + /obj/item/clothing/head/costume/griffin, + /obj/item/clothing/head/costume/hasturhood, + /obj/item/clothing/head/costume/irs, + /obj/item/clothing/head/costume/jackbros, + /obj/item/clothing/head/costume/jester, + /obj/item/clothing/head/costume/jester/alt, + /obj/item/clothing/head/costume/justice, + /obj/item/clothing/head/costume/kitty, + /obj/item/clothing/head/costume/lizard, + /obj/item/clothing/head/costume/lobsterhat, + /obj/item/clothing/head/costume/maidheadband, + /obj/item/clothing/head/costume/mailman, + /obj/item/clothing/head/costume/nemes, + /obj/item/clothing/head/costume/nightcap/blue, + /obj/item/clothing/head/costume/nightcap/red, + /obj/item/clothing/head/costume/nursehat, + /obj/item/clothing/head/costume/papersack, + /obj/item/clothing/head/costume/papersack/smiley, + /obj/item/clothing/head/costume/pharaoh, + /obj/item/clothing/head/costume/pirate, + /obj/item/clothing/head/costume/pirate/bandana, + /obj/item/clothing/head/costume/pirate/captain, + /obj/item/clothing/head/costume/pot, + /obj/item/clothing/head/costume/powdered_wig, + /obj/item/clothing/head/costume/rabbitears, + /obj/item/clothing/head/costume/redcoat, + /obj/item/clothing/head/costume/rice_hat, + /obj/item/clothing/head/costume/santa, + /obj/item/clothing/head/costume/scarecrow_hat, + /obj/item/clothing/head/costume/shrine_wig, + /obj/item/clothing/head/costume/snowman, + /obj/item/clothing/head/costume/sombrero, + /obj/item/clothing/head/costume/space_marine, + /obj/item/clothing/head/costume/spacepolice, + /obj/item/clothing/head/costume/strigihat, + /obj/item/clothing/head/costume/tmc, + /obj/item/clothing/head/costume/tv_head/fov_less, + /obj/item/clothing/head/costume/ushanka, + /obj/item/clothing/head/costume/ushanka/frosty, + /obj/item/clothing/head/costume/weddingveil, + /obj/item/clothing/head/costume/witchwig, + /obj/item/clothing/head/costume/xenos, + /obj/item/clothing/head/costume/yuri, + /obj/item/clothing/head/cowboy/black/lootbox, + /obj/item/clothing/head/cowboy/bounty/lootbox, + /obj/item/clothing/head/cowboy/brown/lootbox, + /obj/item/clothing/head/cowboy/grey/lootbox, + /obj/item/clothing/head/cowboy/red/lootbox, + /obj/item/clothing/head/cowboy/white/lootbox, + /obj/item/clothing/head/fedora, + /obj/item/clothing/head/fedora/carpskin, + /obj/item/clothing/head/fedora/white, + /obj/item/clothing/head/hats/bowler, + /obj/item/clothing/head/hats/caphat/lootbox, + /obj/item/clothing/head/hats/caphat/parade/lootbox, + /obj/item/clothing/head/hats/centcom_cap/lootbox, + /obj/item/clothing/head/hats/centhat/lootbox, + /obj/item/clothing/head/hats/coordinator/lootbox, + /obj/item/clothing/head/hats/hopcap/lootbox, + /obj/item/clothing/head/hats/hos/beret/lootbox, + /obj/item/clothing/head/hats/hos/cap/lootbox, + /obj/item/clothing/head/hats/hos/shako/lootbox, + /obj/item/clothing/head/hats/intern, + /obj/item/clothing/head/hats/tophat, + /obj/item/clothing/head/hats/warden/lootbox, + /obj/item/clothing/head/hats/warden/drill/lootbox, + /obj/item/clothing/head/hats/warden/red/lootbox, + /obj/item/clothing/head/mikuhair, + /obj/item/clothing/head/morningstar, + /obj/item/clothing/head/mothcap, + /obj/item/clothing/head/nanner_crown, + /obj/item/clothing/head/nanotrasen_consultant/hubert/lootbox, + /obj/item/clothing/head/rasta, + /obj/item/clothing/head/recruiter_cap/lootbox, + /obj/item/clothing/head/saints, + /obj/item/clothing/head/soft/fishing_hat, //im tempted to make this extra rare + /obj/item/clothing/head/soft/rainbow, + /obj/item/clothing/head/soft/sec/lootbox, + /obj/item/clothing/head/utility/hardhat/pumpkinhead/lootbox, + /obj/item/clothing/head/utility/hardhat/pumpkinhead/blumpkin/lootbox, + /obj/item/clothing/head/waldo, + /obj/item/clothing/head/wizard/lootbox, + /obj/item/clothing/head/wizard/black/lootbox, + /obj/item/clothing/head/wizard/marisa/lootbox, + /obj/item/clothing/head/wonka, +)) diff --git a/tgstation.dme b/tgstation.dme index af7f0211c34f..c088ca91c50e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6551,6 +6551,7 @@ #include "monkestation\code\modules\surgery\organs\internal\tongue.dm" #include "monkestation\code\modules\trading\box_rolling.dm" #include "monkestation\code\modules\trading\lootbox_buying.dm" +#include "monkestation\code\modules\trading\lootbox_clothing.dm" #include "monkestation\code\modules\trading\lootbox_odds.dm" #include "monkestation\code\modules\trading\save_unusual_preference.dm" #include "monkestation\code\modules\trading\unusual_effects\_unusual_component.dm" From 270ca3581b9c16f8d65fa64b9fba66e4ebca8493 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 15 Dec 2023 02:48:40 -0800 Subject: [PATCH 40/60] sql again --- monkestation/code/datums/meta_tokens.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/monkestation/code/datums/meta_tokens.dm b/monkestation/code/datums/meta_tokens.dm index 12031c8c2d3e..276ea00c4ad2 100644 --- a/monkestation/code/datums/meta_tokens.dm +++ b/monkestation/code/datums/meta_tokens.dm @@ -83,6 +83,7 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( if(use_donor) if(donator_token) donator_token = FALSE + add_event_to_buffer(owner, data = "used donator token [owner.prefs.token_month].", log_key = "META") owner.prefs.token_month = text2num(time2text(world.time, "MM")) owner.prefs.save_preferences() return @@ -117,6 +118,7 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( return to_chat(owner, "Your request to play as [in_queue] has been approved.") + add_event_to_buffer(owner, data = "antag token for [in_queue] approved.", log_key = "META") spend_antag_token(in_queued_tier, queued_donor) if(!owner.mob.mind) owner.mob.mind_initialize() @@ -132,6 +134,7 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( return to_chat(owner, "Your request to play as [in_queue] has been denied.") + add_event_to_buffer(owner, data = "antag token for [in_queue] denied.", log_key = "META") in_queue = null in_queued_tier = null queued_donor = FALSE From 6f81683aaa8cfc506583c8e1d4448062d6506340 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 15 Dec 2023 02:51:24 -0800 Subject: [PATCH 41/60] rename --- code/__DEFINES/~monkestation/{_uplink.dm => uplink.dm} | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename code/__DEFINES/~monkestation/{_uplink.dm => uplink.dm} (100%) diff --git a/code/__DEFINES/~monkestation/_uplink.dm b/code/__DEFINES/~monkestation/uplink.dm similarity index 100% rename from code/__DEFINES/~monkestation/_uplink.dm rename to code/__DEFINES/~monkestation/uplink.dm diff --git a/tgstation.dme b/tgstation.dme index c088ca91c50e..772ba7d6e4c7 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -380,7 +380,6 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_spawner.dm" #include "code\__DEFINES\research\anomalies.dm" #include "code\__DEFINES\research\research_categories.dm" -#include "code\__DEFINES\~monkestation\_uplink.dm" #include "code\__DEFINES\~monkestation\access.dm" #include "code\__DEFINES\~monkestation\ai.dm" #include "code\__DEFINES\~monkestation\antagonists.dm" @@ -405,6 +404,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\virology.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_atom.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_carbon.dm" From c50d0d8ff0e727dca0593b30ace57e51f14346cf Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Fri, 15 Dec 2023 09:57:08 -0800 Subject: [PATCH 42/60] correct sql --- monkestation/code/datums/meta_tokens.dm | 2 ++ monkestation/code/modules/client/verbs.dm | 1 + 2 files changed, 3 insertions(+) diff --git a/monkestation/code/datums/meta_tokens.dm b/monkestation/code/datums/meta_tokens.dm index 276ea00c4ad2..e4d49cb1c017 100644 --- a/monkestation/code/datums/meta_tokens.dm +++ b/monkestation/code/datums/meta_tokens.dm @@ -158,6 +158,7 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( return to_chat(owner, "Your request to trigger [queued_token_event] has been approved.") + add_event_to_buffer(owner, data = "event tokens for [queued_token_event] approved.", log_key = "META") adjust_event_tokens(-queued_token_event.token_cost) SStwitch.add_to_queue(initial(queued_token_event.id_tag)) queued_token_event = null @@ -167,4 +168,5 @@ GLOBAL_LIST_INIT(patreon_etoken_values, list( return to_chat(owner, "Your request to trigger [queued_token_event] has been denied.") + add_event_to_buffer(owner, data = "event tokens for [queued_token_event] denied.", log_key = "META") queued_token_event = null diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index c2e6f50688c1..57e840af3048 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -109,6 +109,7 @@ GLOBAL_LIST_INIT(low_threat_antags, list( if(client_token_holder.event_tokens >= selected_event.token_cost) client_token_holder.queued_token_event = selected_event to_chat(src, "Your request has been sent.") + add_event_to_buffer(requestor, data = "has requested to use their event tokens to be a [selected_event].", log_key = "META") SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_admin("[span_prefix("TOKEN EVENT:")] [key_name(src)] \ [ADMIN_APPROVE_TOKEN_EVENT(src)] [ADMIN_REJECT_TOKEN_EVENT(src)] | \ [src] has requested use their event tokens to trigger [selected_event].")]") From 3a86269d3f937bdbcc7d68b6b5c1bf33ffc9b4ef Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Sat, 16 Dec 2023 21:34:13 -0800 Subject: [PATCH 43/60] no explosion --- code/modules/cargo/supplypod.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm index ef1776aa3eaa..9db511ea2775 100644 --- a/code/modules/cargo/supplypod.dm +++ b/code/modules/cargo/supplypod.dm @@ -76,7 +76,7 @@ specialised = TRUE style = STYLE_SYNDICATE bluespace = TRUE - explosionSize = list(0,0,1,2) + explosionSize = list(0,0,0,0) //monkestation edit: replaced list(0,0,1,2) delays = list(POD_TRANSIT = 25, POD_FALLING = 4, POD_OPENING = 30, POD_LEAVING = 30) reversing = TRUE stay_after_drop = TRUE From 74fffea20e03754c695de6a88e883d0e8fd26c9f Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Sat, 16 Dec 2023 22:55:35 -0800 Subject: [PATCH 44/60] real --- code/modules/clothing/head/soft_caps.dm | 3 ++- monkestation/code/modules/trading/lootbox_clothing.dm | 7 +++++++ monkestation/code/modules/trading/lootbox_odds.dm | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm index edca15b1c8ff..3bf8a7b8fd3b 100644 --- a/code/modules/clothing/head/soft_caps.dm +++ b/code/modules/clothing/head/soft_caps.dm @@ -169,4 +169,5 @@ /obj/item/clothing/head/soft/fishing_hat/Initialize(mapload) . = ..() - AddElement(/datum/element/skill_reward, /datum/skill/fishing) + if(add_element) //monkestation edit + AddElement(/datum/element/skill_reward, /datum/skill/fishing) diff --git a/monkestation/code/modules/trading/lootbox_clothing.dm b/monkestation/code/modules/trading/lootbox_clothing.dm index a38e596deeb5..cb323cf0c78d 100644 --- a/monkestation/code/modules/trading/lootbox_clothing.dm +++ b/monkestation/code/modules/trading/lootbox_clothing.dm @@ -9,6 +9,13 @@ acid = 30 wound = 0 +/obj/item/clothing/head/soft/fishing_hat + ///Do we add the skill reward element to this or not + var/add_element = TRUE + +/obj/item/clothing/head/soft/fishing_hat/lootbox + add_element = FALSE + //versions of clothing with low armor to get given by lootboxes /obj/item/clothing/head/beanie/durathread/lootbox/Initialize(mapload) . = ..() diff --git a/monkestation/code/modules/trading/lootbox_odds.dm b/monkestation/code/modules/trading/lootbox_odds.dm index ea69f45f6510..6bfe6de61bf8 100644 --- a/monkestation/code/modules/trading/lootbox_odds.dm +++ b/monkestation/code/modules/trading/lootbox_odds.dm @@ -211,7 +211,7 @@ GLOBAL_LIST_INIT(possible_lootbox_clothing, list( /obj/item/clothing/head/rasta, /obj/item/clothing/head/recruiter_cap/lootbox, /obj/item/clothing/head/saints, - /obj/item/clothing/head/soft/fishing_hat, //im tempted to make this extra rare + /obj/item/clothing/head/soft/fishing_hat/lootbox, //im tempted to make this extra rare /obj/item/clothing/head/soft/rainbow, /obj/item/clothing/head/soft/sec/lootbox, /obj/item/clothing/head/utility/hardhat/pumpkinhead/lootbox, From 490f8d37ef1ba68b74d4d65a517c08e9e4414648 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Sun, 17 Dec 2023 20:11:28 -0800 Subject: [PATCH 45/60] working codes --- monkestation/code/modules/code_redemption/code_redeemer.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/modules/code_redemption/code_redeemer.dm b/monkestation/code/modules/code_redemption/code_redeemer.dm index 71bf96f9bfc5..325080639d1d 100644 --- a/monkestation/code/modules/code_redemption/code_redeemer.dm +++ b/monkestation/code/modules/code_redemption/code_redeemer.dm @@ -31,7 +31,7 @@ GLOBAL_LIST_INIT(redeemed_codes, list()) to_chat(usr, span_boldnotice("You have successfully redeemed a giveaway code for: [path] Antag Token.")) else if(list_path["unusual_path"]) var/obj/item/unusual = text2path(list_path["unusual_path"]) - unusual = new + unusual = new unusual var/pulled_key = usr.ckey if(!pulled_key) pulled_key = "MissingNo." // have fun trying to get this one lol From 3700713b5f222bf485dbf1bdd60dbefb82ddbf94 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Mon, 18 Dec 2023 11:11:36 -0800 Subject: [PATCH 46/60] handling maybe --- .../code/modules/code_redemption/code_redeemer.dm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/monkestation/code/modules/code_redemption/code_redeemer.dm b/monkestation/code/modules/code_redemption/code_redeemer.dm index 325080639d1d..cb958c0c9f63 100644 --- a/monkestation/code/modules/code_redemption/code_redeemer.dm +++ b/monkestation/code/modules/code_redemption/code_redeemer.dm @@ -35,7 +35,13 @@ GLOBAL_LIST_INIT(redeemed_codes, list()) var/pulled_key = usr.ckey if(!pulled_key) pulled_key = "MissingNo." // have fun trying to get this one lol - unusual.AddComponent(/datum/component/unusual_handler, particle_path = text2path(list_path["effect_path"]), fresh_unusual = TRUE, client_ckey = pulled_key) + var/static/list/valid_effects = subtypesof(/datum/component/particle_spewer) - /datum/component/particle_spewer/movement + var/effect = text2path(list_path["effect_path"]) + if(!is_type_in_list(effect, valid_effects)) + var/fallback_effect = pick(valid_effects) + stack_trace("Redemption for an unusual code tried pass an invalid particle_path [effect]. Replacing with [fallback_effect].") + effect = fallback_effect + unusual.AddComponent(/datum/component/unusual_handler, particle_path = effect, fresh_unusual = TRUE, client_ckey = pulled_key) usr.client.prefs.save_new_unusual(unusual) to_chat(usr, span_greenannounce("You have successfully redeemed a giveaway code for: [unusual]")) if(isliving(usr)) From 399411f0392b88a4ccc530789bca6fc3d4e0115a Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Mon, 18 Dec 2023 21:09:30 -0800 Subject: [PATCH 47/60] dont mute --- .../code/modules/code_redemption/code_redeemer.dm | 10 +++++----- .../modules/mech_comp/objects/messages/regex_find.dm | 4 +++- monkestation/code/modules/mech_comp/vending_machine.dm | 2 +- .../trading/unusual_effects/animation_housing/rain.dm | 1 + tgstation.dme | 1 + 5 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 monkestation/code/modules/trading/unusual_effects/animation_housing/rain.dm diff --git a/monkestation/code/modules/code_redemption/code_redeemer.dm b/monkestation/code/modules/code_redemption/code_redeemer.dm index cb958c0c9f63..d52fc84126ee 100644 --- a/monkestation/code/modules/code_redemption/code_redeemer.dm +++ b/monkestation/code/modules/code_redemption/code_redeemer.dm @@ -36,12 +36,12 @@ GLOBAL_LIST_INIT(redeemed_codes, list()) if(!pulled_key) pulled_key = "MissingNo." // have fun trying to get this one lol var/static/list/valid_effects = subtypesof(/datum/component/particle_spewer) - /datum/component/particle_spewer/movement - var/effect = text2path(list_path["effect_path"]) - if(!is_type_in_list(effect, valid_effects)) + var/effect_path = text2path(list_path["effect_path"]) + if(!is_path_in_list(effect_path, valid_effects)) var/fallback_effect = pick(valid_effects) - stack_trace("Redemption for an unusual code tried pass an invalid particle_path [effect]. Replacing with [fallback_effect].") - effect = fallback_effect - unusual.AddComponent(/datum/component/unusual_handler, particle_path = effect, fresh_unusual = TRUE, client_ckey = pulled_key) + stack_trace("Redemption for an unusual code tried pass an invalid particle_path [effect_path]. Replacing with [fallback_effect].") + effect_path = fallback_effect + unusual.AddComponent(/datum/component/unusual_handler, particle_path = effect_path, fresh_unusual = TRUE, client_ckey = pulled_key) usr.client.prefs.save_new_unusual(unusual) to_chat(usr, span_greenannounce("You have successfully redeemed a giveaway code for: [unusual]")) if(isliving(usr)) diff --git a/monkestation/code/modules/mech_comp/objects/messages/regex_find.dm b/monkestation/code/modules/mech_comp/objects/messages/regex_find.dm index fecf3bde6f60..04206a3f69bb 100644 --- a/monkestation/code/modules/mech_comp/objects/messages/regex_find.dm +++ b/monkestation/code/modules/mech_comp/objects/messages/regex_find.dm @@ -1,3 +1,5 @@ +//nuked from orbit until fixed +/* //Thank you mark /obj/item/mcobject/messaging/regfind name = "regex find component" @@ -64,4 +66,4 @@ fire(stored_message, input) else input.cmd = R.match - fire(input) + fire(input)*/ diff --git a/monkestation/code/modules/mech_comp/vending_machine.dm b/monkestation/code/modules/mech_comp/vending_machine.dm index 35293de5ff7b..9fbf3d97d0e6 100644 --- a/monkestation/code/modules/mech_comp/vending_machine.dm +++ b/monkestation/code/modules/mech_comp/vending_machine.dm @@ -25,7 +25,7 @@ /obj/item/mcobject/messaging/microphone = STANDARD_COMPONENT_SUPPLY, /obj/item/mcobject/messaging/or = STANDARD_COMPONENT_SUPPLY, /obj/item/mcobject/messaging/pressure_sensor = STANDARD_COMPONENT_SUPPLY, - /obj/item/mcobject/messaging/regfind = STANDARD_COMPONENT_SUPPLY, +// /obj/item/mcobject/messaging/regfind = STANDARD_COMPONENT_SUPPLY, /obj/item/mcobject/messaging/regreplace = STANDARD_COMPONENT_SUPPLY, /obj/item/mcobject/messaging/relay = STANDARD_COMPONENT_SUPPLY, /obj/item/mcobject/messaging/signal_builder = STANDARD_COMPONENT_SUPPLY, diff --git a/monkestation/code/modules/trading/unusual_effects/animation_housing/rain.dm b/monkestation/code/modules/trading/unusual_effects/animation_housing/rain.dm new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/monkestation/code/modules/trading/unusual_effects/animation_housing/rain.dm @@ -0,0 +1 @@ + diff --git a/tgstation.dme b/tgstation.dme index 772ba7d6e4c7..7dd9511e3cb3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6562,6 +6562,7 @@ #include "monkestation\code\modules\trading\unusual_effects\animation_housing\galaxies.dm" #include "monkestation\code\modules\trading\unusual_effects\animation_housing\holy_steps.dm" #include "monkestation\code\modules\trading\unusual_effects\animation_housing\music.dm" +#include "monkestation\code\modules\trading\unusual_effects\animation_housing\rain.dm" #include "monkestation\code\modules\trading\unusual_effects\animation_housing\shooting_stars.dm" #include "monkestation\code\modules\trading\unusual_effects\animation_housing\skull_rain.dm" #include "monkestation\code\modules\trading\unusual_effects\animation_housing\snow.dm" From 6382bbaa7013ba2a04f432aa2669e6b0ad9ebb91 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 15:47:51 -0800 Subject: [PATCH 48/60] Update die_fate.dm --- monkestation/code/modules/twitch_bits/events/die_fate.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/modules/twitch_bits/events/die_fate.dm b/monkestation/code/modules/twitch_bits/events/die_fate.dm index 9487260add50..356cc4579d7e 100644 --- a/monkestation/code/modules/twitch_bits/events/die_fate.dm +++ b/monkestation/code/modules/twitch_bits/events/die_fate.dm @@ -3,7 +3,7 @@ event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER id_tag = T_EVENT_OOK_DIE_FATE - token_cost = 2500 + token_cost = 1000 /datum/twitch_event/free_wiz/run_event(name) . = ..() From 3bf3566bf851236309877d298931dfa4ddf697a8 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 15:48:31 -0800 Subject: [PATCH 49/60] Update random_item.dm --- monkestation/code/modules/twitch_bits/events/random_item.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/modules/twitch_bits/events/random_item.dm b/monkestation/code/modules/twitch_bits/events/random_item.dm index 981a54c37a2b..a7247b0abcea 100644 --- a/monkestation/code/modules/twitch_bits/events/random_item.dm +++ b/monkestation/code/modules/twitch_bits/events/random_item.dm @@ -3,7 +3,7 @@ event_duration = 1 SECONDS event_flags = TWITCH_AFFECTS_STREAMER id_tag = T_EVENT_GIVE_OOK_ITEM - token_cost = 1000 + token_cost = 100 /datum/twitch_event/give_smsword/run_event(name) . = ..() From 15a6373e316ada53831bf0e11c2b2cbce9fbf844 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 15:58:52 -0800 Subject: [PATCH 50/60] no conflict once again(hell) --- .../code/modules/{paperwork => _paperwork}/paper_premade.dm | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename monkestation/code/modules/{paperwork => _paperwork}/paper_premade.dm (100%) diff --git a/monkestation/code/modules/paperwork/paper_premade.dm b/monkestation/code/modules/_paperwork/paper_premade.dm similarity index 100% rename from monkestation/code/modules/paperwork/paper_premade.dm rename to monkestation/code/modules/_paperwork/paper_premade.dm diff --git a/tgstation.dme b/tgstation.dme index 7dd9511e3cb3..be1d3b0eb89e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5674,6 +5674,7 @@ #include "monkestation\code\game\objects\items\storage\boxes.dm" #include "monkestation\code\game\objects\items\storage\uplink_kits.dm" #include "monkestation\code\game\turfs\open\water.dm" +#include "monkestation\code\modules\_paperwork\paper_premade.dm" #include "monkestation\code\modules\admin\antag_tokens.dm" #include "monkestation\code\modules\admin\camera_view.dm" #include "monkestation\code\modules\admin\ggg\where_are_your_fingers.dm" @@ -6327,7 +6328,6 @@ #include "monkestation\code\modules\outdoors\code\datum\particle_weathers\weather_types\snow.dm" #include "monkestation\code\modules\outdoors\code\screen_alerts\alert.dm" #include "monkestation\code\modules\outdoors\code\sunlight\sunlight_object.dm" -#include "monkestation\code\modules\paperwork\paper_premade.dm" #include "monkestation\code\modules\pissing\bladder.dm" #include "monkestation\code\modules\pissing\emote.dm" #include "monkestation\code\modules\pissing\piss_effect.dm" From 0376dc9f464413b36679a2fd44d024ea0f5a12b3 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:02:57 -0800 Subject: [PATCH 51/60] Revert "no conflict once again(hell)" This reverts commit 15a6373e316ada53831bf0e11c2b2cbce9fbf844. --- .../code/modules/{_paperwork => paperwork}/paper_premade.dm | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename monkestation/code/modules/{_paperwork => paperwork}/paper_premade.dm (100%) diff --git a/monkestation/code/modules/_paperwork/paper_premade.dm b/monkestation/code/modules/paperwork/paper_premade.dm similarity index 100% rename from monkestation/code/modules/_paperwork/paper_premade.dm rename to monkestation/code/modules/paperwork/paper_premade.dm diff --git a/tgstation.dme b/tgstation.dme index be1d3b0eb89e..7dd9511e3cb3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5674,7 +5674,6 @@ #include "monkestation\code\game\objects\items\storage\boxes.dm" #include "monkestation\code\game\objects\items\storage\uplink_kits.dm" #include "monkestation\code\game\turfs\open\water.dm" -#include "monkestation\code\modules\_paperwork\paper_premade.dm" #include "monkestation\code\modules\admin\antag_tokens.dm" #include "monkestation\code\modules\admin\camera_view.dm" #include "monkestation\code\modules\admin\ggg\where_are_your_fingers.dm" @@ -6328,6 +6327,7 @@ #include "monkestation\code\modules\outdoors\code\datum\particle_weathers\weather_types\snow.dm" #include "monkestation\code\modules\outdoors\code\screen_alerts\alert.dm" #include "monkestation\code\modules\outdoors\code\sunlight\sunlight_object.dm" +#include "monkestation\code\modules\paperwork\paper_premade.dm" #include "monkestation\code\modules\pissing\bladder.dm" #include "monkestation\code\modules\pissing\emote.dm" #include "monkestation\code\modules\pissing\piss_effect.dm" From fe8cd1b5a1e3b83ba359abb36fe294afc3092233 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:08:25 -0800 Subject: [PATCH 52/60] its this again, so fun --- code/__DEFINES/~monkestation/{uplink.dm => _uplink.dm} | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename code/__DEFINES/~monkestation/{uplink.dm => _uplink.dm} (100%) diff --git a/code/__DEFINES/~monkestation/uplink.dm b/code/__DEFINES/~monkestation/_uplink.dm similarity index 100% rename from code/__DEFINES/~monkestation/uplink.dm rename to code/__DEFINES/~monkestation/_uplink.dm diff --git a/tgstation.dme b/tgstation.dme index 7dd9511e3cb3..e51e9263a970 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -380,6 +380,7 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_spawner.dm" #include "code\__DEFINES\research\anomalies.dm" #include "code\__DEFINES\research\research_categories.dm" +#include "code\__DEFINES\~monkestation\_uplink.dm" #include "code\__DEFINES\~monkestation\access.dm" #include "code\__DEFINES\~monkestation\ai.dm" #include "code\__DEFINES\~monkestation\antagonists.dm" @@ -404,7 +405,6 @@ #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\virology.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_atom.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_carbon.dm" From dcbd2896635dc447e384e713471b80e32d5b72da Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:15:49 -0800 Subject: [PATCH 53/60] just uh --- code/__DEFINES/~monkestation/{_uplink.dm => uplink.dm} | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename code/__DEFINES/~monkestation/{_uplink.dm => uplink.dm} (100%) diff --git a/code/__DEFINES/~monkestation/_uplink.dm b/code/__DEFINES/~monkestation/uplink.dm similarity index 100% rename from code/__DEFINES/~monkestation/_uplink.dm rename to code/__DEFINES/~monkestation/uplink.dm diff --git a/tgstation.dme b/tgstation.dme index e51e9263a970..7dd9511e3cb3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -380,7 +380,6 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_spawner.dm" #include "code\__DEFINES\research\anomalies.dm" #include "code\__DEFINES\research\research_categories.dm" -#include "code\__DEFINES\~monkestation\_uplink.dm" #include "code\__DEFINES\~monkestation\access.dm" #include "code\__DEFINES\~monkestation\ai.dm" #include "code\__DEFINES\~monkestation\antagonists.dm" @@ -405,6 +404,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\virology.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_atom.dm" #include "code\__DEFINES\~monkestation\dcs\signals\signals_carbon.dm" From 02a2060f3324eaf5db0abb2f8b568fb8e9ada604 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:39:20 -0800 Subject: [PATCH 54/60] Revert "Revert "no conflict once again(hell)"" This reverts commit 0376dc9f464413b36679a2fd44d024ea0f5a12b3. --- .../code/modules/{paperwork => _paperwork}/paper_premade.dm | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename monkestation/code/modules/{paperwork => _paperwork}/paper_premade.dm (100%) diff --git a/monkestation/code/modules/paperwork/paper_premade.dm b/monkestation/code/modules/_paperwork/paper_premade.dm similarity index 100% rename from monkestation/code/modules/paperwork/paper_premade.dm rename to monkestation/code/modules/_paperwork/paper_premade.dm diff --git a/tgstation.dme b/tgstation.dme index 7dd9511e3cb3..be1d3b0eb89e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5674,6 +5674,7 @@ #include "monkestation\code\game\objects\items\storage\boxes.dm" #include "monkestation\code\game\objects\items\storage\uplink_kits.dm" #include "monkestation\code\game\turfs\open\water.dm" +#include "monkestation\code\modules\_paperwork\paper_premade.dm" #include "monkestation\code\modules\admin\antag_tokens.dm" #include "monkestation\code\modules\admin\camera_view.dm" #include "monkestation\code\modules\admin\ggg\where_are_your_fingers.dm" @@ -6327,7 +6328,6 @@ #include "monkestation\code\modules\outdoors\code\datum\particle_weathers\weather_types\snow.dm" #include "monkestation\code\modules\outdoors\code\screen_alerts\alert.dm" #include "monkestation\code\modules\outdoors\code\sunlight\sunlight_object.dm" -#include "monkestation\code\modules\paperwork\paper_premade.dm" #include "monkestation\code\modules\pissing\bladder.dm" #include "monkestation\code\modules\pissing\emote.dm" #include "monkestation\code\modules\pissing\piss_effect.dm" From 77f4fda5766cfdae7e8ac340e9da640955692837 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:56:49 -0800 Subject: [PATCH 55/60] shut --- code/__DEFINES/~monkestation/{patreon.dm => _patreon.dm} | 0 tgstation.dme | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename code/__DEFINES/~monkestation/{patreon.dm => _patreon.dm} (100%) diff --git a/code/__DEFINES/~monkestation/patreon.dm b/code/__DEFINES/~monkestation/_patreon.dm similarity index 100% rename from code/__DEFINES/~monkestation/patreon.dm rename to code/__DEFINES/~monkestation/_patreon.dm diff --git a/tgstation.dme b/tgstation.dme index 73eb7a29a617..c968e94b7c1c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -378,6 +378,7 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_spawner.dm" #include "code\__DEFINES\research\anomalies.dm" #include "code\__DEFINES\research\research_categories.dm" +#include "code\__DEFINES\~monkestation\_patreon.dm" #include "code\__DEFINES\~monkestation\access.dm" #include "code\__DEFINES\~monkestation\admin.dm" #include "code\__DEFINES\~monkestation\ai.dm" @@ -397,7 +398,6 @@ #include "code\__DEFINES\~monkestation\mecha.dm" #include "code\__DEFINES\~monkestation\misc.dm" #include "code\__DEFINES\~monkestation\mobs.dm" -#include "code\__DEFINES\~monkestation\patreon.dm" #include "code\__DEFINES\~monkestation\robots.dm" #include "code\__DEFINES\~monkestation\smoothing.dm" #include "code\__DEFINES\~monkestation\span.dm" From 8ccca92ee2de71a184f74bc228ef21c8f13db41f Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 17:50:15 -0800 Subject: [PATCH 56/60] copy error --- monkestation/code/modules/client/verbs.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index 57e840af3048..e78ffe388a93 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -109,7 +109,7 @@ GLOBAL_LIST_INIT(low_threat_antags, list( if(client_token_holder.event_tokens >= selected_event.token_cost) client_token_holder.queued_token_event = selected_event to_chat(src, "Your request has been sent.") - add_event_to_buffer(requestor, data = "has requested to use their event tokens to be a [selected_event].", log_key = "META") + add_event_to_buffer(usr, data = "has requested to use their event tokens to be a [selected_event].", log_key = "META") SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_admin("[span_prefix("TOKEN EVENT:")] [key_name(src)] \ [ADMIN_APPROVE_TOKEN_EVENT(src)] [ADMIN_REJECT_TOKEN_EVENT(src)] | \ [src] has requested use their event tokens to trigger [selected_event].")]") From 7b35a0fe27233ee723cd7e9deb85082336130b30 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 18:56:31 -0800 Subject: [PATCH 57/60] I LOVE LOGS --- monkestation/code/modules/client/verbs.dm | 30 ++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index e78ffe388a93..f1bb30a18ad2 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -87,26 +87,47 @@ GLOBAL_LIST_INIT(low_threat_antags, list( if(!isobserver(mob)) to_chat(src, "You can only trigger events as a ghost.") - + return + //I SURE DO LOVE WORKS ON LOCAL + var/static/list/logged = list() + if(!logged["one"]) + stack_trace("ONE") + logged["one"] = TRUE var/static/list/event_list if(!event_list) + if(!logged["two"]) + stack_trace("TWO") + logged["two"] = TRUE event_list = list() for(var/event as anything in SStwitch.twitch_events_by_type) var/datum/twitch_event/event_instance = SStwitch.twitch_events_by_type[event] if(!event_instance.token_cost) continue event_list += event_instance - + if(!logged["three"]) + stack_trace("THREE") + logged["three"] = TRUE client_token_holder.check_event_tokens(src) - + if(!logged["four"]) + stack_trace("FOUR") + logged["four"] = TRUE var/datum/twitch_event/selected_event = tgui_input_list(src, "Event tokens: [client_token_holder.event_tokens]", "Choose an event to trigger", event_list) if(!selected_event) + if(!logged["five"]) + stack_trace("FIVE") + logged["five"] = TRUE return var/confirm = tgui_alert(src, "Are you sure you want to trigger [selected_event.event_name]? It will cost [selected_event.token_cost] event tokens.", "Trigger token event", \ list("Yes", "No")) if(confirm == "Yes") + if(!logged["six"]) + stack_trace("SIX") + logged["six"] = TRUE if(client_token_holder.event_tokens >= selected_event.token_cost) + if(!logged["seven"]) + stack_trace("SEVEN") + logged["seven"] = TRUE client_token_holder.queued_token_event = selected_event to_chat(src, "Your request has been sent.") add_event_to_buffer(usr, data = "has requested to use their event tokens to be a [selected_event].", log_key = "META") @@ -114,6 +135,9 @@ GLOBAL_LIST_INIT(low_threat_antags, list( [ADMIN_APPROVE_TOKEN_EVENT(src)] [ADMIN_REJECT_TOKEN_EVENT(src)] | \ [src] has requested use their event tokens to trigger [selected_event].")]") return + if(!logged["eight"]) + stack_trace("EIGHT") + logged["eight"] = TRUE to_chat(src, "You dont have enough tokens to trigger this event.") #undef ADMIN_APPROVE_ANTAG_TOKEN From f30dc782b3dec422d463d8ee89a1a7e8d8b77741 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 19:14:17 -0800 Subject: [PATCH 58/60] minor fix --- monkestation/code/datums/meta_tokens.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkestation/code/datums/meta_tokens.dm b/monkestation/code/datums/meta_tokens.dm index e4d49cb1c017..912bbc7eb6cf 100644 --- a/monkestation/code/datums/meta_tokens.dm +++ b/monkestation/code/datums/meta_tokens.dm @@ -3,7 +3,7 @@ GLOBAL_LIST_INIT(used_monthly_token, list()) ///assoc list of how many event tokens each role gets each month GLOBAL_LIST_INIT(patreon_etoken_values, list( NO_RANK = 0, - RANK_TANKS = 100, + THANKS_RANK = 100, ASSISTANT_RANK = 500, COMMAND_RANK = 1000, TRAITOR_RANK = 2500, From a3f3d4674e276bf57e4235ae5dc8ce284f6b99f9 Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Tue, 19 Dec 2023 19:23:22 -0800 Subject: [PATCH 59/60] dont --- monkestation/code/modules/client/verbs.dm | 29 +++-------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index f1bb30a18ad2..d69fab075ee0 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -88,46 +88,26 @@ GLOBAL_LIST_INIT(low_threat_antags, list( if(!isobserver(mob)) to_chat(src, "You can only trigger events as a ghost.") return - //I SURE DO LOVE WORKS ON LOCAL - var/static/list/logged = list() - if(!logged["one"]) - stack_trace("ONE") - logged["one"] = TRUE + var/static/list/event_list if(!event_list) - if(!logged["two"]) - stack_trace("TWO") - logged["two"] = TRUE event_list = list() for(var/event as anything in SStwitch.twitch_events_by_type) var/datum/twitch_event/event_instance = SStwitch.twitch_events_by_type[event] if(!event_instance.token_cost) continue event_list += event_instance - if(!logged["three"]) - stack_trace("THREE") - logged["three"] = TRUE + client_token_holder.check_event_tokens(src) - if(!logged["four"]) - stack_trace("FOUR") - logged["four"] = TRUE + var/datum/twitch_event/selected_event = tgui_input_list(src, "Event tokens: [client_token_holder.event_tokens]", "Choose an event to trigger", event_list) if(!selected_event) - if(!logged["five"]) - stack_trace("FIVE") - logged["five"] = TRUE return var/confirm = tgui_alert(src, "Are you sure you want to trigger [selected_event.event_name]? It will cost [selected_event.token_cost] event tokens.", "Trigger token event", \ list("Yes", "No")) if(confirm == "Yes") - if(!logged["six"]) - stack_trace("SIX") - logged["six"] = TRUE if(client_token_holder.event_tokens >= selected_event.token_cost) - if(!logged["seven"]) - stack_trace("SEVEN") - logged["seven"] = TRUE client_token_holder.queued_token_event = selected_event to_chat(src, "Your request has been sent.") add_event_to_buffer(usr, data = "has requested to use their event tokens to be a [selected_event].", log_key = "META") @@ -135,9 +115,6 @@ GLOBAL_LIST_INIT(low_threat_antags, list( [ADMIN_APPROVE_TOKEN_EVENT(src)] [ADMIN_REJECT_TOKEN_EVENT(src)] | \ [src] has requested use their event tokens to trigger [selected_event].")]") return - if(!logged["eight"]) - stack_trace("EIGHT") - logged["eight"] = TRUE to_chat(src, "You dont have enough tokens to trigger this event.") #undef ADMIN_APPROVE_ANTAG_TOKEN From da803ac455afad7ec98aae120d7eb2802054fbcd Mon Sep 17 00:00:00 2001 From: wraith-54321 <69217972+wraith-54321@users.noreply.github.com> Date: Thu, 21 Dec 2023 19:24:18 -0800 Subject: [PATCH 60/60] Update verbs.dm --- monkestation/code/modules/client/verbs.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index d69fab075ee0..e6252599d038 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -110,10 +110,10 @@ GLOBAL_LIST_INIT(low_threat_antags, list( if(client_token_holder.event_tokens >= selected_event.token_cost) client_token_holder.queued_token_event = selected_event to_chat(src, "Your request has been sent.") - add_event_to_buffer(usr, data = "has requested to use their event tokens to be a [selected_event].", log_key = "META") + add_event_to_buffer(usr, data = "has requested to use their event tokens to trigger [selected_event.event_name]([selected_event]).", log_key = "META") SEND_NOTFIED_ADMIN_MESSAGE('sound/items/bikehorn.ogg', "[span_admin("[span_prefix("TOKEN EVENT:")] [key_name(src)] \ [ADMIN_APPROVE_TOKEN_EVENT(src)] [ADMIN_REJECT_TOKEN_EVENT(src)] | \ - [src] has requested use their event tokens to trigger [selected_event].")]") + [src] has requested use their event tokens to trigger [selected_event.event_name]([selected_event]).")]") return to_chat(src, "You dont have enough tokens to trigger this event.")