From 15ced36330fcd3270092a12b4de64f5a30fee775 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Tue, 12 Mar 2024 08:58:27 +0000 Subject: [PATCH 01/62] Directive framework --- beestation.dme | 3 ++ .../traitor/directives/priority_directive.dm | 29 +++++++++++++++++++ .../secure_deaddrop/deaddrop_box.dm | 0 .../secure_deaddrop/secure_deaddrop.dm | 5 ++++ 4 files changed, 37 insertions(+) create mode 100644 code/modules/antagonists/traitor/directives/priority_directive.dm create mode 100644 code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm create mode 100644 code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm diff --git a/beestation.dme b/beestation.dme index e5912ee36fe4a..433b4a82132b9 100644 --- a/beestation.dme +++ b/beestation.dme @@ -2122,6 +2122,9 @@ #include "code\modules\antagonists\traitor\backstory\traitor_backstory_ui.dm" #include "code\modules\antagonists\traitor\backstory\traitor_datum_backstory.dm" #include "code\modules\antagonists\traitor\backstory\traitor_factions.dm" +#include "code\modules\antagonists\traitor\directives\priority_directive.dm" +#include "code\modules\antagonists\traitor\directives\secure_deaddrop\deaddrop_box.dm" +#include "code\modules\antagonists\traitor\directives\secure_deaddrop\secure_deaddrop.dm" #include "code\modules\antagonists\traitor\equipment\contractor.dm" #include "code\modules\antagonists\traitor\equipment\Malf_Modules.dm" #include "code\modules\antagonists\traitor\IAA\internal_affairs.dm" diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm new file mode 100644 index 0000000000000..78184848bdbf2 --- /dev/null +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -0,0 +1,29 @@ +/datum/priority_directive + var/name + var/desc + +/datum/priority_directive/New() + . = ..() + +/// Activate the directive, requires a list of traitor datums and security minsd +/datum/priority_directive/proc/activate(list/antag_datums, list/player_minds) + SHOULD_NOT_OVERRIDE(TRUE) + +/// Advertise this directive to security objectives consoles +/datum/priority_directive/proc/advertise_security() + SHOULD_NOT_OVERRIDE(TRUE) + +/// Pick a random target with some specified restrictions +/datum/priority_directive/proc/get_random_target(list/player_minds, list/allowed_roles = null, list/disallowed_roles = null) + SHOULD_NOT_OVERRIDE(TRUE) + var/list/targets = list() + for (var/datum/mind/mind in player_minds) + var/mob/living/mob = mind.current + if (!ishuman(mob) || !is_station_level(mob.z)) + continue + if (allowed_roles && !(mind.assigned_role in allowed_roles) && !(mind.special_role in allowed_roles))) + continue + if (disallowed_roles && (mind.assigned_role in disallowed_roles || mind.special_role in disallowed_roles)) + continue + targets += mind + return pick(targets) diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm new file mode 100644 index 0000000000000..fe4668de7bedc --- /dev/null +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -0,0 +1,5 @@ +/datum/priority_directive/deaddrop + name = "Secure Deaddrop" + desc = "We have identified a deaddrop that has been placed by a rival spy agency and have maintained an accurate track on the box. \ + You have the option to track and secure the valuable items before anyone else gets to them. The items are stored in a trackable \ + box which will automatically unlock after a set period of time." From f672e583c1f9f95815e0ccc3920f88ec43ebb85c Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:55:19 +0000 Subject: [PATCH 02/62] Directives --- beestation.dme | 1 + .../subsystem/priority_directives.dm | 33 ++++++++++ code/datums/components/uplink.dm | 3 + code/datums/mind.dm | 4 +- code/game/alternate_appearance.dm | 14 +++++ code/game/gamemodes/objectives/_objective.dm | 42 +++++++++---- .../gamemodes/objectives/stash_component.dm | 62 ++++++++++++------- .../traitor/directives/priority_directive.dm | 19 +++++- .../secure_deaddrop/deaddrop_box.dm | 21 +++++++ .../secure_deaddrop/secure_deaddrop.dm | 20 ++++++ code/modules/uplink/uplink_items.dm | 1 + 11 files changed, 180 insertions(+), 40 deletions(-) create mode 100644 code/controllers/subsystem/priority_directives.dm diff --git a/beestation.dme b/beestation.dme index 433b4a82132b9..2eea030c5fa18 100644 --- a/beestation.dme +++ b/beestation.dme @@ -442,6 +442,7 @@ #include "code\controllers\subsystem\pathfinder.dm" #include "code\controllers\subsystem\persistence.dm" #include "code\controllers\subsystem\preferences.dm" +#include "code\controllers\subsystem\priority_directives.dm" #include "code\controllers\subsystem\profiler.dm" #include "code\controllers\subsystem\radiation.dm" #include "code\controllers\subsystem\radio.dm" diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm new file mode 100644 index 0000000000000..05b2750953ed5 --- /dev/null +++ b/code/controllers/subsystem/priority_directives.dm @@ -0,0 +1,33 @@ +SUBSYSTEM_DEF(directives) + name = "Priority Directives" + wait = 10 SECONDS + var/list/current = list() + var/datum/priority_directive/directive = null + var/next_directive_time + +/datum/controller/subsystem/directives/Initialize(start_timeofday) + . = ..() + next_directive_time = world.time + rand(20 MINUTES, 30 MINUTES) + +/datum/controller/subsystem/directives/fire(resumed) + if (directive) + // Are we completed or ended? + if (directive.is_completed() || world.time > directive.end_at) + directive.finish() + return + // Check if we are ready to spawn our next directive + if (world.time < next_directive_time) + return + // Identify all the uplinks and spawn a directive + if (!resumed) + // Find all uplinks + for (var/mob/antag in SSticker.mode.current_players[CURRENT_LIVING_ANTAGS]) + var/datum/component/uplink/uplink = antag.find_syndicate_uplink() + if (!uplink) + continue + current += uplink + if (!length(current)) + can_fire = FALSE + // Bring on the mission + directive = new /obj/item/storage/deaddrop_box() + directive.activate() diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index aaae9dc4770b2..1bcfc70aa4197 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -68,6 +68,9 @@ previous_attempts = list() + // We need to start running this now + SSdirectives.can_fire = TRUE + /datum/component/uplink/InheritComponent(datum/component/uplink/U) lockable |= U.lockable active |= U.active diff --git a/code/datums/mind.dm b/code/datums/mind.dm index baac761495270..2858aed2ac5f6 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -79,8 +79,8 @@ /// A holder datum used to handle holoparasites and their shared behavior. var/datum/holoparasite_holder/holoparasite_holder - /// The atom of our antag stash - var/atom/antag_stash = null + /// A list of all antag stashes that we can see + var/list/antag_stashes = null /// Boolean value indicating if the mob attached to this mind entered cryosleep. var/cryoed = FALSE diff --git a/code/game/alternate_appearance.dm b/code/game/alternate_appearance.dm index c721323a5ea5d..ff31a601a4c5c 100644 --- a/code/game/alternate_appearance.dm +++ b/code/game/alternate_appearance.dm @@ -193,6 +193,20 @@ GLOBAL_LIST_EMPTY(active_alternate_appearances) seer = M add_hud_to(seer) +/datum/atom_hud/alternate_appearance/basic/some_people + var/list/seers + +/datum/atom_hud/alternate_appearance/basic/some_people/mobShouldSee(mob/M) + if(M in seers) + return TRUE + return FALSE + +/datum/atom_hud/alternate_appearance/basic/some_people/New(key, image/I, list/mobs) + ..(key, I, FALSE) + seers = mobs + for (var/mob/seer in mobs) + add_hud_to(seer) + /datum/atom_hud/alternate_appearance/basic/heretics add_ghost_version = FALSE //just in case, to prevent infinite loops diff --git a/code/game/gamemodes/objectives/_objective.dm b/code/game/gamemodes/objectives/_objective.dm index 042cb38a17869..9df471eb5526f 100644 --- a/code/game/gamemodes/objectives/_objective.dm +++ b/code/game/gamemodes/objectives/_objective.dm @@ -225,13 +225,26 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list explanation_text = team_explanation_text /datum/objective/proc/generate_stash(list/special_equipment) - var/datum/mind/receiver = pick(get_owners()) - var/obj/item/storage/backpack/satchel/flat/empty/secret_bag = receiver.antag_stash + var/list/owners = get_owners() + var/datum/mind/tester = pick(owners) + var/obj/item/storage/secret_bag = null + for (var/datum/component/stash/stash in tester.antag_stashes) + // Is this a valid stash + // Must be owned exclusively by our owners + var/valid = TRUE + for (var/datum/mind/mind in stash.stash_minds) + if (!(mind in team.members)) + valid = FALSE + break + if (!valid) + continue + // Must be something that we can store in + if (!istype(stash.parent, /obj/item/storage)) + continue + secret_bag = stash.parent //Find and generate the stash if(!secret_bag) - secret_bag = new() - // Hard-del handling is done by the component - receiver.antag_stash = secret_bag + secret_bag = new /obj/item/storage/backpack/satchel/flat/empty() var/atom_text = "" switch (pick_weight(list("airlock" = 3))) if("airlock") @@ -249,19 +262,22 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list if (!(area.area_flags & HIDDEN_STASH_LOCATION)) continue //This airlock is good for us - A.AddComponent(/datum/component/stash, receiver, secret_bag) + var/stash_comp = A.AddComponent(/datum/component/stash, owners, secret_bag) + for (var/datum/mind/receiver in owners) + if (!islist(receiver.antag_stashes)) + receiver.antag_stashes = list() + receiver.antag_stashes += stash_comp break //Failsafe if(!secret_bag.loc) atom_text = "You" - message_admins("Could not find a location to put [ADMIN_FLW(receiver.current)]'s stash.") - secret_bag.forceMove(get_turf(receiver.current)) - receiver.current.equip_to_appropriate_slot(secret_bag) - // Remove this from memory since the component deals with hard-dels - receiver.antag_stash = null + message_admins("Could not find a location to put [ADMIN_FLW(tester.current)]'s stash.") + secret_bag.forceMove(get_turf(tester.current)) + tester.current.equip_to_appropriate_slot(secret_bag) //Update the mind - receiver.store_memory("You have a secret stash of items hidden on the station required for your objectives. It is hidden inside of [atom_text] ([secret_bag.loc]) located at [get_area(secret_bag.loc)] [COORD(secret_bag.loc)], you may have to search around for it. (Use alt click on the object the stash is inside to access it).") - to_chat(receiver?.current, "You have a secret stash at [get_area(secret_bag)], more details are stored in your notes. (IC > Notes)") + for (var/datum/mind/receiver in owners) + receiver.store_memory("You have a secret stash of items hidden on the station required for your objectives. It is hidden inside of [atom_text] ([secret_bag.loc]) located at [get_area(secret_bag.loc)] [COORD(secret_bag.loc)], you may have to search around for it. (Use alt click on the object the stash is inside to access it).") + to_chat(receiver?.current, "You have a secret stash at [get_area(secret_bag)], more details are stored in your notes. (IC > Notes)") //Create the objects in the bag for(var/eq_path in special_equipment) new eq_path(secret_bag) diff --git a/code/game/gamemodes/objectives/stash_component.dm b/code/game/gamemodes/objectives/stash_component.dm index 3e5d803d6c24a..aaf0afb560bc0 100644 --- a/code/game/gamemodes/objectives/stash_component.dm +++ b/code/game/gamemodes/objectives/stash_component.dm @@ -1,33 +1,38 @@ /datum/component/stash dupe_mode = COMPONENT_DUPE_ALLOWED var/atom/movable/stash_item - var/datum/mind/stash_owner + var/list/stash_minds -/datum/component/stash/Initialize(datum/mind/stash_owner, atom/movable/stash_item) +/datum/component/stash/Initialize(list/stash_minds, atom/movable/stash_item) src.stash_item = stash_item - src.stash_owner = stash_owner + src.stash_minds = islist(stash_minds) ? stash_minds : list(stash_minds) //No thing - if(!isatom(stash_item) || !istype(stash_owner) || !isatom(parent)) + if(!isatom(stash_item) || !length(stash_minds) || !isatom(parent)) return COMPONENT_INCOMPATIBLE stash_item.forceMove(parent) RegisterSignal(stash_item, COMSIG_PARENT_QDELETING, PROC_REF(stash_destroyed)) - RegisterSignal(stash_owner, COMSIG_PARENT_QDELETING, PROC_REF(owner_deleted)) - RegisterSignal(stash_owner, COMSIG_MIND_TRANSFER_TO, PROC_REF(transfer_mind)) + RegisterSignal(stash_item, COMSIG_MOVABLE_MOVED, PROC_REF(stash_item_moved)) + for (var/datum/mind/mind in stash_minds) + RegisterSignal(mind, COMSIG_PARENT_QDELETING, PROC_REF(owner_deleted)) + RegisterSignal(mind, COMSIG_MIND_TRANSFER_TO, PROC_REF(transfer_mind)) RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(access_stash)) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine)) create_owner_icon(parent) /datum/component/stash/Destroy(force, silent) - if(stash_item) + if(!QDELETED(stash_item)) + UnregisterSignal(stash_item, COMSIG_PARENT_QDELETING) + UnregisterSignal(stash_item, COMSIG_MOVABLE_MOVED) //Drop the stash to the ground stash_item.forceMove(get_turf(stash_item)) - UnregisterSignal(stash_item, COMSIG_PARENT_QDELETING) - if(stash_owner) - UnregisterSignal(stash_owner, COMSIG_PARENT_QDELETING) + stash_item = null + for (var/datum/mind/mind in stash_minds) + mind.antag_stashes -= src + UnregisterSignal(mind, COMSIG_PARENT_QDELETING) UnregisterSignal(parent, COMSIG_CLICK_ALT) // Clear the alt appearance var/atom/owner = parent @@ -35,23 +40,25 @@ . = ..() /datum/component/stash/proc/create_owner_icon(atom/owner) - if (!stash_owner.current) - return var/image/overlay = image(icon = 'icons/obj/storage/backpack.dmi', icon_state = "satchel-flat", loc = owner) overlay.appearance_flags = RESET_ALPHA overlay.alpha = 160 overlay.plane = HUD_PLANE - owner.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/one_person, "stash_overlay", overlay, stash_owner.current) + var/list/seers = list() + for (var/datum/mind/mind in stash_minds) + seers += mind.current + owner.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/some_people, "stash_overlay", overlay, seers) /datum/component/stash/proc/transfer_mind(datum/source, mob/old_mob, mob/new_mob) SIGNAL_HANDLER + // Regenerate the stash icons when a mind changes mobs, to fix the alt appearances var/atom/owner = parent owner.remove_alt_appearance("stash_overlay") create_owner_icon(owner) /datum/component/stash/proc/on_examine(datum/source, mob/viewer, list/examine_text) SIGNAL_HANDLER - if (viewer?.mind == stash_owner) + if (viewer?.mind in stash_minds) examine_text += "You have a stash hidden here! Use Alt-Click to access it." /datum/component/stash/proc/access_stash(datum/source, mob/user) @@ -61,12 +68,14 @@ /datum/component/stash/proc/try_access_stash(mob/user) //Not the owner of this stash - if (user.mind != stash_owner) + if (!(user.mind in stash_minds)) return to_chat(user, "You begin removing your stash from [parent]...") if(!do_after(user, 5 SECONDS, parent)) return to_chat(user, "You remove your stash from [parent].") + // Unregister this before moving the stash item + UnregisterSignal(stash_item, COMSIG_MOVABLE_MOVED) //Put in hand stash_item.forceMove(get_turf(user)) user.put_in_hands(stash_item) @@ -76,15 +85,22 @@ //Stash is now used up qdel(src) -/datum/component/stash/proc/owner_deleted(datum/source, force) +/datum/component/stash/proc/owner_deleted(datum/mind/source, force) SIGNAL_HANDLER - stash_owner.antag_stash = null - stash_owner = null - qdel(src) + var/atom/owner = parent + source.antag_stashes -= src + stash_minds -= source + if (!length(stash_minds)) + qdel(src) + else + owner.remove_alt_appearance("stash_overlay") + create_owner_icon(owner) /datum/component/stash/proc/stash_destroyed(datum/source, force) SIGNAL_HANDLER - stash_item = null - if (stash_owner) - stash_owner.antag_stash = null - UnregisterSignal(stash_item, COMSIG_PARENT_QDELETING) + qdel(src) + +/datum/component/stash/proc/stash_item_moved(datum/source, atom/newLoc, dir) + SIGNAL_HANDLER + if (newLoc != parent) + qdel(src) diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 78184848bdbf2..2a39047359285 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -1,10 +1,20 @@ /datum/priority_directive var/name var/desc + var/end_at /datum/priority_directive/New() . = ..() +/// Return the reward type and amount +/datum/priority_directive/proc/generate(list/antag_datums, list/player_minds) + +/// Check if we have finished early. We always complete after a set time period. +/datum/priority_directive/proc/is_completed() + return FALSE + +/datum/priority_directive/proc/finish() + /// Activate the directive, requires a list of traitor datums and security minsd /datum/priority_directive/proc/activate(list/antag_datums, list/player_minds) SHOULD_NOT_OVERRIDE(TRUE) @@ -21,9 +31,14 @@ var/mob/living/mob = mind.current if (!ishuman(mob) || !is_station_level(mob.z)) continue - if (allowed_roles && !(mind.assigned_role in allowed_roles) && !(mind.special_role in allowed_roles))) + if (allowed_roles && !(mind.assigned_role in allowed_roles) && !(mind.special_role in allowed_roles)) continue - if (disallowed_roles && (mind.assigned_role in disallowed_roles || mind.special_role in disallowed_roles)) + if (disallowed_roles && ((mind.assigned_role in disallowed_roles) || (mind.special_role in disallowed_roles))) continue targets += mind return pick(targets) + +/datum/priority_directive/proc/get_independent_difficulty() + +/datum/priority_directive/proc/tc_curve(input) + return input diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm index e69de29bb2d1d..38b65fb7edadb 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm @@ -0,0 +1,21 @@ +/// Deaddrop box, cannot be opened until it is released +/obj/item/storage/deaddrop_box + name = "secured box" + desc = "A secure box that probably contains a variety of items the \ + average crewmember probably wouldn't want around the station." + w_class = WEIGHT_CLASS_NORMAL + // Prevent it from being opened until it is ready to be opened + obj_flags = INDESTRUCTIBLE + component_type = /datum/component/storage/concrete/deaddrop + +/obj/item/storage/deaddrop_box/proc/unlock() + // You can now break it to your hearts desire + obj_flags &= ~INDESTRUCTIBLE + var/datum/component/storage = GetComponent(/datum/component/storage) + storage.locked = FALSE + +/datum/component/storage/concrete/deaddrop + locked = TRUE + can_transfer = FALSE + emp_shielded = TRUE + quickdraw = TRUE diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index fe4668de7bedc..c72796094b810 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -3,3 +3,23 @@ desc = "We have identified a deaddrop that has been placed by a rival spy agency and have maintained an accurate track on the box. \ You have the option to track and secure the valuable items before anyone else gets to them. The items are stored in a trackable \ box which will automatically unlock after a set period of time." + var/obj/item/storage/deaddrop_box/target + +/datum/priority_directive/deaddrop/generate(list/antag_datums, list/player_minds) + // Spawn the deaddrop package + target = new() + var/tc_count = tc_curve(get_independent_difficulty()) + new /obj/item/stack/sheet/telecrystal(target, tc_count) + // Put the deaddrop somewhere + var/list/antag_minds = list() + for (var/datum/antagonist/antag in antag_datums) + antag_minds += antag.owner + new /datum/component/stash(antag_minds, target) + // Return the reward generated + return list( + /obj/item/stack/sheet/telecrystal = tc_count, + ) + +/datum/priority_directive/deaddrop/finish(list/antag_datums, list/player_minds) + . = ..() + target.unlock() diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 73c1eb082e21a..9c679e6528aaf 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -1,4 +1,5 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) + /proc/get_uplink_items(uplink_flag, allow_sales = TRUE, allow_restricted = TRUE) var/list/filtered_uplink_items = list() var/list/sale_items = list() From 22bd6f77ff6425737202299df25d4c20b9fa95bf Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:16:59 +0000 Subject: [PATCH 03/62] stuff --- code/controllers/subsystem/priority_directives.dm | 2 +- .../traitor/directives/secure_deaddrop/deaddrop_box.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 05b2750953ed5..7f3466c76f580 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -22,7 +22,7 @@ SUBSYSTEM_DEF(directives) if (!resumed) // Find all uplinks for (var/mob/antag in SSticker.mode.current_players[CURRENT_LIVING_ANTAGS]) - var/datum/component/uplink/uplink = antag.find_syndicate_uplink() + var/datum/component/uplink/uplink = antag.mind.find_syndicate_uplink() if (!uplink) continue current += uplink diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm index 38b65fb7edadb..d6d6127eec657 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm @@ -11,7 +11,7 @@ /obj/item/storage/deaddrop_box/proc/unlock() // You can now break it to your hearts desire obj_flags &= ~INDESTRUCTIBLE - var/datum/component/storage = GetComponent(/datum/component/storage) + var/datum/component/storage/storage = GetComponent(/datum/component/storage) storage.locked = FALSE /datum/component/storage/concrete/deaddrop From eb6915ae1bfc023a33a732e639e59694f623ca71 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Tue, 12 Mar 2024 18:22:45 +0000 Subject: [PATCH 04/62] Update Uplink.js --- tgui/packages/tgui/interfaces/Uplink.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 32c5394b62b00..5ef2d7d62b578 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -9,10 +9,29 @@ const MAX_SEARCH_RESULTS = 25; export const Uplink = (props, context) => { const { data } = useBackend(context); const { telecrystals } = data; + + const [tab, setTab] = useLocalState(context, 'tab_id', 0); + return ( - + + { + setTab(0); + }}> + Agent Marketplace + + { + setTab(1); + }}> + Priority Directives + + + {tab === 0 ? : 0} ); From e54d4eefee5a33b00be33399594cf6ed9c58a151 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Tue, 12 Mar 2024 23:11:38 +0000 Subject: [PATCH 05/62] Wraps it all together --- .../subsystem/priority_directives.dm | 41 +++++++++++++------ code/modules/admin/admin_verbs.dm | 4 +- code/modules/admin/secrets.dm | 2 +- .../traitor/directives/priority_directive.dm | 14 +++++++ .../secure_deaddrop/secure_deaddrop.dm | 8 ++++ 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 7f3466c76f580..85abe871e27a2 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -1,13 +1,15 @@ SUBSYSTEM_DEF(directives) name = "Priority Directives" wait = 10 SECONDS - var/list/current = list() var/datum/priority_directive/directive = null var/next_directive_time + var/list/directives = list() /datum/controller/subsystem/directives/Initialize(start_timeofday) . = ..() next_directive_time = world.time + rand(20 MINUTES, 30 MINUTES) + for (var/directive_type in subtypesof(/datum/priority_directive)) + directives += new directive_type() /datum/controller/subsystem/directives/fire(resumed) if (directive) @@ -18,16 +20,29 @@ SUBSYSTEM_DEF(directives) // Check if we are ready to spawn our next directive if (world.time < next_directive_time) return - // Identify all the uplinks and spawn a directive - if (!resumed) - // Find all uplinks - for (var/mob/antag in SSticker.mode.current_players[CURRENT_LIVING_ANTAGS]) - var/datum/component/uplink/uplink = antag.mind.find_syndicate_uplink() - if (!uplink) - continue - current += uplink - if (!length(current)) - can_fire = FALSE + // Find all the antags + var/list/antag_datums = list() + for (var/mob/antag in GLOB.alive_mob_list) + var/datum/component/uplink/uplink = antag.mind.find_syndicate_uplink() + if (!uplink || length(antag.mind.antag_datums) == 0) + continue + antag_datums += antag.mind.antag_datums[1] + // Find all the minds + var/list/player_minds = list() + for (var/mob/player in GLOB.alive_mob_list) + if (!ishuman(player) || !is_station_level(player.z) || !player.mind) + continue + player_minds += player.mind // Bring on the mission - directive = new /obj/item/storage/deaddrop_box() - directive.activate() + var/list/valid_directives = list() + for (var/datum/priority_directive/directive in directives) + if (!directive.check(antag_datums, player_minds)) + continue + valid_directives += directive + if (!length(valid_directives)) + // Try again in a minute + next_directive_time = world.time + 1 MINUTES + return + var/datum/priority_directive/selected = pick(valid_directives) + selected.generate(antag_datums, player_minds) + next_directive_time = INFINITY diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 83dcc6760bc19..7e1509dc4c05d 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -739,7 +739,7 @@ GLOBAL_PROTECT(admin_verbs_hideable) log_admin("[src] re-adminned themselves.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Readmin") -/client/proc/populate_world(amount = 50 as num) +/client/proc/populate_world(amount = 50 as num, give_minds as anything in list("Yes", "No")) set name = "Populate World" set category = "Debug" set desc = "(\"Amount of mobs to create\") Populate the world with test mobs." @@ -769,6 +769,8 @@ GLOBAL_PROTECT(admin_verbs_hideable) if(tile) var/mob/living/carbon/human/hooman = new(tile) + if (give_minds == "Yes") + hooman.mind_initialize() hooman.equipOutfit(pick(subtypesof(/datum/outfit))) testing("Spawned test mob at [COORD(tile)]") while(!area && --j > 0) diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm index 377de1703aa4b..00c75b7077cca 100644 --- a/code/modules/admin/secrets.dm +++ b/code/modules/admin/secrets.dm @@ -426,7 +426,7 @@ GLOBAL_DATUM_INIT(admin_secrets, /datum/admin_secrets, new) for(var/mob/living/H in chosenPlayers) if(!(ishuman(H)||istype(H, /mob/living/silicon/))) continue - if(H.stat == DEAD || !H.client || !H.mind || ispAI(H)) + if(H.stat == DEAD || !H.mind || ispAI(H)) continue if(is_special_character(H)) continue diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 2a39047359285..0c864f0dfa79f 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -1,11 +1,18 @@ +/// This can only be running once at a time, do not run in parallel /datum/priority_directive var/name var/desc var/end_at + var/rejected = FALSE /datum/priority_directive/New() . = ..() +/datum/priority_directive/proc/check() + SHOULD_NOT_OVERRIDE(TRUE) + +/datum/priority_directive/proc/allocate_teams(list/antag_datums, list/player_minds) + /// Return the reward type and amount /datum/priority_directive/proc/generate(list/antag_datums, list/player_minds) @@ -23,6 +30,13 @@ /datum/priority_directive/proc/advertise_security() SHOULD_NOT_OVERRIDE(TRUE) +/datum/priority_directive/proc/add_antagonist_team(list/antag_datums) + SHOULD_NOT_OVERRIDE(TRUE) + +/// Reject this directive, prevent it from firing +/datum/priority_directive/proc/reject() + SHOULD_NOT_OVERRIDE(TRUE) + /// Pick a random target with some specified restrictions /datum/priority_directive/proc/get_random_target(list/player_minds, list/allowed_roles = null, list/disallowed_roles = null) SHOULD_NOT_OVERRIDE(TRUE) diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index c72796094b810..86d973e93f388 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -5,6 +5,14 @@ box which will automatically unlock after a set period of time." var/obj/item/storage/deaddrop_box/target +/datum/priority_directive/deaddrop/allocate_teams(list/antag_datums, list/player_minds) + if (length(antag_datums) <= 1) + reject() + return + for (var/datum/antagonist/antag in antag_datums) + // Create individual teams + add_antagonist_team(antag) + /datum/priority_directive/deaddrop/generate(list/antag_datums, list/player_minds) // Spawn the deaddrop package target = new() From 94bb2d5b31fe20af044d9258d7e47c44577ff921 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:06:53 +0000 Subject: [PATCH 06/62] Resizable radar component --- code/datums/components/uplink.dm | 5 + tgui/packages/tgui/interfaces/NtosRadar.js | 251 ++++++++++++------ tgui/packages/tgui/interfaces/Uplink.js | 92 ++++++- .../tgui/styles/components/Uplink.scss | 59 ++++ 4 files changed, 317 insertions(+), 90 deletions(-) create mode 100644 tgui/packages/tgui/styles/components/Uplink.scss diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 1bcfc70aa4197..88ed9e3048d4d 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -234,6 +234,11 @@ compact_mode = !compact_mode return TRUE +/datum/component/uplink/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/radar_assets), + ) + /datum/component/uplink/proc/MakePurchase(mob/user, datum/uplink_item/U) if(!istype(U)) return diff --git a/tgui/packages/tgui/interfaces/NtosRadar.js b/tgui/packages/tgui/interfaces/NtosRadar.js index 532984d029ae9..a741138f380f1 100644 --- a/tgui/packages/tgui/interfaces/NtosRadar.js +++ b/tgui/packages/tgui/interfaces/NtosRadar.js @@ -1,5 +1,5 @@ import { classes } from 'common/react'; -import { Fragment } from 'inferno'; +import { Fragment, Component, createRef } from 'inferno'; import { resolveAsset } from '../assets'; import { useBackend } from '../backend'; import { Box, Button, Flex, Icon, NoticeBox, Section, Tooltip } from '../components'; @@ -22,37 +22,10 @@ export const NtosRadarContentSmall = (props, context) => { const { sig_err } = props; return ( -
- {Object.keys(target).length === 0 ? ( - selected ? ( - - {sig_err} - - ) : ( - No Target Selected. - ) - ) : ( - - Distance: {target.dist} {target.locz_string}{' '} - {target.use_rotate && target.pointer_z && target.pin_grand_z_result ? ( - - - - ) : null} -
- Location: ({target.gpsx}x, {target.gpsy}y, {target.gpsz}z){' '} - {target.use_rotate ? ( - 0 ? 'arrow-up' : 'crosshairs'} - style={{ - 'transform': `rotate(${target.rotate_angle}deg)`, - }} - /> - ) : null}{' '} - {target.use_rotate && target.pointer_z ? : null} -
- )} -
+
@@ -95,13 +94,19 @@ const Directives = (props, context) => {
Tasks - - Assassinate Burnard Silkwind, the roboticist. + {selectedObjective.tasks.map(task => ( + + + {task} + + ))} Additional Details - This mission is part of your assignment and must be - completed. No additional reward will be provided outside of the - terms that have been defined within your contract of employment. + {selectedObjective.details || ( + "This mission is part of your assignment and must be\ + completed. No additional reward will be provided outside of the\ + terms that have been defined within your contract of employment." + )}
@@ -155,7 +160,7 @@ const ObjectiveCard = (props, context) => { className={"objective_card " + (selected && "selected")} onClick={onClick}> - {name} + {capitalize(name)} From 3b0afb9d6050abc903e35d42e0a79b295ca4274e Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:01:51 +0000 Subject: [PATCH 10/62] Steal objectives can now be tracked --- beestation.dme | 1 + .../subsystem/priority_directives.dm | 9 ++++++ code/datums/components/trackable.dm | 24 +++++++++++++++ code/game/gamemodes/objective_items.dm | 6 ++++ code/game/gamemodes/objectives/_objective.dm | 5 ++++ .../gamemodes/objectives/basic/assassinate.dm | 3 ++ .../objectives/basic/changeling/absorb.dm | 3 ++ .../gamemodes/objectives/basic/debrain.dm | 3 ++ .../gamemodes/objectives/basic/destroy_ai.dm | 3 ++ .../game/gamemodes/objectives/basic/maroon.dm | 3 ++ .../gamemodes/objectives/basic/protect.dm | 6 +++- .../objectives/basic/protect_object.dm | 3 ++ code/game/gamemodes/objectives/basic/steal.dm | 11 +++++++ .../gamemodes/objectives/open/explosion.dm | 1 + .../telecomms/machines/message_server.dm | 5 ++++ code/game/objects/items/blueprints.dm | 5 +++- code/game/objects/items/documents.dm | 4 +++ code/game/objects/items/tanks/jetpack.dm | 4 +++ code/game/objects/items/teleportation.dm | 4 +++ code/game/objects/items/theft_tools.dm | 8 +++++ .../game/objects/structures/tank_dispenser.dm | 5 ++++ .../nukeop/equipment/nuclearbomb.dm | 1 + .../backstory/traitor_datum_backstory.dm | 2 +- code/modules/clothing/shoes/magboots.dm | 4 +++ code/modules/clothing/suits/armor.dm | 4 +++ .../modules/clothing/suits/reactive_armour.dm | 4 +++ code/modules/clothing/under/accessories.dm | 4 +++ code/modules/mob/living/silicon/ai/ai.dm | 1 + .../mob/living/simple_animal/slime/life.dm | 4 +++ code/modules/power/supermatter/supermatter.dm | 4 +++ .../projectiles/guns/energy/energy_gun.dm | 4 +++ code/modules/projectiles/guns/energy/laser.dm | 4 +++ .../reagents/reagent_containers/hypospray.dm | 4 +++ .../steal_objectives_trackability.dm | 17 +++++++++++ tgui/packages/tgui/interfaces/Uplink.js | 30 +++++++++++++++---- 35 files changed, 194 insertions(+), 9 deletions(-) create mode 100644 code/datums/components/trackable.dm create mode 100644 code/modules/unit_tests/steal_objectives_trackability.dm diff --git a/beestation.dme b/beestation.dme index 2eea030c5fa18..acdb91e976246 100644 --- a/beestation.dme +++ b/beestation.dme @@ -684,6 +684,7 @@ #include "code\datums\components\team_monitor.dm" #include "code\datums\components\tether.dm" #include "code\datums\components\thermite.dm" +#include "code\datums\components\trackable.dm" #include "code\datums\components\twohanded.dm" #include "code\datums\components\udder.dm" #include "code\datums\components\uplink.dm" diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 474eb8887441f..640bde1554bdb 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -51,6 +51,11 @@ SUBSYSTEM_DEF(directives) /datum/controller/subsystem/directives/proc/get_uplink_data(datum/component/uplink/uplink) var/data = list() data["time"] = world.time + var/atom/uplink_owner = uplink.parent + if (istype(uplink_owner)) + data["pos_x"] = uplink_owner?.x + data["pos_y"] = uplink_owner?.y + data["pos_z"] = uplink_owner?.z // The uplink can only detect syndicate assigned objectives of the owner if (uplink.owner) var/list/known_objectives = list() @@ -59,9 +64,13 @@ SUBSYSTEM_DEF(directives) if (antagonist_type.faction != FACTION_SYNDICATE) continue for (var/datum/objective/objective in antagonist_type.objectives) + var/atom/tracking_target = objective.get_tracking_target(uplink_owner) known_objectives += list(list( "name" = objective.name, "tasks" = list(objective.explanation_text), + "track_x" = tracking_target?.x, + "track_y" = tracking_target?.y, + "track_z" = tracking_target?.z, )) // Add the priority directive if (active_directive) diff --git a/code/datums/components/trackable.dm b/code/datums/components/trackable.dm new file mode 100644 index 0000000000000..92e9a7fcb0110 --- /dev/null +++ b/code/datums/components/trackable.dm @@ -0,0 +1,24 @@ +GLOBAL_LIST_EMPTY(tracks_by_type) + +/datum/component/trackable/Initialize(...) + var/atom/object = parent + if (!istype(object)) + return COMPONENT_INCOMPATIBLE + if (!GLOB.tracks_by_type[object.type]) + GLOB.tracks_by_type[object.type] = list(object) + else + GLOB.tracks_by_type[object.type] += object + +/datum/component/trackable/Destroy(force, silent) + var/atom/object = parent + if (istype(object)) + GLOB.tracks_by_type[object.type] -= object + return ..() + +/proc/get_trackables_by_type(typepath, locate_subtypes) + if (locate_subtypes) + var/list/results = list() + for (var/type in typesof(typepath)) + results += GLOB.tracks_by_type[type] + return results + return GLOB.tracks_by_type[typepath] diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index 1b80a82c1e2fa..00f3458acb4a0 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -10,6 +10,8 @@ var/list/special_equipment = list() /// Require that the target item is spawned at roundstart by closets. var/require_item_spawns_at_roundstart = TRUE + /// If we want a different item other than the target to be the track target + var/special_track_type /datum/objective_item/proc/check_special_completion() //for objectives with special checks (is that slime extract unused? does that intellicard have an ai in it? etcetc) return 1 @@ -125,6 +127,7 @@ name = "a sliver of a supermatter crystal. Be sure to use the proper safety equipment when extracting the sliver!" targetitem = /obj/item/nuke_core/supermatter_sliver difficulty = 15 + special_track_type = /obj/machinery/power/supermatter_crystal /datum/objective_item/steal/supermatter/New() special_equipment += /obj/item/storage/box/syndie_kit/supermatter @@ -139,6 +142,7 @@ targetitem = /obj/item/tank difficulty = 3 excludefromjob = list(JOB_NAME_CHIEFENGINEER,JOB_NAME_RESEARCHDIRECTOR,JOB_NAME_STATIONENGINEER,JOB_NAME_SCIENTIST,JOB_NAME_ATMOSPHERICTECHNICIAN) + special_track_type = /obj/structure/tank_dispenser /datum/objective_item/steal/plasma/check_special_completion(obj/item/tank/T) var/target_amount = text2num(name) @@ -151,6 +155,7 @@ targetitem = /obj/item/aicard difficulty = 20 //beyond the impossible requiredjob = list(JOB_NAME_AI) + special_track_type = /mob/living/silicon/ai /datum/objective_item/steal/functionalai/check_special_completion(obj/item/aicard/C) for(var/mob/living/silicon/ai/A in C) @@ -181,6 +186,7 @@ difficulty = 3 excludefromjob = list(JOB_NAME_RESEARCHDIRECTOR,JOB_NAME_SCIENTIST) requiredjob = list(JOB_NAME_RESEARCHDIRECTOR, JOB_NAME_SCIENTIST) + special_track_type = /mob/living/simple_animal/slime /datum/objective_item/steal/slime/check_special_completion(obj/item/slime_extract/E) if(E.Uses > 0) diff --git a/code/game/gamemodes/objectives/_objective.dm b/code/game/gamemodes/objectives/_objective.dm index 9df471eb5526f..653907689792f 100644 --- a/code/game/gamemodes/objectives/_objective.dm +++ b/code/game/gamemodes/objectives/_objective.dm @@ -302,3 +302,8 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list for(var/datum/mind/own as() in get_owners()) to_chat(own.current, "
You get the feeling your target is no longer within reach. Time for Plan [pick("A","B","C","D","X","Y","Z")]. Objectives updated!") own.announce_objectives() + +/// Get the tracking target for this objective +/datum/objective/proc/get_tracking_target(atom/source) + RETURN_TYPE(/atom) + return null diff --git a/code/game/gamemodes/objectives/basic/assassinate.dm b/code/game/gamemodes/objectives/basic/assassinate.dm index 1fa29331fbf7d..965b1f56b1b41 100644 --- a/code/game/gamemodes/objectives/basic/assassinate.dm +++ b/code/game/gamemodes/objectives/basic/assassinate.dm @@ -20,6 +20,9 @@ /datum/objective/assassinate/admin_edit(mob/admin) admin_simple_target_pick(admin) +/datum/objective/assassinate/get_tracking_target(atom/source) + return target?.current + /datum/objective/assassinate/incursion name = "eliminate" diff --git a/code/game/gamemodes/objectives/basic/changeling/absorb.dm b/code/game/gamemodes/objectives/basic/changeling/absorb.dm index dacbea207a169..90b3b4ac5008a 100644 --- a/code/game/gamemodes/objectives/basic/changeling/absorb.dm +++ b/code/game/gamemodes/objectives/basic/changeling/absorb.dm @@ -46,6 +46,9 @@ var/span = check_completion() ? "grentext" : "redtext" return "[explanation_text] [absorbedcount] lifeform\s absorbed!" +/datum/objective/absorb/get_tracking_target(atom/source) + return target?.current + /datum/objective/absorb_most name = "absorb most" explanation_text = "Extract more compatible genomes than any other Changeling." diff --git a/code/game/gamemodes/objectives/basic/debrain.dm b/code/game/gamemodes/objectives/basic/debrain.dm index 1e9dcf9f18abd..26fff7a617fad 100644 --- a/code/game/gamemodes/objectives/basic/debrain.dm +++ b/code/game/gamemodes/objectives/basic/debrain.dm @@ -31,3 +31,6 @@ /datum/objective/debrain/admin_edit(mob/admin) admin_simple_target_pick(admin) + +/datum/objective/debrain/get_tracking_target(atom/source) + return target?.current diff --git a/code/game/gamemodes/objectives/basic/destroy_ai.dm b/code/game/gamemodes/objectives/basic/destroy_ai.dm index feaf4ac62e7a2..8f4397945a8e6 100644 --- a/code/game/gamemodes/objectives/basic/destroy_ai.dm +++ b/code/game/gamemodes/objectives/basic/destroy_ai.dm @@ -38,5 +38,8 @@ to_chat(admin, "No active AIs with minds") update_explanation_text() +/datum/objective/destroy/get_tracking_target(atom/source) + return target?.current + /datum/objective/destroy/internal var/stolen = FALSE //Have we already eliminated this target? diff --git a/code/game/gamemodes/objectives/basic/maroon.dm b/code/game/gamemodes/objectives/basic/maroon.dm index 712dca6c76833..e87c289a5cb0c 100644 --- a/code/game/gamemodes/objectives/basic/maroon.dm +++ b/code/game/gamemodes/objectives/basic/maroon.dm @@ -18,3 +18,6 @@ /datum/objective/maroon/admin_edit(mob/admin) admin_simple_target_pick(admin) + +/datum/objective/maroon/get_tracking_target(atom/source) + return target?.current diff --git a/code/game/gamemodes/objectives/basic/protect.dm b/code/game/gamemodes/objectives/basic/protect.dm index 74ad524178246..ff33da4d08db7 100644 --- a/code/game/gamemodes/objectives/basic/protect.dm +++ b/code/game/gamemodes/objectives/basic/protect.dm @@ -1,4 +1,5 @@ -/datum/objective/protect//The opposite of killing a dude. +//The opposite of killing a dude. +/datum/objective/protect name = "protect" var/target_role_type = FALSE var/human_check = TRUE @@ -30,6 +31,9 @@ /datum/objective/protect/admin_edit(mob/admin) admin_simple_target_pick(admin) +/datum/objective/protect/get_tracking_target(atom/source) + return target?.current + /datum/objective/protect/nonhuman name = "protect nonhuman" human_check = FALSE diff --git a/code/game/gamemodes/objectives/basic/protect_object.dm b/code/game/gamemodes/objectives/basic/protect_object.dm index 736c820c156f5..35a98c5c9926e 100644 --- a/code/game/gamemodes/objectives/basic/protect_object.dm +++ b/code/game/gamemodes/objectives/basic/protect_object.dm @@ -15,3 +15,6 @@ /datum/objective/protect_object/check_completion() return !QDELETED(protect_target) || ..() + +/datum/objective/protect_object/get_tracking_target(atom/source) + return protect_target diff --git a/code/game/gamemodes/objectives/basic/steal.dm b/code/game/gamemodes/objectives/basic/steal.dm index b6ccf9b4e3dd0..0e920cada2fee 100644 --- a/code/game/gamemodes/objectives/basic/steal.dm +++ b/code/game/gamemodes/objectives/basic/steal.dm @@ -8,6 +8,17 @@ GLOBAL_LIST_EMPTY(possible_items) /datum/objective/steal/get_target() return steal_target +/datum/objective/steal/get_tracking_target(atom/source) + var/closest = INFINITY + var/atom/tracked = null + for (var/atom/target in get_trackables_by_type(steal_target, TRUE)) + var/dist = get_dist(target, source) + if (dist > closest) + continue + closest = dist + tracked = target + return tracked + /datum/objective/steal/New() ..() if(!GLOB.possible_items.len)//Only need to fill the list when it's needed. diff --git a/code/game/gamemodes/objectives/open/explosion.dm b/code/game/gamemodes/objectives/open/explosion.dm index 5f5cfe04fa983..b083c59e04c8c 100644 --- a/code/game/gamemodes/objectives/open/explosion.dm +++ b/code/game/gamemodes/objectives/open/explosion.dm @@ -21,6 +21,7 @@ var/devistation = 0 var/heavy = 0 var/light = 0 + var/turf/generic_track_location /datum/objective/open/explosion/New(text) . = ..() diff --git a/code/game/machinery/telecomms/machines/message_server.dm b/code/game/machinery/telecomms/machines/message_server.dm index 5f7003e346d4d..65b63e09eef3b 100644 --- a/code/game/machinery/telecomms/machines/message_server.dm +++ b/code/game/machinery/telecomms/machines/message_server.dm @@ -56,6 +56,7 @@ else icon_state = "blackbox_b" return ..() + /obj/item/blackbox name = "the blackbox" desc = "A strange relic, capable of recording data on extradimensional vertices. It lives inside the blackbox recorder for safe keeping." @@ -66,6 +67,10 @@ w_class = WEIGHT_CLASS_BULKY resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF +/obj/item/blackbox/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + #define MESSAGE_SERVER_FUNCTIONING_MESSAGE "This is an automated message. The messaging system is functioning correctly." // The message server itself. diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index de93897096974..edfdab19a07c1 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -51,11 +51,14 @@ var/legend = FALSE //Viewing the wire legend investigate_flags = ADMIN_INVESTIGATE_TARGET +/obj/item/areaeditor/blueprints/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/areaeditor/blueprints/Destroy() clear_viewer() return ..() - /obj/item/areaeditor/blueprints/attack_self(mob/user) . = ..() if(!legend) diff --git a/code/game/objects/items/documents.dm b/code/game/objects/items/documents.dm index 9976848bdfc46..8ec6acc044bbc 100644 --- a/code/game/objects/items/documents.dm +++ b/code/game/objects/items/documents.dm @@ -12,6 +12,10 @@ pressure_resistance = 2 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF +/obj/item/documents/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/documents/nanotrasen desc = "\"Top Secret\" Nanotrasen documents, filled with complex diagrams and lists of names, dates and coordinates." icon_state = "docs_verified" diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm index 36b06e40ff658..aa40367241eb1 100644 --- a/code/game/objects/items/tanks/jetpack.dm +++ b/code/game/objects/items/tanks/jetpack.dm @@ -196,6 +196,10 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF //steal objective items are hard to destroy. investigate_flags = ADMIN_INVESTIGATE_TARGET +/obj/item/tank/jetpack/oxygen/captain/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/tank/jetpack/oxygen/security name = "security jetpack (oxygen)" desc = "A tank of compressed oxygen for use as propulsion in zero-gravity areas by security forces." diff --git a/code/game/objects/items/teleportation.dm b/code/game/objects/items/teleportation.dm index 9f67d17f582b5..2fe27d2051fce 100644 --- a/code/game/objects/items/teleportation.dm +++ b/code/game/objects/items/teleportation.dm @@ -121,6 +121,10 @@ . = ..() active_portal_pairs = list() +/obj/item/hand_tele/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/hand_tele/pre_attack(atom/target, mob/user, params) if(try_dispel_portal(target, user)) return FALSE diff --git a/code/game/objects/items/theft_tools.dm b/code/game/objects/items/theft_tools.dm index e92289f30efa1..1b78b4ad07d81 100644 --- a/code/game/objects/items/theft_tools.dm +++ b/code/game/objects/items/theft_tools.dm @@ -20,6 +20,10 @@ . = ..() START_PROCESSING(SSobj, src) +/obj/item/nuke_core/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/nuke_core/Destroy() STOP_PROCESSING(SSobj, src) return ..() @@ -127,6 +131,10 @@ item_state = "supermattersliver" pulseicon = "supermatter_sliver_pulse" +/obj/item/nuke_core/supermatter_sliver/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/nuke_core/supermatter_sliver/attack_tk() // no TK dusting memes return FALSE diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index eb3e049d16d30..03a7ce467429b 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -11,6 +11,11 @@ var/oxygentanks = TANK_DISPENSER_CAPACITY var/plasmatanks = TANK_DISPENSER_CAPACITY +/obj/structure/tank_dispenser/ComponentInitialize() + . = ..() + if (plasmatanks > 0) + AddComponent(/datum/component/trackable) + /obj/structure/tank_dispenser/oxygen plasmatanks = 0 diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm index 9f79aaf5d78c7..713ca09d590e1 100644 --- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm +++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm @@ -677,6 +677,7 @@ This is here to make the tiles around the station mininuke change when it's arme if(!fake) //Global teamfinder signal trackable on the synd frequency. AddComponent(/datum/component/tracking_beacon, "synd", null, null, TRUE, "#ebeca1", TRUE, TRUE, "#818157") + AddComponent(/datum/component/trackable) /obj/item/disk/nuclear/process() ++process_tick diff --git a/code/modules/antagonists/traitor/backstory/traitor_datum_backstory.dm b/code/modules/antagonists/traitor/backstory/traitor_datum_backstory.dm index 840c87245edcd..61137689a96b3 100644 --- a/code/modules/antagonists/traitor/backstory/traitor_datum_backstory.dm +++ b/code/modules/antagonists/traitor/backstory/traitor_datum_backstory.dm @@ -37,7 +37,7 @@ /datum/antagonist/traitor/proc/set_faction(datum/traitor_faction/new_faction) if(!istype(new_faction)) return - var/no_faction = isnull(faction) + var/no_faction = isnull(traitor_faction) traitor_faction = new_faction employer = new_faction.employer_name if(no_faction) diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm index d2475cf7ac92a..573359fa4b5ba 100644 --- a/code/modules/clothing/shoes/magboots.dm +++ b/code/modules/clothing/shoes/magboots.dm @@ -52,6 +52,10 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF investigate_flags = ADMIN_INVESTIGATE_TARGET +/obj/item/clothing/shoes/magboots/advance/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/clothing/shoes/magboots/syndie desc = "Reverse-engineered magnetic boots that have a heavy magnetic pull. Property of Gorlex Marauders." name = "blood-red magboots" diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index f19bba0ef3643..f1e656daf4c67 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -178,6 +178,10 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF var/hit_reflect_chance = 40 +/obj/item/clothing/suit/armor/laserproof/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/clothing/suit/armor/laserproof/IsReflect(def_zone) if(!(def_zone in list(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_GROIN))) //If not shot where ablative is covering you, you don't get the reflection bonus! return 0 diff --git a/code/modules/clothing/suits/reactive_armour.dm b/code/modules/clothing/suits/reactive_armour.dm index 2586acfefa579..380b71f6b6189 100644 --- a/code/modules/clothing/suits/reactive_armour.dm +++ b/code/modules/clothing/suits/reactive_armour.dm @@ -134,6 +134,10 @@ var/tele_range = 6 var/rad_amount= 15 +/obj/item/clothing/suit/armor/reactive/teleport/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/clothing/suit/armor/reactive/teleport/reactive_activation(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", damage = 0, attack_type = MELEE_ATTACK) owner.visible_message("The reactive teleport system flings [owner] clear of [attack_text], shutting itself off in the process!") playsound(get_turf(owner),'sound/magic/blink.ogg', 100, 1) diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm index 22b024c42f02b..cdb4c9d9dc3c1 100755 --- a/code/modules/clothing/under/accessories.dm +++ b/code/modules/clothing/under/accessories.dm @@ -219,6 +219,10 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF investigate_flags = ADMIN_INVESTIGATE_TARGET +/obj/item/clothing/accessory/medal/gold/captain/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/clothing/accessory/medal/gold/heroism name = "medal of exceptional heroism" desc = "An extremely rare golden medal awarded only by CentCom. To receive such a medal is the highest honor and as such, very few exist. This medal is almost never awarded to anybody but commanders." diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 8e7290fc2ea32..723f4108731b8 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -110,6 +110,7 @@ /mob/living/silicon/ai/Initialize(mapload, datum/ai_laws/L, mob/target_ai) default_access_list = get_all_accesses() . = ..() + AddComponent(/datum/component/trackable) add_sensors() if(!target_ai) //If there is no player/brain inside. new/obj/structure/AIcore/deactivated(loc) //New empty terminal. diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm index ec700c523c358..1445746f730fb 100644 --- a/code/modules/mob/living/simple_animal/slime/life.dm +++ b/code/modules/mob/living/simple_animal/slime/life.dm @@ -6,6 +6,10 @@ var/attack_cooldown = 0 var/attack_cooldown_time = 20 //How long, in deciseconds, the cooldown of attacks is +/mob/living/simple_animal/slime/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /mob/living/simple_animal/slime/Life() set invisibility = 0 if(notransform) diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index f9a76a0002bfb..b00f889c4b60c 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -170,6 +170,10 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/boh_tear )) +/obj/machinery/power/supermatter_crystal/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/machinery/power/supermatter_crystal/Destroy() investigate_log("has been destroyed.", INVESTIGATE_ENGINES) SSair.stop_processing_machine(src) diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index 3bbfc202bb1ba..3d9c8113f4b62 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -78,6 +78,10 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF investigate_flags = ADMIN_INVESTIGATE_TARGET +/obj/item/gun/energy/e_gun/hos/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/gun/energy/e_gun/dragnet name = "\improper DRAGnet" desc = "The \"Dynamic Rapid-Apprehension of the Guilty\" net is a revolution in law enforcement technology." diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 92cc334fbdaea..535e0d6225269 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -45,6 +45,10 @@ weapon_weight = WEAPON_LIGHT investigate_flags = ADMIN_INVESTIGATE_TARGET +/obj/item/gun/energy/laser/captain/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/gun/energy/laser/captain/scattershot name = "scatter shot laser rifle" icon_state = "lasercannon" diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 4d9cfde8bd1ac..22dfb185345c4 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -74,6 +74,10 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF investigate_flags = ADMIN_INVESTIGATE_TARGET +/obj/item/reagent_containers/hypospray/CMO/ComponentInitialize() + . = ..() + AddComponent(/datum/component/trackable) + /obj/item/reagent_containers/hypospray/combat name = "combat stimulant injector" desc = "A modified air-needle autoinjector, used by support operatives to quickly heal injuries in combat." diff --git a/code/modules/unit_tests/steal_objectives_trackability.dm b/code/modules/unit_tests/steal_objectives_trackability.dm new file mode 100644 index 0000000000000..e8252fca76e98 --- /dev/null +++ b/code/modules/unit_tests/steal_objectives_trackability.dm @@ -0,0 +1,17 @@ +/datum/unit_test/trackable/Run() + var/list/fails = list() + for (var/datum/objective_item/steal/item as() in subtypesof(/datum/objective_item/steal)) + if (ispath(item, /datum/objective_item/special) || ispath(item, /datum/objective_item/stack)) + continue + var/item_target = initial(item.special_track_type) || initial(item.targetitem) + // Accepted ignore: AIs get deleted during init but will be trackable + if (ispath(item_target, /mob/living/silicon/ai)) + continue + var/atom/created = new item_target(run_loc_floor_bottom_left) + if (!created.GetComponent(/datum/component/trackable)) + fails += "[item_target] is not trackable but is the target of a steal objective. Add the following code:\n[item_target]/ComponentInitialize()\n\t. = ..()\n\tAddComponent(/datum/component/trackable)" + qdel(created) + for (var/atom/a in run_loc_floor_bottom_left) + qdel(a) + if (length(fails)) + Fail(jointext(fails, "\n")) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 5b8f770238d85..a44133db15f41 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -46,10 +46,21 @@ const Directives = (props, context) => { const [selected, setSelected] = useLocalState(context, "sel_obj", 0); const { act, data } = useBackend(context); const { + pos_x = 0, + pos_y = 0, + pos_z = 0, time, objectives = [], } = data.objectives; const selectedObjective = objectives[selected]; + const { + track_x, + track_y, + track_z, + } = selectedObjective || {}; + const dx = track_x - pos_x; + const dy = track_y - pos_y; + const angle = (360 / (Math.PI * 2)) * (Math.atan2(dx, dy)); return ( @@ -76,14 +87,21 @@ const Directives = (props, context) => {
- track_z ? "caret-up" : poz_z < track_z ? "caret-down" : null, }} />
From b6c41792caa011e0d5f0407e268b4d1a5721faff Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 14 Mar 2024 21:18:11 +0000 Subject: [PATCH 11/62] Live objective tracking --- .../subsystem/priority_directives.dm | 18 ++++++++++-------- code/datums/components/uplink.dm | 4 +--- tgui/packages/tgui/interfaces/Uplink.js | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 640bde1554bdb..f3b16df1b83c3 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -52,10 +52,11 @@ SUBSYSTEM_DEF(directives) var/data = list() data["time"] = world.time var/atom/uplink_owner = uplink.parent - if (istype(uplink_owner)) - data["pos_x"] = uplink_owner?.x - data["pos_y"] = uplink_owner?.y - data["pos_z"] = uplink_owner?.z + var/turf/uplink_turf = uplink_owner && get_turf(uplink_owner) + if (istype(uplink_turf)) + data["pos_x"] = uplink_turf?.x + data["pos_y"] = uplink_turf?.y + data["pos_z"] = uplink_turf?.z // The uplink can only detect syndicate assigned objectives of the owner if (uplink.owner) var/list/known_objectives = list() @@ -64,13 +65,14 @@ SUBSYSTEM_DEF(directives) if (antagonist_type.faction != FACTION_SYNDICATE) continue for (var/datum/objective/objective in antagonist_type.objectives) - var/atom/tracking_target = objective.get_tracking_target(uplink_owner) + var/atom/tracking_target = objective.get_tracking_target(uplink_turf) + var/turf/tracking_turf = tracking_target && get_turf(tracking_target) known_objectives += list(list( "name" = objective.name, "tasks" = list(objective.explanation_text), - "track_x" = tracking_target?.x, - "track_y" = tracking_target?.y, - "track_z" = tracking_target?.z, + "track_x" = tracking_turf?.x, + "track_y" = tracking_turf?.y, + "track_z" = tracking_turf?.z, )) // Add the priority directive if (active_directive) diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 4413a91e22622..8097d2b20b1b5 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -156,9 +156,7 @@ ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "Uplink", name) - // This UI is only ever opened by one person, - // and never is updated outside of user input. - ui.set_autoupdate(FALSE) + ui.set_autoupdate(TRUE) ui.open() /datum/component/uplink/ui_data(mob/user) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index a44133db15f41..f0c016cd0c00a 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -92,16 +92,16 @@ const Directives = (props, context) => { selected={!track_x} rightAlign target={!track_x ? {} : { - dist: Math.sqrt((pos_x - track_x) ** 2 + (pos_y - track_y) ** 2), + dist: Math.abs((pos_x - track_x)) + Math.abs((pos_y - track_y)), gpsx: track_x, gpsy: track_y, locy: (pos_y - track_y) + 24, locx: (track_x - pos_x) + 24, gpsz: track_z, - use_rotate: true, + use_rotate: Math.abs((pos_x - track_x)) + Math.abs((pos_y - track_y)) > 30, rotate_angle: angle, arrowstyle: "ntosradarpointer.png", - pointer_z: pos_z > track_z ? "caret-up" : poz_z < track_z ? "caret-down" : null, + pointer_z: pos_z > track_z ? "caret-up" : pos_z < track_z ? "caret-down" : null, }} />
From e82058edc20b22547c727fe5ddebdc527dde477c Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 14 Mar 2024 22:34:22 +0000 Subject: [PATCH 12/62] Completes secure deaddrop --- .../subsystem/priority_directives.dm | 37 +++++++++++++------ code/datums/components/uplink.dm | 4 ++ code/game/gamemodes/objectives/basic/steal.dm | 5 ++- .../traitor/directives/priority_directive.dm | 23 ++++++++---- .../secure_deaddrop/deaddrop_box.dm | 1 + .../secure_deaddrop/secure_deaddrop.dm | 15 ++++---- tgui/packages/tgui/interfaces/Uplink.js | 8 ++-- 7 files changed, 63 insertions(+), 30 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index f3b16df1b83c3..85f35e2de9c58 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -20,13 +20,6 @@ SUBSYSTEM_DEF(directives) // Check if we are ready to spawn our next active_directive if (world.time < next_directive_time) return - // Find all the antags - var/list/antag_datums = list() - for (var/mob/antag in GLOB.alive_mob_list) - var/datum/component/uplink/uplink = antag.mind.find_syndicate_uplink() - if (!uplink || length(antag.mind.antag_datums) == 0) - continue - antag_datums += antag.mind.antag_datums[1] // Find all the minds var/list/player_minds = list() for (var/mob/player in GLOB.alive_mob_list) @@ -36,18 +29,35 @@ SUBSYSTEM_DEF(directives) // Bring on the mission var/list/valid_directives = list() for (var/datum/priority_directive/directive in directives) - if (!directive.check(antag_datums, player_minds)) + if (!directive.check(GLOB.uplinks, player_minds)) continue valid_directives += directive if (!length(valid_directives)) // Try again in a minute next_directive_time = world.time + 1 MINUTES return - var/datum/priority_directive/selected = pick(valid_directives) - selected.generate(antag_datums, player_minds) + var/datum/priority_directive/selected = pick(active_directive) + selected.activate(GLOB.uplinks, player_minds) next_directive_time = INFINITY active_directive = selected +/client/verb/force_directive() + set name = "force directive" + set category = "powerfulbacon" + if (SSdirectives.active_directive) + message_admins("not yet") + return + // Find all the minds + var/list/player_minds = list() + for (var/mob/player in GLOB.alive_mob_list) + if (!ishuman(player) || !is_station_level(player.z) || !player.mind) + continue + player_minds += player.mind + var/datum/priority_directive/selected = pick(SSdirectives.directives) + selected.activate(GLOB.uplinks, player_minds) + SSdirectives.next_directive_time = INFINITY + SSdirectives.active_directive = selected + /datum/controller/subsystem/directives/proc/get_uplink_data(datum/component/uplink/uplink) var/data = list() data["time"] = world.time @@ -76,12 +86,17 @@ SUBSYSTEM_DEF(directives) )) // Add the priority directive if (active_directive) + var/atom/track_atom = active_directive.get_track_atom() + var/turf/track_turf = get_turf(track_atom) known_objectives += list(list( "name" = active_directive.name, "tasks" = list(active_directive.objective_explanation), "time" = active_directive.end_at, "details" = active_directive.details, - "reward" = active_directive.tc_reward + "reward" = active_directive.tc_reward, + "track_x" = track_turf?.x, + "track_y" = track_turf?.y, + "track_z" = track_turf?.z, )) data["objectives"] = known_objectives return data diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 8097d2b20b1b5..78bb73ffc3efa 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -1,5 +1,7 @@ #define PEN_ROTATIONS 2 +GLOBAL_LIST_EMPTY(uplinks) + /** * Uplinks * @@ -71,6 +73,7 @@ // We need to start running this now SSdirectives.can_fire = TRUE + GLOB.uplinks += src /datum/component/uplink/InheritComponent(datum/component/uplink/U) lockable |= U.lockable @@ -82,6 +85,7 @@ /datum/component/uplink/Destroy() purchase_log = null + GLOB.uplinks -= src return ..() /datum/component/uplink/proc/update_items() diff --git a/code/game/gamemodes/objectives/basic/steal.dm b/code/game/gamemodes/objectives/basic/steal.dm index 0e920cada2fee..7cbd2f2e6089a 100644 --- a/code/game/gamemodes/objectives/basic/steal.dm +++ b/code/game/gamemodes/objectives/basic/steal.dm @@ -10,9 +10,12 @@ GLOBAL_LIST_EMPTY(possible_items) /datum/objective/steal/get_tracking_target(atom/source) var/closest = INFINITY + var/turf/source_turf = get_turf(source) var/atom/tracked = null for (var/atom/target in get_trackables_by_type(steal_target, TRUE)) - var/dist = get_dist(target, source) + var/turf/target_turf = get_turf(target) + // Prioritise things that are on the same z + var/dist = get_dist(target, source) + abs(source_turf.z - target_turf.z) * 1000 if (dist > closest) continue closest = dist diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index fb935f5e77880..c38b5692a13d2 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -4,30 +4,42 @@ var/objective_explanation var/details var/end_at - var/tc_reward = 0 var/rejected = FALSE + var/tc_reward + VAR_PRIVATE/list/teams = list() /datum/priority_directive/New() . = ..() -/datum/priority_directive/proc/check() +/// Check if we are allowed to run this directive or not +/datum/priority_directive/proc/check(list/uplinks, list/player_minds) SHOULD_NOT_OVERRIDE(TRUE) + teams.Cut() + allocate_teams(uplinks, player_minds) + return !rejected +/// Allocate teams for this directive. Call reject() to reject this directive and +/// add_antagonist_team to add antagonist teams. /datum/priority_directive/proc/allocate_teams(list/uplinks, list/player_minds) /// Return the reward type and amount /datum/priority_directive/proc/generate(list/uplinks, list/player_minds) +/// Get the tracking target of this atom +/datum/priority_directive/proc/get_track_atom() + /// Check if we have finished early. We always complete after a set time period. /datum/priority_directive/proc/is_completed() return FALSE /datum/priority_directive/proc/finish() + SSdirectives.active_directive = null /// Activate the directive, requires a list of traitor datums and security minsd /datum/priority_directive/proc/activate(list/uplinks, list/player_minds) SHOULD_NOT_OVERRIDE(TRUE) end_at = world.time + 10 MINUTES + tc_reward = generate(uplinks, player_minds) /// Advertise this directive to security objectives consoles /datum/priority_directive/proc/advertise_security() @@ -35,10 +47,12 @@ /datum/priority_directive/proc/add_antagonist_team(list/uplinks) SHOULD_NOT_OVERRIDE(TRUE) + teams += list(uplinks) /// Reject this directive, prevent it from firing /datum/priority_directive/proc/reject() SHOULD_NOT_OVERRIDE(TRUE) + rejected = TRUE /// Pick a random target with some specified restrictions /datum/priority_directive/proc/get_random_target(list/player_minds, list/allowed_roles = null, list/disallowed_roles = null) @@ -54,8 +68,3 @@ continue targets += mind return pick(targets) - -/datum/priority_directive/proc/get_independent_difficulty() - -/datum/priority_directive/proc/tc_curve(input) - return input diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm index d6d6127eec657..c75cb595a82f2 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm @@ -3,6 +3,7 @@ name = "secured box" desc = "A secure box that probably contains a variety of items the \ average crewmember probably wouldn't want around the station." + icon_state = "safe" w_class = WEIGHT_CLASS_NORMAL // Prevent it from being opened until it is ready to be opened obj_flags = INDESTRUCTIBLE diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index bde9f154bbbb7..300cbf54ea516 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -16,21 +16,22 @@ /datum/priority_directive/deaddrop/generate(list/uplinks, list/player_minds) // Spawn the deaddrop package - target = new() - var/tc_count = tc_curve(get_independent_difficulty()) - new /obj/item/stack/sheet/telecrystal(target, tc_count) + var/tc_count = rand(4, 3 + length(uplinks)) // Put the deaddrop somewhere var/turf/selected = get_random_station_turf() while (!istype(selected, /turf/open/floor/plasteel)) selected = get_random_station_turf() - var/datum/secret_bag = new /obj/item/storage/backpack/satchel/flat(selected) + var/atom/secret_bag = new /obj/item/storage/backpack/satchel/flat/empty(selected) + target = new(secret_bag) + new /obj/item/stack/sheet/telecrystal(target, tc_count) SEND_SIGNAL(secret_bag, COMSIG_OBJ_HIDE, selected.underfloor_accessibility < UNDERFLOOR_VISIBLE) new /obj/item/storage/deaddrop_box(secret_bag) // Return the reward generated - return list( - /obj/item/stack/sheet/telecrystal = tc_count, - ) + return tc_count /datum/priority_directive/deaddrop/finish(list/uplinks, list/player_minds) . = ..() target.unlock() + +/datum/priority_directive/deaddrop/get_track_atom() + return target diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index f0c016cd0c00a..9c49090015882 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -52,7 +52,7 @@ const Directives = (props, context) => { time, objectives = [], } = data.objectives; - const selectedObjective = objectives[selected]; + const selectedObjective = objectives[selected] || objectives[0]; const { track_x, track_y, @@ -78,7 +78,7 @@ const Directives = (props, context) => { objective_info={{ name: objective.name, reward: objective.reward || 0, - time_left: objective.time ? objective.time - time : null, + time_left: objective.time ? (objective.time - time) * 0.1 : null, }} /> ))} @@ -98,7 +98,7 @@ const Directives = (props, context) => { locy: (pos_y - track_y) + 24, locx: (track_x - pos_x) + 24, gpsz: track_z, - use_rotate: Math.abs((pos_x - track_x)) + Math.abs((pos_y - track_y)) > 30, + use_rotate: Math.abs((pos_x - track_x)) + Math.abs((pos_y - track_y)) > 26, rotate_angle: angle, arrowstyle: "ntosradarpointer.png", pointer_z: pos_z > track_z ? "caret-up" : pos_z < track_z ? "caret-down" : null, @@ -185,7 +185,7 @@ const ObjectiveCard = (props, context) => { {reward === 0 ? "Assignment" : (reward + " TC Reward")} - {time_left === null ? "--:--" : ("00:" + String(Math.floor(time_left / 60)).padStart(2, '0') + ":" + String(time_left % 60).padStart(2, '0'))} + {time_left === null ? "--:--" : ("00:" + String(Math.floor(time_left / 60)).padStart(2, '0') + ":" + String(Math.floor(time_left) % 60).padStart(2, '0'))} ); From 397c07731a6a4700336b70684a6ef4c339990be9 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 14 Mar 2024 22:41:29 +0000 Subject: [PATCH 13/62] Update secure_deaddrop.dm --- .../traitor/directives/secure_deaddrop/secure_deaddrop.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index 300cbf54ea516..1ffabbebc81d3 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -25,7 +25,6 @@ target = new(secret_bag) new /obj/item/stack/sheet/telecrystal(target, tc_count) SEND_SIGNAL(secret_bag, COMSIG_OBJ_HIDE, selected.underfloor_accessibility < UNDERFLOOR_VISIBLE) - new /obj/item/storage/deaddrop_box(secret_bag) // Return the reward generated return tc_count From 2d45631daa6b88ca9a41daeba7aa4b3d4e695d1f Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 14 Mar 2024 22:58:40 +0000 Subject: [PATCH 14/62] Moves the uplink styling sheets to the correct place --- .../tgui/styles/{components => interfaces}/Uplink.scss | 0 tgui/packages/tgui/styles/themes/syndicate.scss | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) rename tgui/packages/tgui/styles/{components => interfaces}/Uplink.scss (100%) diff --git a/tgui/packages/tgui/styles/components/Uplink.scss b/tgui/packages/tgui/styles/interfaces/Uplink.scss similarity index 100% rename from tgui/packages/tgui/styles/components/Uplink.scss rename to tgui/packages/tgui/styles/interfaces/Uplink.scss diff --git a/tgui/packages/tgui/styles/themes/syndicate.scss b/tgui/packages/tgui/styles/themes/syndicate.scss index 97009ffbee980..4078dab53f0d8 100644 --- a/tgui/packages/tgui/styles/themes/syndicate.scss +++ b/tgui/packages/tgui/styles/themes/syndicate.scss @@ -36,9 +36,11 @@ @include meta.load-css('../components/NumberInput.scss', $with: ('border-color': #87ce87)); @include meta.load-css('../components/ProgressBar.scss', $with: ('background-color': rgba(0, 0, 0, 0.5))); @include meta.load-css('../components/Section.scss'); - @include meta.load-css('../components/Uplink.scss'); @include meta.load-css('../components/Tooltip.scss', $with: ('background-color': #4a0202)); + // Interfaces + @include meta.load-css('../interfaces/Uplink.scss'); + // Layouts @include meta.load-css('../layouts/Layout.scss'); @include meta.load-css('../layouts/Window.scss'); From 6a6b45ee314685aec5b8d93b18e50c19cb23fbc3 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 14 Mar 2024 22:59:42 +0000 Subject: [PATCH 15/62] Executes TGUI prettier. --- tgui/packages/tgui/interfaces/NtosRadar.js | 40 ++--- tgui/packages/tgui/interfaces/Uplink.js | 160 ++++++++---------- .../tgui/styles/interfaces/Uplink.scss | 1 - 3 files changed, 90 insertions(+), 111 deletions(-) diff --git a/tgui/packages/tgui/interfaces/NtosRadar.js b/tgui/packages/tgui/interfaces/NtosRadar.js index 35e1d5ec17e50..89f803d80011d 100644 --- a/tgui/packages/tgui/interfaces/NtosRadar.js +++ b/tgui/packages/tgui/interfaces/NtosRadar.js @@ -22,10 +22,7 @@ export const NtosRadarContentSmall = (props, context) => { const { sig_err } = props; return ( - +
@@ -161,31 +152,30 @@ const Directives = (props, context) => { const ObjectiveCard = (props, context) => { const { objective_info = { - name: "Assassination", + name: 'Assassination', reward: 0, time_left: null, }, selected = 0, onClick, } = props; - const { - name, - reward, - time_left, - } = objective_info; + const { name, reward, time_left } = objective_info; return ( - + {capitalize(name)} - - {reward === 0 ? "Assignment" : (reward + " TC Reward")} + + {reward === 0 ? 'Assignment' : reward + ' TC Reward'} - {time_left === null ? "--:--" : ("00:" + String(Math.floor(time_left / 60)).padStart(2, '0') + ":" + String(Math.floor(time_left) % 60).padStart(2, '0'))} + {time_left === null + ? '--:--' + : '00:' + + String(Math.floor(time_left / 60)).padStart(2, '0') + + ':' + + String(Math.floor(time_left) % 60).padStart(2, '0')} ); diff --git a/tgui/packages/tgui/styles/interfaces/Uplink.scss b/tgui/packages/tgui/styles/interfaces/Uplink.scss index feef11f78596c..40a1271f82102 100644 --- a/tgui/packages/tgui/styles/interfaces/Uplink.scss +++ b/tgui/packages/tgui/styles/interfaces/Uplink.scss @@ -1,4 +1,3 @@ - @use '../base.scss'; @use '../colors.scss'; From ec48143bb4428a6a8d5e57cafdcd9418fe82b27b Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 14 Mar 2024 23:08:53 +0000 Subject: [PATCH 16/62] Update tgui/packages/tgui/interfaces/Uplink.js --- tgui/packages/tgui/interfaces/Uplink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index bd8347c6730c8..071557d7a5016 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -3,7 +3,7 @@ import { useBackend, useLocalState } from '../backend'; import { Stack, Box, Button, Flex, Input, Section, Table, Tabs, NoticeBox, Grid, Divider, Icon, Tooltip } from '../components'; import { formatMoney } from '../format'; import { Window } from '../layouts'; -import '../styles/components/Uplink.scss'; +import '../styles/interfaces/Uplink.scss'; import { NtosRadarMap } from './NtosRadar'; const MAX_SEARCH_RESULTS = 25; From d8191343e04ff4ba6a9e96ed3b52220e0c5b56ce Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 07:31:42 +0000 Subject: [PATCH 17/62] Uses SSticker.minds instead of looping through mobs --- code/controllers/subsystem/priority_directives.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 85f35e2de9c58..03a1b3293297c 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -22,10 +22,10 @@ SUBSYSTEM_DEF(directives) return // Find all the minds var/list/player_minds = list() - for (var/mob/player in GLOB.alive_mob_list) - if (!ishuman(player) || !is_station_level(player.z) || !player.mind) + for (var/datum/mind/player_mind in SSticker.minds) + if (!ishuman(player_mind.current) || !is_station_level(player_mind.current.z)) continue - player_minds += player.mind + player_minds += player_mind // Bring on the mission var/list/valid_directives = list() for (var/datum/priority_directive/directive in directives) From 7cefd478c4c9fc18f66971187d6a2b085a3cbf3f Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 07:35:28 +0000 Subject: [PATCH 18/62] Make things in different orbital locations not trackable entirely --- code/game/gamemodes/objectives/basic/steal.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/game/gamemodes/objectives/basic/steal.dm b/code/game/gamemodes/objectives/basic/steal.dm index 7cbd2f2e6089a..7d01a28dfe5b5 100644 --- a/code/game/gamemodes/objectives/basic/steal.dm +++ b/code/game/gamemodes/objectives/basic/steal.dm @@ -14,6 +14,9 @@ GLOBAL_LIST_EMPTY(possible_items) var/atom/tracked = null for (var/atom/target in get_trackables_by_type(steal_target, TRUE)) var/turf/target_turf = get_turf(target) + // Objectives in incorrect locations are simply not trackable + if (!compare_z(source_turf, target_turf)) + continue // Prioritise things that are on the same z var/dist = get_dist(target, source) + abs(source_turf.z - target_turf.z) * 1000 if (dist > closest) From c0a7f2bfcc38ec212fc0af3c86159c6fd65bd1a0 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 07:43:44 +0000 Subject: [PATCH 19/62] Clearly indicates internal function vs public ones, renames activate() to start() and check() to can_run() --- code/controllers/subsystem/priority_directives.dm | 6 +++--- .../traitor/directives/priority_directive.dm | 12 ++++++------ .../directives/secure_deaddrop/secure_deaddrop.dm | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 03a1b3293297c..796db9118aa7b 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -29,7 +29,7 @@ SUBSYSTEM_DEF(directives) // Bring on the mission var/list/valid_directives = list() for (var/datum/priority_directive/directive in directives) - if (!directive.check(GLOB.uplinks, player_minds)) + if (!directive.can_run(GLOB.uplinks, player_minds)) continue valid_directives += directive if (!length(valid_directives)) @@ -37,7 +37,7 @@ SUBSYSTEM_DEF(directives) next_directive_time = world.time + 1 MINUTES return var/datum/priority_directive/selected = pick(active_directive) - selected.activate(GLOB.uplinks, player_minds) + selected.start(GLOB.uplinks, player_minds) next_directive_time = INFINITY active_directive = selected @@ -54,7 +54,7 @@ SUBSYSTEM_DEF(directives) continue player_minds += player.mind var/datum/priority_directive/selected = pick(SSdirectives.directives) - selected.activate(GLOB.uplinks, player_minds) + selected.start(GLOB.uplinks, player_minds) SSdirectives.next_directive_time = INFINITY SSdirectives.active_directive = selected diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index c38b5692a13d2..b9825fd60b4bf 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -12,18 +12,18 @@ . = ..() /// Check if we are allowed to run this directive or not -/datum/priority_directive/proc/check(list/uplinks, list/player_minds) +/datum/priority_directive/proc/can_run(list/uplinks, list/player_minds) SHOULD_NOT_OVERRIDE(TRUE) teams.Cut() - allocate_teams(uplinks, player_minds) + _allocate_teams(uplinks, player_minds) return !rejected /// Allocate teams for this directive. Call reject() to reject this directive and /// add_antagonist_team to add antagonist teams. -/datum/priority_directive/proc/allocate_teams(list/uplinks, list/player_minds) +/datum/priority_directive/proc/_allocate_teams(list/uplinks, list/player_minds) /// Return the reward type and amount -/datum/priority_directive/proc/generate(list/uplinks, list/player_minds) +/datum/priority_directive/proc/_generate(list/uplinks, list/player_minds) /// Get the tracking target of this atom /datum/priority_directive/proc/get_track_atom() @@ -36,10 +36,10 @@ SSdirectives.active_directive = null /// Activate the directive, requires a list of traitor datums and security minsd -/datum/priority_directive/proc/activate(list/uplinks, list/player_minds) +/datum/priority_directive/proc/start(list/uplinks, list/player_minds) SHOULD_NOT_OVERRIDE(TRUE) end_at = world.time + 10 MINUTES - tc_reward = generate(uplinks, player_minds) + tc_reward = _generate(uplinks, player_minds) /// Advertise this directive to security objectives consoles /datum/priority_directive/proc/advertise_security() diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index 1ffabbebc81d3..8904ac823f808 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -6,7 +6,7 @@ box which will automatically unlock after a set period of time." var/obj/item/storage/deaddrop_box/target -/datum/priority_directive/deaddrop/allocate_teams(list/uplinks, list/player_minds) +/datum/priority_directive/deaddrop/_allocate_teams(list/uplinks, list/player_minds) if (length(uplinks) <= 1) reject() return @@ -14,7 +14,7 @@ // Create individual teams add_antagonist_team(antag) -/datum/priority_directive/deaddrop/generate(list/uplinks, list/player_minds) +/datum/priority_directive/deaddrop/_generate(list/uplinks, list/player_minds) // Spawn the deaddrop package var/tc_count = rand(4, 3 + length(uplinks)) // Put the deaddrop somewhere From fc2f357e48026b05dfee5b2d007b4eb3e87696ed Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 08:41:00 +0000 Subject: [PATCH 20/62] Start of the beacon objective --- beestation.dme | 1 + .../directives/deploy_beacon/deploy_beacon.dm | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm diff --git a/beestation.dme b/beestation.dme index acdb91e976246..50a32543d24e1 100644 --- a/beestation.dme +++ b/beestation.dme @@ -2125,6 +2125,7 @@ #include "code\modules\antagonists\traitor\backstory\traitor_datum_backstory.dm" #include "code\modules\antagonists\traitor\backstory\traitor_factions.dm" #include "code\modules\antagonists\traitor\directives\priority_directive.dm" +#include "code\modules\antagonists\traitor\directives\deploy_beacon\deploy_beacon.dm" #include "code\modules\antagonists\traitor\directives\secure_deaddrop\deaddrop_box.dm" #include "code\modules\antagonists\traitor\directives\secure_deaddrop\secure_deaddrop.dm" #include "code\modules\antagonists\traitor\equipment\contractor.dm" diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm new file mode 100644 index 0000000000000..3eeddfa606a93 --- /dev/null +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -0,0 +1,28 @@ +/datum/priority_directive/deploy_beacon + name = "Deploy Beacon" + objective_explanation = "Secure a trackable lockbox which will unlock after 10 minutes." + details = "We have identified a deaddrop that has been placed by a rival spy agency and have maintained an accurate track on the box. \ + You have the option to track and secure the valuable items before anyone else gets to them. The items are stored in a trackable \ + box which will automatically unlock after a set period of time." + +/datum/priority_directive/deploy_beacon/_allocate_teams(list/uplinks, list/player_minds) + if (length(uplinks) <= 3) + reject() + return + var/list/a = list() + var/list/b = list() + var/i = 0 + for (var/datum/component/uplink/antag in uplinks) + if ((i++ % 2) == 0) + a += antag + else + b += antag + // Create 2 teams + add_antagonist_team(a) + add_antagonist_team(b) + +/datum/priority_directive/deploy_beacon/_generate(list/uplinks, list/player_minds) + return + +/datum/priority_directive/deploy_beacon/get_track_atom() + return target From 5fda2f08195ab9d35c8a456f13fbfdd8fcca6694 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:23:23 +0000 Subject: [PATCH 21/62] Play a sound when the box unlocks --- .../traitor/directives/deploy_beacon/deploy_beacon.dm | 6 ++++++ .../traitor/directives/secure_deaddrop/deaddrop_box.dm | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index 3eeddfa606a93..14ad728a92283 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -4,11 +4,17 @@ details = "We have identified a deaddrop that has been placed by a rival spy agency and have maintained an accurate track on the box. \ You have the option to track and secure the valuable items before anyone else gets to them. The items are stored in a trackable \ box which will automatically unlock after a set period of time." + // Don't track this for deletion, since we need to maintain a track on the same position + // when a turf is changed. + var/turf/center_turf /datum/priority_directive/deploy_beacon/_allocate_teams(list/uplinks, list/player_minds) if (length(uplinks) <= 3) reject() return + // Pick a location that the beacon needs to be deployed at, somewhere out of prying eyes + + // Generate the teams var/list/a = list() var/list/b = list() var/i = 0 diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm index c75cb595a82f2..8ad4d5fa1a5d4 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm @@ -14,9 +14,14 @@ obj_flags &= ~INDESTRUCTIBLE var/datum/component/storage/storage = GetComponent(/datum/component/storage) storage.locked = FALSE + if (ismob(loc)) + var/mob/person = loc + to_chat(person, "[name] unlocks!") + // Sound only plays 3 tile range + playsound(src, 'sound/machines/boltsup.ogg', 40, extra_range = -SOUND_RANGE + 3) /datum/component/storage/concrete/deaddrop locked = TRUE can_transfer = FALSE emp_shielded = TRUE - quickdraw = TRUE + quickdraw = FALSE From 86eab2fd7497e3260aea7b9991be25a4020090b7 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 10:48:01 +0000 Subject: [PATCH 22/62] Adds in a notification when a new directive comes in --- .../controllers/subsystem/priority_directives.dm | 2 +- .../directives/deploy_beacon/deploy_beacon.dm | 2 +- .../traitor/directives/priority_directive.dm | 16 ++++++++++++++++ interface/stylesheet.dm | 9 +++++++++ .../tgui-panel/styles/goon/chat-dark.scss | 9 +++++++++ .../tgui-panel/styles/goon/chat-light.scss | 9 +++++++++ 6 files changed, 45 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 796db9118aa7b..eccb1f67207f7 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -53,7 +53,7 @@ SUBSYSTEM_DEF(directives) if (!ishuman(player) || !is_station_level(player.z) || !player.mind) continue player_minds += player.mind - var/datum/priority_directive/selected = pick(SSdirectives.directives) + var/datum/priority_directive/selected = locate(/datum/priority_directive/deaddrop) in SSdirectives.directives selected.start(GLOB.uplinks, player_minds) SSdirectives.next_directive_time = INFINITY SSdirectives.active_directive = selected diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index 14ad728a92283..70db1acd69f62 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -31,4 +31,4 @@ return /datum/priority_directive/deploy_beacon/get_track_atom() - return target + return null diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index b9825fd60b4bf..831b1e0fb88f1 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -40,6 +40,22 @@ SHOULD_NOT_OVERRIDE(TRUE) end_at = world.time + 10 MINUTES tc_reward = _generate(uplinks, player_minds) + for (var/datum/component/uplink/uplink in GLOB.uplinks) + var/syndicate_antag = FALSE + var/mob/living/current = uplink.parent + while (current && !istype(current)) + current = current.loc + if (istype(current)) + for (var/datum/antagonist/antag in current.mind?.antag_datums) + syndicate_antag ||= antag.faction == FACTION_SYNDICATE + else + // Nobody to notify + continue + // If we are not held by a syndicate, and we are locked then do not give a notification + if (!syndicate_antag && uplink.locked) + continue + to_chat(current, "NEW PRIORITY DIRECTIVE RECEIVED. SEE UPLINK FOR DETAILS.") + SEND_SOUND(current, sound('sound/machines/twobeep_high.ogg', volume = 50)) /// Advertise this directive to security objectives consoles /datum/priority_directive/proc/advertise_security() diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index dd4a8786dc2f2..d0d29bc370f9c 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -69,6 +69,15 @@ h1.alert, h2.alert {color: #000000;} .disarm {color: #990000;} .passive {color: #660000;} +.traitor_objective { + font-family: monospace; + color: #f08181; + background-color: #000000; + border: 1px solid #f08181; + padding-left: 5px; + padding-right: 5px; +} + .userdanger {color: #ff0000; font-weight: bold; font-size: 3;} .danger {color: #ff0000;} .warning {color: #ff0000; font-style: italic;} diff --git a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss index f31a16878b8e3..a009b08915026 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss @@ -553,6 +553,15 @@ em { color: #a00f0f; } +.traitor_objective { + font-family: monospace; + color: #f08181; + background-color: #000000; + border: 1px solid #f08181; + padding-left: 5px; + padding-right: 5px; +} + .userdanger { color: #c51e1e; font-weight: bold; diff --git a/tgui/packages/tgui-panel/styles/goon/chat-light.scss b/tgui/packages/tgui-panel/styles/goon/chat-light.scss index 52900f43b4ac1..e1bacc847ac15 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-light.scss @@ -553,6 +553,15 @@ h2.alert { color: #660000; } +.traitor_objective { + font-family: monospace; + color: #f08181; + background-color: #000000; + border: 1px solid #f08181; + padding-left: 5px; + padding-right: 5px; +} + .userdanger { color: #ff0000; font-weight: bold; From eb60dad2beea2a4997a57e7485460d973622cffd Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:31:39 +0000 Subject: [PATCH 23/62] Traitors lose 5 TC --- beestation.dme | 2 + code/__DEFINES/antagonists.dm | 6 +-- code/__HELPERS/tuples.dm | 21 ++++++++++ .../subsystem/priority_directives.dm | 6 ++- .../directives/deploy_beacon/beacon.dm | 11 ++++++ .../directives/deploy_beacon/deploy_beacon.dm | 38 +++++++++++++------ .../traitor/directives/priority_directive.dm | 20 +++++++--- .../secure_deaddrop/secure_deaddrop.dm | 8 ++-- 8 files changed, 87 insertions(+), 25 deletions(-) create mode 100644 code/__HELPERS/tuples.dm create mode 100644 code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm diff --git a/beestation.dme b/beestation.dme index 50a32543d24e1..35ce06e06e13b 100644 --- a/beestation.dme +++ b/beestation.dme @@ -282,6 +282,7 @@ #include "code\__HELPERS\string_lists.dm" #include "code\__HELPERS\text.dm" #include "code\__HELPERS\time.dm" +#include "code\__HELPERS\tuples.dm" #include "code\__HELPERS\turfs.dm" #include "code\__HELPERS\type2type.dm" #include "code\__HELPERS\type_processing.dm" @@ -2125,6 +2126,7 @@ #include "code\modules\antagonists\traitor\backstory\traitor_datum_backstory.dm" #include "code\modules\antagonists\traitor\backstory\traitor_factions.dm" #include "code\modules\antagonists\traitor\directives\priority_directive.dm" +#include "code\modules\antagonists\traitor\directives\deploy_beacon\beacon.dm" #include "code\modules\antagonists\traitor\directives\deploy_beacon\deploy_beacon.dm" #include "code\modules\antagonists\traitor\directives\secure_deaddrop\deaddrop_box.dm" #include "code\modules\antagonists\traitor\directives\secure_deaddrop\secure_deaddrop.dm" diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 3bcd628b099d9..b6a4875b346b7 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -112,13 +112,13 @@ #define BLOB_REROLL_COST 40 /// How many telecrystals a normal traitor starts with -#define TELECRYSTALS_DEFAULT 20 +#define TELECRYSTALS_DEFAULT 15 /// How many telecrystals mapper/admin only "precharged" uplink implant #define TELECRYSTALS_PRELOADED_IMPLANT 10 -/// The normal cost of an uplink implant; used for calcuating how many +/// The cost of a roundstart uplink implant; used for calcuating how many /// TC to charge someone if they get a free implant through choice or /// because they have nothing else that supports an implant. -#define UPLINK_IMPLANT_TELECRYSTAL_COST 3 +#define UPLINK_IMPLANT_TELECRYSTAL_COST 1 ///Checks if given mob is a hive host #define IS_HIVEHOST(mob) (mob.mind?.has_antag_datum(/datum/antagonist/hivemind)) diff --git a/code/__HELPERS/tuples.dm b/code/__HELPERS/tuples.dm new file mode 100644 index 0000000000000..2cc35765d938c --- /dev/null +++ b/code/__HELPERS/tuples.dm @@ -0,0 +1,21 @@ +/** + * Tuple types are basic types that hold data. + * It is a shorthand for creating basic types. + * This can be simplified with pointers. + */ + +#define NAMED_TUPLE_1(NAME, TYPE_1, NAME_1) /datum/##NAME {\ + var##TYPE_1/##NAME_1;\ +}\ +/datum/##NAME/New(...) {\ + src.##NAME_1 = args[1];\ +} + +#define NAMED_TUPLE_2(NAME, TYPE_1, NAME_1, TYPE_2, NAME_2) /datum/##NAME {\ + var##TYPE_1/##NAME_1;\ + var##TYPE_2/##NAME_2;\ +}\ +/datum/##NAME/New(...) {\ + src.##NAME_1 = args[1];\ + src.##NAME_2 = args[2];\ +} diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index eccb1f67207f7..5e4798ff36b7b 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -53,7 +53,10 @@ SUBSYSTEM_DEF(directives) if (!ishuman(player) || !is_station_level(player.z) || !player.mind) continue player_minds += player.mind - var/datum/priority_directive/selected = locate(/datum/priority_directive/deaddrop) in SSdirectives.directives + var/datum/priority_directive/selected = input(src, "What do you want?", "What do you want?") as null|anything in SSdirectives.directives + if (!selected) + return + selected.can_run(GLOB.uplinks, player_minds, TRUE) selected.start(GLOB.uplinks, player_minds) SSdirectives.next_directive_time = INFINITY SSdirectives.active_directive = selected @@ -97,6 +100,7 @@ SUBSYSTEM_DEF(directives) "track_x" = track_turf?.x, "track_y" = track_turf?.y, "track_z" = track_turf?.z, + "action" = active_directive.get_special_action()?.action_name )) data["objectives"] = known_objectives return data diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm new file mode 100644 index 0000000000000..b87f7e46dcd2e --- /dev/null +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -0,0 +1,11 @@ +/obj/item/uplink_beacon + name = "uplink beacon" + desc = "A portable, deployable beacon used to establish long-range communications." + +/obj/item/uplink_beacon/ComponentInitialize() + . = ..() + AddComponent(/datum/component/deployable, /obj/structure/uplink_beacon, time_to_deploy = 3 SECONDS) + +/obj/structure/uplink_beacon + name = "uplink beacon" + desc = "A small beacon attempting to establish communication with an unknown source." diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index 70db1acd69f62..18b3834f2492e 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -1,19 +1,32 @@ /datum/priority_directive/deploy_beacon name = "Deploy Beacon" - objective_explanation = "Secure a trackable lockbox which will unlock after 10 minutes." - details = "We have identified a deaddrop that has been placed by a rival spy agency and have maintained an accurate track on the box. \ - You have the option to track and secure the valuable items before anyone else gets to them. The items are stored in a trackable \ - box which will automatically unlock after a set period of time." + objective_explanation = "Activate a beacon with your team's signal at the specified location." + details = "An opportunity has opened up for communication to be established with ground agents, you need \ + to deploy a beacon encoded our organisation's encrypion code. Hostile agents may try to swap the code \ + for their own, which you need to prevent from happening. There are friendly agents supporting you on this mission \ + but their identities are unknown." // Don't track this for deletion, since we need to maintain a track on the same position - // when a turf is changed. + // when a turf is changed. var/turf/center_turf -/datum/priority_directive/deploy_beacon/_allocate_teams(list/uplinks, list/player_minds) - if (length(uplinks) <= 3) +/datum/priority_directive/deploy_beacon/_allocate_teams(list/uplinks, list/player_minds, force = FALSE) + if (length(uplinks) <= 3 && !force) reject() return // Pick a location that the beacon needs to be deployed at, somewhere out of prying eyes - + var/area_types = list() + area_types += typesof(/area/maintenance) + center_turf = null + while (!isturf(center_turf) && length(area_types)) + var/target_type = pick(area_types) + var/area/area = GLOB.areas_by_type[target_type] + if (!area) + area_types -= target_type + continue + center_turf = pick(area.contained_turfs) + if (!center_turf) + reject() + return // Generate the teams var/list/a = list() var/list/b = list() @@ -27,8 +40,11 @@ add_antagonist_team(a) add_antagonist_team(b) -/datum/priority_directive/deploy_beacon/_generate(list/uplinks, list/player_minds) - return +/datum/priority_directive/deploy_beacon/_generate(list/teams) + return rand(5, 9) /datum/priority_directive/deploy_beacon/get_track_atom() - return null + return center_turf + +/datum/priority_directive/deploy_beacon/get_special_action(datum/component/uplink) + return new /datum/directive_special_action("Get beacon") diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 831b1e0fb88f1..75850fb78f1f4 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -1,3 +1,6 @@ +NAMED_TUPLE_1(directive_team, /list, uplinks) +NAMED_TUPLE_1(directive_special_action,, action_name) + /// This can only be running once at a time, do not run in parallel /datum/priority_directive var/name @@ -12,18 +15,18 @@ . = ..() /// Check if we are allowed to run this directive or not -/datum/priority_directive/proc/can_run(list/uplinks, list/player_minds) +/datum/priority_directive/proc/can_run(list/uplinks, list/player_minds, force = FALSE) SHOULD_NOT_OVERRIDE(TRUE) teams.Cut() - _allocate_teams(uplinks, player_minds) + _allocate_teams(uplinks, player_minds, force) return !rejected /// Allocate teams for this directive. Call reject() to reject this directive and /// add_antagonist_team to add antagonist teams. -/datum/priority_directive/proc/_allocate_teams(list/uplinks, list/player_minds) +/datum/priority_directive/proc/_allocate_teams(list/uplinks, list/player_minds, force = FALSE) /// Return the reward type and amount -/datum/priority_directive/proc/_generate(list/uplinks, list/player_minds) +/datum/priority_directive/proc/_generate(list/teams) /// Get the tracking target of this atom /datum/priority_directive/proc/get_track_atom() @@ -39,7 +42,7 @@ /datum/priority_directive/proc/start(list/uplinks, list/player_minds) SHOULD_NOT_OVERRIDE(TRUE) end_at = world.time + 10 MINUTES - tc_reward = _generate(uplinks, player_minds) + tc_reward = _generate(teams) for (var/datum/component/uplink/uplink in GLOB.uplinks) var/syndicate_antag = FALSE var/mob/living/current = uplink.parent @@ -63,7 +66,7 @@ /datum/priority_directive/proc/add_antagonist_team(list/uplinks) SHOULD_NOT_OVERRIDE(TRUE) - teams += list(uplinks) + teams += new /datum/directive_team(uplinks) /// Reject this directive, prevent it from firing /datum/priority_directive/proc/reject() @@ -84,3 +87,8 @@ continue targets += mind return pick(targets) + +/// Get any special uplink actions +/datum/priority_directive/proc/get_special_action(datum/component/uplink) + RETURN_TYPE(/datum/directive_special_action) + return null diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index 8904ac823f808..4374a54beb809 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -6,17 +6,17 @@ box which will automatically unlock after a set period of time." var/obj/item/storage/deaddrop_box/target -/datum/priority_directive/deaddrop/_allocate_teams(list/uplinks, list/player_minds) - if (length(uplinks) <= 1) +/datum/priority_directive/deaddrop/_allocate_teams(list/uplinks, list/player_minds, force = FALSE) + if (length(uplinks) <= 1 && !force) reject() return for (var/datum/component/uplink/antag in uplinks) // Create individual teams add_antagonist_team(antag) -/datum/priority_directive/deaddrop/_generate(list/uplinks, list/player_minds) +/datum/priority_directive/deaddrop/_generate(list/teams) // Spawn the deaddrop package - var/tc_count = rand(4, 3 + length(uplinks)) + var/tc_count = rand(4, 3 + length(teams)) // Put the deaddrop somewhere var/turf/selected = get_random_station_turf() while (!istype(selected, /turf/open/floor/plasteel)) From f87e1d3ef7240000b637107183bf2b94f8e5763c Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:56:18 +0000 Subject: [PATCH 24/62] Fixes review --- .../controllers/subsystem/priority_directives.dm | 5 +++++ code/datums/components/uplink.dm | 3 +++ code/game/gamemodes/objectives/_objective.dm | 9 +++++++++ code/game/gamemodes/objectives/basic/steal.dm | 2 +- .../traitor/directives/deploy_beacon/beacon.dm | 16 ++++++++++++++++ .../directives/deploy_beacon/deploy_beacon.dm | 12 ++++++++++++ .../traitor/directives/priority_directive.dm | 3 +++ .../directives/secure_deaddrop/deaddrop_box.dm | 2 +- tgui/packages/tgui/interfaces/Uplink.js | 16 +++++++++++----- tgui/packages/tgui/interfaces/UplinkBeacon.js | 13 +++++++++++++ tgui/packages/tgui/styles/interfaces/Uplink.scss | 4 ++-- 11 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/UplinkBeacon.js diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 5e4798ff36b7b..c591029866342 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -104,3 +104,8 @@ SUBSYSTEM_DEF(directives) )) data["objectives"] = known_objectives return data + +/datum/controller/subsystem/directives/proc/directive_action(datum/component/uplink/uplink, mob/living/user) + if (!active_directive) + return + active_directive.perform_special_action(uplink, user) diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 78bb73ffc3efa..492a605b6df84 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -237,6 +237,9 @@ GLOBAL_LIST_EMPTY(uplinks) if("compact_toggle") compact_mode = !compact_mode return TRUE + if ("directive_action") + SSdirectives.directive_action(src, usr) + return TRUE /datum/component/uplink/ui_assets(mob/user) return list( diff --git a/code/game/gamemodes/objectives/_objective.dm b/code/game/gamemodes/objectives/_objective.dm index 653907689792f..572be01f75708 100644 --- a/code/game/gamemodes/objectives/_objective.dm +++ b/code/game/gamemodes/objectives/_objective.dm @@ -238,6 +238,15 @@ GLOBAL_LIST(admin_objective_list) //Prefilled admin assignable objective list break if (!valid) continue + // Everyone on the team must own this stash. + // Its not good enough for a team item to go into + // a stash owned by 1 person. + for (var/datum/mind/mind in owners) + if (!(mind in stash.stash_minds)) + valid = FALSE + break + if (!valid) + continue // Must be something that we can store in if (!istype(stash.parent, /obj/item/storage)) continue diff --git a/code/game/gamemodes/objectives/basic/steal.dm b/code/game/gamemodes/objectives/basic/steal.dm index 7d01a28dfe5b5..d25ea539f65d1 100644 --- a/code/game/gamemodes/objectives/basic/steal.dm +++ b/code/game/gamemodes/objectives/basic/steal.dm @@ -15,7 +15,7 @@ GLOBAL_LIST_EMPTY(possible_items) for (var/atom/target in get_trackables_by_type(steal_target, TRUE)) var/turf/target_turf = get_turf(target) // Objectives in incorrect locations are simply not trackable - if (!compare_z(source_turf, target_turf)) + if (!compare_z(source_turf.z, target_turf.z)) continue // Prioritise things that are on the same z var/dist = get_dist(target, source) + abs(source_turf.z - target_turf.z) * 1000 diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index b87f7e46dcd2e..02a1414ac8cfb 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -1,6 +1,8 @@ /obj/item/uplink_beacon name = "uplink beacon" desc = "A portable, deployable beacon used to establish long-range communications." + icon = 'icons/obj/fulton.dmi' + icon_state = "extraction_point" /obj/item/uplink_beacon/ComponentInitialize() . = ..() @@ -9,3 +11,17 @@ /obj/structure/uplink_beacon name = "uplink beacon" desc = "A small beacon attempting to establish communication with an unknown source." + icon = 'icons/obj/fulton.dmi' + icon_state = "extraction_point" + var/current_frequency = 0 + +/obj/structure/uplink_beacon/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "UplinkBeacon") + ui.open() + +/obj/structure/uplink_beacon/ui_data(mob/user) + var/list/data = list() + data["frequency"] = current_frequency + return data diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index 18b3834f2492e..edf6224226058 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -8,8 +8,11 @@ // Don't track this for deletion, since we need to maintain a track on the same position // when a turf is changed. var/turf/center_turf + // List of the uplinks that already took the beacon + var/list/empty_uplinks = list() /datum/priority_directive/deploy_beacon/_allocate_teams(list/uplinks, list/player_minds, force = FALSE) + empty_uplinks.Cut() if (length(uplinks) <= 3 && !force) reject() return @@ -48,3 +51,12 @@ /datum/priority_directive/deploy_beacon/get_special_action(datum/component/uplink) return new /datum/directive_special_action("Get beacon") + +/datum/priority_directive/deploy_beacon/perform_special_action(datum/component/uplink, mob/living/user) + if (uplink in empty_uplinks) + to_chat(user, "You have already received your beacon! Pick it up or find someone aligned with your mission.") + return + empty_uplinks += uplink + // Give the requester a beacon + var/obj/item/spawned = new /obj/item/uplink_beacon(user.loc) + user.put_in_active_hand(spawned) diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 75850fb78f1f4..9ee28dba16fcb 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -92,3 +92,6 @@ NAMED_TUPLE_1(directive_special_action,, action_name) /datum/priority_directive/proc/get_special_action(datum/component/uplink) RETURN_TYPE(/datum/directive_special_action) return null + +/// Perform the special directive action +/datum/priority_directive/proc/perform_special_action(datum/component/uplink, mob/living/user) diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm index 8ad4d5fa1a5d4..b13292b03885d 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm @@ -18,7 +18,7 @@ var/mob/person = loc to_chat(person, "[name] unlocks!") // Sound only plays 3 tile range - playsound(src, 'sound/machines/boltsup.ogg', 40, extra_range = -SOUND_RANGE + 3) + playsound(src, 'sound/machines/boltsup.ogg', 40, extrarange = -SOUND_RANGE + 3) /datum/component/storage/concrete/deaddrop locked = TRUE diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 071557d7a5016..3abf7faf1fcd9 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -47,7 +47,7 @@ const Directives = (props, context) => { const { act, data } = useBackend(context); const { pos_x = 0, pos_y = 0, pos_z = 0, time, objectives = [] } = data.objectives; const selectedObjective = objectives[selected] || objectives[0]; - const { track_x, track_y, track_z } = selectedObjective || {}; + const { track_x, track_y, track_z, action } = selectedObjective || {}; const dx = track_x - pos_x; const dy = track_y - pos_y; const angle = (360 / (Math.PI * 2)) * Math.atan2(dx, dy); @@ -131,14 +131,20 @@ const Directives = (props, context) => {
- + - - No Reward + + {selectedObjective.reward ? selectedObjective.reward + " Telecrystals" : "No reward"}
-
diff --git a/tgui/packages/tgui/interfaces/UplinkBeacon.js b/tgui/packages/tgui/interfaces/UplinkBeacon.js new file mode 100644 index 0000000000000..ee915ea497003 --- /dev/null +++ b/tgui/packages/tgui/interfaces/UplinkBeacon.js @@ -0,0 +1,13 @@ +import { Window } from '../layouts'; + +export const UplinkBeacon = (props, context) => { + return ( + + + 1 2 3 + 4 5 6 + 7 8 9 + + + ); +}; diff --git a/tgui/packages/tgui/styles/interfaces/Uplink.scss b/tgui/packages/tgui/styles/interfaces/Uplink.scss index 40a1271f82102..c51cb82922caf 100644 --- a/tgui/packages/tgui/styles/interfaces/Uplink.scss +++ b/tgui/packages/tgui/styles/interfaces/Uplink.scss @@ -89,10 +89,10 @@ .directive_prize_info { display: flex; flex-direction: row; - min-width: 30%; + min-width: 40%; vertical-align: middle; height: 40px; - text-align: center; + text-align: left; align-items: center; padding: 10px; } From 0fef14e8421d0dcca8bdada1b662148d674716d6 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 17:15:43 +0000 Subject: [PATCH 25/62] Adds the beacon calibration UI --- .../directives/deploy_beacon/beacon.dm | 13 ++ tgui/packages/tgui/interfaces/UplinkBeacon.js | 134 +++++++++++++++++- 2 files changed, 143 insertions(+), 4 deletions(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index 02a1414ac8cfb..69d477f158406 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -25,3 +25,16 @@ var/list/data = list() data["frequency"] = current_frequency return data + +/obj/structure/uplink_beacon/ui_act(action, params) + if (..()) + return FALSE + var/new_num = text2num(params["freq"]) + if (!new_num) + return FALSE + new_num = round(new_num) + if (new_num < 0 || new_num > 8) + return FALSE + current_frequency = new_num + ui_update() + return TRUE diff --git a/tgui/packages/tgui/interfaces/UplinkBeacon.js b/tgui/packages/tgui/interfaces/UplinkBeacon.js index ee915ea497003..41d97c220a73c 100644 --- a/tgui/packages/tgui/interfaces/UplinkBeacon.js +++ b/tgui/packages/tgui/interfaces/UplinkBeacon.js @@ -1,12 +1,138 @@ +import { Button, NoticeBox, Table } from 'tgui/components'; import { Window } from '../layouts'; export const UplinkBeacon = (props, context) => { + const { act, data } = useBackend(context); + const { + frequency, + } = data; + let channel = "green"; + switch (frequency) + { + case 1: + channel = "purple"; + break; + case 2: + channel = "yellow"; + break; + case 3: + channel = "orange"; + break; + case 4: + channel = "red"; + break; + case 5: + channel = "black"; + break; + case 6: + channel = "white"; + break; + case 7: + channel = "blue"; + break; + case 8: + channel = "brown"; + break; + } return ( - + - 1 2 3 - 4 5 6 - 7 8 9 + + Beacon broadcasting on {channel} channel + + + + +
); From f6db5e0e6a3e3941e40cc3c9dffa4742eec0ff7d Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:39:23 +0000 Subject: [PATCH 26/62] Stuff --- code/datums/components/deployable.dm | 7 ++++++- .../traitor/directives/deploy_beacon/beacon.dm | 14 ++++++++++++-- .../directives/deploy_beacon/deploy_beacon.dm | 1 + tgui/packages/tgui/interfaces/UplinkBeacon.js | 6 +++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/code/datums/components/deployable.dm b/code/datums/components/deployable.dm index f2b031c58b8c5..9561bfc9079b1 100644 --- a/code/datums/components/deployable.dm +++ b/code/datums/components/deployable.dm @@ -13,13 +13,15 @@ var/empty_icon /// The type that we can use to reload this deployable var/reload_type + /// The can deploy check + var/datum/callback/can_deploy_check = null /// For when consumed is false, is the carrier object currently loaded and ready to deploy its payload item? /// Private as we don't want external modifications to this VAR_PRIVATE/loaded = FALSE /// The atom parent of this VAR_PRIVATE/obj/item/item_parent -/datum/component/deployable/Initialize(deployed_object, consumed = TRUE, time_to_deploy = 0 SECONDS, ignores_mob_density = TRUE, dense_deployment = FALSE, empty_icon = null, loaded = FALSE, reload_type = null) +/datum/component/deployable/Initialize(deployed_object, consumed = TRUE, time_to_deploy = 0 SECONDS, ignores_mob_density = TRUE, dense_deployment = FALSE, empty_icon = null, loaded = FALSE, reload_type = null, datum/callback/can_deploy_check) . = ..() if (!isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -34,6 +36,7 @@ src.empty_icon = empty_icon src.loaded = loaded src.reload_type = reload_type + src.can_deploy_check = can_deploy_check RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_attack_self)) RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_afterattack)) @@ -111,6 +114,8 @@ if (user) to_chat(user, "[item_parent] has nothing to deploy!") return + if (can_deploy_check && !can_deploy_check.Invoke(user, location)) + return if(!location) //if no location was passed we use the current location. location = item_parent.loc if(isopenturf(location)) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index 69d477f158406..44e9b2ca9ff5f 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -6,7 +6,17 @@ /obj/item/uplink_beacon/ComponentInitialize() . = ..() - AddComponent(/datum/component/deployable, /obj/structure/uplink_beacon, time_to_deploy = 3 SECONDS) + AddComponent(/datum/component/deployable, /obj/structure/uplink_beacon, time_to_deploy = 3 SECONDS, can_deploy_check = PROC_REF(can_deploy)) + +/obj/item/uplink_beacon/proc/can_deploy(mob/user, atom/location) + var/datum/priority_directive/deploy_beacon/beacon = SSdirectives.active_directive + if (!istype(beacon)) + to_chat(user, "The beacon doesn't work in this location.") + return FALSE + if (beacon.deployed_beacon) + to_chat(user, "A beacon is already active, find and interact with it to modify its tramission frequency.") + return FALSE + return TRUE /obj/structure/uplink_beacon name = "uplink beacon" @@ -30,7 +40,7 @@ if (..()) return FALSE var/new_num = text2num(params["freq"]) - if (!new_num) + if (isnull(new_num)) return FALSE new_num = round(new_num) if (new_num < 0 || new_num > 8) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index edf6224226058..ed46c54ababbc 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -5,6 +5,7 @@ to deploy a beacon encoded our organisation's encrypion code. Hostile agents may try to swap the code \ for their own, which you need to prevent from happening. There are friendly agents supporting you on this mission \ but their identities are unknown." + var/obj/item/uplink_beacon/deployed_beacon // Don't track this for deletion, since we need to maintain a track on the same position // when a turf is changed. var/turf/center_turf diff --git a/tgui/packages/tgui/interfaces/UplinkBeacon.js b/tgui/packages/tgui/interfaces/UplinkBeacon.js index 41d97c220a73c..a9a2896fbce13 100644 --- a/tgui/packages/tgui/interfaces/UplinkBeacon.js +++ b/tgui/packages/tgui/interfaces/UplinkBeacon.js @@ -1,5 +1,6 @@ import { Button, NoticeBox, Table } from 'tgui/components'; import { Window } from '../layouts'; +import { useBackend } from '../backend'; export const UplinkBeacon = (props, context) => { const { act, data } = useBackend(context); @@ -9,6 +10,9 @@ export const UplinkBeacon = (props, context) => { let channel = "green"; switch (frequency) { + case 0: + channel = "green"; + break; case 1: channel = "purple"; break; @@ -61,7 +65,7 @@ export const UplinkBeacon = (props, context) => { height="100%" color="purple" onClick={() => act('set_freq', { - freq: 2, + freq: 1, })} /> From f337ce14dc4c89996467a16e68565a2fb51771c6 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Sat, 16 Mar 2024 10:27:16 +0000 Subject: [PATCH 27/62] A few more beacon things --- .../subsystem/priority_directives.dm | 4 ++-- .../directives/deploy_beacon/beacon.dm | 14 +++++++++++++ .../directives/deploy_beacon/deploy_beacon.dm | 15 ++++++++++++-- .../traitor/directives/priority_directive.dm | 20 ++++++++++++++++--- 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index c591029866342..04a6f27706298 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -93,9 +93,9 @@ SUBSYSTEM_DEF(directives) var/turf/track_turf = get_turf(track_atom) known_objectives += list(list( "name" = active_directive.name, - "tasks" = list(active_directive.objective_explanation), + "tasks" = list(active_directive.get_explanation(uplink)), "time" = active_directive.end_at, - "details" = active_directive.details, + "details" = active_directive.get_details(uplink), "reward" = active_directive.tc_reward, "track_x" = track_turf?.x, "track_y" = track_turf?.y, diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index 44e9b2ca9ff5f..ec0259c5cb2fe 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -48,3 +48,17 @@ current_frequency = new_num ui_update() return TRUE + +/proc/uplink_beacon_channel_to_color(channel) + var/static/list/colours = list( + "green", + "purple", + "yellow", + "orange", + "red", + "black", + "white", + "blue", + "brown" + ) + return colours[channel + 1] diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index ed46c54ababbc..1ab8ea63f26ef 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -31,6 +31,7 @@ if (!center_turf) reject() return + var/list/valid_codes = list(0, 1, 2, 3, 4, 5, 6, 7, 8) // Generate the teams var/list/a = list() var/list/b = list() @@ -41,8 +42,12 @@ else b += antag // Create 2 teams - add_antagonist_team(a) - add_antagonist_team(b) + add_antagonist_team(a, list( + "code" = pick_n_take(valid_codes) + )) + add_antagonist_team(b, list( + "code" = pick_n_take(valid_codes) + )) /datum/priority_directive/deploy_beacon/_generate(list/teams) return rand(5, 9) @@ -61,3 +66,9 @@ // Give the requester a beacon var/obj/item/spawned = new /obj/item/uplink_beacon(user.loc) user.put_in_active_hand(spawned) + +/datum/priority_directive/deploy_beacon/get_explanation(datum/component/uplink) + return "Activate a beacon in the specified location that is broadcasting on the [uplink_beacon_channel_to_color(get_team(uplink).data["code"])] channel." + +/datum/priority_directive/deploy_beacon/get_details(datum/component/uplink) + return objective_explanation diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 9ee28dba16fcb..0684d90807854 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -1,4 +1,4 @@ -NAMED_TUPLE_1(directive_team, /list, uplinks) +NAMED_TUPLE_2(directive_team, /list, uplinks, /list, data) NAMED_TUPLE_1(directive_special_action,, action_name) /// This can only be running once at a time, do not run in parallel @@ -64,9 +64,9 @@ NAMED_TUPLE_1(directive_special_action,, action_name) /datum/priority_directive/proc/advertise_security() SHOULD_NOT_OVERRIDE(TRUE) -/datum/priority_directive/proc/add_antagonist_team(list/uplinks) +/datum/priority_directive/proc/add_antagonist_team(list/uplinks, list/data = null) SHOULD_NOT_OVERRIDE(TRUE) - teams += new /datum/directive_team(uplinks) + teams += new /datum/directive_team(uplinks, islist(data) ? data : list()) /// Reject this directive, prevent it from firing /datum/priority_directive/proc/reject() @@ -93,5 +93,19 @@ NAMED_TUPLE_1(directive_special_action,, action_name) RETURN_TYPE(/datum/directive_special_action) return null +/datum/priority_directive/proc/get_team(datum/component/uplink) + SHOULD_NOT_OVERRIDE(TRUE) + RETURN_TYPE(/datum/directive_team) + for (var/datum/directive_team/team in teams) + if (uplink in team.uplinks) + return team + return null + /// Perform the special directive action /datum/priority_directive/proc/perform_special_action(datum/component/uplink, mob/living/user) + +/datum/priority_directive/proc/get_explanation(datum/component/uplink) + return objective_explanation + +/datum/priority_directive/proc/get_details(datum/component/uplink) + return details From 5937fef7059d4d8e0bc9cf7d140bf353af324ca4 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Wed, 20 Mar 2024 16:33:52 +0000 Subject: [PATCH 28/62] Completes the beacon deployment --- code/__HELPERS/tuples.dm | 6 +- code/datums/components/deployable.dm | 6 +- .../directives/deploy_beacon/beacon.dm | 164 +++++++++++++++++- .../directives/deploy_beacon/deploy_beacon.dm | 37 +++- .../traitor/directives/priority_directive.dm | 52 +++++- icons/obj/traitor_beacon.dmi | Bin 0 -> 1106 bytes interface/stylesheet.dm | 5 + .../tgui-panel/styles/goon/chat-dark.scss | 5 + .../tgui-panel/styles/goon/chat-light.scss | 4 + 9 files changed, 261 insertions(+), 18 deletions(-) create mode 100644 icons/obj/traitor_beacon.dmi diff --git a/code/__HELPERS/tuples.dm b/code/__HELPERS/tuples.dm index 2cc35765d938c..8f31613a93ef2 100644 --- a/code/__HELPERS/tuples.dm +++ b/code/__HELPERS/tuples.dm @@ -5,15 +5,15 @@ */ #define NAMED_TUPLE_1(NAME, TYPE_1, NAME_1) /datum/##NAME {\ - var##TYPE_1/##NAME_1;\ + ##TYPE_1/##NAME_1;\ }\ /datum/##NAME/New(...) {\ src.##NAME_1 = args[1];\ } #define NAMED_TUPLE_2(NAME, TYPE_1, NAME_1, TYPE_2, NAME_2) /datum/##NAME {\ - var##TYPE_1/##NAME_1;\ - var##TYPE_2/##NAME_2;\ + ##TYPE_1/##NAME_1;\ + ##TYPE_2/##NAME_2;\ }\ /datum/##NAME/New(...) {\ src.##NAME_1 = args[1];\ diff --git a/code/datums/components/deployable.dm b/code/datums/components/deployable.dm index 9561bfc9079b1..9bfbc35f1f375 100644 --- a/code/datums/components/deployable.dm +++ b/code/datums/components/deployable.dm @@ -13,7 +13,7 @@ var/empty_icon /// The type that we can use to reload this deployable var/reload_type - /// The can deploy check + /// The can deploy check. Parameters are user and location, a nullable atom and a turf. var/datum/callback/can_deploy_check = null /// For when consumed is false, is the carrier object currently loaded and ready to deploy its payload item? /// Private as we don't want external modifications to this @@ -151,6 +151,8 @@ ///Do not call this directly, use try_deploy instead or else deployed items may end up in invalid locations /datum/component/deployable/proc/deploy(mob/user, atom/location) + if (can_deploy_check && !can_deploy_check.Invoke(user, location)) + return if (user) item_parent.add_fingerprint(user) if(isnull(deployed_object)) //then this must have saved contents to dump directly instead @@ -159,7 +161,7 @@ if (!QDELETED(item_parent)) item_parent.transfer_fingerprints_to(A) else - var/atom/R = new deployed_object(location) + var/atom/R = new deployed_object(location, user) for(var/atom/movable/A in item_parent.contents) A.forceMove(R) if (!QDELETED(item_parent)) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index ec0259c5cb2fe..520453c7486a2 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -1,31 +1,99 @@ /obj/item/uplink_beacon name = "uplink beacon" desc = "A portable, deployable beacon used to establish long-range communications." - icon = 'icons/obj/fulton.dmi' - icon_state = "extraction_point" + icon = 'icons/obj/traitor_beacon.dmi' + icon_state = "base" /obj/item/uplink_beacon/ComponentInitialize() . = ..() - AddComponent(/datum/component/deployable, /obj/structure/uplink_beacon, time_to_deploy = 3 SECONDS, can_deploy_check = PROC_REF(can_deploy)) + AddComponent(/datum/component/deployable, /obj/structure/uplink_beacon, time_to_deploy = 3 SECONDS, can_deploy_check = CALLBACK(src, PROC_REF(can_deploy))) /obj/item/uplink_beacon/proc/can_deploy(mob/user, atom/location) + if (!user || !location) + return FALSE + if (!user.mind.has_antag_datum(/datum/antagonist)) + to_chat(user, "You aren't sure what to do with this.") + return FALSE var/datum/priority_directive/deploy_beacon/beacon = SSdirectives.active_directive if (!istype(beacon)) - to_chat(user, "The beacon doesn't work in this location.") + to_chat(user, "This beacon cannot be used anymore!") return FALSE if (beacon.deployed_beacon) to_chat(user, "A beacon is already active, find and interact with it to modify its tramission frequency.") return FALSE + if (get_dist(src, beacon.center_turf) > 5) + to_chat(user, "You are too far away from the deployment location, check your uplink for the deployment site.") + return FALSE return TRUE /obj/structure/uplink_beacon name = "uplink beacon" desc = "A small beacon attempting to establish communication with an unknown source." - icon = 'icons/obj/fulton.dmi' - icon_state = "extraction_point" + icon = 'icons/obj/traitor_beacon.dmi' + icon_state = "base" + light_system = MOVABLE_LIGHT + light_power = 0.7 + light_range = 1.4 var/current_frequency = 0 + var/time_left = 180 SECONDS + var/spam_cooldown = 0 + +/obj/structure/uplink_beacon/Initialize(mapload, mob/living/user) + . = ..() + var/datum/priority_directive/deploy_beacon/beacon = SSdirectives.active_directive + if (!istype(beacon)) + log_runtime("A traitor beacon was initialised but there is no directive for it to complete. It has been deleted.") + return INITIALIZE_HINT_QDEL + if (user != null) + // Try to find the team colour of the user + var/datum/component/uplink/uplink = user.mind.find_syndicate_uplink() + if (uplink) + var/code = beacon.get_team(uplink).data["code"] + current_frequency = code + else + current_frequency = rand(0, 8) + else + current_frequency = rand(0, 8) + beacon.deployed_beacon = src + beacon.on_beacon_planted(uplink_beacon_channel_to_color(current_frequency)) + update_appearance(UPDATE_OVERLAYS) + START_PROCESSING(SSprocessing, src) + +/obj/structure/uplink_beacon/Destroy() + var/datum/priority_directive/deploy_beacon/beacon = SSdirectives.active_directive + if (istype(beacon)) + beacon.beacon_broken() + return ..() + +/obj/structure/uplink_beacon/process(delta_time) + var/datum/priority_directive/deploy_beacon/beacon = SSdirectives.active_directive + if (!istype(beacon)) + log_runtime("A traitor beacon was processed but there is no directive for it to complete. It has been deleted.") + qdel(src) + return PROCESS_KILL + if (time_left <= 0) + // Complete the mission + beacon.complete(current_frequency) + establish_connection() + return PROCESS_KILL + time_left -= delta_time * 1 SECONDS + beacon.update_time(time_left) + +/obj/structure/uplink_beacon/update_overlays() + . = ..() + var/mutable_appearance/overlay_image = mutable_appearance(icon, "overlay", layer, plane) + var/colour = uplink_beacon_channel_to_color_code(current_frequency) + overlay_image.color = colour + . += overlay_image + . += emissive_appearance(icon, "overlay", layer, alpha = 120) + set_light_color(colour) + // So that we glow in the dark correctly + ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) /obj/structure/uplink_beacon/ui_interact(mob/user, datum/tgui/ui) + // You must be something to interact with this + if (!user.mind.has_antag_datum(/datum/antagonist)) + return ui = SStgui.try_update_ui(user, src, ui) if(!ui) ui = new(user, src, "UplinkBeacon") @@ -37,7 +105,7 @@ return data /obj/structure/uplink_beacon/ui_act(action, params) - if (..()) + if (..() || time_left <= 0) return FALSE var/new_num = text2num(params["freq"]) if (isnull(new_num)) @@ -45,10 +113,73 @@ new_num = round(new_num) if (new_num < 0 || new_num > 8) return FALSE - current_frequency = new_num - ui_update() + if (spam_cooldown > world.time) + to_chat(usr, "[src] needs another [DisplayTimeText(spam_cooldown)] before it can change frequency!") + return FALSE + spam_cooldown = world.time + 10 SECONDS + update_frequency(new_num) return TRUE +/obj/structure/uplink_beacon/proc/update_frequency(new_frequency) + current_frequency = new_frequency + update_appearance(UPDATE_OVERLAYS) + ui_update() + var/datum/priority_directive/deploy_beacon/beacon = SSdirectives.active_directive + if (!istype(beacon)) + return + // If there is less than 30 seconds less on the timer, reset the timer to 30 seconds + if (time_left < 30 SECONDS) + time_left = 30 SECONDS + beacon.beacon_colour_update(uplink_beacon_channel_to_color(current_frequency), time_left) + +/// Establish connection with the syndicate base. +/// Grants everyone who was on the established frequency with their prize TC +/// and spews out some additional TC for people near the beacon to squabble over. +/obj/structure/uplink_beacon/proc/establish_connection() + DECLARE_ASYNC + var/datum/priority_directive/deploy_beacon/beacon = SSdirectives.active_directive + if (!istype(beacon)) + log_runtime("A traitor beacon was processed but there is no directive for it to complete. It has been deleted.") + qdel(src) + return + var/turf/origin = get_turf(src) + var/list/throw_target_turfs = view(6, origin) + for (var/i in 1 to rand(3, 6)) + var/turf/tc_turf = pick(throw_target_turfs) + var/obj/item/stack/sheet/telecrystal/telecrystal = new(tc_turf, 1) + telecrystal.pixel_x = 32 * (origin.x - tc_turf.x) + telecrystal.pixel_y = 32 * (origin.y - tc_turf.y) + animate(telecrystal, time = 5, pixel_x = 0, pixel_y = 0) + self_destruct() + ASYNC_FINISH + +/obj/structure/uplink_beacon/proc/self_destruct() + balloon_alert_to_viewers("[src] establishes a connection, and engages its self-destruct mechanism!") + playsound(src, 'sound/items/timer.ogg', 20) + sleep(50) + playsound(src, 'sound/items/timer.ogg', 40) + sleep(30) + playsound(src, 'sound/items/timer.ogg', 60) + sleep(20) + playsound(src, 'sound/items/timer.ogg', 80) + sleep(10) + playsound(src, 'sound/items/timer.ogg', 80) + sleep(5) + playsound(src, 'sound/items/timer.ogg', 100) + sleep(4) + playsound(src, 'sound/items/timer.ogg', 100) + sleep(3) + playsound(src, 'sound/items/timer.ogg', 100) + sleep(2) + playsound(src, 'sound/items/timer.ogg', 100) + sleep(2) + playsound(src, 'sound/items/timer.ogg', 100) + sleep(2) + playsound(src, 'sound/items/timer.ogg', 100) + sleep(2) + explosion(src, 0, 0, 4, 6) + qdel(src) + /proc/uplink_beacon_channel_to_color(channel) var/static/list/colours = list( "green", @@ -62,3 +193,18 @@ "brown" ) return colours[channel + 1] + +/proc/uplink_beacon_channel_to_color_code(channel) + var/static/list/colours = list( + "#4bad4b", + "#c179d9", + "#e0da84", + "#e38e3f", + "#f65f5f", + "#4c4c4c", + "#d5d5d4", + "#5960e9", + "#744d23" + ) + return colours[channel + 1] + diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index 1ab8ea63f26ef..04a1668719cb0 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -5,12 +5,13 @@ to deploy a beacon encoded our organisation's encrypion code. Hostile agents may try to swap the code \ for their own, which you need to prevent from happening. There are friendly agents supporting you on this mission \ but their identities are unknown." - var/obj/item/uplink_beacon/deployed_beacon + var/obj/structure/uplink_beacon/deployed_beacon // Don't track this for deletion, since we need to maintain a track on the same position // when a turf is changed. var/turf/center_turf // List of the uplinks that already took the beacon var/list/empty_uplinks = list() + var/last_time_update = INFINITY /datum/priority_directive/deploy_beacon/_allocate_teams(list/uplinks, list/player_minds, force = FALSE) empty_uplinks.Cut() @@ -48,6 +49,7 @@ add_antagonist_team(b, list( "code" = pick_n_take(valid_codes) )) + last_time_update = INFINITY /datum/priority_directive/deploy_beacon/_generate(list/teams) return rand(5, 9) @@ -71,4 +73,35 @@ return "Activate a beacon in the specified location that is broadcasting on the [uplink_beacon_channel_to_color(get_team(uplink).data["code"])] channel." /datum/priority_directive/deploy_beacon/get_details(datum/component/uplink) - return objective_explanation + return deployed_beacon || objective_explanation + +/datum/priority_directive/deploy_beacon/proc/update_time(time_left) + end_at = world.time + time_left + var/time_update = FLOOR(time_left / (30 SECONDS), 1) + if (time_update < last_time_update) + mission_update("Beacon activation in [DisplayTimeText(time_left)].") + last_time_update = time_update + +/datum/priority_directive/deploy_beacon/proc/beacon_broken() + if (deployed_beacon.time_left <= 0) + deployed_beacon = null + return + deployed_beacon = null + end_at = world.time + 2 MINUTES + mission_update("Beacon destroyed. Two minutes on the mission remain to re-establish connection.") + +/datum/priority_directive/deploy_beacon/proc/on_beacon_planted(team_colour) + mission_update("A broadcasting signal has been detected on the [team_colour] channel and will establish connection in 180 seconds if uninterupted. The beacon's position and \ + time left can be tracked via the uplink.") + +/datum/priority_directive/deploy_beacon/proc/beacon_colour_update(colour, time_left) + mission_update("Beacon is now broadcasting on the [colour] channel. [DisplayTimeText(time_left)] until connection is established.") + +/datum/priority_directive/deploy_beacon/proc/complete(channel) + deployed_beacon = null + for (var/datum/directive_team/team in teams) + if (team.data["code"] == channel) + team.send_message("Beacon communication successfully established on the [uplink_beacon_channel_to_color(channel)] channel.") + team.grant_reward(tc_reward) + else + team.send_message("You have failed to deploy the beacon on your allocated channel. Mission failed.") diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 0684d90807854..09ee78230c3b8 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -1,5 +1,28 @@ -NAMED_TUPLE_2(directive_team, /list, uplinks, /list, data) -NAMED_TUPLE_1(directive_special_action,, action_name) +NAMED_TUPLE_2(directive_team, var/list, uplinks, var/list, data) +NAMED_TUPLE_1(directive_special_action, var, action_name) + +/datum/directive_team/proc/grant_reward(amount) + for (var/datum/component/uplink/uplink in uplinks) + uplink.telecrystals += amount + send_message("[amount] telecrystals have been deposited into your uplink.") + +/datum/directive_team/proc/send_message(message) + for (var/datum/component/uplink/uplink in uplinks) + var/syndicate_antag = FALSE + var/mob/living/current = uplink.parent + while (current && !istype(current)) + current = current.loc + if (istype(current)) + for (var/datum/antagonist/antag in current.mind?.antag_datums) + syndicate_antag ||= antag.faction == FACTION_SYNDICATE + else + // Nobody to notify + continue + // If we are not held by a syndicate, and we are locked then do not give a notification + if (!syndicate_antag && uplink.locked) + continue + to_chat(current, "[uppertext(message)].") + SEND_SOUND(current, sound('sound/machines/twobeep_high.ogg', volume = 50)) /// This can only be running once at a time, do not run in parallel /datum/priority_directive @@ -24,9 +47,11 @@ NAMED_TUPLE_1(directive_special_action,, action_name) /// Allocate teams for this directive. Call reject() to reject this directive and /// add_antagonist_team to add antagonist teams. /datum/priority_directive/proc/_allocate_teams(list/uplinks, list/player_minds, force = FALSE) + PROTECTED_PROC(TRUE) /// Return the reward type and amount /datum/priority_directive/proc/_generate(list/teams) + PROTECTED_PROC(TRUE) /// Get the tracking target of this atom /datum/priority_directive/proc/get_track_atom() @@ -62,14 +87,17 @@ NAMED_TUPLE_1(directive_special_action,, action_name) /// Advertise this directive to security objectives consoles /datum/priority_directive/proc/advertise_security() + PROTECTED_PROC(TRUE) SHOULD_NOT_OVERRIDE(TRUE) /datum/priority_directive/proc/add_antagonist_team(list/uplinks, list/data = null) SHOULD_NOT_OVERRIDE(TRUE) + PROTECTED_PROC(TRUE) teams += new /datum/directive_team(uplinks, islist(data) ? data : list()) /// Reject this directive, prevent it from firing /datum/priority_directive/proc/reject() + PROTECTED_PROC(TRUE) SHOULD_NOT_OVERRIDE(TRUE) rejected = TRUE @@ -109,3 +137,23 @@ NAMED_TUPLE_1(directive_special_action,, action_name) /datum/priority_directive/proc/get_details(datum/component/uplink) return details + +/datum/priority_directive/proc/mission_update(message) + PROTECTED_PROC(TRUE) + for (var/datum/component/uplink/uplink in GLOB.uplinks) + var/syndicate_antag = FALSE + var/mob/living/current = uplink.parent + while (current && !istype(current)) + current = current.loc + if (istype(current)) + for (var/datum/antagonist/antag in current.mind?.antag_datums) + syndicate_antag ||= antag.faction == FACTION_SYNDICATE + else + // Nobody to notify + continue + // If we are not held by a syndicate, and we are locked then do not give a notification + if (!syndicate_antag && uplink.locked) + continue + to_chat(current, "IMPORTANT MISSION CRITICAL NOTIFICATION: [uppertext(message)]") + SEND_SOUND(current, sound('sound/machines/twobeep_high.ogg', volume = 50)) + deadchat_broadcast("Syndicate Mission Update: [message]", follow_target = get_track_atom()) diff --git a/icons/obj/traitor_beacon.dmi b/icons/obj/traitor_beacon.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ed55a603ed0ef06e58b3a6541b6ed713850e47c4 GIT binary patch literal 1106 zcmV-Y1g-mtP)V=-0C=2JR&a84_w-Y6@%7{?OD!tS%+FJ>RWQ*r;NmRLOex6#a*U0*I5Sc+ z(=$pSoZ^zil2jm5DJiiyRf&r;C9|j)$Tj5ROe;#vO@*-Git>S`<|J0)Qm3ro>gNKs z9RNBiB}M~F!SVnA1Di=iK~#90?O4xC8$lF))})DPO*Gga24gp^iBM}T*c1vSQUjKP zhhEy72cb7Xym<8=@FoZz`XBV-p(i0irBG;kP$7q=O_OSg{So3XnkuxU`NmGzH9KZE zS(6R;!7!VdH*eqf&6~HIC2C-#)9HL&19-E<#smsYtPENAl;c!?nABjX*KQ}kW`e-z& ziCaSm0P>tT0P^v8TwxOk1d1X65JHOxRULs^Ku&&OU_h0;+wG=ICd1}n17MAoBVlR* zKtPftMhb0hZA~!`;%IWfhTCIpIT1{I1UUJLi3!@=+*HhAr?KO5baZqmjsW2GdTD-s zo>Hll@Hm)SfZ5sE67n3PB6u7SVS0L6D1fEPI8PNK@*uUau%H+l9v)V;7x~~&tpSg^ z{D!~W==FI##jC+dzDfkZn_V=wZ`jQ_;M0h=M(qCb@^Z;I#xSQBB?9dI%+h0PbD_Fk zH7pC@3qIjnE0W1%)6C3F)%S)E_!7;l9)XP2L80)dAtJyBe8Hz)a1pSxyp4~K)8OD> zi7m!3C$}v}9#9qFd#A7P=-8+_6Zp=<7kpL%5CAdWfT^h|^85Wo8(d=yklU6c4+x(E zx&7UvOb89pO5~NQ2-)m6b_0<}Z0Fy;X1*M)u5z&mp+;nEY>a$9UtTn?6{-T@A6|hp z(dBF8_@4<7qvie(H7_la#VgT=7B|LO0I}{q>f4CX!NDQ@9eKiR>~_1vunsy+3~KeoNDqVo@#2NRAqIMo-r4(lqQf?47ZZc8;X?A`Vm7D- z<>?IM4-WUpZgbMT2O-VmIpiX|d$U5^S9&XMIuTT#0tgfV1K2&$S078WjWsnC>qr4+ zB@YPy4s!u`546}_ir#9qv!*sD@?kaz1^AqL&$0mNyB=L-DQ!F7$_UDPwK3RY4Nrae zswF8sIPrrB0_VjGDedi%sOM%s`ET_Wd-*kb*zhBRwPq#{Xb$eWbXV6Kq1lO_;S5Lk Y2jvKtKB~?*od5s;07*qoM6N<$f)HN?Pyhe` literal 0 HcmV?d00001 diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm index d0d29bc370f9c..8a3877ed7fc4c 100644 --- a/interface/stylesheet.dm +++ b/interface/stylesheet.dm @@ -70,12 +70,17 @@ h1.alert, h2.alert {color: #000000;} .passive {color: #660000;} .traitor_objective { + display: block; + font-size: large; font-family: monospace; color: #f08181; background-color: #000000; border: 1px solid #f08181; padding-left: 5px; padding-right: 5px; + border-radius: 3px; + margin-top: 5px; + margin-bottom: 5px; } .userdanger {color: #ff0000; font-weight: bold; font-size: 3;} diff --git a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss index a009b08915026..53decdfb9e498 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss @@ -554,12 +554,17 @@ em { } .traitor_objective { + display: block; + font-size: large; font-family: monospace; color: #f08181; background-color: #000000; border: 1px solid #f08181; padding-left: 5px; padding-right: 5px; + border-radius: 3px; + margin-top: 5px; + margin-bottom: 5px; } .userdanger { diff --git a/tgui/packages/tgui-panel/styles/goon/chat-light.scss b/tgui/packages/tgui-panel/styles/goon/chat-light.scss index e1bacc847ac15..8156aa4c6881a 100644 --- a/tgui/packages/tgui-panel/styles/goon/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/goon/chat-light.scss @@ -554,12 +554,16 @@ h2.alert { } .traitor_objective { + display: block; + font-size: large; font-family: monospace; color: #f08181; background-color: #000000; border: 1px solid #f08181; padding-left: 5px; padding-right: 5px; + margin-top: 5px; + margin-bottom: 5px; } .userdanger { From d9d17b7ce1576271b7595c79ee607648bef0f709 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Wed, 20 Mar 2024 16:34:20 +0000 Subject: [PATCH 29/62] Removes some debug code --- code/controllers/subsystem/priority_directives.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 04a6f27706298..e1a43dac71c0d 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -41,6 +41,7 @@ SUBSYSTEM_DEF(directives) next_directive_time = INFINITY active_directive = selected +/* /client/verb/force_directive() set name = "force directive" set category = "powerfulbacon" @@ -60,6 +61,7 @@ SUBSYSTEM_DEF(directives) selected.start(GLOB.uplinks, player_minds) SSdirectives.next_directive_time = INFINITY SSdirectives.active_directive = selected +*/ /datum/controller/subsystem/directives/proc/get_uplink_data(datum/component/uplink/uplink) var/data = list() From cef507aa47eaf7622c89ffeecd643279a02d9434 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Wed, 20 Mar 2024 16:42:18 +0000 Subject: [PATCH 30/62] Fixes late joining traitors --- .../traitor/directives/deploy_beacon/deploy_beacon.dm | 11 +++++++++++ .../traitor/directives/priority_directive.dm | 11 +++++++++-- .../directives/secure_deaddrop/secure_deaddrop.dm | 3 +++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index 04a1668719cb0..58707160f513b 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -51,6 +51,17 @@ )) last_time_update = INFINITY +/datum/priority_directive/deploy_beacon/late_allocate(datum/component/uplink/uplink) + var/smallest_team_size = INFINITY + var/datum/directive_team/smallest_team + for (var/datum/directive_team/team in teams) + if (length(team.uplinks) > smallest_team_size) + continue + smallest_team = team + smallest_team_size = length(team.uplinks) + smallest_team.uplinks += uplink + return smallest_team + /datum/priority_directive/deploy_beacon/_generate(list/teams) return rand(5, 9) diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 09ee78230c3b8..fd4a1a7f3a2c2 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -49,6 +49,10 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) /datum/priority_directive/proc/_allocate_teams(list/uplinks, list/player_minds, force = FALSE) PROTECTED_PROC(TRUE) +/// Handle late allocation +/datum/priority_directive/proc/late_allocate(datum/component/uplink) + RETURN_TYPE(/datum/directive_team) + /// Return the reward type and amount /datum/priority_directive/proc/_generate(list/teams) PROTECTED_PROC(TRUE) @@ -93,7 +97,10 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) /datum/priority_directive/proc/add_antagonist_team(list/uplinks, list/data = null) SHOULD_NOT_OVERRIDE(TRUE) PROTECTED_PROC(TRUE) - teams += new /datum/directive_team(uplinks, islist(data) ? data : list()) + RETURN_TYPE(/datum/directive_team) + var/created = new /datum/directive_team(uplinks, islist(data) ? data : list()) + teams += created + return created /// Reject this directive, prevent it from firing /datum/priority_directive/proc/reject() @@ -127,7 +134,7 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) for (var/datum/directive_team/team in teams) if (uplink in team.uplinks) return team - return null + return late_allocate(uplink) /// Perform the special directive action /datum/priority_directive/proc/perform_special_action(datum/component/uplink, mob/living/user) diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index 4374a54beb809..1281b03b7fb88 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -14,6 +14,9 @@ // Create individual teams add_antagonist_team(antag) +/datum/priority_directive/deaddrop/late_allocate(datum/component/uplink/uplink) + return add_antagonist_team(uplink) + /datum/priority_directive/deaddrop/_generate(list/teams) // Spawn the deaddrop package var/tc_count = rand(4, 3 + length(teams)) From 626760b760fec9446a00e23dda0b7a7f03d61004 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Wed, 20 Mar 2024 16:44:30 +0000 Subject: [PATCH 31/62] Pretty TGUI --- tgui/packages/tgui/interfaces/Uplink.js | 9 +- tgui/packages/tgui/interfaces/UplinkBeacon.js | 114 ++++++++++-------- 2 files changed, 72 insertions(+), 51 deletions(-) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 3abf7faf1fcd9..356ed6d7ed8c8 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -131,20 +131,21 @@ const Directives = (props, context) => {
- + - {selectedObjective.reward ? selectedObjective.reward + " Telecrystals" : "No reward"} + {selectedObjective.reward ? selectedObjective.reward + ' Telecrystals' : 'No reward'}
diff --git a/tgui/packages/tgui/interfaces/UplinkBeacon.js b/tgui/packages/tgui/interfaces/UplinkBeacon.js index a9a2896fbce13..75ae66cd02fc7 100644 --- a/tgui/packages/tgui/interfaces/UplinkBeacon.js +++ b/tgui/packages/tgui/interfaces/UplinkBeacon.js @@ -4,48 +4,41 @@ import { useBackend } from '../backend'; export const UplinkBeacon = (props, context) => { const { act, data } = useBackend(context); - const { - frequency, - } = data; - let channel = "green"; - switch (frequency) - { + const { frequency } = data; + let channel = 'green'; + switch (frequency) { case 0: - channel = "green"; + channel = 'green'; break; case 1: - channel = "purple"; + channel = 'purple'; break; case 2: - channel = "yellow"; + channel = 'yellow'; break; case 3: - channel = "orange"; + channel = 'orange'; break; case 4: - channel = "red"; + channel = 'red'; break; case 5: - channel = "black"; + channel = 'black'; break; case 6: - channel = "white"; + channel = 'white'; break; case 7: - channel = "blue"; + channel = 'blue'; break; case 8: - channel = "brown"; + channel = 'brown'; break; } return ( - + Beacon broadcasting on {channel} channel @@ -55,27 +48,36 @@ export const UplinkBeacon = (props, context) => { width="100%" height="100%" color="green" - onClick={() => act('set_freq', { - freq: 0, - })} /> + onClick={() => + act('set_freq', { + freq: 0, + }) + } + />
From 8e5a90f63ab0613122b742fad557b1bf792e201f Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:13:13 +0000 Subject: [PATCH 32/62] Repeat directives, fixes directive spawning --- code/controllers/subsystem/priority_directives.dm | 3 ++- code/modules/admin/admin_verbs.dm | 2 +- .../traitor/directives/priority_directive.dm | 1 + tgui/packages/tgui/interfaces/Uplink.js | 12 +++++++++--- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index e1a43dac71c0d..267e845d13113 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -16,6 +16,7 @@ SUBSYSTEM_DEF(directives) // Are we completed or ended? if (active_directive.is_completed() || world.time > active_directive.end_at) active_directive.finish() + next_directive_time = world.time + rand(10 MINUTES, 15 MINUTES) return // Check if we are ready to spawn our next active_directive if (world.time < next_directive_time) @@ -36,7 +37,7 @@ SUBSYSTEM_DEF(directives) // Try again in a minute next_directive_time = world.time + 1 MINUTES return - var/datum/priority_directive/selected = pick(active_directive) + var/datum/priority_directive/selected = pick(valid_directives) selected.start(GLOB.uplinks, player_minds) next_directive_time = INFINITY active_directive = selected diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 7e1509dc4c05d..cc3b0c733156c 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -739,7 +739,7 @@ GLOBAL_PROTECT(admin_verbs_hideable) log_admin("[src] re-adminned themselves.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Readmin") -/client/proc/populate_world(amount = 50 as num, give_minds as anything in list("Yes", "No")) +/client/proc/populate_world(amount = 50 as num, give_minds as anything in list("Give minds", "Don't give minds")) set name = "Populate World" set category = "Debug" set desc = "(\"Amount of mobs to create\") Populate the world with test mobs." diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index fd4a1a7f3a2c2..c8cee8cfb5e5c 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -41,6 +41,7 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) /datum/priority_directive/proc/can_run(list/uplinks, list/player_minds, force = FALSE) SHOULD_NOT_OVERRIDE(TRUE) teams.Cut() + rejected = FALSE _allocate_teams(uplinks, player_minds, force) return !rejected diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 356ed6d7ed8c8..e07cfb27735f9 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -51,6 +51,12 @@ const Directives = (props, context) => { const dx = track_x - pos_x; const dy = track_y - pos_y; const angle = (360 / (Math.PI * 2)) * Math.atan2(dx, dy); + if (selectedObjective === null) + { + return ( + No associated objectives. + ); + } return ( @@ -111,7 +117,7 @@ const Directives = (props, context) => { Tasks - {selectedObjective.tasks.map((task) => ( + {selectedObjective?.tasks.map((task) => ( {task} @@ -121,7 +127,7 @@ const Directives = (props, context) => { Additional Details - {selectedObjective.details || + {selectedObjective?.details || 'This mission is part of your assignment and must be\ completed. No additional reward will be provided outside of the\ terms that have been defined within your contract of employment.'} @@ -134,7 +140,7 @@ const Directives = (props, context) => { - {selectedObjective.reward ? selectedObjective.reward + ' Telecrystals' : 'No reward'} + {selectedObjective?.reward ? selectedObjective?.reward + ' Telecrystals' : 'No reward'} From 3a26e31ade7c5be369397c6cbff1672d5924aae1 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:16:58 +0000 Subject: [PATCH 33/62] Stupid prettier again --- tgui/packages/tgui/interfaces/Uplink.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index e07cfb27735f9..6d1c2cd13790d 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -51,11 +51,8 @@ const Directives = (props, context) => { const dx = track_x - pos_x; const dy = track_y - pos_y; const angle = (360 / (Math.PI * 2)) * Math.atan2(dx, dy); - if (selectedObjective === null) - { - return ( - No associated objectives. - ); + if (selectedObjective === null) { + return No associated objectives.; } return ( From fc0ff960f2e53c3ad9c47b8f85df5826f1c74074 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 21 Mar 2024 09:05:08 +0000 Subject: [PATCH 34/62] Anchors the beacon --- .../antagonists/traitor/directives/deploy_beacon/beacon.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index 520453c7486a2..3f0e5969943b8 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -34,6 +34,7 @@ light_system = MOVABLE_LIGHT light_power = 0.7 light_range = 1.4 + anchored = TRUE var/current_frequency = 0 var/time_left = 180 SECONDS var/spam_cooldown = 0 From 6ee4f9fb230f8fd57b31b2724bb2b9da7b286aa7 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 22 Mar 2024 12:40:12 +0000 Subject: [PATCH 35/62] Makes the deaddrop box big, makes the priority directive messages followable --- .../traitor/directives/priority_directive.dm | 33 ++++++++----------- .../secure_deaddrop/deaddrop_box.dm | 7 ++-- .../secure_deaddrop/secure_deaddrop.dm | 1 + 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index c8cee8cfb5e5c..0a3e4d0f517f2 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -29,6 +29,7 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) var/name var/objective_explanation var/details + var/last_for = 10 MINUTES var/end_at var/rejected = FALSE var/tc_reward @@ -71,24 +72,9 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) /// Activate the directive, requires a list of traitor datums and security minsd /datum/priority_directive/proc/start(list/uplinks, list/player_minds) SHOULD_NOT_OVERRIDE(TRUE) - end_at = world.time + 10 MINUTES + end_at = world.time + last_for tc_reward = _generate(teams) - for (var/datum/component/uplink/uplink in GLOB.uplinks) - var/syndicate_antag = FALSE - var/mob/living/current = uplink.parent - while (current && !istype(current)) - current = current.loc - if (istype(current)) - for (var/datum/antagonist/antag in current.mind?.antag_datums) - syndicate_antag ||= antag.faction == FACTION_SYNDICATE - else - // Nobody to notify - continue - // If we are not held by a syndicate, and we are locked then do not give a notification - if (!syndicate_antag && uplink.locked) - continue - to_chat(current, "NEW PRIORITY DIRECTIVE RECEIVED. SEE UPLINK FOR DETAILS.") - SEND_SOUND(current, sound('sound/machines/twobeep_high.ogg', volume = 50)) + mission_update("NEW PRIORITY DIRECTIVE RECEIVED. SEE UPLINK FOR DETAILS.", prefix = "") /// Advertise this directive to security objectives consoles /datum/priority_directive/proc/advertise_security() @@ -146,7 +132,7 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) /datum/priority_directive/proc/get_details(datum/component/uplink) return details -/datum/priority_directive/proc/mission_update(message) +/datum/priority_directive/proc/mission_update(message, prefix = "IMPORTANT MISSION CRITICAL NOTIFICATION: ") PROTECTED_PROC(TRUE) for (var/datum/component/uplink/uplink in GLOB.uplinks) var/syndicate_antag = FALSE @@ -162,6 +148,13 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) // If we are not held by a syndicate, and we are locked then do not give a notification if (!syndicate_antag && uplink.locked) continue - to_chat(current, "IMPORTANT MISSION CRITICAL NOTIFICATION: [uppertext(message)]") + to_chat(current, "[prefix][uppertext(message)]") SEND_SOUND(current, sound('sound/machines/twobeep_high.ogg', volume = 50)) - deadchat_broadcast("Syndicate Mission Update: [message]", follow_target = get_track_atom()) + var/atom/follow_atom = get_track_atom() + if (follow_atom) + if (ismob(follow_atom.loc)) + deadchat_broadcast("Syndicate Mission Update: [message]", follow_target = follow_atom) + else + deadchat_broadcast("Syndicate Mission Update: [message]", turf_target = get_turf(follow_atom)) + else + deadchat_broadcast("Syndicate Mission Update: [message]") diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm index b13292b03885d..9b5f2b1366cb6 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/deaddrop_box.dm @@ -2,9 +2,12 @@ /obj/item/storage/deaddrop_box name = "secured box" desc = "A secure box that probably contains a variety of items the \ - average crewmember probably wouldn't want around the station." + average crewmember probably wouldn't want around the station. It is \ + exceptionally heavy and hard to carry around." icon_state = "safe" - w_class = WEIGHT_CLASS_NORMAL + // This is heavy so that people have to hold it or hide it, making it much easier for other traitors to steal without + // requiring them to straight up kill and rob them. + w_class = WEIGHT_CLASS_BULKY // Prevent it from being opened until it is ready to be opened obj_flags = INDESTRUCTIBLE component_type = /datum/component/storage/concrete/deaddrop diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index 1281b03b7fb88..a1517be42a98f 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -4,6 +4,7 @@ details = "We have identified a deaddrop that has been placed by a rival spy agency and have maintained an accurate track on the box. \ You have the option to track and secure the valuable items before anyone else gets to them. The items are stored in a trackable \ box which will automatically unlock after a set period of time." + last_for = 6 MINUTES var/obj/item/storage/deaddrop_box/target /datum/priority_directive/deaddrop/_allocate_teams(list/uplinks, list/player_minds, force = FALSE) From ff60ffe204e9b92523d8e6667c32add219bd805d Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 22 Mar 2024 12:41:32 +0000 Subject: [PATCH 36/62] Runtime fix --- .../antagonists/traitor/directives/deploy_beacon/beacon.dm | 2 +- .../traitor/directives/secure_deaddrop/secure_deaddrop.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index 3f0e5969943b8..680c3d0d457a1 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -93,7 +93,7 @@ /obj/structure/uplink_beacon/ui_interact(mob/user, datum/tgui/ui) // You must be something to interact with this - if (!user.mind.has_antag_datum(/datum/antagonist)) + if (!user.mind || !user.mind.has_antag_datum(/datum/antagonist)) return ui = SStgui.try_update_ui(user, src, ui) if(!ui) diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index a1517be42a98f..0a6e3676cc3b3 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -3,7 +3,7 @@ objective_explanation = "Secure a trackable lockbox which will unlock after 10 minutes." details = "We have identified a deaddrop that has been placed by a rival spy agency and have maintained an accurate track on the box. \ You have the option to track and secure the valuable items before anyone else gets to them. The items are stored in a trackable \ - box which will automatically unlock after a set period of time." + box which will automatically unlock after a set period of time. The items have been hidden in a bag underneath the floor tiles." last_for = 6 MINUTES var/obj/item/storage/deaddrop_box/target From 0731a159c170031da34610aa96a0f7556b2417c5 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 22 Mar 2024 12:42:38 +0000 Subject: [PATCH 37/62] Fixes traitors starting with too much TC --- code/datums/mind.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 5943b37f872b3..e8baf8d928ade 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -291,7 +291,7 @@ remove_rev() SSticker.mode.update_cult_icons_removed(src) -/datum/mind/proc/equip_traitor(employer = "The Syndicate", silent = FALSE, datum/antagonist/uplink_owner, telecrystals = 20, datum/game_mode/gamemode) +/datum/mind/proc/equip_traitor(employer = "The Syndicate", silent = FALSE, datum/antagonist/uplink_owner, telecrystals = TELECRYSTALS_DEFAULT, datum/game_mode/gamemode) if(!current) return var/mob/living/carbon/human/traitor_mob = current From f61e03575b92f41bebbb7af193a43e312ee8cded Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 22 Mar 2024 12:45:54 +0000 Subject: [PATCH 38/62] Makes it so that the beacon objective will not timeout --- code/controllers/subsystem/priority_directives.dm | 3 +-- .../traitor/directives/deploy_beacon/deploy_beacon.dm | 3 +++ .../antagonists/traitor/directives/priority_directive.dm | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 267e845d13113..e604f8657670e 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -14,9 +14,8 @@ SUBSYSTEM_DEF(directives) /datum/controller/subsystem/directives/fire(resumed) if (active_directive) // Are we completed or ended? - if (active_directive.is_completed() || world.time > active_directive.end_at) + if (active_directive.is_completed() || active_directive.is_timed_out()) active_directive.finish() - next_directive_time = world.time + rand(10 MINUTES, 15 MINUTES) return // Check if we are ready to spawn our next active_directive if (world.time < next_directive_time) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index 58707160f513b..9b36c674f5ea5 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -99,17 +99,20 @@ return deployed_beacon = null end_at = world.time + 2 MINUTES + can_timeout = TRUE mission_update("Beacon destroyed. Two minutes on the mission remain to re-establish connection.") /datum/priority_directive/deploy_beacon/proc/on_beacon_planted(team_colour) mission_update("A broadcasting signal has been detected on the [team_colour] channel and will establish connection in 180 seconds if uninterupted. The beacon's position and \ time left can be tracked via the uplink.") + can_timeout = FALSE /datum/priority_directive/deploy_beacon/proc/beacon_colour_update(colour, time_left) mission_update("Beacon is now broadcasting on the [colour] channel. [DisplayTimeText(time_left)] until connection is established.") /datum/priority_directive/deploy_beacon/proc/complete(channel) deployed_beacon = null + finish() for (var/datum/directive_team/team in teams) if (team.data["code"] == channel) team.send_message("Beacon communication successfully established on the [uplink_beacon_channel_to_color(channel)] channel.") diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 0a3e4d0f517f2..4d89e3ed11be1 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -33,6 +33,7 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) var/end_at var/rejected = FALSE var/tc_reward + var/can_timeout = TRUE VAR_PRIVATE/list/teams = list() /datum/priority_directive/New() @@ -43,6 +44,7 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) SHOULD_NOT_OVERRIDE(TRUE) teams.Cut() rejected = FALSE + can_timeout = TRUE _allocate_teams(uplinks, player_minds, force) return !rejected @@ -66,8 +68,14 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) /datum/priority_directive/proc/is_completed() return FALSE +/datum/priority_directive/proc/is_timed_out() + SHOULD_NOT_OVERRIDE(TRUE) + return can_timeout && (world.time > end_at) + /datum/priority_directive/proc/finish() + SHOULD_CALL_PARENT(TRUE) SSdirectives.active_directive = null + SSdirectives.next_directive_time = world.time + rand(10 MINUTES, 15 MINUTES) /// Activate the directive, requires a list of traitor datums and security minsd /datum/priority_directive/proc/start(list/uplinks, list/player_minds) From 141d749aebbc8ba70c8410d861aa5752e072b3e1 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 22 Mar 2024 12:50:53 +0000 Subject: [PATCH 39/62] Makes it more clear when you are losing --- .../directives/deploy_beacon/beacon.dm | 5 +++-- .../directives/deploy_beacon/deploy_beacon.dm | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index 680c3d0d457a1..4da0016691a3e 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -56,7 +56,7 @@ else current_frequency = rand(0, 8) beacon.deployed_beacon = src - beacon.on_beacon_planted(uplink_beacon_channel_to_color(current_frequency)) + beacon.on_beacon_planted(current_frequency) update_appearance(UPDATE_OVERLAYS) START_PROCESSING(SSprocessing, src) @@ -122,6 +122,7 @@ return TRUE /obj/structure/uplink_beacon/proc/update_frequency(new_frequency) + var/old_freq = current_frequency current_frequency = new_frequency update_appearance(UPDATE_OVERLAYS) ui_update() @@ -131,7 +132,7 @@ // If there is less than 30 seconds less on the timer, reset the timer to 30 seconds if (time_left < 30 SECONDS) time_left = 30 SECONDS - beacon.beacon_colour_update(uplink_beacon_channel_to_color(current_frequency), time_left) + beacon.beacon_colour_update(old_freq, current_frequency, time_left) /// Establish connection with the syndicate base. /// Grants everyone who was on the established frequency with their prize TC diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index 9b36c674f5ea5..cd7f17572a8d0 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -102,13 +102,22 @@ can_timeout = TRUE mission_update("Beacon destroyed. Two minutes on the mission remain to re-establish connection.") -/datum/priority_directive/deploy_beacon/proc/on_beacon_planted(team_colour) - mission_update("A broadcasting signal has been detected on the [team_colour] channel and will establish connection in 180 seconds if uninterupted. The beacon's position and \ - time left can be tracked via the uplink.") +/datum/priority_directive/deploy_beacon/proc/on_beacon_planted(channel) can_timeout = FALSE + for (var/datum/directive_team/team in teams) + if (team.data["code"] == channel) + team.send_message("The beacon is now broadcasting on your team's channel.") + else + team.send_message("Warning, a beacon has been planted on an opposing team's channel.
You will fail if you don't change the beacon's frequency to [uplink_beacon_channel_to_color(channel)]!") -/datum/priority_directive/deploy_beacon/proc/beacon_colour_update(colour, time_left) - mission_update("Beacon is now broadcasting on the [colour] channel. [DisplayTimeText(time_left)] until connection is established.") +/datum/priority_directive/deploy_beacon/proc/beacon_colour_update(old_colour, colour, time_left) + if (old_colour == colour) + return + for (var/datum/directive_team/team in teams) + if (team.data["code"] == channel) + team.send_message("The beacon is now broadcasting on your team's channel. Maintain the beacon for [DisplayTimeText(time_left)] to succeed.") + else + team.send_message("Warning, the beacon is now broadcasting on another team's channel.
You will fail if you don't change the beacon's frequency to [uplink_beacon_channel_to_color(channel)] in [DisplayTimeText(time_left)]!") /datum/priority_directive/deploy_beacon/proc/complete(channel) deployed_beacon = null From 3d0b692f5b05522ec1b8a7a31fe52eb675e08195 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 22 Mar 2024 12:53:18 +0000 Subject: [PATCH 40/62] Fixes some compilation issues --- .../traitor/directives/deploy_beacon/deploy_beacon.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index cd7f17572a8d0..2acfc79cdb3f2 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -110,13 +110,13 @@ else team.send_message("Warning, a beacon has been planted on an opposing team's channel.
You will fail if you don't change the beacon's frequency to [uplink_beacon_channel_to_color(channel)]!") -/datum/priority_directive/deploy_beacon/proc/beacon_colour_update(old_colour, colour, time_left) - if (old_colour == colour) +/datum/priority_directive/deploy_beacon/proc/beacon_colour_update(old_channel, channel, time_left) + if (old_channel == channel) return for (var/datum/directive_team/team in teams) if (team.data["code"] == channel) team.send_message("The beacon is now broadcasting on your team's channel. Maintain the beacon for [DisplayTimeText(time_left)] to succeed.") - else + else if (old_channel == team.data["code"]) team.send_message("Warning, the beacon is now broadcasting on another team's channel.
You will fail if you don't change the beacon's frequency to [uplink_beacon_channel_to_color(channel)] in [DisplayTimeText(time_left)]!") /datum/priority_directive/deploy_beacon/proc/complete(channel) From d8ad7038c9e8464315738de8387c05a3963b9b75 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 22 Mar 2024 13:05:26 +0000 Subject: [PATCH 41/62] Bug fixes --- .../antagonists/traitor/directives/deploy_beacon/beacon.dm | 2 +- .../traitor/directives/deploy_beacon/deploy_beacon.dm | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index 4da0016691a3e..7720547386039 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -115,7 +115,7 @@ if (new_num < 0 || new_num > 8) return FALSE if (spam_cooldown > world.time) - to_chat(usr, "[src] needs another [DisplayTimeText(spam_cooldown)] before it can change frequency!") + to_chat(usr, "[src] needs another [DisplayTimeText(spam_cooldown - world.time)] before it can change frequency!") return FALSE spam_cooldown = world.time + 10 SECONDS update_frequency(new_num) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index 2acfc79cdb3f2..f77b04b7741a7 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -108,7 +108,7 @@ if (team.data["code"] == channel) team.send_message("The beacon is now broadcasting on your team's channel.") else - team.send_message("Warning, a beacon has been planted on an opposing team's channel.
You will fail if you don't change the beacon's frequency to [uplink_beacon_channel_to_color(channel)]!") + team.send_message("Warning, a beacon has been planted on an opposing team's channel.
You will fail if you don't change the beacon's frequency to [uplink_beacon_channel_to_color(team.data["code"])]!") /datum/priority_directive/deploy_beacon/proc/beacon_colour_update(old_channel, channel, time_left) if (old_channel == channel) @@ -117,7 +117,7 @@ if (team.data["code"] == channel) team.send_message("The beacon is now broadcasting on your team's channel. Maintain the beacon for [DisplayTimeText(time_left)] to succeed.") else if (old_channel == team.data["code"]) - team.send_message("Warning, the beacon is now broadcasting on another team's channel.
You will fail if you don't change the beacon's frequency to [uplink_beacon_channel_to_color(channel)] in [DisplayTimeText(time_left)]!") + team.send_message("Warning, the beacon is now broadcasting on another team's channel.
You will fail if you don't change the beacon's frequency to [uplink_beacon_channel_to_color(team.data["code"])] in [DisplayTimeText(time_left)]!") /datum/priority_directive/deploy_beacon/proc/complete(channel) deployed_beacon = null From 3bd6c6103fdb15583982af5e8e56c792225b83d8 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Fri, 22 Mar 2024 13:07:50 +0000 Subject: [PATCH 42/62] Beacon explodes again --- .../antagonists/traitor/directives/deploy_beacon/beacon.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index 7720547386039..34189802b5e25 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -74,8 +74,8 @@ return PROCESS_KILL if (time_left <= 0) // Complete the mission - beacon.complete(current_frequency) establish_connection() + beacon.complete(current_frequency) return PROCESS_KILL time_left -= delta_time * 1 SECONDS beacon.update_time(time_left) From ee6f790119b3b8d9caceda9518c54192f058c6b0 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Tue, 26 Mar 2024 20:38:49 +0000 Subject: [PATCH 43/62] Some uplink improvements --- .../subsystem/priority_directives.dm | 2 +- .../traitor/directives/priority_directive.dm | 2 +- tgui/packages/tgui/interfaces/Uplink.js | 34 ++++++++++++++++--- .../tgui/styles/interfaces/Uplink.scss | 34 +++++++++++++++++-- 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index e604f8657670e..75db9c2743c66 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -7,7 +7,7 @@ SUBSYSTEM_DEF(directives) /datum/controller/subsystem/directives/Initialize(start_timeofday) . = ..() - next_directive_time = world.time + rand(20 MINUTES, 30 MINUTES) + next_directive_time = world.time + rand(10 MINUTES, 15 MINUTES) for (var/directive_type in subtypesof(/datum/priority_directive)) directives += new directive_type() diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 4d89e3ed11be1..07823043b9b40 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -75,7 +75,7 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) /datum/priority_directive/proc/finish() SHOULD_CALL_PARENT(TRUE) SSdirectives.active_directive = null - SSdirectives.next_directive_time = world.time + rand(10 MINUTES, 15 MINUTES) + SSdirectives.next_directive_time = world.time + rand(5 MINUTES, 10 MINUTES) /// Activate the directive, requires a list of traitor datums and security minsd /datum/priority_directive/proc/start(list/uplinks, list/player_minds) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 6d1c2cd13790d..fc56927a4e783 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -1,5 +1,5 @@ import { capitalize, createSearch, decodeHtmlEntities } from 'common/string'; -import { useBackend, useLocalState } from '../backend'; +import { useBackend, useLocalState, useSharedState } from '../backend'; import { Stack, Box, Button, Flex, Input, Section, Table, Tabs, NoticeBox, Grid, Divider, Icon, Tooltip } from '../components'; import { formatMoney } from '../format'; import { Window } from '../layouts'; @@ -12,12 +12,19 @@ export const Uplink = (props, context) => { const { data } = useBackend(context); const { telecrystals } = data; - const [tab, setTab] = useLocalState(context, 'tab_id', 0); + const [tab, setTab] = useSharedState(context, 'tab_id', 2); return ( + { + setTab(2); + }}> + Career Homepage + { @@ -35,13 +42,32 @@ export const Uplink = (props, context) => { + + Neutral Reputation + - {tab === 0 ? : tab === 1 && } + {tab === 0 + ? + : tab === 1 + ? + : } ); }; +const HomePage = (props, context) => { + return ( + + +
+
+
+
+ ); +}; + const Directives = (props, context) => { const [selected, setSelected] = useLocalState(context, 'sel_obj', 0); const { act, data } = useBackend(context); @@ -55,7 +81,7 @@ const Directives = (props, context) => { return No associated objectives.; } return ( - +
0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + + margin-left: auto; + margin-right: 5px; + border-radius: 5px; + font-weight: bold; + color: $text-color; + background-image: repeating-linear-gradient( + -45deg, + transparent, + transparent base.em(10px), + rgba(0, 0, 0, 0.1) base.em(10px), + rgba(0, 0, 0, 0.1) base.em(20px) + ); +} + +@mixin box-color($color) { + $luminance: luminance($color); + $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + color: $text-color; + background-color: color.adjust($color, $saturation: -15%, $lightness: -15%); +} From 671efd6729a100eba050158f6a0e1caf72da4c0b Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Sat, 30 Mar 2024 14:05:16 +0000 Subject: [PATCH 44/62] Rank Cards --- tgui/packages/tgui/interfaces/Uplink.js | 40 +++++++++++- .../tgui/styles/interfaces/Uplink.scss | 65 +++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 75ba94f3431f4..8b888b6a3a3a2 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -61,8 +61,44 @@ const HomePage = (props, context) => { return ( -
-
+
+
+
+ Welcome, Agent. +
+
+
+
+
+ Previous Rank +
+ Ex-Communication +
+
+ A traitor to the cause, betraying their brothers to seek personal gain. +
+
+
+
+ sup +
+
+
+
+ sup +
+
+
+
+ sup +
+
+
+
+
+ right +
+
); diff --git a/tgui/packages/tgui/styles/interfaces/Uplink.scss b/tgui/packages/tgui/styles/interfaces/Uplink.scss index 2b1e3bab01045..642362a5c81ed 100644 --- a/tgui/packages/tgui/styles/interfaces/Uplink.scss +++ b/tgui/packages/tgui/styles/interfaces/Uplink.scss @@ -7,6 +7,71 @@ height: calc(100% - 45px); } +.Home { + position: relative; + height: 100%; + width: 100%; +} + +.HomeLeft { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 70%; + margin: 10px; +} + +.HomeRight { + position: absolute; + right: 0; + top: 0; + bottom: 0; + width: 30%; + margin: 10px; +} + +.HomeTitle { + width: 100%; + font-size: x-large; +} + +.HomeRanks { + overflow-y: hidden; + margin-top: 30px; + height: calc(100% - 50px); +} + +.RankCard { + width: 100%; + padding-bottom: 20px; + color: #d4d4d4; +} + +.RankCardMain { + width: calc(100% - 200px); + height: 90px; + background: linear-gradient(0deg, #b457385a, #8D3E3E5a); + padding: 10px; + border-radius: 13px; +} + +.RankCardTitle { + position: relative; + width: 100%; + font-size: 1.3em; + margin-bottom: 6px; +} + +.RankCardName { + position: absolute; + left: 0; + top: 0; + right: 0; + text-align: right; + font-weight: bold; +} + .objective_card { position: relative; width: 180px; From b06371fb3d3913f9c8abe1c9b9aa956776c7c7a3 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Sat, 30 Mar 2024 16:14:49 +0000 Subject: [PATCH 45/62] ig this is iron now --- .../traitor/directives/secure_deaddrop/secure_deaddrop.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index 0a6e3676cc3b3..10789f7ddf744 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -23,7 +23,7 @@ var/tc_count = rand(4, 3 + length(teams)) // Put the deaddrop somewhere var/turf/selected = get_random_station_turf() - while (!istype(selected, /turf/open/floor/plasteel)) + while (!istype(selected, /turf/open/floor/iron)) selected = get_random_station_turf() var/atom/secret_bag = new /obj/item/storage/backpack/satchel/flat/empty(selected) target = new(secret_bag) From 1399e36aa10697aab85d0809be606873387946d3 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Sat, 30 Mar 2024 16:56:26 +0000 Subject: [PATCH 46/62] Career homepage --- tgui/packages/tgui/interfaces/Uplink.js | 93 +++++++++++++------ .../tgui/styles/interfaces/Uplink.scss | 26 +++++- 2 files changed, 89 insertions(+), 30 deletions(-) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 8b888b6a3a3a2..ec160f4f9d6b3 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -5,6 +5,7 @@ import { formatMoney } from '../format'; import { Window } from '../layouts'; import '../styles/interfaces/Uplink.scss'; import { NtosRadarMap } from './NtosRadar'; +import { Color } from 'common/color'; const MAX_SEARCH_RESULTS = 25; @@ -67,36 +68,43 @@ const HomePage = (props, context) => { Welcome, Agent.
-
-
-
- Previous Rank -
- Ex-Communication -
-
- A traitor to the cause, betraying their brothers to seek personal gain. -
-
-
-
- sup -
-
-
-
- sup -
-
-
-
- sup -
-
+ + + +
- right +
@@ -104,6 +112,37 @@ const HomePage = (props, context) => { ); }; +const RankCard = (props, contxt) => { + const { + relation, + name, + description, + reputation, + reputation_delta, + current_rank = false, + progression_colour = "#6B1313", + } = props; + return ( +
+
+
+ {relation} +
+ {name} +
+
+ {description} +
+
+ {reputation} Reputation
+ ({reputation_delta}) +
+
+ ); +}; + const Directives = (props, context) => { const [selected, setSelected] = useLocalState(context, 'sel_obj', 0); const { act, data } = useBackend(context); diff --git a/tgui/packages/tgui/styles/interfaces/Uplink.scss b/tgui/packages/tgui/styles/interfaces/Uplink.scss index 642362a5c81ed..a2dc5288bdd68 100644 --- a/tgui/packages/tgui/styles/interfaces/Uplink.scss +++ b/tgui/packages/tgui/styles/interfaces/Uplink.scss @@ -18,7 +18,7 @@ left: 0; top: 0; bottom: 0; - width: 70%; + width: 60%; margin: 10px; } @@ -27,7 +27,7 @@ right: 0; top: 0; bottom: 0; - width: 30%; + width: 40%; margin: 10px; } @@ -43,24 +43,44 @@ } .RankCard { + position: relative; width: 100%; padding-bottom: 20px; color: #d4d4d4; } +.RankCardHighlight { + border: 1px solid rgb(255, 209, 70); + box-shadow: black 3px 3px; +} + .RankCardMain { - width: calc(100% - 200px); + width: calc(100% - 164px); height: 90px; background: linear-gradient(0deg, #b457385a, #8D3E3E5a); padding: 10px; border-radius: 13px; } +.RankCardProgression { + position: absolute; + right: 10px; + top: calc(45px - 20px); + width: 144px; + height: 40px; + padding: 10px; + border-radius: 13px; + text-align: center; + vertical-align: middle; + padding-top: 5px; +} + .RankCardTitle { position: relative; width: 100%; font-size: 1.3em; margin-bottom: 6px; + height: 1.3em; } .RankCardName { From f92d4d7b05da0c0ce569c72935c3d5547dd88f3f Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Sun, 31 Mar 2024 14:31:43 +0100 Subject: [PATCH 47/62] Backend reputation and a host of balancing changes to the uplink --- code/__DEFINES/antagonists.dm | 26 +++++ code/datums/components/uplink.dm | 18 +++- code/modules/uplink/uplink_items.dm | 98 +++++++++++++------ config/dbconfig.txt | 10 +- tgui/packages/tgui/interfaces/Uplink.js | 13 ++- .../tgui/styles/interfaces/Uplink.scss | 39 ++++++-- 6 files changed, 157 insertions(+), 47 deletions(-) diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index b6a4875b346b7..224b13fe9241e 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -120,6 +120,32 @@ /// because they have nothing else that supports an implant. #define UPLINK_IMPLANT_TELECRYSTAL_COST 1 +/// Traitor reputation levels + +/// Ex-communicated +#define REPUTATION_EXCOMMUNICATED 0 +/// Blood brother level: Untrusted +#define REPUTATION_LOW 100 +/// Standard traitor level +#define REPUTATION_STANDARD 200 +/// Good reputation, additional gear +#define REPUTATION_GOOD 400 +/// Excellent reputation, more murderboney stuff +#define REPUTATION_EXCELLENT 600 +/// Elite reputation, access to rare and unique items. +/// Nuclear operative level +#define REPUTATION_ELITE 800 +/// Access to anything your heart could ever desire +#define REPUTATION_MAX 1000 + +/// How much reputation is gained per completed directive +#define REPUTATION_GAIN_PER_DIRECTIVE 200 + +/// How much reputation you lose for failing a solo directive +#define REPUTATION_LOSS_SOLO_DIRECTIVE 50 +/// How much reputation you lose for failing a team-directive +#define REPUTATION_LOSS_TEAM_DIRECTIVE 100 + ///Checks if given mob is a hive host #define IS_HIVEHOST(mob) (mob.mind?.has_antag_datum(/datum/antagonist/hivemind)) ///Checks if given mob is an awakened vessel diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 19db740a0e05f..bca06f1635ce4 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -5,9 +5,9 @@ GLOBAL_LIST_EMPTY(uplinks) /** * Uplinks * - * All /obj/item(s) have a hidden_uplink var. By default it's null. Give the item one with 'new(src') (it must be in it's contents). Then add 'uses.' - * Use whatever conditionals you want to check that the user has an uplink, and then call interact() on their uplink. - * You might also want the uplink menu to open if active. Check if the uplink is 'active' and then interact() with it. + * All /obj/item(s) can be given an uplink. Give the item one with AddComponent(/datum/component/uplink, mind) + * Use whatever conditionals you want to check that the user has an uplink + * This component will handle UI interactions. **/ /datum/component/uplink dupe_mode = COMPONENT_DUPE_UNIQUE @@ -31,10 +31,19 @@ GLOBAL_LIST_EMPTY(uplinks) var/compact_mode = FALSE var/debug = FALSE var/non_traitor_allowed = TRUE + // Tied to uplink rather than mind since generally traitors only have 1 uplink + // and tying it to anything else is difficult due to how much uses an uplink + var/reputation = 200 var/list/previous_attempts -/datum/component/uplink/Initialize(datum/mind/_owner, _lockable = TRUE, _enabled = FALSE, uplink_flag = UPLINK_TRAITORS, starting_tc = TELECRYSTALS_DEFAULT) +/datum/component/uplink/Initialize(datum/mind/_owner, + _lockable = TRUE + _enabled = FALSE, + uplink_flag = UPLINK_TRAITORS, + starting_tc = TELECRYSTALS_DEFAULT, + _reputation = 200, + ) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -62,6 +71,7 @@ GLOBAL_LIST_EMPTY(uplinks) purchase_log = new(owner.key, src) lockable = _lockable active = _enabled + reputation = _reputation src.uplink_flag = uplink_flag update_items() telecrystals = starting_tc diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 63da060a91b5f..99ed6026833c7 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -138,6 +138,9 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( var/spawn_amount = 1 //How many times we should run the spawn var/additional_uplink_entry = null //Bonus items you gain if you purchase it var/is_bonus = FALSE // entry in 'additional_uplink_entry' will have this as TRUE. Used for logging detail + /// How much reputation is required to purchase this item. + /// Things that can be used for indiscriminant murder should require more work to get. + var/reputation_required = REPUTATION_EXCOMMUNICATED /datum/uplink_item/New() . = ..() @@ -269,7 +272,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( standard contractor gear to help with your mission - comes supplied with the tablet, specialised space suit, chameleon jumpsuit and mask, \ agent card, specialised contractor baton, and three randomly selected low cost items. Can include otherwise unobtainable items." item = /obj/item/storage/box/syndie_kit/contract_kit - cost = 20 + cost = 15 + reputation_required = REPUTATION_GOOD player_minimum = 15 purchasable_from = ~(UPLINK_INCURSION | UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) @@ -279,7 +283,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( These items are collectively worth more than 20 telecrystals, but you do not know which specialization \ you will receive. May contain discontinued and/or exotic items." item = /obj/item/storage/box/syndie_kit/bundle_A - cost = 20 + cost = 15 + reputation_required = REPUTATION_STANDARD purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) /datum/uplink_item/bundles_TC/bundle_B @@ -287,7 +292,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "Syndicate Bundles, also known as Syndi-Kits, are specialized groups of items that arrive in a plain box. \ In Syndi-kit Special, you will receive items used by famous syndicate agents of the past. Collectively worth more than 20 telecrystals, the syndicate loves a good throwback." item = /obj/item/storage/box/syndie_kit/bundle_B - cost = 20 + cost = 15 + reputation_required = REPUTATION_STANDARD purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) /datum/uplink_item/bundles_TC/surplus @@ -295,7 +301,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "A dusty crate from the back of the Syndicate warehouse. Rumored to contain a valuable assortment of items, \ but you never know. Contents are sorted to always be worth 50 TC." item = /obj/structure/closet/crate - cost = 20 + cost = 18 + reputation_required = REPUTATION_GOOD player_minimum = 20 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) var/starting_crate_value = 50 @@ -305,7 +312,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( name = "Super Surplus Crate" desc = "A dusty SUPER-SIZED from the back of the Syndicate warehouse. Rumored to contain a valuable assortment of items, \ but you never know. Contents are sorted to always be worth 125 TC." - cost = 40 + cost = 25 + reputation_required = REPUTATION_EXCELLENT player_minimum = 30 starting_crate_value = 125 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) @@ -343,6 +351,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( purchasable_from = ~(UPLINK_INCURSION | UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) uplink_contents = (UPLINK_TRAITORS | UPLINK_NUKE_OPS) player_minimum = 30 + cost = 15 + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/bundles_TC/surplus/random/purchase(mob/user, datum/component/uplink/U) var/index = rand(1, 20) @@ -414,7 +424,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( /datum/uplink_item/bundles_TC/crate name = "Bulk Hardsuit Bundle" desc = "A crate containing 4 valueable syndicate hardsuits." - cost = 18 + cost = 8 purchasable_from = UPLINK_INCURSION item = /obj/effect/gibspawner/generic var/list/contents = list( @@ -437,7 +447,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( name = "Syndicate Medical Bundle" desc = "Contains an assortment of syndicate medical equipment for you and your team.\ Comes with a variety of first-aid kits, pill bottles, a compact defibrillator and 4 stimpacks." - cost = 12 + cost = 8 contents = list( /obj/item/storage/firstaid/tactical = 2, //8 TC /obj/item/storage/firstaid/brute = 2, @@ -454,7 +464,10 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "Every syndicate team needs their own shuttle. It's a shame you weren't supplied with one, but thats not a problem\ if you can spare some TC! The all new shuttle creation kit (produced by the syndicate) contains everything you need\ to get flying! All syndicate agents are advised to ignore the Nanotrasen labels on products. Space proof suits not included." - cost = 15 //There are multiple uses for the RCD and plasma canister, but both are easilly accessible for items that cost less than all of their TC. + reputation_required = REPUTATION_STANDARD + // There are multiple uses for the RCD and plasma canister, but both are easilly accessible for items that cost less than all of their TC. + // Should be cheaper than the shuttle capsule + cost = 5 contents = list( /obj/machinery/portable_atmospherics/canister/plasma = 1, /obj/item/construction/rcd/combat = 1, @@ -612,13 +625,15 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "These gloves let the user punch people very fast. Does not improve weapon attack speed or the meaty fists of a hulk." item = /obj/item/clothing/gloves/rapid cost = 8 + reputation_required = REPUTATION_STANDARD /datum/uplink_item/dangerous/holoparasite name = "Holoparasites" desc = "Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, they require an \ organic host as a home base and source of fuel. Holoparasites come in various types and share damage with their host." item = /obj/item/holoparasite_creator/tech - cost = 18 + cost = 15 + reputation_required = REPUTATION_EXCELLENT surplus = 10 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) player_minimum = 25 @@ -700,6 +715,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/gun/ballistic/revolver player_minimum = 25 cost = 12 + reputation_required = REPUTATION_GOOD surplus = 50 purchasable_from = ~UPLINK_CLOWN_OPS @@ -802,7 +818,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "This scroll contains the secrets of an ancient martial arts technique. You will master unarmed combat, \ deflecting all ranged weapon fire, but you also refuse to use dishonorable ranged weaponry." item = /obj/item/book/granter/martial/carp - cost = 16 + cost = 15 + reputation_required = REPUTATION_EXCELLENT player_minimum = 20 surplus = 10 purchasable_from = ~(UPLINK_INCURSION | UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) @@ -817,6 +834,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/gun/energy/kinetic_accelerator/crossbow/radbow cost = 8 surplus = 50 + reputation_required = REPUTATION_GOOD /datum/uplink_item/stealthy_weapons/crossbow name = "Miniature Energy Crossbow" @@ -827,7 +845,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( slur as if inebriated. It can produce an infinite number \ of bolts, but takes a small amount of time to automatically recharge after each shot." item = /obj/item/gun/energy/kinetic_accelerator/crossbow - cost = 12 + cost = 10 + reputation_required = REPUTATION_GOOD surplus = 50 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) @@ -845,7 +864,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( name = "Poison Kit" desc = "An assortment of deadly chemicals packed into a compact box. Comes with a syringe for more precise application." item = /obj/item/storage/box/syndie_kit/chemical - cost = 7 + cost = 6 surplus = 50 /datum/uplink_item/stealthy_weapons/romerol_kit @@ -854,7 +873,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( On death, these nodules take control of the dead body, causing limited revivification, \ along with slurred speech, aggression, and the ability to infect others with this agent." item = /obj/item/storage/box/syndie_kit/romerol - cost = 20 + cost = 15 + reputation_required = REPUTATION_ELITE cant_discount = TRUE murderbone_type = TRUE surplus = 0 @@ -1253,7 +1273,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( name = "Bag of C-4 explosives" desc = "Because sometimes quantity is quality. Contains 10 C-4 plastic explosives." item = /obj/item/storage/backpack/duffelbag/syndie/c4 - cost = 8 //20% discount! + cost = 6 //40 % discount + reputation_required = REPUTATION_GOOD cant_discount = TRUE /datum/uplink_item/explosives/x4bag @@ -1262,7 +1283,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( X-4 can be placed on a solid surface, such as a wall or window, and it will blast through the wall, injuring anything on the opposite side, while being safer to the user. \ For when you want a controlled explosion that leaves a wider, deeper, hole." item = /obj/item/storage/backpack/duffelbag/syndie/x4 - cost = 4 // + cost = 4 + reputation_required = REPUTATION_GOOD cant_discount = TRUE /datum/uplink_item/explosives/clown_bomb_clownops @@ -1284,6 +1306,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( The concussive effect from the explosion will knock the recipient out for a short period, and deafen them for longer." item = /obj/item/computer_hardware/hard_drive/role/virus/syndicate cost = 6 + reputation_required = REPUTATION_GOOD restricted = TRUE /datum/uplink_item/explosives/emp @@ -1331,6 +1354,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( This variant has been fitted with high yield X4 charges for a larger explosion." item = /obj/item/deployablemine/traitor/bigboom cost = 10 + reputation_required = REPUTATION_GOOD /datum/uplink_item/explosives/pizza_bomb name = "Pizza Bomb" @@ -1356,6 +1380,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( The bomb core can be pried out and manually detonated with other explosives." item = /obj/item/sbeacondrop/bomb cost = 12 + reputation_required = REPUTATION_GOOD /datum/uplink_item/explosives/syndicate_detonator name = "Syndicate Detonator" @@ -1374,6 +1399,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/grenade/syndieminibomb cost = 4 purchasable_from = ~UPLINK_CLOWN_OPS + reputation_required = REPUTATION_STANDARD /datum/uplink_item/explosives/tearstache name = "Teachstache Grenade" @@ -1623,6 +1649,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/clothing/suit/space/hardsuit/syndi cost = 7 purchasable_from = ~UPLINK_NUKE_OPS //you can't buy it in nuke, because the elite hardsuit costs the same while being better + reputation_required = REPUTATION_STANDARD /datum/uplink_item/suits/hardsuit/spawn_item(spawn_path, mob/user, datum/component/uplink/U) var/obj/item/clothing/suit/space/hardsuit/suit = ..() @@ -1701,7 +1728,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( an in-built shuttle interdictor and a single canister of plasma to fuel your adventures! \ This innovative shuttle can seat up to 4 passengers, willing or not! Shuttle must be deployed in space or on lavaland, space suits not included." item = /obj/item/survivalcapsule/shuttle/traitor - cost = 8 + cost = 7 + reputation_required = REPUTATION_GOOD purchasable_from = (UPLINK_INCURSION | UPLINK_TRAITORS) /datum/uplink_item/device_tools/magboots @@ -1748,6 +1776,9 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( in electronic devices, subverts intended functions, and easily breaks security mechanisms." item = /obj/item/card/emag cost = 6 + // I don't want people using this to break into captain's office at roundstart, at least + // wait until 1 directive appears + reputation_required = REPUTATION_GOOD /datum/uplink_item/device_tools/fakenucleardisk name = "Decoy Nuclear Authentication Disk" @@ -1774,7 +1805,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( You will receive the unlock code upon activating the virus, and the new uplink may be charged with \ telecrystals normally." item = /obj/item/computer_hardware/hard_drive/role/virus/frame - cost = 4 + cost = 3 restricted = TRUE /datum/uplink_item/device_tools/failsafe @@ -1826,6 +1857,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "A modified flash able to hypnotize targets. If the target is not in a mentally vulnerable state, it will only confuse and pacify them temporarily." item = /obj/item/assembly/flash/hypnotic cost = 7 + reputation_required = REPUTATION_GOOD /datum/uplink_item/device_tools/medgun name = "Medbeam Gun" @@ -1843,6 +1875,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( sends you a small beacon that will teleport the larger beacon to your location upon activation." item = /obj/item/sbeacondrop cost = 10 + reputation_required = REPUTATION_ELITE /datum/uplink_item/device_tools/powersink name = "Power Sink" @@ -2207,14 +2240,16 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( are very sensitive. Now with our included lube defense mechanism which will protect you against any angry shitcurity! \ Premium features can be unlocked with a cryptographic sequencer!" item = /obj/vehicle/sealed/car/clowncar - cost = 20 + cost = 14 + reputation_required = REPUTATION_EXCELLENT restricted_roles = list(JOB_NAME_CLOWN) purchasable_from = ~UPLINK_INCURSION /datum/uplink_item/role_restricted/taeclowndo_shoes name = "Tae-clown-do Shoes" desc = "A pair of shoes for the most elite agents of the honkmotherland. They grant the mastery of taeclowndo with some honk-fu moves as long as they're worn." - cost = 12 + cost = 10 + reputation_required = REPUTATION_GOOD item = /obj/item/clothing/shoes/clown_shoes/taeclowndo restricted_roles = list(JOB_NAME_CLOWN) @@ -2249,7 +2284,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "Most magic eightballs are toys with dice inside. Although identical in appearance to the harmless toys, this occult device reaches into the spirit world to find its answers. \ Be warned, that spirits are often capricious or just little assholes. To use, simply speak your question aloud, then begin shaking." item = /obj/item/toy/eightball/haunted - cost = 2 + cost = 1 restricted_roles = list(JOB_NAME_CURATOR) limited_stock = 1 //please don't spam deadchat @@ -2264,7 +2299,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( name = "Prison Cube" desc = "A very strange artifact recovered from a volcanic planet that is useful for keeping people locked away, but not very useful for keeping their disappearance unknown" item = /obj/item/prisoncube - cost = 6 + cost = 5 restricted_roles = list(JOB_NAME_CURATOR) /datum/uplink_item/role_restricted/his_grace @@ -2274,7 +2309,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( However, if left alone for long enough, He will fall back to slumber. \ To activate His Grace, simply unlatch Him." item = /obj/item/his_grace - cost = 20 + cost = 14 + reputation_required = REPUTATION_ELITE restricted_roles = list(JOB_NAME_CHAPLAIN) murderbone_type = TRUE surplus = 0 @@ -2283,7 +2319,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( name = "Cult Construct Kit" desc = "Recovered from an abandoned Nar'sie cult lair two construct shells and a stash of empty soulstones was found. These were purified to prevent occult contamination and have been put in a belt so they may be used as an accessible source of disposable minions. The construct shells have been packaged into two beacons for rapid and portable deployment." item = /obj/item/storage/box/syndie_kit/cultconstructkit - cost = 20 + cost = 14 + reputation_required = REPUTATION_ELITE restricted_roles = list(JOB_NAME_CHAPLAIN) /datum/uplink_item/role_restricted/shadowmutationtoxin @@ -2298,7 +2335,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "A bottle of cursed blood, full of angry spirits which will burn all the heretics with the fires of hell. \ At least, that's what the label says" item = /obj/item/reagent_containers/glass/bottle/fluspanish - cost = 12 + cost = 10 + reputation_required = REPUTATION_EXCELLENT restricted_roles = list(JOB_NAME_CHAPLAIN, JOB_NAME_VIROLOGIST) /datum/uplink_item/role_restricted/retrovirus @@ -2306,7 +2344,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "A bottle of contagious DNA bugs, which will manually rearrange the DNA of hosts. \ At least, that's what the label says." item = /obj/item/reagent_containers/glass/bottle/retrovirus - cost = 12 + cost = 10 + reputation_required = REPUTATION_EXCELLENT restricted_roles = list(JOB_NAME_VIROLOGIST, JOB_NAME_GENETICIST) /datum/uplink_item/role_restricted/anxiety @@ -2339,12 +2378,13 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "Fishsticks prepared through ritualistic means in honor of the god Carp-sie, capable of binding a holocarp \ to act as a servant and guardian to their host." item = /obj/item/holoparasite_creator/carp - cost = 18 + cost = 16 surplus = 5 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) player_minimum = 25 restricted = TRUE restricted_roles = list(JOB_NAME_COOK, JOB_NAME_CHAPLAIN) + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/role_restricted/ez_clean_bundle name = "EZ Clean Grenade Bundle" @@ -2430,7 +2470,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( name = "Reverse Revolver" desc = "A revolver that always fires at its user. \"Accidentally\" drop your weapon, then watch as the greedy corporate pigs blow their own brains all over the wall. \ The revolver itself is actually real. Only clumsy people, and clowns, can fire it normally. Comes in a box of hugs. Honk." - cost = 13 + cost = 8 item = /obj/item/storage/box/hug/reverse_revolver restricted_roles = list(JOB_NAME_CLOWN) @@ -2485,7 +2525,9 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "For showing that you are THE BOSS: A useless red balloon with the Syndicate logo on it. \ Can blow the deepest of covers." item = /obj/item/toy/syndicateballoon - cost = 20 + cost = 8 + // Only for the best + reputation_required = REPUTATION_ELITE cant_discount = TRUE illegal_tech = FALSE surplus = 0 diff --git a/config/dbconfig.txt b/config/dbconfig.txt index ffcbe885689dd..35443519b1c3e 100644 --- a/config/dbconfig.txt +++ b/config/dbconfig.txt @@ -3,17 +3,17 @@ ## administration, and the in game library. ## Should SQL be enabled? Uncomment to enable -#SQL_ENABLED +SQL_ENABLED ## Server the MySQL database can be found at. ## Examples: localhost, 200.135.5.43, www.mysqldb.com, etc. -ADDRESS localhost +ADDRESS 127.0.0.1 ## MySQL server port (default is 3306). PORT 3306 ## Database for all SQL functions, not just feedback. -FEEDBACK_DATABASE ss13beedb +FEEDBACK_DATABASE beestation13 ## Prefix to be added to the name of every table, older databases will require this be set to erro_ ## Note, this does not change the table names in the database, you will have to do that yourself. @@ -24,7 +24,7 @@ FEEDBACK_DATABASE ss13beedb FEEDBACK_TABLEPREFIX SS13_ ## Username/Login used to access the database. -FEEDBACK_LOGIN ss13dbuser +FEEDBACK_LOGIN beestation13 ## Password used to access the database. FEEDBACK_PASSWORD password1 @@ -45,4 +45,4 @@ BSQL_THREAD_LIMIT 50 MAX_CONCURRENT_QUERIES 25 ## Disable advanced feedback tracking, saving a substantial amount of database space. -LIMITED_FEEDBACK +#LIMITED_FEEDBACK diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index ec160f4f9d6b3..4cf274afdf802 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -104,7 +104,18 @@ const HomePage = (props, context) => {
- + Current Reputation +
+ 200 Reputation +
+ Uplink Services +
+ Shop Now +
+ Special Directives +
+ None Available +
diff --git a/tgui/packages/tgui/styles/interfaces/Uplink.scss b/tgui/packages/tgui/styles/interfaces/Uplink.scss index a2dc5288bdd68..85e8785a7587c 100644 --- a/tgui/packages/tgui/styles/interfaces/Uplink.scss +++ b/tgui/packages/tgui/styles/interfaces/Uplink.scss @@ -22,15 +22,6 @@ margin: 10px; } -.HomeRight { - position: absolute; - right: 0; - top: 0; - bottom: 0; - width: 40%; - margin: 10px; -} - .HomeTitle { width: 100%; font-size: x-large; @@ -92,6 +83,36 @@ font-weight: bold; } +.HomeRight { + position: absolute; + right: 0; + top: 0; + bottom: 0; + width: 40%; + margin: 10px; +} + +.HomeButton { + width: 176px; + height: 40px; + padding: 10px; + margin-left: calc(100% - 176px); + border-radius: 13px; + text-align: center; + vertical-align: middle; + padding-top: 12px; + background-color: red; + margin-bottom: 40px; + box-shadow: black 3px 3px; + margin-top: 2px; + + &:hover { + margin-left: calc(100% - 174px); + margin-bottom: 40px; + box-shadow: black 1px 1px; + } +} + .objective_card { position: relative; width: 180px; From b06f5bc42414415f399720e051e5aa14164fac82 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Sun, 31 Mar 2024 20:02:40 +0100 Subject: [PATCH 48/62] Adds in ranks and reputation --- code/datums/components/uplink.dm | 8 +- tgui/packages/tgui/interfaces/Uplink.js | 93 +++++++++++++++---- .../tgui/styles/interfaces/Uplink.scss | 65 +++++++++++-- 3 files changed, 135 insertions(+), 31 deletions(-) diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index bca06f1635ce4..46e7290ced9e7 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -38,7 +38,7 @@ GLOBAL_LIST_EMPTY(uplinks) var/list/previous_attempts /datum/component/uplink/Initialize(datum/mind/_owner, - _lockable = TRUE + _lockable = TRUE, _enabled = FALSE, uplink_flag = UPLINK_TRAITORS, starting_tc = TELECRYSTALS_DEFAULT, @@ -181,6 +181,7 @@ GLOBAL_LIST_EMPTY(uplinks) data["lockable"] = lockable data["compactMode"] = compact_mode data["objectives"] = SSdirectives.get_uplink_data(src) + data["reputation"] = reputation return data /datum/component/uplink/ui_static_data(mob/user) @@ -219,7 +220,8 @@ GLOBAL_LIST_EMPTY(uplinks) "cost" = I.cost, "desc" = I.desc, "is_illegal" = I.illegal_tech, - "are_contents_illegal" = I.contents_are_illegal_tech + "are_contents_illegal" = I.contents_are_illegal_tech, + "reputation" = I.reputation_required )) data["categories"] += list(cat) return data @@ -266,6 +268,8 @@ GLOBAL_LIST_EMPTY(uplinks) if(telecrystals < U.cost || U.limited_stock == 0) return + if (reputation < U.reputation_required) + return telecrystals -= U.cost U.purchase(user, src) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 4cf274afdf802..629020e1c7180 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -6,15 +6,38 @@ import { Window } from '../layouts'; import '../styles/interfaces/Uplink.scss'; import { NtosRadarMap } from './NtosRadar'; import { Color } from 'common/color'; +import { classes } from 'common/react'; const MAX_SEARCH_RESULTS = 25; +const reputationLevels = { + 0: { name: "Ex-Communicate", description: "A traitor to the cause, betraying their brothers to seek personal gain. Reaching this level will result in halted services and a termination order after 5 minutes." }, + 100: { name: "Blood Servant", description: "An operative with a reason to act, but without the will to fulfill their greater purpose." }, + 200: { name: "Field Agent", description: "An operative acting on the ground, with access to some standard equipment that can be used to complete their mission." }, + 400: { name: "Specialist", description: "An operative with specialized skills and knowledge, granted with additional resources and services for completing critical missions." }, + 600: { name: "Operative", description: "An experienced operative who has demonstrated competence and effectiveness in completing various missions for the Syndicate." }, + 800: { name: "Director", description: "A high-ranking official responsible for overseeing and coordinating operations with their team, ensuring the success of its objectives." }, + 1000: { name: "Archon", description: "A high ranking and secretive authority, possessing unparalleled knowledge, influence, and control over operations and resources." }, +}; + + export const Uplink = (props, context) => { const { data } = useBackend(context); - const { telecrystals } = data; + const { telecrystals, reputation } = data; const [tab, setTab] = useSharedState(context, 'tab_id', 2); + let currentLevel = null; + + // Find the highest reputation level that is less than the current reputation + for (const level in reputationLevels) { + if (level <= reputation) { + currentLevel = reputationLevels[level].name; + } else { + break; + } + } + return ( @@ -43,9 +66,8 @@ export const Uplink = (props, context) => { - - Neutral Reputation + + {currentLevel ? currentLevel : "Neutral Reputation"} ({reputation}) {tab === 0 @@ -306,7 +328,7 @@ const ObjectiveCard = (props, context) => { export const GenericUplink = (props, context) => { const { currencyAmount = 0, currencySymbol = 'cr' } = props; const { act, data } = useBackend(context); - const { compactMode, lockable, categories = [] } = data; + const { compactMode, lockable, categories = [], reputation } = data; const [searchText, setSearchText] = useLocalState(context, 'searchText', ''); const [selectedCategory, setSelectedCategory] = useLocalState(context, 'category', categories[0]?.name); const testSearch = createSearch(searchText, (item) => { @@ -362,6 +384,7 @@ export const GenericUplink = (props, context) => { {searchText.length === 0 ? 'No items in this category.' : 'No results found.'} )} 0 || compactMode} currencyAmount={currencyAmount} currencySymbol={currencySymbol} @@ -374,16 +397,16 @@ export const GenericUplink = (props, context) => { }; const ItemList = (props, context) => { - const { compactMode, currencyAmount, currencySymbol } = props; + const { reputation, compactMode, currencyAmount, currencySymbol } = props; const { act } = useBackend(context); const [hoveredItem, setHoveredItem] = useLocalState(context, 'hoveredItem', {}); - const hoveredCost = (hoveredItem && hoveredItem.cost) || 0; + const hoveredCost = (hoveredItem && hoveredItem.cost && reputation >= hoveredItem.reputation) || 0; // Append extra hover data to items const items = props.items.map((item) => { const notSameItem = hoveredItem && hoveredItem.name !== item.name; const notEnoughHovered = currencyAmount - hoveredCost < item.cost; const disabledDueToHovered = notSameItem && notEnoughHovered; - const disabled = currencyAmount < item.cost || disabledDueToHovered; + const disabled = reputation < item.reputation || currencyAmount < item.cost || disabledDueToHovered; return { ...item, disabled, @@ -422,6 +445,20 @@ const ItemList = (props, context) => { {items.map((item) => ( {decodeHtmlEntities(item.name)} + {item.reputation ? ( + + = item.reputation ? "green" : "red"}> + {item.reputation} reputation + + + ) : } + {currencyAmount < item.cost ? ( + + + Insufficient Funds + + + ) : }
diff --git a/tgui/packages/tgui/styles/interfaces/Uplink.scss b/tgui/packages/tgui/styles/interfaces/Uplink.scss index 85e8785a7587c..547bf3caebf2b 100644 --- a/tgui/packages/tgui/styles/interfaces/Uplink.scss +++ b/tgui/packages/tgui/styles/interfaces/Uplink.scss @@ -243,13 +243,12 @@ } } -$background-color: #bb9b68 !default; - .reputation { - background-color: $background-color !important; - $luminance: luminance($background-color); + $luminance: luminance(#bb9b68); $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + width: 160px; + text-align: center; margin-left: auto; margin-right: 5px; border-radius: 5px; @@ -262,11 +261,57 @@ $background-color: #bb9b68 !default; rgba(0, 0, 0, 0.1) base.em(10px), rgba(0, 0, 0, 0.1) base.em(20px) ); -} -@mixin box-color($color) { - $luminance: luminance($color); - $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); - color: $text-color; - background-color: color.adjust($color, $saturation: -15%, $lightness: -15%); + &.excommunicate { + background-color: #B92F27; // Dark red for Ex-Communication rank + $luminance: luminance(#B92F27); + $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + color: $text-color; + } + + &.blood-servant { + background-color: #543219; // Saddle brown for Blood Servant rank + $luminance: luminance(#543219); + $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + color: $text-color; + } + + &.field-agent { + background-color: #3960aa; // Cornflower blue for Field Agent rank + $luminance: luminance(#3960aa); + $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + color: $text-color; + } + + &.specialist { + background-color: #6724a6; // Hot pink for Specialist rank + $luminance: luminance(#6724a6); + $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + color: $text-color; + } + + &.operative { + background-color: #cb2e7d; // Blue violet for Operative rank + $luminance: luminance(#cb2e7d); + $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + color: $text-color; + } + + &.director { + background-color: #821111; // Firebrick for Director rank + $luminance: luminance(#821111); + $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + color: $text-color; + } + + &.archon { + background-color: #ffd059; // Gold for Archon rank + $luminance: luminance(#ffd059); + $text-color: if($luminance > 0.35, rgba(0, 0, 0, 1), rgba(255, 255, 255, 1)); + color: $text-color; + } + + } + + From 48a2374f992d53274bfe347edf68e9c07458548d Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:42:43 +0100 Subject: [PATCH 49/62] Ties reputation to directives --- .../directives/deploy_beacon/deploy_beacon.dm | 5 +- .../traitor/directives/priority_directive.dm | 21 ++- .../secure_deaddrop/secure_deaddrop.dm | 13 +- code/modules/uplink/uplink_items.dm | 3 + tgui/packages/tgui/interfaces/Uplink.js | 145 +++++++++++++----- .../tgui/styles/interfaces/Uplink.scss | 3 +- 6 files changed, 142 insertions(+), 48 deletions(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm index f77b04b7741a7..032de3c5d6cfd 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/deploy_beacon.dm @@ -5,6 +5,7 @@ to deploy a beacon encoded our organisation's encrypion code. Hostile agents may try to swap the code \ for their own, which you need to prevent from happening. There are friendly agents supporting you on this mission \ but their identities are unknown." + reputation_loss = REPUTATION_LOSS_TEAM_DIRECTIVE var/obj/structure/uplink_beacon/deployed_beacon // Don't track this for deletion, since we need to maintain a track on the same position // when a turf is changed. @@ -122,9 +123,11 @@ /datum/priority_directive/deploy_beacon/proc/complete(channel) deployed_beacon = null finish() + var/datum/directive_team/winner = null for (var/datum/directive_team/team in teams) if (team.data["code"] == channel) + winner = team team.send_message("Beacon communication successfully established on the [uplink_beacon_channel_to_color(channel)] channel.") - team.grant_reward(tc_reward) else team.send_message("You have failed to deploy the beacon on your allocated channel. Mission failed.") + grant_victory(winner) diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 07823043b9b40..9325aec3da78c 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -1,10 +1,16 @@ NAMED_TUPLE_2(directive_team, var/list, uplinks, var/list, data) NAMED_TUPLE_1(directive_special_action, var, action_name) -/datum/directive_team/proc/grant_reward(amount) +/datum/directive_team/proc/grant_reward(tc_amount, reputation_amount) for (var/datum/component/uplink/uplink in uplinks) - uplink.telecrystals += amount - send_message("[amount] telecrystals have been deposited into your uplink.") + uplink.telecrystals += tc_amount + uplink.reputation += reputation_amount + send_message("[tc_amount] telecrystals and [reputation_amount] reputation points have been authorised for your use.") + +/datum/directive_team/proc/grant_punishment(loss_amount) + for (var/datum/component/uplink/uplink in uplinks) + uplink.reputation -= reputation_amount + send_message("You have failed to complete a direct order from Syndicate command. You have lost [loss_amount] reputation points as a result of administrative punishment.") /datum/directive_team/proc/send_message(message) for (var/datum/component/uplink/uplink in uplinks) @@ -33,6 +39,8 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) var/end_at var/rejected = FALSE var/tc_reward + var/reputation_reward = REPUTATION_GAIN_PER_DIRECTIVE + var/reputation_loss = REPUTATION_LOSS_SOLO_DIRECTIVE var/can_timeout = TRUE VAR_PRIVATE/list/teams = list() @@ -166,3 +174,10 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) deadchat_broadcast("Syndicate Mission Update: [message]", turf_target = get_turf(follow_atom)) else deadchat_broadcast("Syndicate Mission Update: [message]") + +/datum/priority_directive/proc/grant_victory(datum/directive_team/victor_team) + victor_team?.grant_reward(tc_reward, reputation_reward) + for (var/datum/directive_team/team in teams) + if (team == victor_team) + continue + team.grant_punishment(reputation_loss) diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index 10789f7ddf744..363a22b1083d4 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -8,7 +8,7 @@ var/obj/item/storage/deaddrop_box/target /datum/priority_directive/deaddrop/_allocate_teams(list/uplinks, list/player_minds, force = FALSE) - if (length(uplinks) <= 1 && !force) + if (length(uplinks) < 1 && !force) reject() return for (var/datum/component/uplink/antag in uplinks) @@ -32,9 +32,18 @@ // Return the reward generated return tc_count -/datum/priority_directive/deaddrop/finish(list/uplinks, list/player_minds) +/datum/priority_directive/deaddrop/finish() . = ..() target.unlock() + var/atom/current = target + while (!ismob(current) && !isturf(current) && current) + current = current.loc + if (ismob(current)) + var/mob/living/living_holder = current + var/datum/component/uplink/uplink = living_holder.mind.find_syndicate_uplink() + grant_victory(uplink != null ? get_team(uplink) : null) + else + grant_victory(null) /datum/priority_directive/deaddrop/get_track_atom() return target diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 99ed6026833c7..c81ee18a1d2fb 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -1748,6 +1748,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/disk/surgery/brainwashing player_minimum = 25 cost = 5 + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/device_tools/briefcase_launchpad name = "Briefcase Launchpad" @@ -1756,6 +1757,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( surplus = 30 item = /obj/item/storage/briefcase/launchpad cost = 5 + reputation_required = REPUTATION_GOOD /datum/uplink_item/device_tools/camera_bug name = "Camera Bug" @@ -1885,6 +1887,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/powersink cost = 10 player_minimum = 35 + reputation_required = REPUTATION_GOOD /datum/uplink_item/device_tools/stimpack name = "Stimpack" diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 629020e1c7180..b7a958a9245d9 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -11,32 +11,96 @@ import { classes } from 'common/react'; const MAX_SEARCH_RESULTS = 25; const reputationLevels = { - 0: { name: "Ex-Communicate", description: "A traitor to the cause, betraying their brothers to seek personal gain. Reaching this level will result in halted services and a termination order after 5 minutes." }, - 100: { name: "Blood Servant", description: "An operative with a reason to act, but without the will to fulfill their greater purpose." }, - 200: { name: "Field Agent", description: "An operative acting on the ground, with access to some standard equipment that can be used to complete their mission." }, - 400: { name: "Specialist", description: "An operative with specialized skills and knowledge, granted with additional resources and services for completing critical missions." }, - 600: { name: "Operative", description: "An experienced operative who has demonstrated competence and effectiveness in completing various missions for the Syndicate." }, - 800: { name: "Director", description: "A high-ranking official responsible for overseeing and coordinating operations with their team, ensuring the success of its objectives." }, - 1000: { name: "Archon", description: "A high ranking and secretive authority, possessing unparalleled knowledge, influence, and control over operations and resources." }, + 0: { + name: "Ex-Communicate", + description: "A traitor to the cause, betraying their brothers to seek personal gain. Reaching this level will result in halted services and a termination order after 5 minutes.", + min_reputation: null, + max_reputation: 99, + }, + 100: { + name: "Blood Servant", + description: "An operative with a reason to act, but without the will to fulfill their greater purpose.", + min_reputation: 100, + max_reputation: 199, + }, + 200: { + name: "Field Agent", + description: "An operative acting on the ground, with access to some standard equipment that can be used to complete their mission.", + min_reputation: 200, + max_reputation: 399, + }, + 400: { + name: "Specialist", + description: "An operative with specialized skills and knowledge, granted with additional resources and services for completing critical missions.", + min_reputation: 400, + max_reputation: 599, + }, + 600: { + name: "Operative", + description: "An experienced operative who has demonstrated competence and effectiveness in completing various missions for the Syndicate.", + min_reputation: 600, + max_reputation: 799, + }, + 800: { + name: "Director", + description: "A high-ranking official responsible for overseeing and coordinating operations with their team, ensuring the success of its objectives.", + min_reputation: 800, + max_reputation: 999, + }, + 1000: { + name: "Archon", + description: "A high ranking and secretive authority, possessing unparalleled knowledge, influence, and control over operations and resources.", + min_reputation: 1000, + max_reputation: null, + }, }; - -export const Uplink = (props, context) => { - const { data } = useBackend(context); - const { telecrystals, reputation } = data; - - const [tab, setTab] = useSharedState(context, 'tab_id', 2); - +const GetLevel = (reputation, index_change = 0) => { let currentLevel = null; + let index = -1; // Find the highest reputation level that is less than the current reputation for (const level in reputationLevels) { - if (level <= reputation) { - currentLevel = reputationLevels[level].name; + if (level <= reputation || currentLevel === null) { + currentLevel = reputationLevels[level]; + index ++; } else { break; } } + // Adjust the index based on the change provided + index += index_change; + + if (index < 0) + { + return { + name: "", + description: "There are no lower levels within the Syndicate database.", + }; + } + else if (index >= Object.keys(reputationLevels).length) + { + return { + name: "", + description: "You are at the highest rank an agent can reach within the Syndicate.", + }; + } + + // Get the reputation level at the adjusted index + const levels = Object.keys(reputationLevels); + const levelKey = levels[index]; + currentLevel = reputationLevels[levelKey]; + + return currentLevel; +}; + +export const Uplink = (props, context) => { + const { data } = useBackend(context); + const { telecrystals, reputation } = data; + + const [tab, setTab] = useSharedState(context, 'tab_id', 2); + + let currentLevel = GetLevel(reputation).name; return ( @@ -81,6 +145,11 @@ export const Uplink = (props, context) => { }; const HomePage = (props, context) => { + const { data } = useBackend(context); + const { reputation } = data; + let previousLevel = GetLevel(reputation, -1); + let currentLevel = GetLevel(reputation); + let nextLevel = GetLevel(reputation, 1); return ( @@ -91,36 +160,28 @@ const HomePage = (props, context) => {
-
@@ -166,12 +227,14 @@ const RankCard = (props, contxt) => { {description} -
- {reputation} Reputation
- ({reputation_delta}) -
+ {!current_rank && !!reputation_delta && ( +
+ {reputation_delta > 0 ? ("Gain " + reputation_delta + " reputation to reach promotion") : ("Demotion if " + -reputation_delta + " reputation is lost")} +
+ )} + ); }; @@ -400,7 +463,7 @@ const ItemList = (props, context) => { const { reputation, compactMode, currencyAmount, currencySymbol } = props; const { act } = useBackend(context); const [hoveredItem, setHoveredItem] = useLocalState(context, 'hoveredItem', {}); - const hoveredCost = (hoveredItem && hoveredItem.cost && reputation >= hoveredItem.reputation) || 0; + const hoveredCost = (hoveredItem && hoveredItem.cost) || 0; // Append extra hover data to items const items = props.items.map((item) => { const notSameItem = hoveredItem && hoveredItem.name !== item.name; diff --git a/tgui/packages/tgui/styles/interfaces/Uplink.scss b/tgui/packages/tgui/styles/interfaces/Uplink.scss index 547bf3caebf2b..256ebda291613 100644 --- a/tgui/packages/tgui/styles/interfaces/Uplink.scss +++ b/tgui/packages/tgui/styles/interfaces/Uplink.scss @@ -36,6 +36,7 @@ .RankCard { position: relative; width: 100%; + padding-top: 20px; padding-bottom: 20px; color: #d4d4d4; } @@ -56,7 +57,7 @@ .RankCardProgression { position: absolute; right: 10px; - top: calc(45px - 20px); + top: calc(45px); width: 144px; height: 40px; padding: 10px; From 39f0752b917e43fd33137ad0110b3a3b6bd11f0c Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:42:54 +0100 Subject: [PATCH 50/62] Compilation issue --- .../antagonists/traitor/directives/priority_directive.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 9325aec3da78c..4e891f9cd5b79 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -9,7 +9,7 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) /datum/directive_team/proc/grant_punishment(loss_amount) for (var/datum/component/uplink/uplink in uplinks) - uplink.reputation -= reputation_amount + uplink.reputation -= loss_amount send_message("You have failed to complete a direct order from Syndicate command. You have lost [loss_amount] reputation points as a result of administrative punishment.") /datum/directive_team/proc/send_message(message) From 042cc0337fc124a59a2510ac7f344e9a4169eb18 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Mon, 8 Apr 2024 18:29:52 +0100 Subject: [PATCH 51/62] Fixes victory not working --- .../antagonists/traitor/directives/priority_directive.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/directives/priority_directive.dm b/code/modules/antagonists/traitor/directives/priority_directive.dm index 4e891f9cd5b79..9da48458ce45a 100644 --- a/code/modules/antagonists/traitor/directives/priority_directive.dm +++ b/code/modules/antagonists/traitor/directives/priority_directive.dm @@ -101,7 +101,7 @@ NAMED_TUPLE_1(directive_special_action, var, action_name) SHOULD_NOT_OVERRIDE(TRUE) PROTECTED_PROC(TRUE) RETURN_TYPE(/datum/directive_team) - var/created = new /datum/directive_team(uplinks, islist(data) ? data : list()) + var/created = new /datum/directive_team(islist(uplinks) ? uplinks : list(uplinks), islist(data) ? data : list()) teams += created return created From cb8e5a5fb92e1c8d7bbcdae9c64978695105ad6c Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Mon, 8 Apr 2024 18:54:30 +0100 Subject: [PATCH 52/62] Stops bags from spawning under objects --- .../traitor/directives/secure_deaddrop/secure_deaddrop.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm index 363a22b1083d4..80e3741258036 100644 --- a/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm +++ b/code/modules/antagonists/traitor/directives/secure_deaddrop/secure_deaddrop.dm @@ -23,7 +23,7 @@ var/tc_count = rand(4, 3 + length(teams)) // Put the deaddrop somewhere var/turf/selected = get_random_station_turf() - while (!istype(selected, /turf/open/floor/iron)) + while (!istype(selected, /turf/open/floor/iron) || selected.is_blocked_turf(TRUE)) selected = get_random_station_turf() var/atom/secret_bag = new /obj/item/storage/backpack/satchel/flat/empty(selected) target = new(secret_bag) From af4b57901904019a5c5e3f5fc8c412bc200a50c7 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Mon, 8 Apr 2024 18:54:57 +0100 Subject: [PATCH 53/62] Update beacon.dm --- .../antagonists/traitor/directives/deploy_beacon/beacon.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index 34189802b5e25..cf7dec303645c 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -36,7 +36,7 @@ light_range = 1.4 anchored = TRUE var/current_frequency = 0 - var/time_left = 180 SECONDS + var/time_left = 4 MINUTES var/spam_cooldown = 0 /obj/structure/uplink_beacon/Initialize(mapload, mob/living/user) From 650827384df56837d7e7ca02dd8a6cadb161ba36 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Mon, 8 Apr 2024 18:55:42 +0100 Subject: [PATCH 54/62] Protect from nulls in ui_itneract --- .../antagonists/traitor/directives/deploy_beacon/beacon.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm index cf7dec303645c..7259e9580dee9 100644 --- a/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm +++ b/code/modules/antagonists/traitor/directives/deploy_beacon/beacon.dm @@ -93,7 +93,7 @@ /obj/structure/uplink_beacon/ui_interact(mob/user, datum/tgui/ui) // You must be something to interact with this - if (!user.mind || !user.mind.has_antag_datum(/datum/antagonist)) + if (!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist)) return ui = SStgui.try_update_ui(user, src, ui) if(!ui) From 02a9ac9b941612383fc879cb5e0cf7b9ff7022ef Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:22:03 +0100 Subject: [PATCH 55/62] Display reputation and fix nukies --- code/__DEFINES/antagonists.dm | 2 + .../subsystem/priority_directives.dm | 6 +- code/datums/components/uplink.dm | 4 +- code/game/gamemodes/nuclear/nuclear.dm | 5 +- code/modules/uplink/uplink_devices.dm | 12 +-- code/modules/uplink/uplink_items.dm | 98 ++++++++++++++----- tgui/packages/tgui/interfaces/Uplink.js | 38 ++++++- .../tgui/styles/interfaces/Uplink.scss | 3 +- 8 files changed, 126 insertions(+), 42 deletions(-) diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 224b13fe9241e..114a97015fca2 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -138,6 +138,8 @@ /// Access to anything your heart could ever desire #define REPUTATION_MAX 1000 +#define REPUTATION_TRAITOR_START 300 + /// How much reputation is gained per completed directive #define REPUTATION_GAIN_PER_DIRECTIVE 200 diff --git a/code/controllers/subsystem/priority_directives.dm b/code/controllers/subsystem/priority_directives.dm index 75db9c2743c66..81c5e03efd200 100644 --- a/code/controllers/subsystem/priority_directives.dm +++ b/code/controllers/subsystem/priority_directives.dm @@ -7,7 +7,7 @@ SUBSYSTEM_DEF(directives) /datum/controller/subsystem/directives/Initialize(start_timeofday) . = ..() - next_directive_time = world.time + rand(10 MINUTES, 15 MINUTES) + next_directive_time = world.time + 10 MINUTES for (var/directive_type in subtypesof(/datum/priority_directive)) directives += new directive_type() @@ -102,7 +102,9 @@ SUBSYSTEM_DEF(directives) "track_x" = track_turf?.x, "track_y" = track_turf?.y, "track_z" = track_turf?.z, - "action" = active_directive.get_special_action()?.action_name + "action" = active_directive.get_special_action()?.action_name, + "rep_loss" = active_directive.reputation_loss, + "rep_gain" = active_directive.reputation_reward, )) data["objectives"] = known_objectives return data diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 46e7290ced9e7..781c0d7042fd4 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -33,7 +33,7 @@ GLOBAL_LIST_EMPTY(uplinks) var/non_traitor_allowed = TRUE // Tied to uplink rather than mind since generally traitors only have 1 uplink // and tying it to anything else is difficult due to how much uses an uplink - var/reputation = 200 + var/reputation = REPUTATION_TRAITOR_START var/list/previous_attempts @@ -42,7 +42,7 @@ GLOBAL_LIST_EMPTY(uplinks) _enabled = FALSE, uplink_flag = UPLINK_TRAITORS, starting_tc = TELECRYSTALS_DEFAULT, - _reputation = 200, + _reputation = REPUTATION_TRAITOR_START, ) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 34f92120e4b10..f340503bd45e2 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -129,6 +129,7 @@ /obj/item/knife/combat/survival) var/tc = 25 + var/reputation = REPUTATION_EXCELLENT var/command_radio = FALSE var/uplink_type = /obj/item/uplink/nuclear @@ -139,6 +140,7 @@ gloves = /obj/item/clothing/gloves/krav_maga/combatglovesplus r_hand = /obj/item/nuclear_challenge command_radio = TRUE + reputation = REPUTATION_ELITE /datum/outfit/syndicate/no_crystals name = "Syndicate Operative - Reinforcement" @@ -153,7 +155,7 @@ R.use_command = TRUE if(ispath(uplink_type, /obj/item/uplink/nuclear) || tc) // /obj/item/uplink/nuclear understands 0 tc - var/obj/item/U = new uplink_type(H, H, tc) + var/obj/item/U = new uplink_type(H, H, tc, reputation) H.equip_to_slot_or_del(U, ITEM_SLOT_BACKPACK) var/obj/item/implant/explosive/E = new/obj/item/implant/explosive(H) @@ -177,6 +179,7 @@ /obj/item/tank/jetpack/oxygen/harness=1,\ /obj/item/gun/ballistic/automatic/pistol=1,\ /obj/item/knife/combat/survival) + reputation = REPUTATION_ELITE /datum/game_mode/nuclear/generate_credit_text() diff --git a/code/modules/uplink/uplink_devices.dm b/code/modules/uplink/uplink_devices.dm index 6e4ebd8dbbb51..a20bb6069fcf0 100644 --- a/code/modules/uplink/uplink_devices.dm +++ b/code/modules/uplink/uplink_devices.dm @@ -21,14 +21,14 @@ var/uplink_flag = UPLINK_TRAITORS -/obj/item/uplink/Initialize(mapload, mob/owner, tc_amount = 20) +/obj/item/uplink/Initialize(mapload, mob/owner, tc_amount = 20, rep_amount = TRAITOR_REPUTATION_START) . = ..() AddComponent(/datum/component/uplink, owner?.mind, FALSE, TRUE, uplink_flag, tc_amount) /obj/item/uplink/debug name = "debug uplink" -/obj/item/uplink/debug/Initialize(mapload, mob/owner, tc_amount = 9000) +/obj/item/uplink/debug/Initialize(mapload, mob/owner, tc_amount = 9000, rep_amount = REPUTATION_MAX) . = ..() var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink) hidden_uplink.name = "debug uplink" @@ -41,7 +41,7 @@ name = "debug nuclear uplink" uplink_flag = UPLINK_NUKE_OPS -/obj/item/uplink/nuclear/debug/Initialize(mapload, mob/owner, tc_amount = 9000) +/obj/item/uplink/nuclear/debug/Initialize(mapload, mob/owner, tc_amount = 9000, rep_amount = REPUTATION_MAX) . = ..() var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink) hidden_uplink.name = "debug nuclear uplink" @@ -62,17 +62,17 @@ name = "dusty radio" desc = "A dusty looking radio." -/obj/item/uplink/old/Initialize(mapload, mob/owner, tc_amount = 10) +/obj/item/uplink/old/Initialize(mapload, mob/owner, tc_amount = 10, rep_amount = REPUTATION_LOW) . = ..() var/datum/component/uplink/hidden_uplink = GetComponent(/datum/component/uplink, owner?.mind) hidden_uplink.name = "dusty radio" // Multitool uplink -/obj/item/multitool/uplink/Initialize(mapload, mob/owner, tc_amount = 20) +/obj/item/multitool/uplink/Initialize(mapload, mob/owner, tc_amount = 20, rep_amount = TRAITOR_REPUTATION_START) . = ..() AddComponent(/datum/component/uplink, owner?.mind, FALSE, TRUE, UPLINK_TRAITORS, tc_amount) // Pen uplink -/obj/item/pen/uplink/Initialize(mapload, mob/owner, tc_amount = 20) +/obj/item/pen/uplink/Initialize(mapload, mob/owner, tc_amount = 20, rep_amount = TRAITOR_REPUTATION_START) . = ..() AddComponent(/datum/component/uplink, owner?.mind, TRUE, FALSE, UPLINK_TRAITORS, tc_amount) diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index c81ee18a1d2fb..673bef24379ed 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -284,7 +284,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( you will receive. May contain discontinued and/or exotic items." item = /obj/item/storage/box/syndie_kit/bundle_A cost = 15 - reputation_required = REPUTATION_STANDARD + reputation_required = REPUTATION_GOOD purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) /datum/uplink_item/bundles_TC/bundle_B @@ -293,7 +293,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( In Syndi-kit Special, you will receive items used by famous syndicate agents of the past. Collectively worth more than 20 telecrystals, the syndicate loves a good throwback." item = /obj/item/storage/box/syndie_kit/bundle_B cost = 15 - reputation_required = REPUTATION_STANDARD + reputation_required = REPUTATION_GOOD purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) /datum/uplink_item/bundles_TC/surplus @@ -493,6 +493,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "A knife that is made of two razor sharp blades, it has a secret compartment in the handle to store liquids which are injected when stabbing something. Can hold up to forty units of reagents but comes empty." item = /obj/item/knife/poison cost = 6 // all in all it's not super stealthy and you have to get some chemicals yourself + reputation_required = REPUTATION_GOOD /datum/uplink_item/dangerous/rawketlawnchair name = "84mm Rocket Propelled Grenade Launcher" @@ -588,6 +589,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( player_minimum = 25 cost = 18 purchasable_from = ~UPLINK_CLOWN_OPS + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/dangerous/doublesword/get_discount() return pick(4;0.8,2;0.65,1;0.5) @@ -599,6 +601,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/melee/transforming/energy/sword/saber cost = 8 purchasable_from = ~UPLINK_CLOWN_OPS + reputation_required = REPUTATION_STANDARD /datum/uplink_item/dangerous/shield name = "Energy Shield" @@ -632,8 +635,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, they require an \ organic host as a home base and source of fuel. Holoparasites come in various types and share damage with their host." item = /obj/item/holoparasite_creator/tech - cost = 15 - reputation_required = REPUTATION_EXCELLENT + cost = 12 + reputation_required = REPUTATION_ELITE surplus = 10 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) player_minimum = 25 @@ -691,6 +694,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/gun/ballistic/automatic/pistol cost = 7 purchasable_from = ~UPLINK_CLOWN_OPS + reputation_required = REPUTATION_STANDARD /datum/uplink_item/dangerous/derringer name = "'Infiltrator' Coat Pistol" @@ -713,11 +717,10 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( name = "Syndicate Revolver" desc = "A brutally simple Syndicate revolver that fires .357 Magnum rounds and has 7 chambers." item = /obj/item/gun/ballistic/revolver - player_minimum = 25 cost = 12 - reputation_required = REPUTATION_GOOD surplus = 50 purchasable_from = ~UPLINK_CLOWN_OPS + reputation_required = REPUTATION_GOOD /datum/uplink_item/dangerous/foamsmg name = "Toy Submachine Gun" @@ -866,6 +869,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/storage/box/syndie_kit/chemical cost = 6 surplus = 50 + reputation_required = REPUTATION_GOOD /datum/uplink_item/stealthy_weapons/romerol_kit name = "Romerol" @@ -888,6 +892,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/pen/sleepy cost = 5 purchasable_from = ~UPLINK_NUKE_OPS + reputation_required = REPUTATION_GOOD /datum/uplink_item/stealthy_weapons/suppressor name = "Suppressor" @@ -910,6 +915,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( purchasable_from = ~UPLINK_CLOWN_OPS illegal_tech = FALSE contents_are_illegal_tech = FALSE + reputation_required = REPUTATION_STANDARD /datum/uplink_item/ammo/pistolap name = "10mm Armour Piercing Magazine" @@ -920,6 +926,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( purchasable_from = ~UPLINK_CLOWN_OPS illegal_tech = FALSE contents_are_illegal_tech = FALSE + reputation_required = REPUTATION_STANDARD /datum/uplink_item/ammo/pistolhp name = "10mm Hollow Point Magazine" @@ -930,6 +937,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( purchasable_from = ~UPLINK_CLOWN_OPS illegal_tech = FALSE contents_are_illegal_tech = FALSE + reputation_required = REPUTATION_STANDARD /datum/uplink_item/ammo/pistolfire name = "10mm Incendiary Magazine" @@ -940,6 +948,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( purchasable_from = ~UPLINK_CLOWN_OPS illegal_tech = FALSE contents_are_illegal_tech = FALSE + reputation_required = REPUTATION_STANDARD /datum/uplink_item/ammo/shotgun cost = 2 @@ -995,6 +1004,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( purchasable_from = ~UPLINK_CLOWN_OPS illegal_tech = FALSE contents_are_illegal_tech = FALSE + reputation_required = REPUTATION_GOOD /datum/uplink_item/ammo/c38 name = ".38-special Speed Loader" @@ -1306,7 +1316,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( The concussive effect from the explosion will knock the recipient out for a short period, and deafen them for longer." item = /obj/item/computer_hardware/hard_drive/role/virus/syndicate cost = 6 - reputation_required = REPUTATION_GOOD + reputation_required = REPUTATION_EXCELLENT restricted = TRUE /datum/uplink_item/explosives/emp @@ -1315,12 +1325,14 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( security's energy weapons and silicon lifeforms when you're in a tight spot." item = /obj/item/storage/box/syndie_kit/emp cost = 4 + reputation_required = REPUTATION_GOOD /datum/uplink_item/explosives/ducky name = "Exploding Rubber Duck" desc = "A seemingly innocent rubber duck. When placed, it arms, and will violently explode when stepped on." item = /obj/item/deployablemine/traitor cost = 4 + reputation_required = REPUTATION_GOOD /datum/uplink_item/explosives/doorCharge name = "Airlock Charge" @@ -1328,6 +1340,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( To apply, remove the airlock's maintenance panel and place it within." item = /obj/item/doorCharge cost = 4 + reputation_required = REPUTATION_GOOD /datum/uplink_item/explosives/virus_grenade name = "Fungal Tuberculosis Grenade" @@ -1354,7 +1367,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( This variant has been fitted with high yield X4 charges for a larger explosion." item = /obj/item/deployablemine/traitor/bigboom cost = 10 - reputation_required = REPUTATION_GOOD + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/explosives/pizza_bomb name = "Pizza Bomb" @@ -1363,6 +1376,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/pizzabox/bomb cost = 3 surplus = 8 + reputation_required = REPUTATION_GOOD /datum/uplink_item/explosives/soap_clusterbang name = "Slipocalypse Clusterbang" @@ -1379,8 +1393,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( be defused, and some crew may attempt to do so. \ The bomb core can be pried out and manually detonated with other explosives." item = /obj/item/sbeacondrop/bomb - cost = 12 - reputation_required = REPUTATION_GOOD + cost = 8 + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/explosives/syndicate_detonator name = "Syndicate Detonator" @@ -1399,7 +1413,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/grenade/syndieminibomb cost = 4 purchasable_from = ~UPLINK_CLOWN_OPS - reputation_required = REPUTATION_STANDARD + reputation_required = REPUTATION_GOOD /datum/uplink_item/explosives/tearstache name = "Teachstache Grenade" @@ -1536,7 +1550,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "Projects an image across a user, disguising them as an object scanned with it, as long as they don't \ move the projector from their hand. Disguised users move slowly, and projectiles pass over them." item = /obj/item/chameleon - cost = 7 + cost = 6 + reputation_required = REPUTATION_GOOD /datum/uplink_item/stealthy_tools/codespeak_manual name = "Codespeak Manual" @@ -1585,8 +1600,9 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "These shoes will allow the wearer to run on wet floors and slippery objects without falling down. \ They do not work on heavily lubricated surfaces." item = /obj/item/clothing/shoes/chameleon/noslip - cost = 3 + cost = 2 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) + reputation_required = REPUTATION_GOOD /datum/uplink_item/stealthy_tools/syndigaloshes/nuke item = /obj/item/clothing/shoes/chameleon/noslip @@ -1616,6 +1632,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "This device will disrupt any nearby outgoing wireless signals when activated." item = /obj/item/jammer cost = 5 + reputation_required = REPUTATION_GOOD /datum/uplink_item/stealthy_tools/smugglersatchel name = "Smuggler's Satchel" @@ -1638,6 +1655,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( sightings, however." item = /obj/item/storage/box/syndie_kit/space cost = 3 + reputation_required = REPUTATION_STANDARD /datum/uplink_item/suits/hardsuit name = "Syndicate Hardsuit" @@ -1647,9 +1665,9 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( Additionally the suit is collapsible, making it small enough to fit within a backpack. \ Nanotrasen crew who spot these suits are known to panic." item = /obj/item/clothing/suit/space/hardsuit/syndi - cost = 7 + cost = 5 purchasable_from = ~UPLINK_NUKE_OPS //you can't buy it in nuke, because the elite hardsuit costs the same while being better - reputation_required = REPUTATION_STANDARD + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/suits/hardsuit/spawn_item(spawn_path, mob/user, datum/component/uplink/U) var/obj/item/clothing/suit/space/hardsuit/suit = ..() @@ -1710,6 +1728,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( cost = 4 surplus = 75 restricted = TRUE + reputation_required = REPUTATION_GOOD /datum/uplink_item/device_tools/compressionkit name = "Bluespace Compression Kit" @@ -1798,7 +1817,8 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( Due to the Syndicate's more limited research of teleportation technologies, it is incapable of phasing the user \ through solid matter nor is it capable of teleporting them across longer ranges." item = /obj/item/teleporter - cost = 7 + cost = 5 + reputation_required = REPUTATION_GOOD /datum/uplink_item/device_tools/frame name = "F.R.A.M.E. PDA Disk" @@ -1853,13 +1873,14 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( Be careful with wording, as artificial intelligences may look for loopholes to exploit." item = /obj/item/aiModule/syndicate cost = 3 + reputation_required = REPUTATION_GOOD /datum/uplink_item/device_tools/hypnotic_flash name = "Hypnotic Flash" desc = "A modified flash able to hypnotize targets. If the target is not in a mentally vulnerable state, it will only confuse and pacify them temporarily." item = /obj/item/assembly/flash/hypnotic cost = 7 - reputation_required = REPUTATION_GOOD + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/device_tools/medgun name = "Medbeam Gun" @@ -1896,6 +1917,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/reagent_containers/hypospray/medipen/stimulants cost = 5 surplus = 90 + reputation_required = REPUTATION_GOOD /datum/uplink_item/device_tools/medkit name = "Syndicate Combat Medic Kit" @@ -1921,6 +1943,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( a Syndicate brand MMI, a straitjacket, and a muzzle." item = /obj/item/storage/backpack/duffelbag/syndie/surgery cost = 3 + reputation_required = REPUTATION_GOOD /datum/uplink_item/device_tools/encryptionkey name = "Syndicate Encryption Key" @@ -1966,6 +1989,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( and artificial intelligence cores emit more of this light than cooler objects like walls and airlocks." item = /obj/item/clothing/glasses/thermal/syndi cost = 3 + reputation_required = REPUTATION_GOOD // Implants /datum/uplink_item/implants @@ -1979,6 +2003,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/storage/box/syndie_kit/imp_adrenal cost = 8 player_minimum = 20 + reputation_required = REPUTATION_GOOD /datum/uplink_item/implants/antistun name = "CNS Rebooter Implant" @@ -2035,14 +2060,16 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( desc = "This one-of-a-kind implant will make you almost invisible if you play your cards right. \ On activation, it will conceal you inside a chameleon cardboard box that is only revealed once someone bumps into it." item = /obj/item/storage/box/syndie_kit/imp_stealth - cost = 7 + cost = 6 + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/implants/storage name = "Storage Implant" desc = "An implant injected into the body, and later activated at the user's will. It will open a small bluespace \ pocket capable of storing two regular-sized items." item = /obj/item/storage/box/syndie_kit/imp_storage - cost = 7 + cost = 5 + reputation_required = REPUTATION_GOOD /datum/uplink_item/implants/thermals name = "Thermal Eyes" @@ -2138,6 +2165,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( cost = 2 restricted_roles = list(JOB_NAME_ASSISTANT) surplus = 0 + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/pie_cannon name = "Banana Cream Pie Cannon" @@ -2146,6 +2174,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/pneumatic_cannon/pie/selfcharge restricted_roles = list(JOB_NAME_CLOWN) surplus = 0 //No fun unless you're the clown! + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/blastcannon name = "Blast Cannon" @@ -2156,6 +2185,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/gun/blastcannon cost = 14 //High cost because of the potential for extreme damage in the hands of a skilled scientist. restricted_roles = list(JOB_NAME_RESEARCHDIRECTOR, JOB_NAME_SCIENTIST) + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/role_restricted/crushmagboots name = "Crushing Magboots" @@ -2171,6 +2201,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/storage/box/gorillacubes cost = 6 restricted_roles = list(JOB_NAME_GENETICIST, JOB_NAME_CHIEFMEDICALOFFICER) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/rad_laser name = "Radioactive Microlaser" @@ -2181,6 +2212,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/healthanalyzer/rad_laser restricted_roles = list(JOB_NAME_MEDICALDOCTOR, JOB_NAME_CHIEFMEDICALOFFICER, JOB_NAME_ROBOTICIST, JOB_NAME_PARAMEDIC, JOB_NAME_BRIGPHYSICIAN) cost = 3 + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/syndicate_mmi name = "Syndicate MMI" @@ -2215,6 +2247,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/sbeacondrop/clownbomb cost = 10 restricted_roles = list(JOB_NAME_CLOWN) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/clown_grenade name = "C.L.U.W.N.E" @@ -2223,6 +2256,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/grenade/spawnergrenade/clown cost = 3 restricted_roles = list(JOB_NAME_CLOWN) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/clown_grenade_broken @@ -2233,6 +2267,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/grenade/spawnergrenade/clown_broken cost = 5 restricted_roles = list(JOB_NAME_CLOWN) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/clowncar name = "Clown Car" @@ -2256,22 +2291,24 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/clothing/shoes/clown_shoes/taeclowndo restricted_roles = list(JOB_NAME_CLOWN) -/datum/uplink_item/role_restricted/superior_honkrender - name = "Superior Honkrender" +/datum/uplink_item/role_restricted/honkrender + name = "Honkrender" desc = "An ancient artifact recovered from an ancient cave. Opens the way to the Dark Carnival" item = /obj/item/veilrender/honkrender - cost = 8 + cost = 6 restricted = TRUE restricted_roles = list(JOB_NAME_CLOWN, JOB_NAME_CHAPLAIN) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/superior_honkrender name = "Superior Honkrender" desc = "An ancient artifact recovered from -. Opens the way to TRANSMISSION OFFLINE\ All praise be to the honkmother" item = /obj/item/veilrender/honkrender/honkhulkrender - cost = 20 + cost = 12 restricted = TRUE restricted_roles = list(JOB_NAME_CLOWN, JOB_NAME_CHAPLAIN) + reputation_required = REPUTATION_EXCELLENT /datum/uplink_item/role_restricted/concealed_weapon_bay name = "Concealed Weapon Bay" @@ -2281,6 +2318,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/mecha_parts/concealed_weapon_bay cost = 3 restricted_roles = list(JOB_NAME_ROBOTICIST, JOB_NAME_RESEARCHDIRECTOR) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/haunted_magic_eightball name = "Haunted Magic Eightball" @@ -2304,6 +2342,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/prisoncube cost = 5 restricted_roles = list(JOB_NAME_CURATOR) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/his_grace name = "His Grace" @@ -2375,6 +2414,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( cost = 10 player_minimum = 25 restricted_roles = list(JOB_NAME_BOTANIST, JOB_NAME_COOK, JOB_NAME_BARTENDER) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/holocarp name = "Holocarp Parasites" @@ -2423,6 +2463,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( cost = 5 //you need one for full damage, so total of 5 for maximum damage limited_stock = 1 //you can't use more than one! restricted_roles = list(JOB_NAME_SHAFTMINER) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/esaw name = "Energy Saw" @@ -2437,28 +2478,32 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( cost = 8 item = /obj/item/autosurgeon/syndicate/esaw_arm restricted_roles = list(JOB_NAME_MEDICALDOCTOR, JOB_NAME_CHIEFMEDICALOFFICER, JOB_NAME_PARAMEDIC, JOB_NAME_BRIGPHYSICIAN) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/magillitis_serum name = "Magillitis Serum Autoinjector" desc = "A single-use autoinjector which contains an experimental serum that causes rapid muscular growth in Hominidae. \ Side-affects may include hypertrichosis, violent outbursts, and an unending affinity for bananas." item = /obj/item/reagent_containers/hypospray/medipen/magillitis - cost = 15 + cost = 13 restricted_roles = list(JOB_NAME_GENETICIST, JOB_NAME_CHIEFMEDICALOFFICER) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/modified_syringe_gun name = "Modified Syringe Gun" desc = "A syringe gun that fires DNA injectors instead of normal syringes." item = /obj/item/gun/syringe/dna - cost = 14 + cost = 12 restricted_roles = list(JOB_NAME_GENETICIST, JOB_NAME_CHIEFMEDICALOFFICER) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/chemical_gun name = "Reagent Dartgun" desc = "A heavily modified syringe gun which is capable of synthesizing its own chemical darts using input reagents. Can hold 100u of reagents." item = /obj/item/gun/chem - cost = 12 + cost = 11 restricted_roles = list(JOB_NAME_CHEMIST, JOB_NAME_CHIEFMEDICALOFFICER) + reputation_required = REPUTATION_GOOD /datum/uplink_item/role_restricted/reverse_bear_trap name = "Reverse Bear Trap" @@ -2483,6 +2528,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( cost = 12 item = /obj/item/autosurgeon/syndicate/laser_arm restricted_roles = list(JOB_NAME_ROBOTICIST, JOB_NAME_RESEARCHDIRECTOR) + reputation_required = REPUTATION_GOOD // Pointless diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index b7a958a9245d9..0e7ab328c3bda 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -270,6 +270,8 @@ const Directives = (props, context) => { name: objective.name, reward: objective.reward || 0, time_left: objective.time ? (objective.time - time) * 0.1 : null, + rep_gain: objective.rep_gain || null, + rep_loss: objective.rep_loss || null, }} /> ))} @@ -317,6 +319,20 @@ const Directives = (props, context) => { {task}
))} + {(selectedObjective?.rep_gain || selectedObjective?.rep_loss) && ( + <> + + Reputation Details + + + This mission will affect your reputation level.
+
    +
  • Success will result in gaining {selectedObjective?.rep_gain} reputation.
  • +
  • Failure will result in losing {selectedObjective?.rep_loss} reputation.
  • +
+
+ + )} Additional Details @@ -331,10 +347,13 @@ const Directives = (props, context) => {
- + {selectedObjective?.reward ? selectedObjective?.reward + ' Telecrystals' : 'No reward'} + {(selectedObjective?.rep_gain) && ( + {selectedObjective?.rep_gain} Reputation + )}
@@ -362,19 +381,30 @@ const ObjectiveCard = (props, context) => { name: 'Assassination', reward: 0, time_left: null, + rep_gain: null, + rep_loss: null, }, selected = 0, onClick, } = props; - const { name, reward, time_left } = objective_info; + const { name, reward, time_left, rep_gain, rep_loss } = objective_info; return ( - + {capitalize(name)} - {reward === 0 ? 'Assignment' : reward + ' TC Reward'} + + {(rep_gain || rep_loss) && ( + + -{rep_loss}/+{rep_gain} Reputation + + )} + {reward === 0 ? 'Assignment' : reward + ' TC Reward'} + {time_left === null diff --git a/tgui/packages/tgui/styles/interfaces/Uplink.scss b/tgui/packages/tgui/styles/interfaces/Uplink.scss index 256ebda291613..0d688d5e3d805 100644 --- a/tgui/packages/tgui/styles/interfaces/Uplink.scss +++ b/tgui/packages/tgui/styles/interfaces/Uplink.scss @@ -138,11 +138,12 @@ right: 5px; box-shadow: 0 0 14px 8px #00000069; background-color: #00000069; + text-align: right; } .time_limit { position: absolute; - top: 40%; + top: 35%; right: 0; left: 0; font-size: x-large; From b21b4a4740cf53da96658cedc91abd765d9659f5 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:24:41 +0100 Subject: [PATCH 56/62] Revert DB config --- config/dbconfig.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/dbconfig.txt b/config/dbconfig.txt index 35443519b1c3e..ffcbe885689dd 100644 --- a/config/dbconfig.txt +++ b/config/dbconfig.txt @@ -3,17 +3,17 @@ ## administration, and the in game library. ## Should SQL be enabled? Uncomment to enable -SQL_ENABLED +#SQL_ENABLED ## Server the MySQL database can be found at. ## Examples: localhost, 200.135.5.43, www.mysqldb.com, etc. -ADDRESS 127.0.0.1 +ADDRESS localhost ## MySQL server port (default is 3306). PORT 3306 ## Database for all SQL functions, not just feedback. -FEEDBACK_DATABASE beestation13 +FEEDBACK_DATABASE ss13beedb ## Prefix to be added to the name of every table, older databases will require this be set to erro_ ## Note, this does not change the table names in the database, you will have to do that yourself. @@ -24,7 +24,7 @@ FEEDBACK_DATABASE beestation13 FEEDBACK_TABLEPREFIX SS13_ ## Username/Login used to access the database. -FEEDBACK_LOGIN beestation13 +FEEDBACK_LOGIN ss13dbuser ## Password used to access the database. FEEDBACK_PASSWORD password1 @@ -45,4 +45,4 @@ BSQL_THREAD_LIMIT 50 MAX_CONCURRENT_QUERIES 25 ## Disable advanced feedback tracking, saving a substantial amount of database space. -#LIMITED_FEEDBACK +LIMITED_FEEDBACK From 932cbbd0531d7f49ccf8c1ef947ae353a3bbf1b1 Mon Sep 17 00:00:00 2001 From: PowerfulBacon <26465327+PowerfulBacon@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:30:12 +0100 Subject: [PATCH 57/62] Runs TGUI uglify --- tgui/packages/tgui/interfaces/Uplink.js | 192 +++++++++--------- .../tgui/styles/interfaces/Uplink.scss | 10 +- 2 files changed, 102 insertions(+), 100 deletions(-) diff --git a/tgui/packages/tgui/interfaces/Uplink.js b/tgui/packages/tgui/interfaces/Uplink.js index 0e7ab328c3bda..945a6381e94c6 100644 --- a/tgui/packages/tgui/interfaces/Uplink.js +++ b/tgui/packages/tgui/interfaces/Uplink.js @@ -12,44 +12,50 @@ const MAX_SEARCH_RESULTS = 25; const reputationLevels = { 0: { - name: "Ex-Communicate", - description: "A traitor to the cause, betraying their brothers to seek personal gain. Reaching this level will result in halted services and a termination order after 5 minutes.", + name: 'Ex-Communicate', + description: + 'A traitor to the cause, betraying their brothers to seek personal gain. Reaching this level will result in halted services and a termination order after 5 minutes.', min_reputation: null, max_reputation: 99, }, 100: { - name: "Blood Servant", - description: "An operative with a reason to act, but without the will to fulfill their greater purpose.", + name: 'Blood Servant', + description: 'An operative with a reason to act, but without the will to fulfill their greater purpose.', min_reputation: 100, max_reputation: 199, }, 200: { - name: "Field Agent", - description: "An operative acting on the ground, with access to some standard equipment that can be used to complete their mission.", + name: 'Field Agent', + description: + 'An operative acting on the ground, with access to some standard equipment that can be used to complete their mission.', min_reputation: 200, max_reputation: 399, }, 400: { - name: "Specialist", - description: "An operative with specialized skills and knowledge, granted with additional resources and services for completing critical missions.", + name: 'Specialist', + description: + 'An operative with specialized skills and knowledge, granted with additional resources and services for completing critical missions.', min_reputation: 400, max_reputation: 599, }, 600: { - name: "Operative", - description: "An experienced operative who has demonstrated competence and effectiveness in completing various missions for the Syndicate.", + name: 'Operative', + description: + 'An experienced operative who has demonstrated competence and effectiveness in completing various missions for the Syndicate.', min_reputation: 600, max_reputation: 799, }, 800: { - name: "Director", - description: "A high-ranking official responsible for overseeing and coordinating operations with their team, ensuring the success of its objectives.", + name: 'Director', + description: + 'A high-ranking official responsible for overseeing and coordinating operations with their team, ensuring the success of its objectives.', min_reputation: 800, max_reputation: 999, }, 1000: { - name: "Archon", - description: "A high ranking and secretive authority, possessing unparalleled knowledge, influence, and control over operations and resources.", + name: 'Archon', + description: + 'A high ranking and secretive authority, possessing unparalleled knowledge, influence, and control over operations and resources.', min_reputation: 1000, max_reputation: null, }, @@ -63,7 +69,7 @@ const GetLevel = (reputation, index_change = 0) => { for (const level in reputationLevels) { if (level <= reputation || currentLevel === null) { currentLevel = reputationLevels[level]; - index ++; + index++; } else { break; } @@ -71,18 +77,15 @@ const GetLevel = (reputation, index_change = 0) => { // Adjust the index based on the change provided index += index_change; - if (index < 0) - { + if (index < 0) { return { - name: "", - description: "There are no lower levels within the Syndicate database.", + name: '', + description: 'There are no lower levels within the Syndicate database.', }; - } - else if (index >= Object.keys(reputationLevels).length) - { + } else if (index >= Object.keys(reputationLevels).length) { return { - name: "", - description: "You are at the highest rank an agent can reach within the Syndicate.", + name: '', + description: 'You are at the highest rank an agent can reach within the Syndicate.', }; } @@ -130,15 +133,21 @@ export const Uplink = (props, context) => { - - {currentLevel ? currentLevel : "Neutral Reputation"} ({reputation}) + + {currentLevel ? currentLevel : 'Neutral Reputation'} ({reputation}) - {tab === 0 - ? - : tab === 1 - ? - : } + {tab === 0 ? ( + + ) : tab === 1 ? ( + + ) : ( + + )} ); @@ -155,9 +164,7 @@ const HomePage = (props, context) => {
-
- Welcome, Agent. -
+
Welcome, Agent.
{ reputation={previousLevel.min_reputation} reputation_delta={previousLevel.max_reputation - reputation} progression_colour="#6B1313" - /> + /> { reputation_delta={0} current_rank progression_colour="#272727" - /> + /> { reputation={nextLevel.min_reputation} reputation_delta={nextLevel.min_reputation - reputation} progression_colour="#134F12" - /> + />
Current Reputation -
- 200 Reputation -
+
200 Reputation
Uplink Services -
- Shop Now -
+
Shop Now
Special Directives -
- None Available -
+
None Available
@@ -214,27 +215,28 @@ const RankCard = (props, contxt) => { reputation, reputation_delta, current_rank = false, - progression_colour = "#6B1313", + progression_colour = '#6B1313', } = props; return (
-
+
{relation} -
- {name} -
+
{name}
{description}
{!current_rank && !!reputation_delta && ( -
- {reputation_delta > 0 ? ("Gain " + reputation_delta + " reputation to reach promotion") : ("Demotion if " + -reputation_delta + " reputation is lost")} +
+ {reputation_delta > 0 + ? 'Gain ' + reputation_delta + ' reputation to reach promotion' + : 'Demotion if ' + -reputation_delta + ' reputation is lost'}
)} -
); }; @@ -321,16 +323,17 @@ const Directives = (props, context) => { ))} {(selectedObjective?.rep_gain || selectedObjective?.rep_loss) && ( <> - - Reputation Details - - - This mission will affect your reputation level.
-
    -
  • Success will result in gaining {selectedObjective?.rep_gain} reputation.
  • -
  • Failure will result in losing {selectedObjective?.rep_loss} reputation.
  • -
-
+ + Reputation Details + + + This mission will affect your reputation level. +
+
    +
  • Success will result in gaining {selectedObjective?.rep_gain} reputation.
  • +
  • Failure will result in losing {selectedObjective?.rep_loss} reputation.
  • +
+
)} @@ -351,9 +354,7 @@ const Directives = (props, context) => { {selectedObjective?.reward ? selectedObjective?.reward + ' Telecrystals' : 'No reward'} - {(selectedObjective?.rep_gain) && ( - {selectedObjective?.rep_gain} Reputation - )} + {selectedObjective?.rep_gain && {selectedObjective?.rep_gain} Reputation}
@@ -389,18 +390,23 @@ const ObjectiveCard = (props, context) => { } = props; const { name, reward, time_left, rep_gain, rep_loss } = objective_info; return ( - + {capitalize(name)} - + {(rep_gain || rep_loss) && ( - -{rep_loss}/+{rep_gain} Reputation + + -{rep_loss} + + / + + +{rep_gain} + {' '} + Reputation )} {reward === 0 ? 'Assignment' : reward + ' TC Reward'} @@ -540,18 +546,18 @@ const ItemList = (props, context) => { {decodeHtmlEntities(item.name)} {item.reputation ? ( - = item.reputation ? "green" : "red"}> - {item.reputation} reputation - + = item.reputation ? 'green' : 'red'}>{item.reputation} reputation - ) : } + ) : ( + + )} {currencyAmount < item.cost ? ( - - Insufficient Funds - + Insufficient Funds - ) : } + ) : ( + + )}