diff --git a/code/__DEFINES/bitrunning.dm b/code/__DEFINES/bitrunning.dm index ba6c3b9b61c..639ae26c3fc 100644 --- a/code/__DEFINES/bitrunning.dm +++ b/code/__DEFINES/bitrunning.dm @@ -26,3 +26,22 @@ /// Camera network bitrunner bodycams are on #define BITRUNNER_CAMERA_NET "bitrunner" + +/** + * Bitrunner Domain External Load Restriction Bitflags + */ +/// Domain forbids external sources from loading items onto avatars +#define DOMAIN_FORBIDS_ITEMS (1<<0) +/// Domain forbids external sources from loading abilities onto avatars +#define DOMAIN_FORBIDS_ABILITIES (1<<1) + +/// Combination flag for blocking anything from being loaded onto avatars by external sources +#define DOMAIN_FORBIDS_ALL ALL + +/** + * COMSIG_BITRUNNER_STOCKING_GEAR Return Bitflags + */ +/// Something failed to load +#define BITRUNNER_GEAR_LOAD_FAILED (1<<0) +/// The domain restrictions blocked something from loading +#define BITRUNNER_GEAR_LOAD_BLOCKED (1<<1) diff --git a/code/__DEFINES/dcs/signals/signals_bitrunning.dm b/code/__DEFINES/dcs/signals/signals_bitrunning.dm index ac3095d6f5a..fcce7ea68d0 100644 --- a/code/__DEFINES/dcs/signals/signals_bitrunning.dm +++ b/code/__DEFINES/dcs/signals/signals_bitrunning.dm @@ -41,6 +41,9 @@ /// from /obj/machienry/quantum_server/station_spawn() #define COMSIG_BITRUNNER_STATION_SPAWN "bitrunner_station_spawn" +/// from /obj/machinery/quantum_server/stock_gear(): (mob/living/carbon/human/avatar, external_load_flags) +#define COMSIG_BITRUNNER_STOCKING_GEAR "bitrunner_stocking_gear" + // Ladder /// from /obj/structure/hololadder/disconnect() diff --git a/code/game/objects/items/maintenance_loot.dm b/code/game/objects/items/maintenance_loot.dm index 5389f7723b9..a8d088a0098 100644 --- a/code/game/objects/items/maintenance_loot.dm +++ b/code/game/objects/items/maintenance_loot.dm @@ -49,3 +49,19 @@ var/initial_percent = rand(40, 60) / 100 // 250kJ to 350kJ charge = initial_percent * maxcharge ADD_TRAIT(src, TRAIT_FISHING_BAIT, INNATE_TRAIT) + AddComponent(/datum/component/loads_avatar_gear, \ + load_callback = CALLBACK(src, PROC_REF(shockingly_improve_avatar)), \ + ) + +// Give our owner shock touch when entering the digital realm +/obj/item/stock_parts/power_store/cell/lead/proc/shockingly_improve_avatar(mob/living/carbon/human/neo, mob/living/carbon/human/avatar, external_load_flags) + if(external_load_flags & DOMAIN_FORBIDS_ABILITIES) + return BITRUNNER_GEAR_LOAD_BLOCKED + + if(!avatar.can_mutate()) + return BITRUNNER_GEAR_LOAD_FAILED + + if(avatar.dna.mutation_in_sequence(/datum/mutation/human/shock)) + avatar.dna.activate_mutation(/datum/mutation/human/shock) + else + avatar.dna.add_mutation(/datum/mutation/human/shock, MUT_EXTRA) diff --git a/code/modules/bitrunning/components/avatar_gear.dm b/code/modules/bitrunning/components/avatar_gear.dm new file mode 100644 index 00000000000..be7ede816fe --- /dev/null +++ b/code/modules/bitrunning/components/avatar_gear.dm @@ -0,0 +1,67 @@ + +/// Tracks the highest up human carrying this item, and loads bitrunning gear onto their avatar when they enter a virtual domain +/datum/component/loads_avatar_gear + /// The callback called when COMSIG_BITRUNNER_STOCKING_GEAR is sent to our host human + var/datum/callback/load_callback + /// Weakref to the human we are currently carried by + var/datum/weakref/tracked_human_ref + +/datum/component/loads_avatar_gear/Initialize(datum/callback/load_callback) + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + src.load_callback = load_callback + +/datum/component/loads_avatar_gear/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_ENTERING, PROC_REF(on_entered_loc)) + + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERING = PROC_REF(on_entered_loc), + ) + AddComponent(/datum/component/connect_containers, parent, loc_connections) + +/datum/component/loads_avatar_gear/UnregisterFromParent() + UnregisterSignal(parent, list( + COMSIG_ATOM_ENTERING, + )) + + qdel(GetComponent(/datum/component/connect_containers)) + +/datum/component/loads_avatar_gear/Destroy(force) + load_callback = null + tracked_human_ref = null + return ..() + + +/datum/component/loads_avatar_gear/proc/on_entered_loc(datum/source, atom/destination, atom/old_loc, list/atom/old_locs) + SIGNAL_HANDLER + + // No need to do checks if we're just moving turfs + if(isturf(destination) && isturf(old_loc)) + return + + // Iterate over list in reverse so we get the topmost human first + // Because it's funnier if you get to use the avatar gear of the people you're carrying + var/list/nested_locs = get_nested_locs(parent) + for(var/i in length(nested_locs) to 1 step -1) + var/atom/container = nested_locs[i] + if(ishuman(container)) + switch_tracking(container) + return + + // No humans found, stop tracking + switch_tracking(null) + +/datum/component/loads_avatar_gear/proc/switch_tracking(mob/living/carbon/human/to_track) + var/mob/living/carbon/human/tracked_human = tracked_human_ref?.resolve() + if(tracked_human == to_track) + return + + if(tracked_human) + UnregisterSignal(tracked_human, COMSIG_BITRUNNER_STOCKING_GEAR) + tracked_human_ref = WEAKREF(to_track) + RegisterSignal(to_track, COMSIG_BITRUNNER_STOCKING_GEAR, PROC_REF(load_onto_avatar)) + +/datum/component/loads_avatar_gear/proc/load_onto_avatar(mob/living/carbon/human/neo, mob/living/carbon/human/avatar, external_load_flags) + SIGNAL_HANDLER + return load_callback?.Invoke(neo, avatar, external_load_flags) diff --git a/code/modules/bitrunning/objects/disks.dm b/code/modules/bitrunning/objects/disks.dm index dd81a0f463e..b51a1dd076c 100644 --- a/code/modules/bitrunning/objects/disks.dm +++ b/code/modules/bitrunning/objects/disks.dm @@ -19,6 +19,10 @@ icon_state = "[base_icon_state][rand(0, 7)]" update_icon() + AddComponent(/datum/component/loads_avatar_gear, \ + load_callback = CALLBACK(src, PROC_REF(load_onto_avatar)), \ + ) + /obj/item/bitrunning_disk/examine(mob/user) . = ..() . += span_infoplain("This disk must be carried on your person into a netpod to be used.") @@ -30,6 +34,11 @@ . += span_info("It has been used to select: [choice_made].") . += span_notice("It cannot make another selection.") +/// Handles loading our stuff onto avatars +/obj/item/bitrunning_disk/proc/load_onto_avatar(mob/living/carbon/human/neo, mob/living/carbon/human/avatar, external_load_flags) + return NONE + + /obj/item/bitrunning_disk/ability desc = "A disk containing source code. It can be used to preload abilities into the virtual domain. Duplicate abilities will be ignored." /// The selected ability that this grants @@ -37,6 +46,20 @@ /// The list of actions that this can grant var/list/datum/action/selectable_actions = list() +/obj/item/bitrunning_disk/ability/load_onto_avatar(mob/living/carbon/human/neo, mob/living/carbon/human/avatar, external_load_flags) + if(external_load_flags & DOMAIN_FORBIDS_ABILITIES) + return BITRUNNER_GEAR_LOAD_BLOCKED + + if(isnull(granted_action)) + return BITRUNNER_GEAR_LOAD_FAILED + + if(locate(granted_action) in avatar.actions) + return BITRUNNER_GEAR_LOAD_FAILED + + var/datum/action/our_action = new granted_action() + our_action.Grant(avatar) + return NONE + /obj/item/bitrunning_disk/ability/attack_self(mob/user, modifiers) . = ..() @@ -87,6 +110,7 @@ /datum/action/cooldown/spell/shapeshift/polar_bear, ) + /obj/item/bitrunning_disk/item desc = "A disk containing source code. It can be used to preload items into the virtual domain." /// The selected item that this grants @@ -94,6 +118,16 @@ /// The list of actions that this can grant var/list/obj/selectable_items = list() +/obj/item/bitrunning_disk/item/load_onto_avatar(mob/living/carbon/human/neo, mob/living/carbon/human/avatar, external_load_flags) + if(external_load_flags & DOMAIN_FORBIDS_ITEMS) + return BITRUNNER_GEAR_LOAD_BLOCKED + + if(isnull(granted_item)) + return BITRUNNER_GEAR_LOAD_FAILED + + avatar.put_in_hands(new granted_item()) + return NONE + /obj/item/bitrunning_disk/item/attack_self(mob/user, modifiers) . = ..() diff --git a/code/modules/bitrunning/objects/gimmick_disks/_gimmick_disk.dm b/code/modules/bitrunning/objects/gimmick_disks/_gimmick_disk.dm new file mode 100644 index 00000000000..2580d8620c7 --- /dev/null +++ b/code/modules/bitrunning/objects/gimmick_disks/_gimmick_disk.dm @@ -0,0 +1,115 @@ + +/** + * Bitrunning tech disks which let you load full loadouts into the vdom on first avatar generation. + */ +/obj/item/bitrunning_disk/gimmick + desc = "A disk containing source code. It can be used to preload gimmick loadouts into the virtual domain." + /// The selected loadout that this grants + var/datum/bitrunning_gimmick/granted_loadout + /// The list of loadouts that this can grant + var/list/datum/bitrunning_gimmick/selectable_loadouts + +/obj/item/bitrunning_disk/gimmick/Destroy() + QDEL_NULL(granted_loadout) + return ..() + +/obj/item/bitrunning_disk/gimmick/load_onto_avatar(mob/living/carbon/human/neo, mob/living/carbon/human/avatar, external_load_flags) + if(isnull(granted_loadout)) + return BITRUNNER_GEAR_LOAD_FAILED + return granted_loadout.grant_loadout(neo, avatar, external_load_flags) + +/obj/item/bitrunning_disk/gimmick/attack_self(mob/user, modifiers) + . = ..() + + if(granted_loadout) + return + + var/names = list() + for(var/datum/bitrunning_gimmick/loadout as anything in selectable_loadouts) + names += initial(loadout.name) + + var/choice = tgui_input_list(user, message = "Select a gimmick loadout", title = "Bitrunning Program", items = names) + if(isnull(choice) || !user.is_holding(src)) + return + + for(var/datum/bitrunning_gimmick/loadout as anything in selectable_loadouts) + if(initial(loadout.name) == choice) + granted_loadout = new loadout() + + balloon_alert(user, "selected") + playsound(user, 'sound/items/click.ogg', 50, TRUE) + choice_made = choice + + +/** + * The datum used by the gimmick loadout disk to determine what a loadout actually spawns. + */ +/datum/bitrunning_gimmick + /// Player readable name of the gimmick loadout + var/name = "Gimmick Loadout" + /// The list of actions that this will grant + var/list/datum/action/granted_actions + /// The list of items that this will grant + var/list/obj/item/granted_items + /// The item type we will use as a container for our granted items, given to the avatar + var/obj/item/container_item_type = /obj/item/storage/briefcase/secure/digital_storage + /// Prefix our name onto the + var/prefix_container_name = TRUE + +/// Grants out loadout. +/datum/bitrunning_gimmick/proc/grant_loadout(mob/living/carbon/human/neo, mob/living/carbon/human/avatar, external_load_flags) + var/return_flags = NONE + return_flags |= grant_items(neo, avatar, external_load_flags) + return_flags |= grant_abilities(neo, avatar, external_load_flags) + return return_flags + +/datum/bitrunning_gimmick/proc/grant_items(mob/living/carbon/human/neo, mob/living/carbon/human/avatar, external_load_flags) + if(!length(granted_items)) + return NONE + + if(external_load_flags & DOMAIN_FORBIDS_ITEMS) + return BITRUNNER_GEAR_LOAD_BLOCKED + + var/obj/item/container_item = new container_item_type() + if(prefix_container_name) + container_item.name = "[LOWER_TEXT(name)]'s [initial(container_item.name)]" + + for(var/obj/item/granted_item as anything in granted_items) + new granted_item(container_item) + + avatar.put_in_hands(container_item) + + return NONE + +/datum/bitrunning_gimmick/proc/grant_abilities(mob/living/carbon/human/neo, mob/living/carbon/human/avatar, external_load_flags) + if(!length(granted_actions)) + return NONE + + if(external_load_flags & DOMAIN_FORBIDS_ABILITIES) + return BITRUNNER_GEAR_LOAD_BLOCKED + + var/return_flags = NONE + + for(var/datum/action/granted_action as anything in granted_actions) + if(locate(granted_action) in avatar.actions) + return_flags |= BITRUNNER_GEAR_LOAD_FAILED + continue + + var/datum/action/our_action = new granted_action() + our_action.Grant(avatar) + + return return_flags + + +/** + * Base container used for gimmick disks. + */ +/obj/item/storage/briefcase/secure/digital_storage + name = "digi-case" + desc = "It's made of AUTHENTIC digital leather and has a price-tag still attached. Its owner must be a real professional." + icon_state = "secure" + base_icon_state = "secure" + inhand_icon_state = "sec-case" + +/obj/item/storage/briefcase/secure/digital_storage/PopulateContents() + return diff --git a/code/modules/bitrunning/objects/gimmick_disks/dungeon_disk.dm b/code/modules/bitrunning/objects/gimmick_disks/dungeon_disk.dm new file mode 100644 index 00000000000..559c7f022df --- /dev/null +++ b/code/modules/bitrunning/objects/gimmick_disks/dungeon_disk.dm @@ -0,0 +1,226 @@ + +/** + * Bitrunning gimmick loadouts themed around dungeon crawling. + * Mostly for fun, have niche but not insignificant advantages. + */ +/obj/item/bitrunning_disk/gimmick/dungeon + name = "bitrunning gimmick: dungeon crawling" + selectable_loadouts = list( + /datum/bitrunning_gimmick/alchemist, + /datum/bitrunning_gimmick/rogue, + /datum/bitrunning_gimmick/healer, + /datum/bitrunning_gimmick/wizard, + ) + + +/datum/bitrunning_gimmick/alchemist + name = "Alchemist" + + granted_items = list( + /obj/item/clothing/suit/bio_suit/plaguedoctorsuit, + /obj/item/clothing/mask/gas/plaguedoctor, + /obj/item/clothing/head/bio_hood/plague, + /obj/item/storage/box/alchemist_basic_chems, + /obj/item/storage/box/alchemist_basic_chems, + /obj/item/storage/box/alchemist_random_chems, + /obj/item/storage/box/alchemist_chemistry_kit, + ) + +/obj/item/reagent_containers/cup/bottle/alchemist_basic + name = "unlabeled bottle" + desc = "A small bottle. You don't remember what you put in it." + + /// List of possible reagents we may pick from + var/static/list/possible_reagents = list( + /datum/reagent/aluminium, // Basic chems + /datum/reagent/bromine, + /datum/reagent/carbon, + /datum/reagent/chlorine, + /datum/reagent/copper, + /datum/reagent/consumable/ethanol, + /datum/reagent/fluorine, + /datum/reagent/hydrogen, + /datum/reagent/iodine, + /datum/reagent/iron, + /datum/reagent/lithium, + /datum/reagent/mercury, + /datum/reagent/nitrogen, + /datum/reagent/oxygen, + /datum/reagent/phosphorus, + /datum/reagent/potassium, + /datum/reagent/uranium/radium, + /datum/reagent/silicon, + /datum/reagent/sodium, + /datum/reagent/stable_plasma, + /datum/reagent/consumable/sugar, + /datum/reagent/sulfur, + /datum/reagent/toxin/acid, + /datum/reagent/water, + /datum/reagent/fuel, + /datum/reagent/toxin/leadacetate, // Funny chems + /datum/reagent/consumable/liquidgibs, + /datum/reagent/consumable/nutriment, + /datum/reagent/consumable/coffee, + ) + +/obj/item/reagent_containers/cup/bottle/alchemist_basic/add_initial_reagents() + var/our_reagent = pick(possible_reagents) + reagents.add_reagent(our_reagent, 50) + +/obj/item/reagent_containers/cup/bottle/alchemist_random + name = "skull-labeled bottle" + desc = "A small bottle. You don't remember what you put in it." + + /// List of random adjectives this bottle may have + var/static/list/possible_adjectives = list( + "unlabeled", + "skull-labeled", // Labels + "heart-labeled", + "explosion-labeled", + "fish-labeled", + "smiley-labeled", + "frown-labeled", + "interrobang-labeled", + "plus-labeled", + "d20-labeled", + "unreadably-labeled", + "black-labeled", + "empty-labeled", + "age-yellowed", // Qualities + "blood-tinged", + "ash-marred", + "claw-scratched", + "marker-marked", + "cracked", + "ominous", // Abstract + ) + +/obj/item/reagent_containers/cup/bottle/alchemist_random/Initialize(mapload) + . = ..() + name = "[pick(possible_adjectives)] bottle" + +/obj/item/reagent_containers/cup/bottle/alchemist_random/add_initial_reagents() + var/our_reagent = get_random_reagent_id() + var/our_amount = rand(20, 50) + reagents.add_reagent(our_reagent, our_amount) + +/obj/item/storage/box/alchemist_basic_chems + name = "box of alchemical bases" + desc = "Contains a set of basic reagents, for all your potion-making needs! If only you labeled them." + illustration = "beaker" + +/obj/item/storage/box/alchemist_basic_chems/PopulateContents() + for(var/i in 1 to 7) + if(prob(1)) + new /obj/item/reagent_containers/cup/glass/coffee(src) + continue + new /obj/item/reagent_containers/cup/bottle/alchemist_basic(src) + +/obj/item/storage/box/alchemist_random_chems + name = "box of potions" + desc = "An especially fancy box to keep your finished potions safe." + icon_state = "syndiebox" + illustration = "beaker" + +/obj/item/storage/box/alchemist_random_chems/PopulateContents() + for(var/i in 1 to 7) + if(prob(1)) + new /obj/item/reagent_containers/cup/glass/coffee(src) + continue + new /obj/item/reagent_containers/cup/bottle/alchemist_random(src) + +/obj/item/storage/box/alchemist_chemistry_kit + name = "box of alchemy tools" + desc = "Contains everything needed for the up and coming chemistry student to enact hazardous chemical mishaps in the comfort of their own home." + +/obj/item/storage/box/alchemist_chemistry_kit/PopulateContents() + new /obj/item/reagent_containers/cup/mortar(src) + new /obj/item/pestle(src) + new /obj/item/lighter/skull(src) + new /obj/item/ph_booklet(src) + new /obj/item/thermometer(src) + new /obj/item/storage/test_tube_rack/full(src) + new /obj/item/reagent_containers/cup/glass/coffee(src) + + +/datum/bitrunning_gimmick/rogue + name = "Rogue" + + granted_items = list( + /obj/item/clothing/under/color/black, + /obj/item/clothing/shoes/sneakers/black, + /obj/item/clothing/mask/facescarf/rogue, + /obj/item/clothing/glasses/eyepatch, + /obj/item/bedsheet/black/rogue_cape, + /obj/item/storage/belt/fannypack/black/rogue, + /obj/item/knife/combat/survival, + ) + +/obj/item/clothing/shoes/sneakers/black + name = "sneaker of SNEAKING" + +/obj/item/clothing/mask/facescarf/rogue + name = "cloth of DOOM" + greyscale_colors = "#292929" + +/obj/item/clothing/glasses/eyepatch + name = "eyepatch of SEALING" + +/obj/item/bedsheet/black/rogue_cape + name = "cape of DARKNESS" + +/obj/item/storage/belt/fannypack/black/rogue + name = "fannypack of ULTIMATE DESPAIR" + +/obj/item/storage/belt/fannypack/black/rogue/PopulateContents() + new /obj/item/food/drug/saturnx(src) + new /obj/item/reagent_containers/cup/blastoff_ampoule(src) + new /obj/item/reagent_containers/hypospray/medipen/methamphetamine(src) + + +/datum/bitrunning_gimmick/healer + name = "Healer" + + granted_items = list( + /obj/item/clothing/under/costume/singer/yellow, + /obj/item/clothing/shoes/singery, + /obj/item/rod_of_asclepius, + /obj/item/storage/medkit/surgery, + /obj/item/emergency_bed, + /obj/item/food/canned/larvae, + /obj/item/reagent_containers/dropper, + ) + + +/datum/bitrunning_gimmick/wizard + name = "Wizard" + + granted_items = list( + /obj/item/clothing/head/wizard/fake, + /obj/item/clothing/suit/wizrobe/fake, + /obj/item/clothing/glasses/eyepatch/medical/chuuni, + /obj/item/staff, + /obj/item/toy/eightball, + /obj/item/storage/fancy/cigarettes/cigpack_cannabis, + /obj/item/storage/box/matches, + ) + + granted_actions = list( + /datum/action/cooldown/spell/pointed/untie_shoes/digital, + /datum/action/cooldown/spell/smoke/digital, + ) + +/datum/action/cooldown/spell/pointed/untie_shoes/digital + name = "Untie Digi-Shoes" + spell_requirements = SPELL_REQUIRES_WIZARD_GARB + +/datum/action/cooldown/spell/smoke/digital + name = "Digi-Smoke" + desc = "This spell spawns a small cloud of smoke at your location." + + school = SCHOOL_CONJURATION + cooldown_time = 36 SECONDS + spell_requirements = SPELL_REQUIRES_WIZARD_GARB + + smoke_type = /datum/effect_system/fluid_spread/smoke + smoke_amt = 2 diff --git a/code/modules/bitrunning/objects/gimmick_disks/sports_disk.dm b/code/modules/bitrunning/objects/gimmick_disks/sports_disk.dm new file mode 100644 index 00000000000..6be07b53d58 --- /dev/null +++ b/code/modules/bitrunning/objects/gimmick_disks/sports_disk.dm @@ -0,0 +1,152 @@ + +/** + * Bitrunning gimmick loadouts themed around sports. + * Mostly for fun, have niche or little advantages. + */ +/obj/item/bitrunning_disk/gimmick/sports + name = "bitrunning gimmick: sports" + selectable_loadouts = list( + /datum/bitrunning_gimmick/boxer, + /datum/bitrunning_gimmick/skater, + /datum/bitrunning_gimmick/archer, + /datum/bitrunning_gimmick/fisher, + /datum/bitrunning_gimmick/gamer, + ) + + +/datum/bitrunning_gimmick/boxer + name = "Boxer" + + granted_items = list( + /obj/item/clothing/gloves/boxing/evil, + /obj/item/clothing/under/shorts/red, + /obj/item/reagent_containers/condiment/protein, + /obj/item/reagent_containers/cup/glass/drinkingglass/filled/protein_blend, + ) + +/obj/item/reagent_containers/cup/glass/drinkingglass/filled/protein_blend + name = "Protein Blend" + list_reagents = list(/datum/reagent/consumable/ethanol/protein_blend = 50) + + +/datum/bitrunning_gimmick/skater + name = "Skater" + + granted_items = list( + /obj/item/clothing/shoes/wheelys, + /obj/item/melee/skateboard, + /obj/item/clothing/suit/costume/wellworn_shirt/graphic, + /obj/item/clothing/head/soft/black, + /obj/item/clothing/shoes/sneakers/black, + /obj/item/storage/cans/sixenergydrink, + ) + +/obj/item/storage/cans/sixenergydrink + name = "energy drink bottle ring" + desc = "Holds six energy drink cans. Remember to recycle when you're done!" + + /// Pool of energy drinks tm we may add from + var/list/energy_drink_options = list( + /obj/item/reagent_containers/cup/soda_cans/space_mountain_wind = 50, + /obj/item/reagent_containers/cup/soda_cans/monkey_energy = 30, + /obj/item/reagent_containers/cup/soda_cans/volt_energy = 15, + /obj/item/reagent_containers/cup/soda_cans/thirteenloko = 5, + ) + +/obj/item/storage/cans/sixenergydrink/PopulateContents() + for(var/i in 1 to 6) + var/obj/item/chosen_energy_drink = pick_weight(energy_drink_options) + new chosen_energy_drink(src) + + +/datum/bitrunning_gimmick/archer + name = "Archer" + + granted_items = list( + /obj/item/clothing/under/costume/kimono, + /obj/item/clothing/shoes/sandal/alt, + /obj/item/storage/bag/quiver/endless, + /obj/item/gun/ballistic/bow/longbow, + /obj/item/ammo_casing/arrow/holy/blazing, + ) + +/obj/item/storage/bag/quiver/endless + name = "endless quiver" + desc = "Holds arrows for your bow. A deep digital void is contained within." + max_slots = 1 + +/obj/item/storage/bag/quiver/endless/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_ATOM_EXITED, PROC_REF(handle_removed)) + +/obj/item/storage/bag/quiver/endless/PopulateContents() + . = ..() + new arrow_path(src) + +/obj/item/storage/bag/quiver/endless/proc/handle_removed(datum/source, obj/item/gone) + new arrow_path(src) + + +/datum/bitrunning_gimmick/fisher + name = "Fisher" + + granted_items = list( + /obj/item/clothing/under/misc/overalls, + /obj/item/clothing/suit/jacket/miljacket, + /obj/item/clothing/head/soft/black, + /obj/item/clothing/shoes/jackboots, + /obj/item/storage/toolbox/fishing/small, + /obj/item/bait_can/worm/premium, + /obj/item/grenade/iedcasing/spawned, + /obj/item/stock_parts/power_store/cell/lead, + /obj/item/reagent_containers/cup/glass/bottle/beer/light, + ) + + +/datum/bitrunning_gimmick/gamer + name = "Gamer" + + granted_items = list( + /obj/item/clothing/under/suit/black_really, + /obj/item/clothing/shoes/laceup, + /obj/item/clothing/gloves/color/black, + /obj/item/clothing/glasses/sunglasses, + /obj/item/modular_computer/laptop/gamer, + /obj/item/storage/cans/sixgamerdrink, + ) + +/obj/item/storage/cans/sixgamerdrink + name = "gamer drink bottle ring" + desc = "Holds six gamer drink cans. Remember to recycle when you're done!" + + /// Pool of gamer drinks tm we may add from + var/list/gamer_drink_options = list( + /obj/item/reagent_containers/cup/soda_cans/pwr_game = 55, + /obj/item/reagent_containers/cup/soda_cans/space_mountain_wind = 15, + /obj/item/reagent_containers/cup/soda_cans/monkey_energy = 15, + /obj/item/reagent_containers/cup/soda_cans/volt_energy = 10, + /obj/item/reagent_containers/cup/soda_cans/thirteenloko = 5, + ) + +/obj/item/storage/cans/sixgamerdrink/PopulateContents() + for(var/i in 1 to 6) + var/obj/item/chosen_gamer_drink = pick_weight(gamer_drink_options) + new chosen_gamer_drink(src) + +/obj/item/modular_computer/laptop/gamer + desc = "A high-end laptop often used for metagaming." + device_theme = PDA_THEME_TERMINAL + starting_programs = list( + /datum/computer_file/program/themeify, + /datum/computer_file/program/filemanager, + /datum/computer_file/program/notepad, + /datum/computer_file/program/arcade/eazy, + /datum/computer_file/program/mafia, + ) + start_open = FALSE + +/obj/item/modular_computer/laptop/gamer/install_default_programs() + // Only install starting programs, we don't want the software downloading program from default programs + for(var/programs as anything in starting_programs) + var/datum/computer_file/program/program_type = new programs + store_file(program_type) diff --git a/code/modules/bitrunning/orders/tech.dm b/code/modules/bitrunning/orders/tech.dm index cb509fb6252..d14cf7bf1a1 100644 --- a/code/modules/bitrunning/orders/tech.dm +++ b/code/modules/bitrunning/orders/tech.dm @@ -31,6 +31,16 @@ purchase_path = /obj/item/bitrunning_disk/ability/tier3 desc = "This disk contains a program that lets you shapeshift into a lesser ashdrake, or a polar bear." +/datum/orderable_item/bitrunning_tech/gimmick_sports + cost_per_order = 750 + purchase_path = /obj/item/bitrunning_disk/gimmick/sports + desc = "This disk contains a program that lets you equip a sports-themed gimmick loadout." + +/datum/orderable_item/bitrunning_tech/gimmick_dungeon_crawling + cost_per_order = 1250 + purchase_path = /obj/item/bitrunning_disk/gimmick/dungeon + desc = "This disk contains a program that lets you equip a dungeon crawling-themed gimmick loadout." + /datum/orderable_item/bitrunning_tech/flip_skillchip purchase_path = /obj/item/skillchip/matrix_taunt cost_per_order = 1500 diff --git a/code/modules/bitrunning/server/obj_generation.dm b/code/modules/bitrunning/server/obj_generation.dm index 9f473980bbf..cd2f39738d6 100644 --- a/code/modules/bitrunning/server/obj_generation.dm +++ b/code/modules/bitrunning/server/obj_generation.dm @@ -129,54 +129,27 @@ /// Scans over neo's contents for bitrunning tech disks. Loads the items or abilities onto the avatar. /obj/machinery/quantum_server/proc/stock_gear(mob/living/carbon/human/avatar, mob/living/carbon/human/neo, datum/lazy_template/virtual_domain/generated_domain) - var/domain_forbids_items = generated_domain.forbids_disk_items - var/domain_forbids_spells = generated_domain.forbids_disk_spells + var/domain_forbids_flags = generated_domain.external_load_flags var/import_ban = list() var/disk_ban = list() - if(domain_forbids_items) + if(domain_forbids_flags & DOMAIN_FORBIDS_ITEMS) import_ban += "smuggled digital equipment" disk_ban += "items" - if(domain_forbids_spells) + if(domain_forbids_flags & DOMAIN_FORBIDS_ABILITIES) import_ban += "imported_abilities" disk_ban += "powers" if(length(import_ban)) - 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!")) + to_chat(neo, span_warning("This domain forbids the use of [english_list(import_ban)], your externally loaded [english_list(disk_ban)] will not be granted!")) - var/failed = FALSE + var/return_flags = NONE + return_flags = SEND_SIGNAL(neo, COMSIG_BITRUNNER_STOCKING_GEAR, avatar, domain_forbids_flags) - // 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) - return - for(var/obj/item/bitrunning_disk/disk in neo.get_contents()) - if(istype(disk, /obj/item/bitrunning_disk/ability) && !domain_forbids_spells) - var/obj/item/bitrunning_disk/ability/ability_disk = disk - - if(isnull(ability_disk.granted_action)) - failed = TRUE - continue - - var/datum/action/our_action = new ability_disk.granted_action() - - if(locate(our_action.type) in avatar.actions) - failed = TRUE - continue - - our_action.Grant(avatar) - continue - - if(istype(disk, /obj/item/bitrunning_disk/item) && !domain_forbids_items) - var/obj/item/bitrunning_disk/item/item_disk = disk - - if(isnull(item_disk.granted_item)) - failed = TRUE - continue - - avatar.put_in_hands(new item_disk.granted_item()) - - if(failed) - to_chat(neo, span_warning("One of your disks failed to load. Check for duplicate or inactive disks.")) + if(return_flags & BITRUNNER_GEAR_LOAD_FAILED) + to_chat(neo, span_warning("At least one of your external data sources has encountered a failure in its loading process. Check for overlapping or inactive disks.")) + if(return_flags & BITRUNNER_GEAR_LOAD_BLOCKED) + to_chat(neo, span_warning("At least one of your external data sources has been blocked from fully loading. Check domain restrictions.")) var/obj/item/organ/brain/neo_brain = neo.get_organ_slot(ORGAN_SLOT_BRAIN) for(var/obj/item/skillchip/skill_chip as anything in neo_brain?.skillchips) diff --git a/code/modules/bitrunning/virtual_domain/virtual_domain.dm b/code/modules/bitrunning/virtual_domain/virtual_domain.dm index f81f6186cbe..7467b8e4c5e 100644 --- a/code/modules/bitrunning/virtual_domain/virtual_domain.dm +++ b/code/modules/bitrunning/virtual_domain/virtual_domain.dm @@ -37,10 +37,8 @@ * Player customization */ - /// If this domain blocks the use of items from disks, for whatever reason - var/forbids_disk_items = FALSE - /// If this domain blocks the use of spells from disks, for whatever reason - var/forbids_disk_spells = FALSE + /// Any restrictions this domain has on what external sources can load in + var/external_load_flags = NONE /// Any outfit that you wish to force on avatars. Overrides preferences var/datum/outfit/forced_outfit diff --git a/tgstation.dme b/tgstation.dme index 25ecd8cb435..465dfbaa341 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3628,6 +3628,7 @@ #include "code\modules\bitrunning\antagonists\ghost_role.dm" #include "code\modules\bitrunning\antagonists\netguardian.dm" #include "code\modules\bitrunning\components\avatar_connection.dm" +#include "code\modules\bitrunning\components\avatar_gear.dm" #include "code\modules\bitrunning\components\bitrunning_points.dm" #include "code\modules\bitrunning\components\glitch.dm" #include "code\modules\bitrunning\components\netpod_healing.dm" @@ -3651,6 +3652,9 @@ #include "code\modules\bitrunning\objects\loot_crate.dm" #include "code\modules\bitrunning\objects\quantum_console.dm" #include "code\modules\bitrunning\objects\vendor.dm" +#include "code\modules\bitrunning\objects\gimmick_disks\_gimmick_disk.dm" +#include "code\modules\bitrunning\objects\gimmick_disks\dungeon_disk.dm" +#include "code\modules\bitrunning\objects\gimmick_disks\sports_disk.dm" #include "code\modules\bitrunning\orders\bepis.dm" #include "code\modules\bitrunning\orders\flair.dm" #include "code\modules\bitrunning\orders\tech.dm"