From b026856526ace8c19378318eb3dd53ae449dd8a3 Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Sun, 15 Dec 2024 20:15:48 +0100 Subject: [PATCH] Implements Bitrunner Prefs Disks (Feat. Quirks & Evil Hacks) (without the blowing up part) (#243) * redraw that horse as penance for rolling worst blunt imaginable * THERE we go --- .../bitrunning/server/obj_generation.dm | 21 ++++ .../code/disks/prefs_disk.dm | 119 ++++++++++++++++++ .../bitrunner_outfit_override.dm | 4 + .../bitrunning_prefs_disks/readme.md | 47 +++++++ tgstation.dme | 2 + 5 files changed, 193 insertions(+) create mode 100644 modular_doppler/bitrunning_prefs_disks/code/disks/prefs_disk.dm create mode 100644 modular_doppler/bitrunning_prefs_disks/code/outfit_overrides/bitrunner_outfit_override.dm create mode 100644 modular_doppler/bitrunning_prefs_disks/readme.md diff --git a/code/modules/bitrunning/server/obj_generation.dm b/code/modules/bitrunning/server/obj_generation.dm index 9f473980bbf96..9d63e153eb347 100644 --- a/code/modules/bitrunning/server/obj_generation.dm +++ b/code/modules/bitrunning/server/obj_generation.dm @@ -145,6 +145,9 @@ to_chat(neo, span_warning("This domain forbids the use of [english_list(import_ban)], your disk [english_list(disk_ban)] will not be granted!")) var/failed = FALSE + //DOPPLER EDIT ADDITION BEGIN - BITRUNNING_PREFS_DISKS - Track if we've used multiple avatar preference disks, for avoiding overrides and displaying the failure message. + var/duplicate_prefs = FALSE + //DOPPLER EDIT ADDITION END // We don't need to bother going over the disks if neither of the types can be used. if(domain_forbids_spells && domain_forbids_items) @@ -175,6 +178,24 @@ avatar.put_in_hands(new item_disk.granted_item()) + //DOPPLER EDIT ADDITION BEGIN - BITRUNNING_PREFS_DISKS - Handles our avatar preference disks, if present. + if(istype(disk, /obj/item/bitrunning_disk/preferences)) + var/obj/item/bitrunning_disk/preferences/prefs_disk = disk + var/datum/preferences/avatar_preference = prefs_disk.chosen_preference + + if(isnull(avatar_preference) || duplicate_prefs) + failed = TRUE + continue + + if(!domain_forbids_spells) + avatar_preference.safe_transfer_prefs_to(avatar) + SSquirks.AssignQuirks(avatar, prefs_disk.mock_client) + if(!domain_forbids_items && prefs_disk.include_loadout) + avatar.equip_outfit_and_loadout(/datum/outfit, avatar_preference) + + duplicate_prefs = TRUE + //DOPPLER EDIT ADDITION END + if(failed) to_chat(neo, span_warning("One of your disks failed to load. Check for duplicate or inactive disks.")) diff --git a/modular_doppler/bitrunning_prefs_disks/code/disks/prefs_disk.dm b/modular_doppler/bitrunning_prefs_disks/code/disks/prefs_disk.dm new file mode 100644 index 0000000000000..6079e81de4beb --- /dev/null +++ b/modular_doppler/bitrunning_prefs_disks/code/disks/prefs_disk.dm @@ -0,0 +1,119 @@ +/** + * Bitrunning tech disks which let you load a custom character preference for your bit avatar. + * This uses a preference selected from your character list. + * Optionally, this may include the loadout as well. + * + * For the sake of domain restrictions: + * - ability blocks block the application of character prefs. + * - item blocks block the application of character loadout. + */ +/obj/item/bitrunning_disk/preferences + name = "bitrunning program: personalized avatar" + desc = "A disk containing source code. It can be used to override your bit avatar's standard appearance. Further avatar disks will be ignored." + + // Allows it to be held in the pocket + w_class = WEIGHT_CLASS_SMALL + + /// Our chosen preference. + var/datum/preferences/chosen_preference + /// Whether we include the loadout as well. + var/include_loadout = FALSE + /// Mock client we use for forwarding to quirk assignment (beware, evil hacks). + var/datum/prefs_disk_client_interface/mock_client + +/obj/item/bitrunning_disk/preferences/Initialize(mapload) + . = ..() + register_context() + +/obj/item/bitrunning_disk/preferences/examine(mob/user) + . = ..() + if(isnull(chosen_preference)) + return + + . += span_info("Loadout application is currently [include_loadout ? "enabled" : "disabled"].") + . += span_notice("Ctrl-click to toggle loadout application.") + +/obj/item/bitrunning_disk/preferences/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + var/result = NONE + if(isnull(chosen_preference) && (held_item == src)) + context[SCREENTIP_CONTEXT_LMB] = "Select avatar" + result = CONTEXTUAL_SCREENTIP_SET + if(!isturf(src.loc)) + context[SCREENTIP_CONTEXT_CTRL_LMB] = "Toggle loadout" + result = CONTEXTUAL_SCREENTIP_SET + + return result + +/obj/item/bitrunning_disk/preferences/Destroy() + QDEL_NULL(chosen_preference) + QDEL_NULL(mock_client) + return ..() + +/obj/item/bitrunning_disk/preferences/attack_self(mob/user, modifiers) + . = ..() + + if(isnull(user.client) || chosen_preference) + return + + var/list/character_profiles = user.client.prefs?.create_character_profiles() + if(isnull(character_profiles) || !length(character_profiles)) + return + + var/choice = tgui_input_list(user, message = "Select a character", title = "Bitrunning Avatar", items = character_profiles) + if(isnull(choice) || !user.is_holding(src)) + return + + choice_made = choice + chosen_preference = new(user.client) + chosen_preference.load_character(character_profiles.Find(choice)) + + // Perform our evil hacks + if(isnull(mock_client)) + mock_client = new + mock_client.prefs = chosen_preference + // Done loading from the client, so replace reference to the real client + chosen_preference.parent = mock_client + + balloon_alert(user, "avatar set!") + playsound(user, 'sound/items/click.ogg', 50, TRUE) + +/obj/item/bitrunning_disk/preferences/item_ctrl_click(mob/user) + if(isturf(src.loc)) // If on a turf, we skip to dragging + return NONE + if(isnull(chosen_preference)) + balloon_alert(user, "set preference first!") + return CLICK_ACTION_BLOCKING + include_loadout = !include_loadout + balloon_alert(user, include_loadout ? "loadout enabled!" : "loadout disabled!") + + // High frequency range when enabled, low when disabled. More tactile. + var/toggle_frequency = include_loadout ? rand(45000, 55000) : rand(32000, 42000) + playsound(user, 'sound/items/click.ogg', 50, TRUE, frequency = toggle_frequency) + + return CLICK_ACTION_SUCCESS + +/** + * Allows for ordering of the prefs disk. + */ +/datum/orderable_item/bitrunning_tech/prefs_disk + cost_per_order = 1000 + purchase_path = /obj/item/bitrunning_disk/preferences + desc = "This disk contains a program that lets you load in custom bit avatars." + +/** + * Evil hack that allows us to assign quirks without needing to forward a real client. + * Using this instead of the normal mock client allows us to include only what we need without editing the base, + * or interfering with things like `mock_client_uid`. + * + * Much the same, this should match the interface of /client wherever necessary. + */ +/datum/prefs_disk_client_interface + /// Player preferences datum for the client + var/datum/preferences/prefs + + /// The mob the client controls + var/mob/mob + +/// We don't actually care about award status, but we don't want it to runtime due to not existing. +/datum/prefs_disk_client_interface/proc/get_award_status(achievement_type, mob/user, value = 1) + return 0 diff --git a/modular_doppler/bitrunning_prefs_disks/code/outfit_overrides/bitrunner_outfit_override.dm b/modular_doppler/bitrunning_prefs_disks/code/outfit_overrides/bitrunner_outfit_override.dm new file mode 100644 index 0000000000000..fbbf76ed1b12a --- /dev/null +++ b/modular_doppler/bitrunning_prefs_disks/code/outfit_overrides/bitrunner_outfit_override.dm @@ -0,0 +1,4 @@ + +// Spawns a single preferences disk to start with for all bitrunners. +/datum/outfit/job/bitrunner + r_pocket = /obj/item/bitrunning_disk/preferences diff --git a/modular_doppler/bitrunning_prefs_disks/readme.md b/modular_doppler/bitrunning_prefs_disks/readme.md new file mode 100644 index 0000000000000..b953df82da844 --- /dev/null +++ b/modular_doppler/bitrunning_prefs_disks/readme.md @@ -0,0 +1,47 @@ + + +SOON + +## Bitrunning Avatar Preference Disks + +Module ID: BITRUNNING_PREFS_DISKS + +### Description: + +Allows bitrunners to buy a personalized avatar disk, which lets them load in a given character preference, with all that entails. +This includes even quirks through evil hacks, and optionally loadouts. +Preference application and quirks are blocked if a domain blocks spells/abilities, loadouts are blocked if a domain blocks items. +The evil hacks this performs are using a barebones mock client to allow for quirk assignment without forwarding or affecting the real client. + + + +### TG Proc/File Changes: + +- `code/modules/bitrunning/server/obj_generation.dm`: `proc/stock_gear` + + +### Modular Overrides: + +- N/A + + +### Defines: + +- N/A + + +### Included files that are not contained in this module: + +- N/A + + +### Credits: 00-Steven + + \ No newline at end of file diff --git a/tgstation.dme b/tgstation.dme index dee7b120891aa..e8e20c0a66b81 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -6571,6 +6571,8 @@ #include "modular_doppler\autotransfer\autotransfer_config.dm" #include "modular_doppler\autotransfer\shuttle.dm" #include "modular_doppler\autotransfer\transfer_vote.dm" +#include "modular_doppler\bitrunning_prefs_disks\code\disks\prefs_disk.dm" +#include "modular_doppler\bitrunning_prefs_disks\code\outfit_overrides\bitrunner_outfit_override.dm" #include "modular_doppler\cell_component\code\cell_component.dm" #include "modular_doppler\colony_fabricator\code\cargo_packs.dm" #include "modular_doppler\colony_fabricator\code\colony_fabricator.dm"