diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 95b71bec9749..d47f688cde91 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -139,6 +139,7 @@ #define TRAIT_INCAPACITATED "incapacitated" #define HANDCUFFED_TRAIT "handcuffed" #define TRAIT_BLIND "blind" +#define HYPNOCHAIR_TRAIT "hypnochair" //dripstation edit #define TRAIT_ECHOLOCATION_RECEIVER "echolocation_receiver" #define TRAIT_MUTE "mute" #define TRAIT_EMOTEMUTE "emotemute" @@ -242,6 +243,7 @@ #define TRAIT_QUICK_CARRY "quick-carry" #define TRAIT_QUICKER_CARRY "quicker-carry" #define TRAIT_QUICKEST_CARRY "quickest-carry" +#define TRAIT_QUICK_BUILD "quick-build" //dripstation edit #define TRAIT_STRONG_GRIP "strong-grip" #define TRAIT_UNINTELLIGIBLE_SPEECH "unintelligible-speech" #define TRAIT_UNSTABLE "unstable" @@ -343,6 +345,7 @@ #define TRAIT_ANXIOUS "anxious" #define TRAIT_SEE_REAGENTS "see_reagents" #define TRAIT_STARGAZED "stargazed" +#define TRAIT_TRANSFORM_ACTIVE "active_transform" //dripstation edit // common trait sources #define TRAIT_GENERIC "generic" diff --git a/code/__DEFINES/{dripstation_defines}/blackmarket.dm b/code/__DEFINES/{dripstation_defines}/blackmarket.dm new file mode 100644 index 000000000000..c5e199546f71 --- /dev/null +++ b/code/__DEFINES/{dripstation_defines}/blackmarket.dm @@ -0,0 +1,9 @@ + +// Shipping methods + +// The BEST way of shipping items: accurate, "undetectable" +#define SHIPPING_METHOD_LTSRBT "LTSRBT" +// Picks a random area to teleport the item to and gives you a minute to get there before it is sent. +#define SHIPPING_METHOD_TELEPORT "Teleport" +// Throws the item from somewhere at the station. +#define SHIPPING_METHOD_LAUNCH "Launch" \ No newline at end of file diff --git a/code/__DEFINES/{dripstation_defines}/cargo.dm b/code/__DEFINES/{dripstation_defines}/cargo.dm new file mode 100644 index 000000000000..b4c8b0c96256 --- /dev/null +++ b/code/__DEFINES/{dripstation_defines}/cargo.dm @@ -0,0 +1,2 @@ +/// Defining standart crate value for blackmarket, some events will change this shit some day +#define CARGO_CRATE_VALUE 200 diff --git a/code/__DEFINES/{dripstation_defines}/dcs/signals/signals_transform.dm b/code/__DEFINES/{dripstation_defines}/dcs/signals/signals_transform.dm new file mode 100644 index 000000000000..a520c050c73b --- /dev/null +++ b/code/__DEFINES/{dripstation_defines}/dcs/signals/signals_transform.dm @@ -0,0 +1,10 @@ +// /datum/component/transforming signals + +/// From /datum/component/transforming/proc/on_attack_self(obj/item/source, mob/user): (obj/item/source, mob/user, active) +#define COMSIG_TRANSFORMING_PRE_TRANSFORM "transforming_pre_transform" + /// Return COMPONENT_BLOCK_TRANSFORM to prevent the item from transforming. + #define COMPONENT_BLOCK_TRANSFORM (1<<0) +/// From /datum/component/transforming/proc/do_transform(obj/item/source, mob/user): (obj/item/source, mob/user, active) +#define COMSIG_TRANSFORMING_ON_TRANSFORM "transforming_on_transform" + /// Return COMPONENT_NO_DEFAULT_MESSAGE to prevent the transforming component from displaying the default transform message / sound. + #define COMPONENT_NO_DEFAULT_MESSAGE (1<<0) \ No newline at end of file diff --git a/code/controllers/subsystem/research.dm b/code/controllers/subsystem/research.dm index 21f998f831de..e51c37e1834c 100644 --- a/code/controllers/subsystem/research.dm +++ b/code/controllers/subsystem/research.dm @@ -27,6 +27,7 @@ SUBSYSTEM_DEF(research) var/list/techweb_categories = list() //category name = list(node.id = TRUE) var/list/techweb_boost_items = list() //associative double-layer path = list(id = list(point_type = point_discount)) var/list/techweb_nodes_hidden = list() //Node ids that should be hidden by default. + var/list/techweb_nodes_experimental = list()//Node ids that are exclusive to the BEPIS. dripstation edit var/list/techweb_point_items = list( //path = list(point type = value) /obj/item/assembly/signaler/anomaly = list(TECHWEB_POINT_TYPE_GENERIC = 10000) ) @@ -256,6 +257,8 @@ SUBSYSTEM_DEF(research) D.unlocked_by += node.id if(node.hidden) techweb_nodes_hidden[node.id] = TRUE + if(node.experimental) //dripstation edit + techweb_nodes_experimental[node.id] = TRUE //dripstation edit CHECK_TICK generate_techweb_unlock_linking() diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm index 5dc854e6dff7..037aa653c4d4 100644 --- a/code/datums/components/chasm.dm +++ b/code/datums/components/chasm.dm @@ -40,8 +40,8 @@ STOP_PROCESSING(SSobj, src) /datum/component/chasm/proc/is_safe() - //if anything matching this typecache is found in the chasm, we don't drop things - var/static/list/chasm_safeties_typecache = typecacheof(list(/obj/structure/lattice/catwalk, /obj/structure/stone_tile)) + //if anything matching this typecache is found in the chasm, we don't drop things, dripstation edit + var/static/list/chasm_safeties_typecache = typecacheof(list(/obj/structure/lattice/catwalk, /obj/structure/lattice/lava, /obj/structure/stone_tile)) var/atom/parent = src.parent var/list/found_safeties = typecache_filter_list(parent.contents, chasm_safeties_typecache) diff --git a/code/datums/components/storage/concrete/pockets.dm b/code/datums/components/storage/concrete/pockets.dm index 4e69c5f7a303..74b33246a7f4 100644 --- a/code/datums/components/storage/concrete/pockets.dm +++ b/code/datums/components/storage/concrete/pockets.dm @@ -44,7 +44,7 @@ /datum/component/storage/concrete/pockets/shoes/Initialize() . = ..() set_holdable(list( - /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, + /obj/item/kitchen/knife, /obj/item/boxcutter, /obj/item/switchblade, /obj/item/pen, //boxcutter dripstation edit /obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector, /obj/item/reagent_containers/autoinjector/medipen, /obj/item/reagent_containers/dropper, /obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini, @@ -56,7 +56,7 @@ /datum/component/storage/concrete/pockets/shoes/clown/Initialize() . = ..() set_holdable(list( - /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, + /obj/item/kitchen/knife, /obj/item/boxcutter, /obj/item/switchblade, /obj/item/pen, //boxcutter dripstation edit /obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector, /obj/item/reagent_containers/autoinjector/medipen, /obj/item/reagent_containers/dropper, /obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini, diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 99dc8e01778b..78bb1d7cafb0 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -1011,6 +1011,8 @@ return FALSE if(force < (move_resist * MOVE_FORCE_PULL_RATIO)) return FALSE + if(SEND_SIGNAL(src, COMSIG_ATOM_CAN_BE_PULLED, user) & COMSIG_ATOM_CANT_PULL) //dripstation edit + return FALSE //dripstation edit return TRUE /// Called when mob changes from a standing position into a prone while lacking the ability to stand up at the moment. diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm index 974f66f8a616..4d4c0185500a 100644 --- a/code/game/gamemodes/dynamic/dynamic.dm +++ b/code/game/gamemodes/dynamic/dynamic.dm @@ -79,7 +79,7 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1) /// Antags rolled by rules so far, to keep track of and discourage scaling past a certain ratio of crew/antags especially on lowpop. var/antags_rolled = 0 /// CRATE DISCOUNT - var/discountedcrates = list( /datum/supply_pack/security/laser, + var/discountedcrates = list( /datum/supply_pack/security/armory/laser, //dripstation edit /datum/supply_pack/security/vending/security, /datum/supply_pack/service/party) diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 6c393d6f367b..e5c37ee4594c 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -17,6 +17,7 @@ var/static/list/allowed_devices = typecacheof(list( /obj/item/gun/energy, + /obj/item/cargo_teleporter, //dripstation edit /obj/item/melee/baton, /obj/item/ammo_box/magazine/recharge, /obj/item/ammo_box/magazine/m308/laser, diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index b28344641425..c9f5ea50b2af 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -58,7 +58,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ new/datum/stack_recipe("floor tile", /obj/item/stack/tile/plasteel, 1, 4, 20), \ new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60), \ null, \ - new/datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 40, one_per_turf = TRUE, on_floor = TRUE), \ + new/datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 40, one_per_turf = TRUE, on_floor = TRUE, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75), \ null, \ new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 25, one_per_turf = TRUE, on_floor = TRUE), \ new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 25, one_per_turf = TRUE, on_floor = TRUE), \ diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index c4b03c4c9928..0a1da50e1df4 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -456,9 +456,13 @@ var/on_floor = FALSE var/window_checks = FALSE var/placement_checks = FALSE + /// What trait, if any, boosts the construction speed of this item dripstation + var/trait_booster + /// How much the trait above, if supplied, boosts the construct speed of this item dripstation + var/trait_modifier = 1 -/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1,time = 0, one_per_turf = FALSE, on_floor = FALSE, window_checks = FALSE, placement_checks = FALSE ) - +/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1,time = 0, one_per_turf = FALSE, on_floor = FALSE, window_checks = FALSE, placement_checks = FALSE, trait_booster, trait_modifier = 1) +//dripstation edit src.title = title src.result_type = result_type @@ -470,6 +474,8 @@ src.on_floor = on_floor src.window_checks = window_checks src.placement_checks = placement_checks + src.trait_booster = trait_booster //dripstation edit + src.trait_modifier = trait_modifier //dripstation edit /* * Recipe list datum */ diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 3015c6b6615c..40e88d172173 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -78,6 +78,7 @@ /obj/item/shuttle_creator, //Yogs: Added this here cause I felt it fits /obj/item/barrier_taperoll/engineering, /obj/item/storage/bag/sheetsnatcher, + /obj/item/boxcutter, //dripstation edit /obj/item/holotool, )) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 66d75d7e3125..aae44479b2cb 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -49,6 +49,8 @@ GLOBAL_LIST_EMPTY(lockers) var/door_anim_angle = 136 var/door_hinge_x = -6.5 var/door_anim_time = 2.5 // set to 0 to make the door not animate at all + /// true whenever someone with the strong pull component (or magnet modsuit module) is dragging this, preventing opening + var/strong_grab = FALSE //dripstation edit /obj/structure/closet/Initialize(mapload) . = ..() @@ -171,7 +173,11 @@ GLOBAL_LIST_EMPTY(lockers) /obj/structure/closet/proc/can_open(mob/living/user) if(welded || locked) - return FALSE + to_chat(user, span_danger("[src] locked or welded to be opened.")) //dripstation edit + return FALSE //dripstation edit + if(strong_grab) //dripstation edit + to_chat(user, span_danger("[pulledby] has an incredibly strong grip on [src], preventing it from opening.")) //dripstation edit + return FALSE //dripstation edit var/turf/T = get_turf(src) for(var/mob/living/L in T) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index c007459bf5e7..34260fc37070 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -10,6 +10,7 @@ max_integrity = 200 flags_1 = RAD_PROTECT_CONTENTS_1 | RAD_NO_CONTAMINATE_1 rad_insulation = RAD_VERY_LIGHT_INSULATION + var/next_beep = 0 //Prevents spamming of the construction sound, dripstation edit /obj/structure/girder/examine(mob/user) . = ..() @@ -27,6 +28,12 @@ . += span_notice("[src] is disassembled! You probably shouldn't be able to see this examine message.") /obj/structure/girder/attackby(obj/item/W, mob/user, params) + var/platingmodifier = 1 //dripstation edit start + if(HAS_TRAIT(user, TRAIT_QUICK_BUILD)) + platingmodifier = 0.7 + if(next_beep <= world.time) + next_beep = world.time + 10 + playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE) //dripstation edit end add_fingerprint(user) if(istype(W, /obj/item/gun/energy/plasmacutter)) @@ -55,7 +62,7 @@ to_chat(user, span_warning("You need at least two rods to create a false wall!")) return to_chat(user, span_notice("You start building a reinforced false wall...")) - if(do_after(user, 2 SECONDS, src)) + if(do_after(user, 20*platingmodifier, src)) //dripstation edit if(S.get_amount() < 2) return S.use(2) @@ -68,7 +75,7 @@ to_chat(user, span_warning("You need at least five rods to add plating!")) return to_chat(user, span_notice("You start adding plating...")) - if(do_after(user, 4 SECONDS, src)) + if(do_after(user, 40*platingmodifier, src)) //dripstation edit if(S.get_amount() < 5) return S.use(5) diff --git a/code/game/turfs/simulated/chasm.dm b/code/game/turfs/simulated/chasm.dm index 482a7a9a7a7e..0b94df0abc73 100644 --- a/code/game/turfs/simulated/chasm.dm +++ b/code/game/turfs/simulated/chasm.dm @@ -57,7 +57,10 @@ to_chat(user, span_notice("You construct a lattice.")) playsound(src, 'sound/weapons/genhit.ogg', 50, 1) // Create a lattice, without reverting to our baseturf - new /obj/structure/lattice(src) + if(istype(R, /obj/item/stack/rods/lava)) //dripstation edit start + new /obj/structure/lattice/lava(src) + else + new /obj/structure/lattice(src) //dripstation edit end else to_chat(user, span_warning("You need one rod to build a lattice.")) return diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm index a55fd9d6da86..35c0f6a6e91c 100644 --- a/code/modules/cargo/console.dm +++ b/code/modules/cargo/console.dm @@ -16,6 +16,7 @@ or homing beacons. Additionally, remove any privately ordered crates from the shuttle." var/blockade_warning = "Bluespace instability detected. Shuttle movement impossible." var/self_paid = FALSE + req_access = list(ACCESS_CARGO) //dripstation edit /obj/machinery/computer/cargo/request name = "supply request console" @@ -25,6 +26,7 @@ requestonly = TRUE can_send = FALSE can_approve_requests = FALSE + req_access = list() //dripstation edit /obj/machinery/computer/cargo/Initialize(mapload) . = ..() @@ -50,6 +52,7 @@ obj_flags |= EMAGGED contraband = TRUE + do_sparks(8, FALSE, loc) //dripstation edit // This also permamently sets this on the circuit board var/obj/item/circuitboard/computer/cargo/board = circuit @@ -133,6 +136,9 @@ /obj/machinery/computer/cargo/ui_act(action, params, datum/tgui/ui) if(..()) return + if(!allowed(usr) && can_approve_requests) //dripstation edit + say("Access denied.") //dripstation edit + return //dripstation edit switch(action) if("send") if(!SSshuttle.supply.canMove()) @@ -148,7 +154,7 @@ investigate_log("[key_name(usr)] sent the supply shuttle away.", INVESTIGATE_CARGO) else investigate_log("[key_name(usr)] called the supply shuttle.", INVESTIGATE_CARGO) - say("The supply shuttle has been called and will arrive in [SSshuttle.supply.timeLeft(600)] minutes.") + say("The supply shuttle has been called and will arrive in [SSshuttle.supply.timeLeft(10)] seconds.") //dripstation edit SSshuttle.moveShuttle("supply", "supply_home", TRUE) . = TRUE if("loan") @@ -171,6 +177,12 @@ var/datum/supply_pack/pack = SSshuttle.supply_packs[id] if(!istype(pack)) return + if(pack.times_ordered >= pack.order_limit && pack.order_limit != -1) //If the crate has reached the limit, do not allow it to be ordered. + say("[pack.name] is out of stock and can no longer be ordered.") + return + if(pack.times_ordered_in_one_order >= pack.order_limit_in_one_order && pack.order_limit_in_one_order != -1) + say("[pack.name] is out of stock for now and can no longer be ordered in this package. Try again later.") + return if((pack.hidden && !(obj_flags & EMAGGED)) || (pack.contraband && !contraband) || pack.DropPodOnly) return @@ -210,6 +222,8 @@ SSshuttle.requestlist += SO else SSshuttle.shoppinglist += SO + SO.pack.times_ordered += 1 //dripstation edit + SO.pack.times_ordered_in_one_order += 1 //dripstation edit if(self_paid) say("Order processed. The price will be charged to [account.account_holder]'s bank account on delivery.") . = TRUE @@ -218,17 +232,30 @@ for(var/datum/supply_order/SO in SSshuttle.shoppinglist) if(SO.id == id) SSshuttle.shoppinglist -= SO + SO.pack.times_ordered -= 1 //dripstation edit + SO.pack.times_ordered_in_one_order -= 1 //dripstation edit . = TRUE break if("clear") + for(var/datum/supply_order/SO in SSshuttle.shoppinglist) //dripstation edit + SO.pack.times_ordered -= 1 //dripstation edit + SO.pack.times_ordered_in_one_order = 0 //dripstation edit SSshuttle.shoppinglist.Cut() . = TRUE if("approve") var/id = text2num(params["id"]) for(var/datum/supply_order/SO in SSshuttle.requestlist) if(SO.id == id) + if(SO.pack.times_ordered >= SO.pack.order_limit && SO.pack.order_limit != -1) //If the crate has reached the limit, do not allow it to be ordered. dripstation edit start + say("[SO.pack.name] is out of stock and can no longer be ordered.") + return + if(SO.pack.times_ordered_in_one_order >= SO.pack.order_limit_in_one_order && SO.pack.order_limit_in_one_order != -1) + say("[SO.pack.name] is out of stock for now and can no longer be ordered in this package. Try again later.") + return //dripstation edit end SSshuttle.requestlist -= SO SSshuttle.shoppinglist += SO + SO.pack.times_ordered += 1 //dripstation edit + SO.pack.times_ordered_in_one_order += 1 //dripstation edit . = TRUE break if("deny") diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm index 6afc883649fe..72d87817bbda 100644 --- a/code/modules/cargo/order.dm +++ b/code/modules/cargo/order.dm @@ -108,7 +108,7 @@ if(paying_account) account_holder = paying_account.account_holder else - account_holder = "Cargo" + account_holder = "Cargo Budget" //dripstation edit var/obj/structure/closet/crate/C = pack.generate(A, paying_account) generateManifest(C, account_holder, pack) return C diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index e6c4eb8ed399..5ceca653bd5c 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -317,7 +317,7 @@ /obj/item/toy/crayon/white, /obj/item/clothing/head/fedora/det_hat) crate_name = "forensics crate" - +/* /datum/supply_pack/security/laser name = "Lasers Crate" desc = "Contains three lethal, high-energy laser guns. Requires Security access to open." @@ -326,7 +326,7 @@ /obj/item/gun/energy/laser, /obj/item/gun/energy/laser) crate_name = "laser crate" - +*/ /datum/supply_pack/security/secfiringpins name = "Mindshield Firing Pins Crate" desc = "Upgrade your arsenal with 10 mindshield firing pins. Requires Security access to open." diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 25436281deae..ea7dd719b615 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -1,7 +1,7 @@ /mob/living/carbon/get_eye_protection() . = ..() - if(HAS_TRAIT(src, TRAIT_BLIND)) - return INFINITY //Can't get flashed if you cant see + if(is_blind() && !HAS_TRAIT_FROM(src, TRAIT_BLIND, UNCONSCIOUS_TRAIT) && !HAS_TRAIT_FROM(src, TRAIT_BLIND, HYPNOCHAIR_TRAIT)) //dripstation edit + return INFINITY //For all my homies that can not see in the world var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES) if(!E) return INFINITY //Can't get flashed without eyes diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index b09e8ed406d9..dfb58e2095ef 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -258,6 +258,7 @@ pulling = AM AM.set_pulledby(src) + SEND_SIGNAL(src, COMSIG_LIVING_START_PULL, AM, state, force) //dripstation edit if(!supress_message) var/sound_to_play = 'sound/weapons/thudswoosh.ogg' if(ishuman(src)) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index f19753ed5eeb..b51b398de598 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -1090,6 +1090,9 @@ Nothing else in the console has ID requirements. stored_research.add_design(D, TRUE) else stored_research.add_design(d_disk.blueprints[n], TRUE) + + say("Uploading blueprints from disk.") //dripstation edit + d_disk.on_upload(stored_research) //dripstation edit updateUsrDialog() diff --git a/code/modules/research/techweb/_techweb_node.dm b/code/modules/research/techweb/_techweb_node.dm index 5bf1cff4a57c..23112ab60175 100644 --- a/code/modules/research/techweb/_techweb_node.dm +++ b/code/modules/research/techweb/_techweb_node.dm @@ -7,6 +7,7 @@ var/display_name = "Errored Node" var/description = "Why are you seeing this?" var/hidden = FALSE //Whether it starts off hidden. + var/experimental = FALSE //If the tech can be randomly generated by the BEPIS as a reward. MEant to be fully given in tech disks, not researched. dripstation edit var/starting_node = FALSE //Whether it's available without any research. var/list/prereq_ids = list() var/list/design_ids = list() @@ -41,6 +42,7 @@ VARSET_TO_LIST(., id) VARSET_TO_LIST(., display_name) VARSET_TO_LIST(., hidden) + VARSET_TO_LIST(., experimental) //dripstation edit VARSET_TO_LIST(., starting_node) VARSET_TO_LIST(., assoc_to_keys(prereq_ids)) VARSET_TO_LIST(., assoc_to_keys(design_ids)) @@ -56,6 +58,7 @@ VARSET_FROM_LIST(input, id) VARSET_FROM_LIST(input, display_name) VARSET_FROM_LIST(input, hidden) + VARSET_FROM_LIST(input, experimental) //dripstation edit VARSET_FROM_LIST(input, starting_node) VARSET_FROM_LIST(input, prereq_ids) VARSET_FROM_LIST(input, design_ids) diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index 3eb91bd880c1..427f98fcdc3d 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -122,6 +122,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( value += SO.pack.get_cost() SSshuttle.shoppinglist -= SO SSshuttle.orderhistory += SO + SO.pack.times_ordered_in_one_order = 0 //dripstation edit if(SO.pack.small_item) //small_item means it gets piled in the miscbox if(SO.paying_account) diff --git a/modular_dripstation/code/controllers/subsystem/blackmarket.dm b/modular_dripstation/code/controllers/subsystem/blackmarket.dm new file mode 100644 index 000000000000..357fa0df2915 --- /dev/null +++ b/modular_dripstation/code/controllers/subsystem/blackmarket.dm @@ -0,0 +1,115 @@ +SUBSYSTEM_DEF(blackmarket) + name = "Blackmarket" + flags = SS_BACKGROUND + init_order = INIT_ORDER_DEFAULT + + /// Descriptions for each shipping methods. + var/shipping_method_descriptions = list( + SHIPPING_METHOD_LAUNCH="Launches the item at the station from space, cheap but you might not receive your item at all.", + SHIPPING_METHOD_LTSRBT="Long-To-Short-Range-Bluespace-Transceiver, a machine that receives items outside the station and then teleports them to the location of the uplink.", + SHIPPING_METHOD_TELEPORT="Teleports the item in a random area in the station, you get 60 seconds to get there first though." + ) + + /// List of all existing markets. + var/list/datum/market/markets = list() + /// List of existing ltsrbts. + var/list/obj/machinery/ltsrbt/telepads = list() + /// Currently queued purchases. + var/list/queued_purchases = list() + +/datum/controller/subsystem/blackmarket/Initialize() + for(var/market in subtypesof(/datum/market)) + markets[market] += new market + + for(var/item in subtypesof(/datum/market_item)) + var/datum/market_item/I = new item() + if(!I.item) + continue + + for(var/M in I.markets) + if(!markets[M]) + stack_trace("SSblackmarket: Item [I] available in market that does not exist.") + continue + markets[M].add_item(item) + qdel(I) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/blackmarket/fire(resumed) + while(length(queued_purchases)) + var/datum/market_purchase/purchase = queued_purchases[1] + queued_purchases.Cut(1,2) + + // Uh oh, uplink is gone. We will just keep the money and you will not get your order. + if(!purchase.uplink || QDELETED(purchase.uplink)) + queued_purchases -= purchase + qdel(purchase) + continue + + switch(purchase.method) + // Find a ltsrbt pad and make it handle the shipping. + if(SHIPPING_METHOD_LTSRBT) + if(!telepads.len) + continue + // Prioritize pads that don't have a cooldown active. + var/free_pad_found = FALSE + for(var/obj/machinery/ltsrbt/pad in telepads) + if(pad.recharge_cooldown) + continue + pad.add_to_queue(purchase) + queued_purchases -= purchase + free_pad_found = TRUE + break + + if(free_pad_found) + continue + + var/obj/machinery/ltsrbt/pad = pick(telepads) + + to_chat(recursive_loc_check(purchase.uplink.loc, /mob), span_notice("[purchase.uplink] flashes a message noting that the order is being processed by [pad].")) + + queued_purchases -= purchase + pad.add_to_queue(purchase) + // Get random area, throw it somewhere there. + if(SHIPPING_METHOD_TELEPORT) + var/turf/targetturf = get_safe_random_station_turf() + // This shouldn't happen. + if (!targetturf) + continue + + to_chat(recursive_loc_check(purchase.uplink.loc, /mob), span_notice("[purchase.uplink] flashes a message noting that the order is being teleported to [get_area(targetturf)] in 60 seconds.")) + + // do_teleport does not want to teleport items from nullspace, so it just forceMoves and does sparks. + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/controller/subsystem/blackmarket,fake_teleport), purchase.entry.spawn_item(), targetturf), 60 SECONDS) + queued_purchases -= purchase + qdel(purchase) + // Get the current location of the uplink if it exists, then throws the item from space at the station from a random direction. + if(SHIPPING_METHOD_LAUNCH) + var/startSide = pick(GLOB.cardinals) + var/turf/T = get_turf(purchase.uplink) + var/pickedloc = spaceDebrisStartLoc(startSide, T.z) + + var/atom/movable/item = purchase.entry.spawn_item(pickedloc) + item.throw_at(purchase.uplink, 3, 3, spin = FALSE) + + to_chat(recursive_loc_check(purchase.uplink.loc, /mob), span_notice("[purchase.uplink] flashes a message noting the order is being launched at the station from [dir2text(startSide)].")) + + queued_purchases -= purchase + qdel(purchase) + + if(MC_TICK_CHECK) + break + +/// Used to make a teleportation effect as do_teleport does not like moving items from nullspace. +/datum/controller/subsystem/blackmarket/proc/fake_teleport(atom/movable/item, turf/target) + item.forceMove(target) + var/datum/effect_system/spark_spread/sparks = new + sparks.set_up(5, 1, target) + sparks.attach(item) + sparks.start() + +/// Used to add /datum/market_purchase to queued_purchases var. Returns TRUE when queued. +/datum/controller/subsystem/blackmarket/proc/queue_item(datum/market_purchase/P) + if(P.method == SHIPPING_METHOD_LTSRBT && !telepads.len) + return FALSE + queued_purchases += P + return TRUE diff --git a/modular_dripstation/code/datum/brain_damage/severe.dm b/modular_dripstation/code/datum/brain_damage/severe.dm new file mode 100644 index 000000000000..247ecd016360 --- /dev/null +++ b/modular_dripstation/code/datum/brain_damage/severe.dm @@ -0,0 +1,31 @@ +/datum/brain_trauma/severe/hypnotic_trigger + name = "Hypnotic Trigger" + desc = "Patient has a trigger phrase set in their subconscious that will trigger a suggestible trance-like state." + scan_desc = "oneiric feedback loop" + gain_text = span_warning("You feel odd, like you just forgot something important.") + lose_text = span_notice("You feel like a weight was lifted from your mind.") + random_gain = FALSE + var/trigger_phrase = "Nanotrasen" + +/datum/brain_trauma/severe/hypnotic_trigger/New(phrase) + ..() + if(phrase) + trigger_phrase = phrase + +/datum/brain_trauma/severe/hypnotic_trigger/on_lose() //hypnosis must be cleared separately, but brain surgery should get rid of both anyway + ..() + owner.remove_status_effect(/datum/status_effect/trance) + +/datum/brain_trauma/severe/hypnotic_trigger/handle_hearing(datum/source, list/hearing_args) + if(!owner.can_hear() || owner == hearing_args[HEARING_SPEAKER]) + return + + var/regex/reg = new("(\\b[REGEX_QUOTE(trigger_phrase)]\\b)","ig") + + if(findtext(hearing_args[HEARING_RAW_MESSAGE], reg)) + addtimer(CALLBACK(src, PROC_REF(hypnotrigger)), 10) //to react AFTER the chat message + hearing_args[HEARING_RAW_MESSAGE] = reg.Replace(hearing_args[HEARING_RAW_MESSAGE], span_hypnophrase("*********")) + +/datum/brain_trauma/severe/hypnotic_trigger/proc/hypnotrigger() + to_chat(owner, span_warning("The words trigger something deep within you, and you feel your consciousness slipping away...")) + owner.apply_status_effect(/datum/status_effect/trance, rand(100,300), FALSE) \ No newline at end of file diff --git a/modular_dripstation/code/datum/component/transforming.dm b/modular_dripstation/code/datum/component/transforming.dm new file mode 100644 index 000000000000..3941d5eabe6c --- /dev/null +++ b/modular_dripstation/code/datum/component/transforming.dm @@ -0,0 +1,258 @@ +/* + * Transforming weapon component. For weapons that swap between states. + * For example: Energy swords, cleaving saws, switch blades. + * + * Used to easily make an item that can be attack_self'd to gain force or change mode. + * + * Only values passed on initialize will update when the item is activated (except the icon_state). + * The icon_state of the item will swap between "[icon_state]" and "[icon_state]_on". + */ +/datum/component/transforming + /// Whether the weapon is transformed + var/active = FALSE + /// Cooldown on transforming this item back and forth + var/transform_cooldown_time + /// Force of the weapon when active + var/force_on + /// Throwforce of the weapon when active + var/throwforce_on + /// Throw speed of the weapon when active + var/throw_speed_on + /// Weight class of the weapon when active + var/w_class_on + /// The sharpness of the weapon when active + var/sharpness_on + /// Hitsound played when active + var/hitsound_on + /// List of the original continuous attack verbs the item has. + var/list/attack_verb_off + /// List of simple attack verbs used when the weapon is enabled + var/list/attack_verb_on + /// Whether clumsy people need to succeed an RNG check to turn it on without hurting themselves + var/clumsy_check + /// If we get sharpened with a whetstone, save the bonus here for later use if we un/redeploy + var/sharpened_bonus = 0 + /// Dictate whether we change inhands or not + var/item_state_change = TRUE + /// Cooldown in between transforms + COOLDOWN_DECLARE(transform_cooldown) + +/datum/component/transforming/Initialize( + start_transformed = FALSE, + transform_cooldown_time = 0 SECONDS, + force_on = 0, + throwforce_on = 0, + throw_speed_on = 2, + sharpness_on = NONE, + hitsound_on = 'sound/weapons/blade1.ogg', + w_class_on = WEIGHT_CLASS_BULKY, + clumsy_check = TRUE, + list/attack_verb_on, + item_state_change = TRUE, +) + + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + var/obj/item/item_parent = parent + + src.transform_cooldown_time = transform_cooldown_time + src.force_on = force_on + src.throwforce_on = throwforce_on + src.throw_speed_on = throw_speed_on + src.sharpness_on = sharpness_on + src.hitsound_on = hitsound_on + src.w_class_on = w_class_on + src.clumsy_check = clumsy_check + src.item_state_change = item_state_change + + if(attack_verb_on) + src.attack_verb_on = attack_verb_on + attack_verb_off = item_parent.attack_verb + + if(start_transformed) + toggle_active(parent) + +/datum/component/transforming/RegisterWithParent() + var/obj/item/item_parent = parent + + RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_attack_self)) + if(item_parent.sharpness || sharpness_on) + RegisterSignal(parent, COMSIG_ITEM_SHARPEN_ACT, PROC_REF(on_sharpen)) + + RegisterSignal(parent, COMSIG_DETECTIVE_SCANNED, PROC_REF(on_scan)) + +/datum/component/transforming/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_ITEM_ATTACK_SELF, COMSIG_ITEM_SHARPEN_ACT, COMSIG_DETECTIVE_SCANNED)) + +/datum/component/transforming/proc/on_scan(datum/source, mob/user, list/extra_data) + SIGNAL_HANDLER + LAZYADD(extra_data[DETSCAN_CATEGORY_NOTES], "Readings suggest some form of state changing.") + + +/* + * Called on [COMSIG_ITEM_ATTACK_SELF]. + * + * Check if we can transform our weapon, and if so, call [do_transform]. + * Sends signal [COMSIG_TRANSFORMING_PRE_TRANSFORM], and stops the transform action if it returns [COMPONENT_BLOCK_TRANSFORM]. + * And, if [do_transform] was successful, do a clumsy effect from [clumsy_transform_effect]. + * + * source - source of the signal, the item being transformed / parent + * user - the mob transforming the weapon + */ +/datum/component/transforming/proc/on_attack_self(obj/item/source, mob/user) + SIGNAL_HANDLER + + if(!COOLDOWN_FINISHED(src, transform_cooldown)) + to_chat(user, span_warning("Wait a bit before trying to use [source] again!")) + return + + if(SEND_SIGNAL(source, COMSIG_TRANSFORMING_PRE_TRANSFORM, user, active) & COMPONENT_BLOCK_TRANSFORM) + return + + if(do_transform(source, user)) + clumsy_transform_effect(user) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/* + * Transform the weapon into its alternate form, calling [toggle_active]. + * + * Sends signal [COMSIG_TRANSFORMING_ON_TRANSFORM], and calls [default_transform_message] if it does not return [COMPONENT_NO_DEFAULT_MESSAGE]. + * Also starts the [transform_cooldown] if we have a set [transform_cooldown_time]. + * + * source - the item being transformed / parent + * user - the mob transforming the item + * + * returns TRUE. + */ +/datum/component/transforming/proc/do_transform(obj/item/source, mob/user) + toggle_active(source) + if(!(SEND_SIGNAL(source, COMSIG_TRANSFORMING_ON_TRANSFORM, user, active) & COMPONENT_NO_DEFAULT_MESSAGE)) + default_transform_message(source, user) + + if(isnum(transform_cooldown_time)) + COOLDOWN_START(src, transform_cooldown, transform_cooldown_time) + if(user) + source.add_fingerprint(user) + return TRUE + +/* + * The default feedback message and sound effect for an item transforming. + * + * source - the item being transformed / parent + * user - the mob transforming the item + */ +/datum/component/transforming/proc/default_transform_message(obj/item/source, mob/user) + if(user) + source.balloon_alert(user, "[active ? "enabled" : "disabled"] [source]") + playsound(source, 'sound/weapons/batonextend.ogg', 50, TRUE) + +/* + * Toggle active between true and false, and call + * either set_active or set_inactive depending on whichever state is toggled. + * + * source - the item being transformed / parent + */ +/datum/component/transforming/proc/toggle_active(obj/item/source) + active = !active + if(active) + set_active(source) + else + set_inactive(source) + +/* + * Set our transformed item into its active state. + * Updates all the values that were passed from init and the icon_state. + * + * source - the item being transformed / parent + */ +/datum/component/transforming/proc/set_active(obj/item/source) + ADD_TRAIT(source, TRAIT_TRANSFORM_ACTIVE, REF(src)) + if(sharpness_on) + source.sharpness = sharpness_on + if(force_on) + source.force = force_on + (source.sharpness ? sharpened_bonus : 0) + if(throwforce_on) + source.throwforce = throwforce_on + (source.sharpness ? sharpened_bonus : 0) + if(throw_speed_on) + source.throw_speed = throw_speed_on + + if(LAZYLEN(attack_verb_on)) + source.attack_verb = attack_verb_on + + source.hitsound = hitsound_on + source.w_class = w_class_on + source.icon_state = "[source.icon_state]_on" + if(item_state_change && source.item_state) + source.item_state = "[source.item_state]_on" + source.update_icon() + +/* + * Set our transformed item into its inactive state. + * Updates all the values back to the item's initial values. + * + * source - the item being un-transformed / parent + */ +/datum/component/transforming/proc/set_inactive(obj/item/source) + REMOVE_TRAIT(source, TRAIT_TRANSFORM_ACTIVE, REF(src)) + if(sharpness_on) + source.sharpness = initial(source.sharpness) + if(force_on) + source.force = initial(source.force) + (source.sharpness ? sharpened_bonus : 0) + if(throwforce_on) + source.throwforce = initial(source.throwforce) + (source.sharpness ? sharpened_bonus : 0) + if(throw_speed_on) + source.throw_speed = initial(source.throw_speed) + + if(LAZYLEN(attack_verb_on)) + source.attack_verb = attack_verb_off + + source.hitsound = initial(source.hitsound) + source.w_class = initial(source.w_class) + source.icon_state = initial(source.icon_state) + source.item_state = initial(source.item_state) + +/* + * If [clumsy_check] is set to TRUE, attempt to cause a side effect for clumsy people activating this item. + * Called after the transform is done, meaning [active] var has already updated. + * + * user - the clumsy mob, transforming our item (parent) + * + * Returns TRUE if side effects happened, FALSE otherwise + */ +/datum/component/transforming/proc/clumsy_transform_effect(mob/living/user) + if(!clumsy_check) + return FALSE + + if(!user || !HAS_TRAIT(user, TRAIT_CLUMSY)) + return FALSE + + if(active && prob(50)) + var/hurt_self_verb = LAZYLEN(attack_verb_on) ? pick(attack_verb_on) : "hited" + user.visible_message( + span_warning("[user] triggers [parent] while holding it backwards and [hurt_self_verb] themself, like a doofus!"), + span_warning("You trigger [parent] while holding it backwards and [hurt_self_verb] yourself, like a doofus!"), + ) + user.take_bodypart_damage(10) + return TRUE + return FALSE + +/* + * Called on [COMSIG_ITEM_SHARPEN_ACT]. + * We need to track our sharpened bonus here, so we correctly apply and unapply it + * if our item's sharpness state changes from transforming. + * + * source - the item being sharpened / parent + * increment - the amount of force added + * max - the maximum force that the item can be adjusted to. + * + * Does not return naturally [COMPONENT_BLOCK_SHARPEN_APPLIED] as this is only to track our sharpened bonus between transformation. + */ +/datum/component/transforming/proc/on_sharpen(obj/item/source, increment, max) + SIGNAL_HANDLER + + if(sharpened_bonus) + return COMPONENT_BLOCK_SHARPEN_ALREADY + if(force_on + increment > max) + return COMPONENT_BLOCK_SHARPEN_MAXED + sharpened_bonus = increment diff --git a/modular_dripstation/code/datum/reagent/baldium.dm b/modular_dripstation/code/datum/reagent/baldium.dm new file mode 100644 index 000000000000..82a53e58bf36 --- /dev/null +++ b/modular_dripstation/code/datum/reagent/baldium.dm @@ -0,0 +1,16 @@ +/datum/reagent/baldium + name = "Baldium" + description = "A major cause of hair loss across the world." + reagent_state = LIQUID + color = "#ecb2cf" + taste_description = "bitterness" + +/datum/reagent/baldium/reaction_mob(mob/living/L, method=TOUCH, reac_volume, show_message=TRUE, touch_protection=FALSE) + . = ..() + if(!(method & (TOUCH|VAPOR)) || !ishuman(L)) + return + + var/mob/living/carbon/human/baldtarget = L + to_chat(baldtarget, span_danger("Your hair is falling out in clumps!")) + baldtarget.facial_hair_style = "Shaved" + baldtarget.hair_style = "Bald" diff --git a/modular_dripstation/code/datum/reagent/chemoverride.dm b/modular_dripstation/code/datum/reagent/chemoverride.dm new file mode 100644 index 000000000000..1e69ac66b919 --- /dev/null +++ b/modular_dripstation/code/datum/reagent/chemoverride.dm @@ -0,0 +1,40 @@ +/datum/reagent/medicine/mannitol + name = "Mannitolin" + description = "Generic drug that uses a patented active substance molecule to restore brain damage. Unfortunately it isn`t too effective and requires very cold temperatures to properly metabolize." + color = "#DCDCFF" + metabolization_rate = 1.5 * REAGENTS_METABOLISM + +/datum/reagent/medicine/mannitol/on_mob_life(mob/living/carbon/M) + if(M.bodytemperature < T0C) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, (holder.has_reagent(/datum/reagent/drug/methamphetamine) ? 0 : -2)*REM) + . = 1 + else + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, (holder.has_reagent(/datum/reagent/drug/methamphetamine) ? 0 : -0.2)*REM) + metabolization_rate = REAGENTS_METABOLISM * (0.00001 * (M.bodytemperature ** 2) + 0.5) + ..() + +/datum/reagent/medicine/mannitol/advanced + name = "Mannitol" + description = "Efficiently restores brain damage. Brand patented." + color = "#4CE8E2" + metabolization_rate = REAGENTS_METABOLISM + +/datum/reagent/medicine/mannitol/advanced/on_mob_life(mob/living/carbon/M) + M.adjustOrganLoss(ORGAN_SLOT_BRAIN, (holder.has_reagent(/datum/reagent/drug/methamphetamine) ? 0 : -2)*REM) + current_cycle++ + holder.remove_reagent(type, metabolization_rate / M.metabolism_efficiency) //medicine reagents stay longer if you have a better metabolism + +/datum/reagent/medicine/clonexadone + name = "Clonexadone" + description = "A chemical that derives from Cryoxadone. It specializes in healing clone damage, but nothing else. Requires very cold temperatures to properly metabolize, and metabolizes quicker than cryoxadone." + color = "#80BFFF" + taste_description = "muscle" + metabolization_rate = 1.5 * REAGENTS_METABOLISM + +/datum/reagent/medicine/clonexadone/on_mob_life(mob/living/carbon/M) + if(M.bodytemperature < T0C && M.IsSleeping()) //yes you have to be in cryo shut up and drink your corn syrup + M.adjustCloneLoss(0.001 * (M.bodytemperature ** 2) - 100, 0) + REMOVE_TRAIT(M, TRAIT_DISFIGURED, TRAIT_GENERIC) + . = 1 + metabolization_rate = REAGENTS_METABOLISM * (0.000015 * (M.bodytemperature ** 2) + 0.75) + ..() \ No newline at end of file diff --git a/modular_dripstation/code/datum/reagent/leadacetate.dm b/modular_dripstation/code/datum/reagent/leadacetate.dm new file mode 100644 index 000000000000..708ceb1c7d1e --- /dev/null +++ b/modular_dripstation/code/datum/reagent/leadacetate.dm @@ -0,0 +1,16 @@ +/datum/reagent/toxin/leadacetate + name = "Lead Acetate" + description = "Used hundreds of years ago as a sweetener, before it was realized that it's incredibly poisonous." + reagent_state = SOLID + color = "#2b2b2b" // rgb: 127, 132, 0 + toxpwr = 0.5 + taste_mult = 1.3 + taste_description = "sugary sweetness" + +/datum/reagent/toxin/leadacetate/on_mob_life(mob/living/carbon/affected_mob) + affected_mob.adjustOrganLoss(ORGAN_SLOT_EARS, 1 SECONDS * REM) + affected_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, 1 SECONDS * REM) + if(prob(5)) + to_chat(affected_mob, span_notice("Ah, what was that? You thought you heard something...")) + affected_mob.adjust_confusion(5 SECONDS) + return ..() \ No newline at end of file diff --git a/modular_dripstation/code/datum/strong_pull.dm b/modular_dripstation/code/datum/strong_pull.dm new file mode 100644 index 000000000000..8a6d851b7559 --- /dev/null +++ b/modular_dripstation/code/datum/strong_pull.dm @@ -0,0 +1,47 @@ +/* +This component attaches to mobs, and makes their pulls !strong! +Basically, the items they pull cannot be pulled (except by the puller) +*/ +/datum/component/strong_pull + var/atom/movable/strongpulling + +/datum/component/strong_pull/Initialize() + if(!isliving(parent)) + return COMPONENT_INCOMPATIBLE + +/datum/component/strong_pull/Destroy(force, silent) + if(strongpulling) + lose_strong_grip() + return ..() + +/datum/component/strong_pull/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_LIVING_START_PULL, PROC_REF(on_pull)) + +/** + * Called when the parent grabs something, adds signals to the object to reject interactions + */ +/datum/component/strong_pull/proc/on_pull(datum/source, atom/movable/pulled, state, force) + SIGNAL_HANDLER + strongpulling = pulled + RegisterSignal(strongpulling, COMSIG_ATOM_NO_LONGER_PULLED, PROC_REF(on_no_longer_pulled)) + if(istype(strongpulling, /obj/structure/closet) && !istype(strongpulling, /obj/structure/closet/body_bag)) + var/obj/structure/closet/grabbed_closet = strongpulling + grabbed_closet.strong_grab = TRUE + +/** + * Unregisters signals and stops any buffs to pulling. + */ +/datum/component/strong_pull/proc/lose_strong_grip() + UnregisterSignal(strongpulling, list(COMSIG_ATOM_CAN_BE_PULLED, COMSIG_ATOM_NO_LONGER_PULLED)) + if(istype(strongpulling, /obj/structure/closet)) + var/obj/structure/closet/ungrabbed_closet = strongpulling + ungrabbed_closet.strong_grab = FALSE + strongpulling = null + +/** + * Called when the hooked object is no longer pulled and removes the strong grip. + */ +/datum/component/strong_pull/proc/on_no_longer_pulled(datum/source, atom/movable/last_puller) + SIGNAL_HANDLER + lose_strong_grip() \ No newline at end of file diff --git a/modular_dripstation/code/game/effects/effects_foam.dm b/modular_dripstation/code/game/effects/effects_foam.dm new file mode 100644 index 000000000000..44a0869d2d5f --- /dev/null +++ b/modular_dripstation/code/game/effects/effects_foam.dm @@ -0,0 +1,30 @@ +/obj/structure/foamedmetal/attackby(obj/item/W, mob/user, params) + ///A speed modifier for how fast the wall is build + var/platingmodifier = 1 + if(HAS_TRAIT(user, TRAIT_QUICK_BUILD)) + platingmodifier = 0.7 + if(next_beep <= world.time) + next_beep = world.time + 1 SECONDS + playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE) + add_fingerprint(user) + + if(!istype(W, /obj/item/stack/sheet)) + return ..() + + var/obj/item/stack/sheet/sheet_for_plating = W + if(istype(sheet_for_plating, /obj/item/stack/sheet/metal)) + if(sheet_for_plating.get_amount() < 2) + to_chat(user, span_warning("You need two sheets of iron to finish a wall on [src]!")) + return + to_chat(user, span_notice("You start adding plating to the foam structure...")) + if (do_after(user, 40 * platingmodifier, target = src)) + if(!sheet_for_plating.use(2)) + return + to_chat(user, span_notice("You add the plating.")) + var/turf/T = get_turf(src) + T.PlaceOnTop(/turf/closed/wall/metal_foam_base) + transfer_fingerprints_to(T) + qdel(src) + return + + add_hiddenprint(user) diff --git a/modular_dripstation/code/game/mecha/cargo_hauler.dm b/modular_dripstation/code/game/mecha/cargo_hauler.dm new file mode 100644 index 000000000000..c6a106c7b396 --- /dev/null +++ b/modular_dripstation/code/game/mecha/cargo_hauler.dm @@ -0,0 +1,51 @@ +GLOBAL_DATUM(cargo_ripley, /obj/mecha/working/ripley/cargo) + +/obj/mecha/working/ripley/cargo + desc = "An ailing, old, repurposed cargo hauler. Most of its equipment wires are frayed or missing and its frame is rusted. You should handle best queen carefully." + name = "\improper APLU \"Queen Bess II\"" + icon_state = "hauler" + silicon_icon_state = "hauler-empty" + icon = 'modular_dripstation/icons/mob/mecha/cargo_hauler.dmi' + fast_pressure_step_in = 1 //step_in while in low pressure conditions, fast as fuck boi + slow_pressure_step_in = 1.3 //step_in while in normal pressure conditions + step_in = 1.3 + max_equip = 5 //modified exoskeleton power drive + max_integrity = 150 //Lesser health then have normal RIPLEY mech, so it's harder to use as a weapon. + obj_integrity = 75 //Starting at low health + internals_req_access = list(ACCESS_CARGO, ACCESS_MECH_SCIENCE) //Giving access to cargotech & robo + +/obj/mecha/working/ripley/cargo/examine(mob/user) + . = ..() + if(in_range(user, src) || isobserver(user)) + . += "Mech`s power drive looks modified." + +/obj/mecha/working/ripley/cargo/attack_hand(mob/living/carbon/human/user, params) + . = ..() + if(user.a_intent == INTENT_DISARM) + user.say("All hail the queen!") + +/obj/mecha/working/ripley/cargo/Initialize(mapload) + . = ..() + if(cell) + cell.charge = FLOOR(cell.charge * 0.33, 1) //Starts at very low charge + + //Attach hydraulic clamp ONLY + var/obj/item/mecha_parts/mecha_equipment/hydraulic_clamp/HC = new + HC.attach(src) + + take_damage(50, sound_effect=FALSE) //Low starting health + if(!GLOB.cargo_ripley && mapload) + GLOB.cargo_ripley = src + +/obj/mecha/working/ripley/cargo/Destroy() + if(GLOB.cargo_ripley == src) + GLOB.cargo_ripley = null + + return ..() + +/obj/structure/mecha_wreckage/ripley/cargo + name = "\improper APLU \"Queen Bess II\ wreckage" + desc = "Oh no, Bessy!" + icon_state = "hauler-broken" + icon = 'modular_dripstation/icons/mob/mecha/cargo_hauler.dmi' + orig_mecha = /obj/mecha/working/ripley/cargo \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/bepis_items/boomerang.dm b/modular_dripstation/code/game/objects/items/bepis_items/boomerang.dm new file mode 100644 index 000000000000..e515a2776e17 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/boomerang.dm @@ -0,0 +1,34 @@ +//bepis boomerang +/obj/item/melee/baton/boomerang + name = "\improper OZtek Boomerang" + desc = "A device invented in 2486 for the great Space Emu War by the confederacy of Australicus, these high-tech boomerangs also work exceptionally well at stunning crewmembers. Just be careful to catch it when thrown!" + throw_speed = 2 + icon = 'modular_dripstation/icons/obj/weapons/security.dmi' + lefthand_file = 'modular_dripstation/icons/mob/inhands/security_lefthand.dmi' + righthand_file = 'modular_dripstation/icons/mob/inhands/security_righthand.dmi' + icon_state = "boomerang" + item_state = "boomerang" + force = 5 + throwforce = 5 + throw_range = 5 + hitcost = 2000 + throw_hit_chance = 99 //Have you prayed today? + custom_materials = list(/datum/material/iron = 10000, /datum/material/glass = 4000, /datum/material/silver = 10000, /datum/material/gold = 1000) + +/obj/item/melee/baton/boomerang/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) + if(!status) + return ..() + var/caught = hit_atom.hitby(src, skipcatch = FALSE, hitpush = FALSE, throwingdatum = throwingdatum) + if(isliving(hit_atom) && !iscyborg(hit_atom) && !caught && prob(throw_hit_chance))//if they are a living creature and they didn't catch it + baton_stun(hit_atom, thrownby) + throw_at(thrownby, throw_range+3, throw_speed, null) + ..() + +/obj/item/melee/baton/boomerang/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, quickstart = TRUE) + if(iscarbon(thrower)) + var/mob/living/carbon/C = thrower + C.throw_mode_on() + ..() + +/obj/item/melee/baton/boomerang/loaded //Same as above, comes with a cell. + preload_cell_type = /obj/item/stock_parts/cell/high \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/bepis_items/eng_gloves.dm b/modular_dripstation/code/game/objects/items/bepis_items/eng_gloves.dm new file mode 100644 index 000000000000..039bc412e114 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/eng_gloves.dm @@ -0,0 +1,11 @@ +/obj/item/clothing/gloves/tinkerer + name = "tinker's gloves" + desc = "Overdesigned engineering gloves that have automated construction subrutines dialed in, allowing for faster construction while worn." + item_state = "concussive_gauntlets" + icon_state = "concussive_gauntlets" + icon = 'modular_dripstation/icons/obj/clothing/gloves.dmi' + mob_overlay_icon = 'modular_dripstation/icons/mob/clothing/hands.dmi' + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 70, RAD = 0, FIRE = 70, ACID = 50, ELECTRIC = 80) + clothing_flags = list(TRAIT_QUICK_BUILD) + custom_materials = list(/datum/material/iron= 2000, /datum/material/silver= 1500, /datum/material/gold = 1000) + resistance_flags = NONE \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/bepis_items/explorerpin.dm b/modular_dripstation/code/game/objects/items/bepis_items/explorerpin.dm new file mode 100644 index 000000000000..f8b7870f8c3e --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/explorerpin.dm @@ -0,0 +1,14 @@ +// Explorer Firing Pin- Prevents use on station Z-Level, so it's justifiable to give Explorers guns that don't suck. +/obj/item/firing_pin/explorer + name = "outback firing pin" + desc = "A firing pin used by the austrailian defense force, retrofit to prevent weapon discharge on the station." + icon = 'modular_dripstation/icons/obj/device.dmi' + icon_state = "firing_pin_explorer" + fail_message = "Cannot fire while on station, mate!" + +// This checks that the user isn't on the station Z-level. +/obj/item/firing_pin/explorer/pin_auth(mob/living/user) + var/turf/station_check = get_turf(user) + if(!station_check || is_station_level(station_check.z)) + return FALSE + return TRUE \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/bepis_items/hypnochair.dm b/modular_dripstation/code/game/objects/items/bepis_items/hypnochair.dm new file mode 100644 index 000000000000..fea093548bfe --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/hypnochair.dm @@ -0,0 +1,223 @@ +/obj/item/circuitboard/machine/hypnochair + name = "Enhanced Interrogation Chamber" + build_path = /obj/machinery/hypnochair + icon_state = "security" + req_components = list( + /obj/item/stock_parts/micro_laser = 2, + /obj/item/stock_parts/scanning_module = 2 + ) + + +/obj/machinery/hypnochair + name = "enhanced interrogation chamber" + desc = "A device used to perform \"enhanced interrogation\" through invasive mental conditioning." + icon = 'modular_dripstation/icons/obj/hypnochair.dmi' + icon_state = "hypnochair" + base_icon_state = "hypnochair" + circuit = /obj/item/circuitboard/machine/hypnochair + density = TRUE + opacity = FALSE + + var/mob/living/carbon/victim = null ///Keeps track of the victim to apply effects if it teleports away + var/interrogating = FALSE ///Is the device currently interrogating someone? + var/start_time = 0 ///Time when the interrogation was started, to calculate effect in case of interruption + var/trigger_phrase = "" ///Trigger phrase to implant + var/timerid = 0 ///Timer ID for interrogations + var/message_cooldown = 0 ///Cooldown for breakout message + var/resisting = FALSE ///Yeah, shitcode my beloved + +/obj/machinery/hypnochair/Initialize(mapload) + . = ..() + open_machine() + update_icon() + +/obj/machinery/hypnochair/attackby(obj/item/I, mob/user, params) + if(!occupant && default_deconstruction_screwdriver(user, icon_state, icon_state, I)) + update_icon() + return + if(default_pry_open(I)) + return + if(default_deconstruction_crowbar(I)) + return + return ..() + +/obj/machinery/hypnochair/ui_state(mob/user) + return GLOB.notcontained_state + +/obj/machinery/hypnochair/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "HypnoChair", name) + ui.open() + +/obj/machinery/hypnochair/ui_data() + var/list/data = list() + var/mob/living/mob_occupant = occupant + + data["occupied"] = mob_occupant ? 1 : 0 + data["open"] = state_open + data["interrogating"] = interrogating + + data["occupant"] = list() + if(mob_occupant) + data["occupant"]["name"] = mob_occupant.name + data["occupant"]["stat"] = mob_occupant.stat + + data["trigger"] = trigger_phrase + + return data + +/obj/machinery/hypnochair/ui_act(action, params) + . = ..() + if(.) + return + + switch(action) + if("door") + if(state_open) + close_machine() + else + if(!interrogating) + open_machine() + . = TRUE + if("set_phrase") + set_phrase(params["phrase"]) + . = TRUE + if("interrogate") + if(!interrogating) + interrogate() + else + interrupt_interrogation() + . = TRUE + +/obj/machinery/hypnochair/proc/set_phrase(phrase) + trigger_phrase = phrase + +/obj/machinery/hypnochair/proc/interrogate() + if(!trigger_phrase) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 25, TRUE) + return + var/mob/living/carbon/C = occupant + if(!istype(C)) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 25, TRUE) + return + victim = C + if(C.get_eye_protection() <= 0) + to_chat(C, span_warning("Strobing coloured lights assault you relentlessly! You're losing your ability to think straight!")) + C.become_blind(HYPNOCHAIR_TRAIT) + ADD_TRAIT(C, TRAIT_DEAF, HYPNOCHAIR_TRAIT) + interrogating = TRUE + START_PROCESSING(SSobj, src) + start_time = world.time + update_icon() + timerid = addtimer(CALLBACK(src, PROC_REF(finish_interrogation)), 450, TIMER_STOPPABLE) + +/obj/machinery/hypnochair/process(delta_time) + var/mob/living/carbon/C = occupant + if(!istype(C) || C != victim) + interrupt_interrogation() + return + if(DT_PROB(5, delta_time) && !(C.get_eye_protection() > 0)) + to_chat(C, "[pick(\ + "...blue... red... green... blue, red, green, blueredgreen[span_small("blueredgreen")]",\ + "...pretty colors...",\ + "...you keep hearing words, but you can't seem to understand them...",\ + "...so peaceful...",\ + "...an annoying buzz in your ears..."\ + )]") + + use_power(active_power_usage * delta_time) + +/obj/machinery/hypnochair/proc/finish_interrogation() + interrogating = FALSE + STOP_PROCESSING(SSobj, src) + update_icon() + var/temp_trigger = trigger_phrase + trigger_phrase = "" //Erase evidence, in case the subject is able to look at the panel afterwards + audible_message(span_notice("[src] pings!")) + playsound(src, 'sound/machines/ping.ogg', 30, TRUE) + + if(QDELETED(victim) || victim != occupant) + victim = null + return + victim.cure_blind(HYPNOCHAIR_TRAIT) + REMOVE_TRAIT(victim, TRAIT_DEAF, HYPNOCHAIR_TRAIT) + if(!(victim.get_eye_protection() > 0)) + victim.cure_trauma_type(/datum/brain_trauma/severe/hypnotic_trigger, TRAUMA_RESILIENCE_SURGERY) + if(prob(90)) + victim.gain_trauma(new /datum/brain_trauma/severe/hypnotic_trigger(temp_trigger), TRAUMA_RESILIENCE_SURGERY) + else + victim.gain_trauma(new /datum/brain_trauma/severe/hypnotic_stupor(), TRAUMA_RESILIENCE_SURGERY) + victim = null + +/obj/machinery/hypnochair/proc/interrupt_interrogation() + deltimer(timerid) + interrogating = FALSE + STOP_PROCESSING(SSobj, src) + update_icon() + + if(QDELETED(victim)) + victim = null + return + victim.cure_blind(HYPNOCHAIR_TRAIT) + REMOVE_TRAIT(victim, TRAIT_DEAF, HYPNOCHAIR_TRAIT) + if(!(victim.get_eye_protection() > 0)) + var/time_diff = world.time - start_time + switch(time_diff) + if(0 to 100) + victim.adjust_confusion(10 SECONDS) + victim.set_dizzy_if_lower(100 SECONDS) + victim.blur_eyes(100) + if(101 to 200) + victim.adjust_confusion(15 SECONDS) + victim.set_dizzy_if_lower(200 SECONDS) + victim.blur_eyes(200) + if(prob(25)) + victim.apply_status_effect(/datum/status_effect/trance, rand(50,150), FALSE) + if(201 to INFINITY) + victim.adjust_confusion(20 SECONDS) + victim.set_dizzy_if_lower(300 SECONDS) + victim.blur_eyes(300) + if(prob(65)) + victim.apply_status_effect(/datum/status_effect/trance, rand(50,150), FALSE) + victim = null + +/obj/machinery/hypnochair/update_icon_state() + if((stat & MAINT) || panel_open) + icon_state = "[base_icon_state][state_open ? "_open" : null]"+"_maintenance" + else + icon_state = "[base_icon_state][state_open ? "_open" : null][occupant ? "_[interrogating ? "active" : "occupied"]" : null]" + return ..() + +/obj/machinery/hypnochair/update_icon() + . = ..() + update_icon_state() + +/obj/machinery/hypnochair/container_resist(mob/living/user) + user.changeNext_move(CLICK_CD_BREAKOUT) + user.last_special = world.time + CLICK_CD_BREAKOUT + user.visible_message(span_notice("You see [user] kicking against the door of [src]!"), \ + span_notice("You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(600)].)"), \ + span_hear("You hear a metallic creaking from [src].")) + if(do_after(user,(600), target = src)) + if(!user || user.stat != CONSCIOUS || user.loc != src || state_open) + return + user.visible_message(span_warning("[user] successfully broke out of [src]!"), \ + span_notice("You successfully break out of [src]!")) + open_machine() + +/obj/machinery/hypnochair/relaymove(mob/living/user, direction) + if(message_cooldown <= world.time) + message_cooldown = world.time + 50 + to_chat(user, span_warning("[src]'s door won't budge!")) + if(resisting) + return + container_resist(user) + resisting = TRUE + + +/obj/machinery/hypnochair/MouseDrop_T(mob/target, mob/user) + if(HAS_TRAIT(user, TRAIT_UI_BLOCKED) || !Adjacent(user) || !user.Adjacent(target) || !isliving(target) || !user.IsAdvancedToolUser()) + return + + close_machine(target) \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/bepis_items/lava_rods.dm b/modular_dripstation/code/game/objects/items/bepis_items/lava_rods.dm new file mode 100644 index 000000000000..ad31ec9f5b7e --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/lava_rods.dm @@ -0,0 +1,84 @@ +/obj/item/stack/rods/lava + name = "heat resistant rod" + desc = "Treated, specialized iron rods. When exposed to the vaccum of space their coating breaks off, but they can hold up against the extreme heat of active lava." + singular_name = "heat resistant rod" + icon_state = "rods" + item_state = "rods" + color = "#5286b9ff" + flags_1 = CONDUCT_1 + w_class = WEIGHT_CLASS_NORMAL + materials = list(/datum/material/iron = 1000, /datum/material/plasma = 500, /datum/material/titanium = 2000) + max_amount = 30 + resistance_flags = FIRE_PROOF | LAVA_PROOF + merge_type = /obj/item/stack/rods/lava + +/obj/item/stack/rods/lava/thirty + amount = 30 + +/obj/structure/lattice/lava + name = "heatproof support lattice" + desc = "A specialized support beam for building across lava. Watch your step." + icon = 'icons/obj/smooth_structures/catwalk.dmi' + icon_state = "catwalk" + number_of_rods = 1 + color = "#5286b9ff" + obj_flags = CAN_BE_HIT + resistance_flags = FIRE_PROOF | LAVA_PROOF + +/obj/structure/lattice/lava/over + layer = CATWALK_LAYER + plane = GAME_PLANE + +/obj/structure/lattice/lava/deconstruction_hints(mob/user) + return span_notice("The rods look like they could be cut, but the heat treatment will shatter off. There's space for a tile.") + +/obj/structure/lattice/lava/attackby(obj/item/C, mob/user, params) + . = ..() + if(istype(C, /obj/item/stack/tile/plasteel)) + var/obj/item/stack/tile/plasteel/P = C + if(P.use(1)) + to_chat(user, span_notice("You construct a floor plating, as lava settles around the rods.")) + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) + new /turf/open/floor/plating(locate(x, y, z)) + else + to_chat(user, span_warning("You need one floor tile to build atop [src].")) + return + +/turf/open/lava/attackby(obj/item/C, mob/user, params) + ..() + if(istype(C, /obj/item/stack/rods/lava)) + var/obj/item/stack/rods/lava/R = C + var/obj/structure/lattice/lava/H = locate(/obj/structure/lattice/lava, src) + if(H) + to_chat(user, span_warning("There is already a lattice here!")) + return + if(R.use(1)) + to_chat(user, span_notice("You construct a lattice.")) + playsound(src, 'sound/weapons/genhit.ogg', 50, TRUE) + new /obj/structure/lattice/lava(locate(x, y, z)) + else + to_chat(user, span_warning("You need one rod to build a heatproof lattice.")) + return + // Light a cigarette in the lava + if(istype(C, /obj/item/clothing/mask/cigarette)) + var/obj/item/clothing/mask/cigarette/ciggie = C + if(ciggie.lit) + to_chat(user, span_warning("The [ciggie.name] is already lit!")) + return TRUE + var/clumsy_modifier = HAS_TRAIT(user, TRAIT_CLUMSY) ? 2 : 1 + if(prob(25 * clumsy_modifier )) + ciggie.light(span_warning("[user] expertly dips \the [ciggie.name] into [src], along with the rest of [user.p_their()] arm. What a dumbass.")) + var/obj/item/bodypart/affecting = user.get_active_hand() + affecting?.receive_damage(burn = 90) + else + ciggie.light(span_rose("[user] expertly dips \the [ciggie.name] into [src], lighting it with the scorching heat of the planet. Witnessing such a feat is almost enough to make you cry.")) + return TRUE + +/turf/open/lava/is_safe() + //if anything matching this typecache is found in the lava, we don't burn things + var/static/list/lava_safeties_typecache = typecacheof(list(/obj/structure/lattice/catwalk, /obj/structure/lattice/lava, /obj/structure/stone_tile)) + var/list/found_safeties = typecache_filter_list(contents, lava_safeties_typecache) + for(var/obj/structure/stone_tile/S in found_safeties) + if(S.fallen) + LAZYREMOVE(found_safeties, S) + return LAZYLEN(found_safeties) \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/bepis_items/party_pod.dm b/modular_dripstation/code/game/objects/items/bepis_items/party_pod.dm new file mode 100644 index 000000000000..a35f01397169 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/party_pod.dm @@ -0,0 +1,309 @@ +/obj/item/circuitboard/machine/sleeper/party + name = "Party Pod" + build_path = /obj/machinery/party + +/obj/machinery/party + name = "party pod" + desc = "'Sleeper' units were once known for their healing properties, until a lengthy investigation revealed they were also dosing patients with deadly lead acetate. This appears to be one of those old 'sleeper' units repurposed as a 'Party Pod'. It’s probably not a good idea to use it." + icon_state = "partypod" + base_icon_state = "partypod" + icon = 'modular_dripstation/icons/obj/partypod.dmi' + circuit = /obj/item/circuitboard/machine/sleeper/party + + density = FALSE + state_open = TRUE + payment_department = ACCOUNT_MED + fair_market_price = 5 + + ///How much chems is allowed to be in a patient at once, before we force them to wait for the reagent to process. + var/efficiency = 1 + ///Whether the machine can be operated by the person inside of it. + var/controls_inside = TRUE + var/enter_message = "You're surrounded by some funky music inside the chamber. You zone out as you feel waves of krunk vibe within you." + var/min_health = -25 + ///List of currently available chems. + var/list/available_chems = list() + ///Used when emagged to scramble which chem is used, eg: mutadone -> morphine + var/list/chem_buttons + //Exclusively uses non-lethal, "fun" chems. At an obvious downside. + var/list/possible_chems = list( + list( + /datum/reagent/consumable/ethanol/beer, + /datum/reagent/consumable/laughter, + ), + list( + /datum/reagent/spraytan, + /datum/reagent/barbers_aid, + ), + list( + /datum/reagent/colorful_reagent, + /datum/reagent/hair_dye, + ), + list( + /datum/reagent/drug/space_drugs, + /datum/reagent/baldium, + ), + ) + ///Chemicals that need to have a touch or vapor reaction to be applied, not the standard chamber reaction. + var/spray_chems = list( + /datum/reagent/spraytan, + /datum/reagent/hair_dye, + /datum/reagent/baldium, + /datum/reagent/barbers_aid, + ) + +/obj/machinery/party/Initialize(mapload) + . = ..() + if(mapload) + LAZYREMOVE(component_parts, circuit) + QDEL_NULL(circuit) + occupant_typecache = GLOB.typecache_living + update_icon() + reset_chem_buttons() + +/obj/machinery/party/RefreshParts() + . = ..() + var/matterbin_rating + for(var/obj/item/stock_parts/matter_bin/matterbins in component_parts) + matterbin_rating += matterbins.rating + efficiency = initial(efficiency) * matterbin_rating + min_health = initial(min_health) * matterbin_rating + + available_chems.Cut() + for(var/obj/item/stock_parts/manipulator/servos in component_parts) + for(var/i in 1 to servos.rating) + available_chems |= possible_chems[i] + + reset_chem_buttons() + +/obj/machinery/party/emag_act(mob/user, obj/item/card/emag/emag_card) + if(obj_flags & EMAGGED) + return FALSE + + balloon_alert(user, "interface scrambled") + obj_flags |= EMAGGED + + var/list/av_chem = available_chems.Copy() + for(var/chem in av_chem) + chem_buttons[chem] = pick_n_take(av_chem) //no dupes, allow for random buttons to still be correct + return TRUE + +/obj/machinery/party/proc/inject_chem(chem, mob/user) + if(obj_flags & EMAGGED) + occupant.reagents.add_reagent(/datum/reagent/toxin/leadacetate, 4) + else if (prob(20)) //You're injecting chemicals into yourself from a recalled, decrepit medical machine. What did you expect? + occupant.reagents.add_reagent(/datum/reagent/toxin/leadacetate, rand(1,3)) + if(chem in spray_chems) + var/datum/reagents/holder = new() + holder.add_reagent(chem_buttons[chem], 10) //I hope this is the correct way to do this. + holder.trans_to(occupant, 10) //, methods = VAPOR untill proc trans_to remade + playsound(src.loc, 'sound/effects/spray2.ogg', 50, TRUE, -6) + if(user) + log_combat(user, occupant, "sprayed [chem] into", addition = "via [src]") + return TRUE + if((chem in available_chems) && chem_allowed(chem)) + occupant.reagents.add_reagent(chem_buttons[chem], 10) //emag effect kicks in here so that the "intended" chem is used for all checks, for extra FUUU + if(user) + log_combat(user, occupant, "injected [chem] into", addition = "via [src]") + return TRUE + +/obj/machinery/party/proc/chem_allowed(chem) + var/mob/living/mob_occupant = occupant + if(!mob_occupant || !mob_occupant.reagents) + return + var/amount = mob_occupant.reagents.get_reagent_amount(chem) + 10 <= 20 * efficiency + var/occ_health = mob_occupant.health > min_health || chem == /datum/reagent/medicine/epinephrine + return amount && occ_health + +/obj/machinery/party/proc/reset_chem_buttons() + obj_flags &= ~EMAGGED + LAZYINITLIST(chem_buttons) + for(var/chem in available_chems) + chem_buttons[chem] = chem + + +/obj/machinery/party/update_icon() + icon_state = "[base_icon_state][state_open ? "-open" : null]" + return ..() + +/obj/machinery/party/proc/container_resist_act(mob/living/user) + visible_message(span_notice("[occupant] emerges from [src]!"), + span_notice("You climb out of [src]!")) + open_machine() + +/obj/machinery/party/Exited(atom/movable/gone, direction) + . = ..() + if (!state_open && gone == occupant) + container_resist_act(gone) + +/obj/machinery/party/relaymove(mob/living/user, direction) + if (!state_open) + container_resist_act(user) + +/obj/machinery/party/open_machine(drop = TRUE, density_to_set = FALSE) + if(!state_open && !panel_open) + flick("[initial(icon_state)]-anim", src) + return ..() + +/obj/machinery/party/close_machine(mob/user, density_to_set = TRUE) + if((isnull(user) || istype(user)) && state_open && !panel_open) + flick("[initial(icon_state)]-anim", src) + ..() + var/mob/living/mob_occupant = occupant + if(mob_occupant && mob_occupant.stat != DEAD) + to_chat(mob_occupant, "[enter_message]") + +/obj/machinery/party/emp_act(severity) + . = ..() + if (. & EMP_PROTECT_SELF) + return + if(!(stat & (NOPOWER|BROKEN|MAINT)) && occupant) + open_machine() + + +/obj/machinery/party/MouseDrop_T(mob/target, mob/user) + if(HAS_TRAIT(user, TRAIT_UI_BLOCKED) || !Adjacent(user) || !user.Adjacent(target) || !iscarbon(target) || !user.IsAdvancedToolUser()) + return + close_machine(target) + +/obj/machinery/party/screwdriver_act(mob/living/user, obj/item/I) + . = ..() + if(occupant) + to_chat(user, span_warning("[src] is currently occupied!")) + return TRUE + if(state_open) + to_chat(user, span_warning("[src] must be closed to [panel_open ? "close" : "open"] its maintenance hatch!")) + return TRUE + if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I)) + return TRUE + return FALSE + +/obj/machinery/party/wrench_act(mob/living/user, obj/item/I) + . = ..() + if(default_change_direction_wrench(user, I)) + return TRUE + return FALSE + +/obj/machinery/party/crowbar_act(mob/living/user, obj/item/I) + . = ..() + if(default_pry_open(I)) + return TRUE + if(default_deconstruction_crowbar(I)) + return TRUE + return FALSE + +/obj/machinery/party/default_pry_open(obj/item/I) //wew + . = !(state_open || panel_open || (flags_1 & NODECONSTRUCT_1)) && I.tool_behaviour == TOOL_CROWBAR + if(.) + I.play_tool_sound(src, 50) + visible_message(span_notice("[usr] pries open [src]."), span_notice("You pry open [src].")) + open_machine() + +/obj/machinery/party/ui_state(mob/user) + if(!controls_inside) + return GLOB.notcontained_state + return GLOB.default_state + +/obj/machinery/party/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Party", name) + ui.open() + +/obj/machinery/party/AltClick(mob/user) + . = ..() + if(state_open) + close_machine() + else + open_machine() + +/obj/machinery/party/examine(mob/user) + . = ..() + . += span_notice("Alt-click [src] to [state_open ? "close" : "open"] it.") + +/obj/machinery/party/process() + ..() + use_power(idle_power_usage) + +/obj/machinery/party/nap_violation(mob/violator) + . = ..() + open_machine() + +/obj/machinery/party/ui_data() + var/list/data = list() + data["occupied"] = !!occupant + data["open"] = state_open + + data["chems"] = list() + for(var/chem in available_chems) + var/datum/reagent/R = GLOB.chemical_reagents_list[chem] + data["chems"] += list( + list( + "name" = R.name, + "id" = R.type, + "allowed" = chem_allowed(chem), + ), + ) + + data["occupant"] = list() + var/mob/living/mob_occupant = occupant + if(mob_occupant) + data["occupant"]["name"] = mob_occupant.name + switch(mob_occupant.stat) + if(CONSCIOUS) + data["occupant"]["stat"] = "Conscious" + data["occupant"]["statstate"] = "good" + if(SOFT_CRIT) + data["occupant"]["stat"] = "Conscious" + data["occupant"]["statstate"] = "average" + if(UNCONSCIOUS) + data["occupant"]["stat"] = "Unconscious" + data["occupant"]["statstate"] = "average" + if(DEAD) + data["occupant"]["stat"] = "Dead" + data["occupant"]["statstate"] = "bad" + data["occupant"]["health"] = mob_occupant.health + data["occupant"]["maxHealth"] = mob_occupant.maxHealth + data["occupant"]["minHealth"] = HEALTH_THRESHOLD_DEAD + data["occupant"]["bruteLoss"] = mob_occupant.getBruteLoss() + data["occupant"]["oxyLoss"] = mob_occupant.getOxyLoss() + data["occupant"]["toxLoss"] = mob_occupant.getToxLoss() + data["occupant"]["fireLoss"] = mob_occupant.getFireLoss() + data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss() + data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN) + data["occupant"]["reagents"] = list() + if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len) + for(var/datum/reagent/R in mob_occupant.reagents.reagent_list) + data["occupant"]["reagents"] += list( + list( + "name" = R.name, + "volume" = R.volume, + ), + ) + + return data + +/obj/machinery/party/ui_act(action, params) + . = ..() + if(.) + return + + var/mob/living/mob_occupant = occupant + check_nap_violations() + switch(action) + if("door") + if(state_open) + close_machine() + else + open_machine() + . = TRUE + if("inject") + var/chem = text2path(params["chem"]) + if((stat & (NOPOWER|BROKEN|MAINT)) || !mob_occupant || isnull(chem)) + return + if(mob_occupant.health < min_health && !ispath(chem, /datum/reagent/medicine/epinephrine)) + return + if(inject_chem(chem, usr)) + . = TRUE + if((obj_flags & EMAGGED) && prob(5)) + to_chat(usr, span_warning("Chemical system re-route detected, results may not be as expected!")) \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/bepis_items/polycircuit.dm b/modular_dripstation/code/game/objects/items/bepis_items/polycircuit.dm new file mode 100644 index 000000000000..c10d74a8960a --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/polycircuit.dm @@ -0,0 +1,59 @@ +/obj/item/stack/circuit_stack + name = "polycircuit aggregate" + desc = "A dense, overdesigned cluster of electronics which attempted to function as a multipurpose circuit electronic. Circuits can be removed from it... if you don't bleed out in the process." + icon = 'modular_dripstation/icons/obj/circuit_mess.dmi' + icon_state = "circuit_mess" + item_state = "rods" + w_class = WEIGHT_CLASS_TINY + max_amount = 8 + merge_type = /obj/item/stack/circuit_stack + singular_name = "circuit aggregate" + var/circuit_type = /obj/item/electronics/airlock + var/chosen_circuit = "airlock" + +/obj/item/stack/circuit_stack/attack_self(mob/user)// Prevents the crafting menu, and tells you how to use it. + to_chat(user, span_warning("You can't use [src] by itself, you'll have to try and remove one of these circuits by hand... carefully.")) + +/obj/item/stack/circuit_stack/attack_hand(mob/user, list/modifiers) + var/mob/living/carbon/human/H = user + if(user.get_inactive_held_item() != src) + return ..() + else + if(zero_amount()) + return + chosen_circuit = tgui_input_list(user, "Circuit to remove", "Circuit Removal", list("airlock","firelock","fire alarm","air alarm","APC"), chosen_circuit) + if(isnull(chosen_circuit)) + to_chat(user, span_notice("You wisely avoid putting your hands anywhere near [src].")) + return + if(zero_amount()) + return + if(loc != user) + return + switch(chosen_circuit) + if("airlock") + circuit_type = /obj/item/electronics/airlock + if("firelock") + circuit_type = /obj/item/electronics/firelock + if("fire alarm") + circuit_type = /obj/item/electronics/firealarm + if("air alarm") + circuit_type = /obj/item/electronics/airalarm + if("APC") + circuit_type = /obj/item/electronics/apc + to_chat(user, span_notice("You spot your circuit, and carefully attempt to remove it from [src], hold still!")) + if(do_after(user, 30, target = user)) + if(!src || QDELETED(src))//Sanity Check. + return + var/returned_circuit = new circuit_type(src) + user.put_in_hands(returned_circuit) + use(1) + if(!amount) + to_chat(user, span_notice("You navigate the sharp edges of circuitry and remove the last board.")) + else + to_chat(user, span_notice("You navigate the sharp edges of circuitry and remove a single board from [src]")) + else + H.apply_damage(15, BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) + to_chat(user, span_warning("You give yourself a wicked cut on [src]'s many sharp corners and edges!")) + +/obj/item/stack/circuit_stack/full + amount = 8 diff --git a/modular_dripstation/code/game/objects/items/bepis_items/rldmini.dm b/modular_dripstation/code/game/objects/items/bepis_items/rldmini.dm new file mode 100644 index 000000000000..c59ca00262d0 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/rldmini.dm @@ -0,0 +1,5 @@ +/obj/item/construction/rld/mini + name = "mini-rapid-light-device" + desc = "A device used to rapidly provide lighting sources to an area. Reload with iron, plasteel, glass or compressed matter cartridges." + matter = 100 + max_matter = 100 \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/bepis_items/sprayoncan.dm b/modular_dripstation/code/game/objects/items/bepis_items/sprayoncan.dm new file mode 100644 index 000000000000..71a5f8c01212 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/sprayoncan.dm @@ -0,0 +1,48 @@ +/obj/item/toy/sprayoncan + name = "spray-on insulation applicator" + desc = "What is the number one problem facing our station today?" + icon = 'modular_dripstation/icons/obj/clothing/gloves.dmi' + icon_state = "sprayoncan" + +/obj/item/toy/sprayoncan/afterattack(atom/target, mob/living/carbon/user, proximity) + if(iscarbon(target) && proximity) + var/mob/living/carbon/C = target + var/mob/living/carbon/U = user + var/obj/item/clothing/gloves/color/yellow/sprayon/spr = new(src) + var/success = C.equip_to_slot_or_del(spr, ITEM_SLOT_GLOVES) + if(success) + if(C == U) + C.visible_message(span_notice("[U] sprays their hands with glittery rubber!")) + else + C.visible_message(span_warning("[U] sprays glittery rubber on the hands of [C]!")) + else + C.visible_message(span_warning("The rubber fails to stick to [C]'s hands!")) + +/obj/item/clothing/gloves/color/yellow/sprayon + desc = "How're you gonna get 'em off, nerd?" + name = "spray-on insulated gloves" + icon = 'modular_dripstation/icons/obj/clothing/gloves.dmi' + mob_overlay_icon = 'modular_dripstation/icons/mob/clothing/hands.dmi' + icon_state = "sprayon" + item_state = "sprayon" + item_flags = DROPDEL + resistance_flags = ACID_PROOF + var/charges_remaining = 10 + +/obj/item/clothing/gloves/color/yellow/sprayon/Initialize(mapload) + .=..() + ADD_TRAIT(src, TRAIT_NODROP, INNATE_TRAIT) + +/obj/item/clothing/gloves/color/yellow/sprayon/equipped(mob/user, slot) + . = ..() + RegisterSignal(user, COMSIG_LIVING_SHOCK_PREVENTED, PROC_REF(use_charge)) + RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(use_charge)) + +/obj/item/clothing/gloves/color/yellow/sprayon/proc/use_charge() + SIGNAL_HANDLER + + charges_remaining-- + if(charges_remaining <= 0) + var/turf/location = get_turf(src) + location.visible_message(span_warning("[src] crumble[p_s()] away into nothing.")) // just like my dreams after working with .dm + qdel(src) \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/bepis_items/survival_pen.dm b/modular_dripstation/code/game/objects/items/bepis_items/survival_pen.dm new file mode 100644 index 000000000000..9238fc9e9c76 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/bepis_items/survival_pen.dm @@ -0,0 +1,21 @@ +/obj/item/pen/fountain/survival + name = "survival pen" + desc = "The latest in portable survival technology, this pen was designed as a miniature hardlight shovel. Watchers find them very desirable for their diamond exterior." + icon = 'modular_dripstation/icons/obj/bureaucracy.dmi' + icon_state = "digging_pen" + item_state = "pen" + force = 8 //hard light beats hard, still weaker than the kitchen knife + throwforce = 0 //ineffective at long range + sharpness = SHARP_EDGED // Sharp shovel + resistance_flags = FIRE_PROOF //lavaland is dangerous + attack_verb = list("robusted", "slashed", "stabbed", "sliced", "thrashed", "whacked") + custom_materials = list(/datum/material/iron = 100, /datum/material/diamond = 200, /datum/material/titanium = 100) + pressure_resistance = 2 * ONE_ATMOSPHERE + grind_results = list(/datum/reagent/iron = 2, /datum/reagent/iodine = 1) + tool_behaviour = TOOL_MINING //For the classic "digging out of prison with a spoon but you're in space so this analogy doesn't work" situation. + toolspeed = 2 //You will never willingly choose to use one of these over a shovel. + hitsound = 'sound/weapons/blade1.ogg' + +/obj/item/pen/fountain/survival/Initialize() + . = ..() + AddComponent(/datum/component/butchering, 60, 100, 0, 'sound/weapons/blade1.ogg') //it's a strange hardlight tech \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/blackmarketstuff.dm b/modular_dripstation/code/game/objects/items/blackmarketstuff.dm new file mode 100644 index 000000000000..4d8f1de8d7bb --- /dev/null +++ b/modular_dripstation/code/game/objects/items/blackmarketstuff.dm @@ -0,0 +1,17 @@ +/obj/item/reagent_containers/glass/beaker/thermite + name = "thermite beaker" + desc = "Beaker with thermite. Danger, flammable." + list_reagents = list(/datum/reagent/thermite = 30) + +/obj/item/clothing/shoes/bhop/rocket + name = "rocket boots" + desc = "Very special boots with built-in rocket thrusters! SHAZBOT!" + icon_state = "rocketboots" + icon = 'modular_dripstation/icons/obj/clothing/shoes.dmi' + actions_types = list(/datum/action/cooldown/boost/brocket) + jumpdistance = 20 //great for throwing yourself into walls and people at high speeds + jumpspeed = 5 + +/datum/action/cooldown/boost/brocket + name = "Activate Rocket Boots" + desc = "Activates the boot's rocket propulsion system, allowing the user to hurl themselves great distances." \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/cargo_boxcutter.dm b/modular_dripstation/code/game/objects/items/cargo_boxcutter.dm new file mode 100644 index 000000000000..5b76290d89cc --- /dev/null +++ b/modular_dripstation/code/game/objects/items/cargo_boxcutter.dm @@ -0,0 +1,46 @@ +/obj/item/boxcutter + name = "boxcutter" + desc = "A tool for cutting boxes, or throats." + icon = 'modular_dripstation/icons/obj/cargo/boxcutter.dmi' + icon_state = "boxcutter" + item_state = "boxcutter" + lefthand_file = 'modular_dripstation/icons/mob/inhands/equipment/boxcutter_lefthand.dmi' + righthand_file = 'modular_dripstation/icons/mob/inhands/equipment/boxcutter_righthand.dmi' + attack_verb = list("proded", "poked") + w_class = WEIGHT_CLASS_SMALL + slot_flags = ITEM_SLOT_BELT + resistance_flags = FIRE_PROOF + force = 0 + bare_wound_bonus = 20 + /// Used on Initialize, how much time to cut cable restraints and zipties. + //var/snap_time_weak_handcuffs = 0 SECONDS + /// Used on Initialize, how much time to cut real handcuffs. Null means it can't. + //var/snap_time_strong_handcuffs = null + +/obj/item/boxcutter/Initialize(mapload) + . = ..() + AddComponent(/datum/component/butchering, 70, 100) + + AddComponent( \ + /datum/component/transforming, \ + force_on = 10, \ + throwforce_on = 4, \ + throw_speed_on = throw_speed, \ + sharpness_on = SHARP_EDGED, \ + hitsound_on = 'sound/weapons/bladeslice.ogg', \ + w_class_on = WEIGHT_CLASS_NORMAL, \ + attack_verb_on = list("cuted", "stabed", "slashed"), \ + ) + + RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) + +/obj/item/boxcutter/proc/on_transform(obj/item/source, mob/user, active) + SIGNAL_HANDLER + + playsound(src, 'modular_dripstation/sound/item/boxcutter_activate.ogg', 50) + //tool_behaviour = (active ? TOOL_KNIFE : NONE) + //if(active) + // AddElement(/datum/element/cuffsnapping, snap_time_weak_handcuffs, snap_time_strong_handcuffs) + //else + // RemoveElement(/datum/element/cuffsnapping, snap_time_weak_handcuffs, snap_time_strong_handcuffs) + //return COMPONENT_NO_DEFAULT_MESSAGE diff --git a/modular_dripstation/code/game/objects/items/cargo_inducer.dm b/modular_dripstation/code/game/objects/items/cargo_inducer.dm new file mode 100644 index 000000000000..b9b0eb579fbe --- /dev/null +++ b/modular_dripstation/code/game/objects/items/cargo_inducer.dm @@ -0,0 +1,12 @@ +/obj/item/inducer/cargo + name = "inducer" + icon_state = "inducer-cargo" + icon = 'modular_dripstation/icons/obj/cargo/cargo_inducer.dmi' + desc = "A tool for inductively charging internal power cells. This one has a cargo color scheme, and is less potent than its engineering counterpart." + cell_type = /obj/item/stock_parts/cell/high/empty + powertransfer = 500 + opened = TRUE + +/obj/item/inducer/cargo/Initialize() + . = ..() + update_icon() \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/cargo_teleporter.dm b/modular_dripstation/code/game/objects/items/cargo_teleporter.dm new file mode 100644 index 000000000000..91943a298afd --- /dev/null +++ b/modular_dripstation/code/game/objects/items/cargo_teleporter.dm @@ -0,0 +1,320 @@ +GLOBAL_LIST_EMPTY(cargo_marks) + +/obj/item/cargo_teleporter + name = "cargo handheld teleporter" + desc = "Specialised personal teleporter based on modern bluespace technology. This one issued to QM for moving crates, closets and none-living objects to previously marked locations." + icon = 'modular_dripstation/icons/obj/cargo/cargo_teleporter.dmi' + mob_overlay_icon = 'modular_dripstation/icons/mob/clothing/belt.dmi' + lefthand_file = 'modular_dripstation/icons/mob/inhands/equipment/cargo_teleporter_lefthand.dmi' + righthand_file = 'modular_dripstation/icons/mob/inhands/equipment/cargo_teleporter_righthand.dmi' + icon_state = "cargo_tele" + item_state = "cargo_tele" + materials = list(MAT_METAL=10000) + slot_flags = ITEM_SLOT_BELT + cryo_preserve = TRUE + flags_1 = CONDUCT_1 + force = 10 + throwforce = 10 + throw_speed = 3 + throw_range = 5 + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 30, BIO = 0, RAD = 0, FIRE = 100, ACID = 100) + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + var/list/marker_children = list() //the list of markers spawned by this item + var/choice //storing marker of choice + var/cooldown_in_seconds = 16 SECONDS //cooldown, made for upgrades + var/emagged = FALSE //emagged? + var/emped = FALSE //emped? + verb_say = "beeps" + verb_exclaim = "blares" + var/obj/item/stock_parts/manipulator/manipulator = null + var/obj/item/stock_parts/cell/high/ctcell = null // Power cell (10000W) + var/chargecost = 1000 // How much energy tele use + var/static/list/high_risk_teleporting = typecacheof(list( + /obj/item/disk/nuclear, + /obj/item/gun/energy/laser/captain, + /obj/item/hand_tele, + /obj/item/clothing/accessory/medal/gold/captain, + /obj/item/melee/sabre, + /obj/item/clothing/gloves/krav_maga/sec, + /obj/item/gun/energy/e_gun/hos, + /obj/item/card/id/captains_spare, + /obj/item/tank/jetpack/oxygen/captain, + /obj/item/aicard, + /obj/item/hypospray/deluxe/cmo, + /obj/item/clothing/suit/armor/reactive/teleport, + /obj/item/clothing/suit/armor/laserproof, + /obj/item/blackbox, + /obj/item/holotool, + /obj/item/areaeditor/blueprints) + ) + var/static/list/blacklisted_turfs = typecacheof(list( + /turf/closed, + /turf/open/chasm, + /turf/open/lava)) + var/static/list/deathtrap_list = typecacheof(list( + /obj/machinery/power/supermatter_crystal, + /obj/machinery/conveyor, + /obj/machinery/recycler)) + + COOLDOWN_DECLARE(use_cooldown) + +/obj/item/cargo_teleporter/get_cell() + return ctcell + +/obj/item/cargo_teleporter/Initialize() + . = ..() + manipulator = new /obj/item/stock_parts/manipulator(src) + ctcell = new(src) + +/obj/item/cargo_teleporter/emp_act(severity) + if (. & EMP_PROTECT_SELF) + return + emped = TRUE + SStgui.close_uis(src) //Close the UI control if it is open. I guess do not work, will work with ui refactor, if it will be made some day + if(severity > EMP_LIGHT) + ctcell.charge = 0 + if(emagged) + emagged = FALSE + if(prob(50)) + var/mob/living/carbon/human/user = src.loc + say("E:FATAL:PWR_BUS_OVERLOAD") + if(user.is_holding(src)) + if(user.dna && user.dna.species.id == "human") + say("E:FATAL:STACK_EMPTY\nE:FATAL:READ_NULL_POINT") + to_chat(user, span_danger("An electromagnetic pulse disrupts your hacked teleporter and violently turns you into abomination.")) + to_chat(user, span_userdanger("You SEE THE LIGHT.")) + user.set_species(/datum/species/moth) + else + ctcell.use(chargecost) + if(emagged) + emagged = FALSE + +/obj/item/cargo_teleporter/examine(mob/user) + . = ..() + if(in_range(user, src) || isobserver(user)) + if(emagged) + . += "Warning: Safety protocols disabled." + if(!manipulator) + . += "The manipulator is missing." + else + . += "A tier [manipulator.rating] manipulator is installed. It is screwed in place." + . += "There are [round(ctcell.charge/chargecost)] charge\s left." + . += span_notice("Attack itself to set down the markers!") + . += span_notice("ALT-CLICK to change destination marker!") + +/obj/item/cargo_teleporter/Destroy() + if(length(marker_children)) + for(var/obj/effect/decal/cleanable/cargo_mark/destroy_children in marker_children) + destroy_children.parent_item = null + qdel(destroy_children) + QDEL_NULL(manipulator) + QDEL_NULL(ctcell) + return ..() + +/obj/item/cargo_teleporter/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/stock_parts/manipulator)) + if(!manipulator) + if(!user.transferItemToLoc(W, src)) + return + manipulator = W + playsound(src, 'sound/machines/click.ogg', 25) + to_chat(user, span_notice("You install a [manipulator.name] in [src].")) + else + to_chat(user, span_notice("[src] already has a manipulator installed.")) + +/obj/item/cargo_teleporter/screwdriver_act(mob/living/user, obj/item/I) + if(manipulator) + I.play_tool_sound(src) + to_chat(user, span_notice("You remove the [manipulator.name] from \the [src].")) + manipulator.forceMove(drop_location()) + manipulator = null + +/obj/item/cargo_teleporter/emag_act(user) + if(!emagged) + emagged = TRUE + do_sparks(3, TRUE, src) + say("SAFETY PROTOCOLS OVERRIDE DETECTED!") + return + +/obj/item/cargo_teleporter/attack_self(mob/user, modifiers) + if(isnull(manipulator)) + say("\The [src] is missing it's manipulator, and cannot function.") + return + var/turf/current_location = get_turf(user)//What turf is the user on? + var/area/current_area = current_location.loc + if(!current_location || current_area.noteleport || is_away_level(current_location.z) || !isturf(user.loc))//If turf was not found or they're on z level 2 or >7 which does not currently exist. or if user is not located on a turf + say("\The [src] is malfunctioning.") + return + if(!is_station_level(current_location.z)) + var/lava_emag + if(emagged & is_mining_level(current_location.z)) + lava_emag = TRUE + if(!lava_emag) + say("Error 503. Marker location undefined. Bluespace signal is not tracing. Try again onboard.") + return + if(isspaceturf(current_location)) + say("You cannot place markers in space.") + return + if(is_type_in_typecache(current_location, blacklisted_turfs)) + say("You cannot place markers here.") + return + if(length(marker_children) >= manipulator.rating) + say("You may only have [manipulator.rating] spawned markers from [src].") + return + if(locate(/obj/effect/decal/cleanable/cargo_mark) in current_location) + say("There is already a marker here.") + return + var/obj/effect/decal/cleanable/cargo_mark/spawned_marker = new /obj/effect/decal/cleanable/cargo_mark(get_turf(src)) + to_chat(user, span_notice("You place a cargo marker below your feet.")) + playsound(src, 'sound/machines/click.ogg', 50) + spawned_marker.parent_item = src + marker_children += spawned_marker + +/obj/item/cargo_teleporter/AltClick(mob/user) + if(!user.is_holding(src)) + to_chat(user, span_notice("You should be able to press the change destination button to to interact with interface.")) + return + if(emped) + to_chat(user, "Teleporter restarts by itself!") + playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, 3) + emped = FALSE + choice = null + return + makingchoice(user) + +/obj/item/cargo_teleporter/proc/makingchoice(mob/user) + choice = tgui_input_list(user, "Select which cargo mark to teleport the items to?", "Cargo Mark Selection", GLOB.cargo_marks) + if(!choice) + return + + +/obj/item/cargo_teleporter/verb/remove_all_markers() + set name = "Cargo Tele: Remove All Markers" + set category = "Object" + + if(!usr.is_holding(src)) + return + if(length(marker_children)) + for(var/obj/effect/decal/cleanable/cargo_mark/destroy_children in marker_children) + qdel(destroy_children) + marker_children = list() + choice = null + playsound(src, 'sound/machines/click.ogg', 50) + to_chat(usr, span_notice("You destroyed all markers.")) + +/obj/item/cargo_teleporter/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + if(!user.is_holding(src)) + to_chat(user, span_notice("You should be able to press the teleportation button to be able teleport something.")) + return ..() + if(isnull(manipulator)) + say("\The [src] is missing it's manipulator, and cannot function.") + return ..() + if(ctcell.charge < chargecost) + say("Unable to teleport, insufficient charge.") + return ..() + if(!emagged && !proximity_flag) + return ..() + if(emagged && (get_dist(user, target) > manipulator.rating)) + return ..() + if(target == src) + return ..() + if(emped) + say("\The [src] malfunctioning and needs to be restarted.") + to_chat(user, span_notice("AltClick on device to restart it.")) + return ..() + if(!COOLDOWN_FINISHED(src, use_cooldown)) + say("\The [src] is still on cooldown.") + return + if(!choice) + return makingchoice(user) + var/turf/moving_turf = get_turf(choice) + var/turf/target_turf = get_turf(target) + var/area/current_area = target_turf.loc + if(current_area.noteleport)//If z level disables teleportation + say("\The [src] is malfunctioning.") + return + var/destination_incorrect = FALSE //prevent spamming on one turf and primitive deathraps + for(var/deathtrap_check in moving_turf.contents) //deathrap checking + if(emagged & is_type_in_typecache(deathtrap_check, deathtrap_list)) //preventing oneclick deathraps, say no to oneturf recycler bins + destination_incorrect = TRUE + continue + if(moving_turf == target_turf) //die spamm + destination_incorrect = TRUE + continue + if(destination_incorrect) //prevent oneturf sound spamming and primitive deathraps + say("Teleportation error detected. Destination incorrect.") + playsound(src, 'sound/machines/terminal_alert.ogg', 50) + return ..() + var/dust = FALSE + for(var/check_content in target_turf.contents) + if(isobserver(check_content)) + continue + if(!ismovable(check_content)) + continue + if(is_type_in_typecache(check_content, high_risk_teleporting)) + playsound(src, 'sound/machines/terminal_alert.ogg', 50) + continue + var/atom/movable/movable_content = check_content + if(isliving(movable_content) && !emagged) + playsound(src, 'sound/machines/terminal_alert.ogg', 50) + continue + if(HAS_TRAIT(movable_content, TRAIT_NO_TELEPORT)) + playsound(src, 'sound/machines/terminal_alert.ogg', 50) + continue + if(length(movable_content.get_all_contents_type(/mob/living)) && !emagged) + playsound(src, 'sound/machines/terminal_alert.ogg', 50) + continue + if(length(typecache_filter_list(movable_content.get_all_contents_type(/obj/item), high_risk_teleporting))) + playsound(src, 'sound/machines/terminal_alert.ogg', 50) + continue + if(movable_content.anchored) + continue + if(length(movable_content.get_all_contents_type(/obj/item/cargo_teleporter))) + playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, 1) + say("Teleportation error detected. Do not try teleport teleporter.") + continue + dust = TRUE + do_teleport(movable_content, moving_turf, asoundout = 'sound/magic/Disable_Tech.ogg') + if(dust) + new /obj/effect/decal/cleanable/ash(target_turf) + ctcell.use(chargecost) + say("Teleportation successful. [round(ctcell.charge/chargecost)] charge\s left.") + cooldown_in_seconds -= (manipulator.rating * 2) + COOLDOWN_START(src, use_cooldown, cooldown_in_seconds) + +/obj/effect/decal/cleanable/cargo_mark + name = "cargo mark" + desc = "A mark left behind by a cargo teleporter, which allows targeted teleportation. Can be removed by the cargo teleporter." + icon = 'modular_dripstation/icons/obj/cargo/cargo_teleporter.dmi' + icon_state = "marker" + ///the reference to the item that spawned the cargo mark + var/obj/item/cargo_teleporter/parent_item + + light_range = 3 + light_color = COLOR_VIVID_YELLOW + +/obj/effect/decal/cleanable/cargo_mark/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/cargo_teleporter)) + to_chat(user, span_notice("You remove [src] using [W].")) + playsound(src, 'sound/machines/click.ogg', 50) + if(parent_item.choice) + if(get_turf(parent_item.choice) == get_turf(src)) + parent_item.choice = null + qdel(src) + return + return ..() + +/obj/effect/decal/cleanable/cargo_mark/Destroy() + if(parent_item) + parent_item.marker_children -= src + if(parent_item.choice) + if(get_turf(parent_item.choice) == get_turf(src)) + parent_item.choice = null + GLOB.cargo_marks -= src + return ..() + +/obj/effect/decal/cleanable/cargo_mark/Initialize(mapload, list/datum/disease/diseases) + . = ..() + var/area/src_area = get_area(src) + name = "[src_area.name] ([rand(100000,999999)])" + GLOB.cargo_marks += src diff --git a/modular_dripstation/code/game/objects/items/clothing/gloves.dm b/modular_dripstation/code/game/objects/items/clothing/gloves.dm new file mode 100644 index 000000000000..7c59113fcdc7 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/clothing/gloves.dm @@ -0,0 +1,66 @@ +/obj/item/clothing/gloves/cargo_gauntlet + name = "\improper cargo gauntlets" + desc = "These rubberized gauntlets have high adhesion to the metal surface that allows you to drag crates and lockers with more confidence on them not getting nabbed from you." + icon = 'modular_dripstation/icons/obj/clothing/gloves.dmi' + mob_overlay_icon = 'modular_dripstation/icons/mob/clothing/hands.dmi' + icon_state = "cargogloves" + item_state = "cargogloves" + cold_protection = HANDS + heat_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT + undyeable = TRUE + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 50, ELECTRIC = 60) + var/datum/weakref/pull_component_weakref + +/obj/item/clothing/gloves/cargo_gauntlet/Initialize(mapload) + . = ..() + RegisterSignal(src, COMSIG_ITEM_EQUIPPED, PROC_REF(on_glove_equip)) + RegisterSignal(src, COMSIG_ITEM_POST_UNEQUIP, PROC_REF(on_glove_unequip)) + +/// Called when the glove is equipped. Adds a component to the equipper and stores a weak reference to it. +/obj/item/clothing/gloves/cargo_gauntlet/proc/on_glove_equip(datum/source, mob/equipper, slot) + SIGNAL_HANDLER + + if(!(slot & ITEM_SLOT_GLOVES)) + return + + var/datum/component/strong_pull/pull_component = pull_component_weakref?.resolve() + if(pull_component) + stack_trace("Gloves already have a pull component associated with \[[pull_component.parent]\] when \[[equipper]\] is trying to equip them.") + QDEL_NULL(pull_component_weakref) + + to_chat(equipper, span_notice("You feel the gauntlets activate as soon as you fit them on, making your pulls stronger!")) + + pull_component_weakref = WEAKREF(equipper.AddComponent(/datum/component/strong_pull)) + +/* + * Called when the glove is unequipped. Deletes the component if one exists. + * + * No component being associated on equip is a valid state, as holding the gloves in your hands also counts + * as having them equipped, or even in pockets. They only give the component when they're worn on the hands. + */ +/obj/item/clothing/gloves/cargo_gauntlet/proc/on_glove_unequip(datum/source, force, atom/newloc, no_move, invdrop, silent) + SIGNAL_HANDLER + + var/datum/component/strong_pull/pull_component = pull_component_weakref?.resolve() + + if(!pull_component) + return + + to_chat(pull_component.parent, span_warning("You have lost the grip power of [src]!")) + + QDEL_NULL(pull_component_weakref) + + +/obj/item/clothing/gloves/krav_maga/sec + name = "krav maga gloves" + desc = "These gloves can teach you to perform Krav Maga using nanochips." + icon_state = "fightgloves" + item_state = "fightgloves" + cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT + heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT + resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF + cryo_preserve = TRUE \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/devices/PDA/PDA_types.dm b/modular_dripstation/code/game/objects/items/devices/PDA/PDA_types.dm new file mode 100644 index 000000000000..24a06170d713 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/devices/PDA/PDA_types.dm @@ -0,0 +1,2 @@ +/obj/item/pda/quartermaster + insert_type = /obj/item/pen/fountain/survival \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/projectiles/guns/ballistic/rifle.dm b/modular_dripstation/code/game/objects/items/projectiles/guns/ballistic/rifle.dm new file mode 100644 index 000000000000..2425712e6b78 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/projectiles/guns/ballistic/rifle.dm @@ -0,0 +1,30 @@ +/obj/item/gun/ballistic/rifle/boltaction/brand_new + desc = "A brand new Mosin Nagant issued by Nanotrasen for their interns. You would rather not to damage it." + icon_state = "mosinprime" + item_state = "mosinprime" + sawn_desc = "A sawn-off Brand New Nagant... Doing this was a sin, I hope you're happy. \ + You are now probably one of the few people in the universe to ever hold a \"Brand New Obrez\". \ + Even thinking about that name combination makes you ill." + icon = 'modular_dripstation/icons/obj/weapons/48x32.dmi' + mob_overlay_icon = 'modular_dripstation/icons/mob/clothing/guns_on_back.dmi' + lefthand_file = 'modular_dripstation/icons/mob/inhands/guns_lefthand.dmi' + righthand_file = 'modular_dripstation/icons/mob/inhands/guns_righthand.dmi' + +/obj/item/gun/ballistic/rifle/boltaction/brand_new/sawoff(mob/user) + . = ..() + if(.) + name = "\improper Brand New Obrez" // wear it loud and proud + +/obj/item/gun/ballistic/rifle/boltaction/qmrifle + name = "\improper 'Forbidden' precision rifle" + desc = "Modernized boltaction rifle, the frame feels robust as cargotech liver. \ + This thing was probably built with a conversion kit from a shady NTnet site. \ +

\ + BRAND NEW: Cannot be sawn off." + icon = 'modular_dripstation/icons/obj/weapons/48x32.dmi' + mob_overlay_icon = 'modular_dripstation/icons/mob/clothing/guns_on_back.dmi' + lefthand_file = 'modular_dripstation/icons/mob/inhands/guns_lefthand.dmi' + righthand_file = 'modular_dripstation/icons/mob/inhands/guns_righthand.dmi' + icon_state = "mosintactical" + item_state = "mosintactical" + can_be_sawn_off = FALSE \ No newline at end of file diff --git a/modular_dripstation/code/game/objects/items/tanks/watertank.dm b/modular_dripstation/code/game/objects/items/tanks/watertank.dm new file mode 100644 index 000000000000..394f296971e7 --- /dev/null +++ b/modular_dripstation/code/game/objects/items/tanks/watertank.dm @@ -0,0 +1,6 @@ +/obj/item/reagent_containers/spray/mister/janitor + possible_transfer_amounts = list(5, 10) + +/obj/item/reagent_containers/spray/mister/janitor/attack_self(var/mob/user) + amount_per_transfer_from_this = (amount_per_transfer_from_this == 10 ? 5 : 10) + to_chat(user, span_notice("You [amount_per_transfer_from_this == 10 ? "remove" : "affix"] the nozzle. You'll now use [amount_per_transfer_from_this] units per spray.")) \ No newline at end of file diff --git a/modular_dripstation/code/game/turfs/simulated/walls.dm b/modular_dripstation/code/game/turfs/simulated/walls.dm new file mode 100644 index 000000000000..50ce45791c7f --- /dev/null +++ b/modular_dripstation/code/game/turfs/simulated/walls.dm @@ -0,0 +1,2 @@ +/turf/closed/wall/metal_foam_base + girder_type = /obj/structure/foamedmetal \ No newline at end of file diff --git a/modular_dripstation/code/modules/antagonists/changeling/panacea.dm b/modular_dripstation/code/modules/antagonists/changeling/panacea.dm new file mode 100644 index 000000000000..4506cafa82f4 --- /dev/null +++ b/modular_dripstation/code/modules/antagonists/changeling/panacea.dm @@ -0,0 +1,39 @@ +/datum/action/changeling/panacea/sting_action(mob/user) + to_chat(user, span_notice("We cleanse impurities from our form.")) + var/mob/living/simple_animal/horror/H = user.has_horror_inside() + if(H) + H.leave_victim() + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.vomit(0) + to_chat(user, span_notice("A parasite exits our form.")) + ..() + var/list/bad_organs = list( + user.getorgan(/obj/item/organ/body_egg), + user.getorgan(/obj/item/organ/internal/shadowtumor), + user.getorgan(/obj/item/organ/zombie_infection)) + + for(var/o in bad_organs) + var/obj/item/organ/O = o + if(!istype(O)) + continue + + O.Remove(user) + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.vomit(0) + O.forceMove(get_turf(user)) + + user.reagents.add_reagent(/datum/reagent/medicine/mutadone, 10) + user.reagents.add_reagent(/datum/reagent/medicine/pen_acid, 20) + user.reagents.add_reagent(/datum/reagent/medicine/antihol, 10) + user.reagents.add_reagent(/datum/reagent/medicine/mannitol/advanced, 25) + + if(isliving(user)) + var/mob/living/L = user + for(var/thing in L.diseases) + var/datum/disease/D = thing + if(D.severity == DISEASE_SEVERITY_POSITIVE) + continue + D.cure() + return TRUE \ No newline at end of file diff --git a/modular_dripstation/code/modules/antagonists/horror/horror_chemicals.dm b/modular_dripstation/code/modules/antagonists/horror/horror_chemicals.dm new file mode 100644 index 000000000000..9de3b73ea26e --- /dev/null +++ b/modular_dripstation/code/modules/antagonists/horror/horror_chemicals.dm @@ -0,0 +1,4 @@ +/datum/horror_chem/mannitol + chemname = "mannitol" + R = /datum/reagent/medicine/mannitol/advanced + chem_desc = "Heals brain damage." \ No newline at end of file diff --git a/modular_dripstation/code/modules/bepis/all_nodes.dm b/modular_dripstation/code/modules/bepis/all_nodes.dm new file mode 100644 index 000000000000..bb93c7073569 --- /dev/null +++ b/modular_dripstation/code/modules/bepis/all_nodes.dm @@ -0,0 +1,51 @@ +////////////////////////B.E.P.I.S. Locked Techs//////////////////////// +/datum/techweb_node/light_apps + id = "light_apps" + display_name = "Illumination Applications" + description = "Applications of lighting and vision technology not originally thought to be commercially viable." + prereq_ids = list("base") + design_ids = list("bright_helmet", "rld_mini") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/spec_eng + id = "spec_eng" + display_name = "Specialized Engineering" + description = "Conventional wisdom has deemed these engineering products 'technically' safe, but far too dangerous to traditionally condone." + prereq_ids = list("base") + design_ids = list("eng_gloves", "lava_rods") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/aus_security + id = "aus_security" + display_name = "Australicus Security Protocols" + description = "It is said that security in the Australicus sector is tight, so we took some pointers from their equipment. Thankfully, our sector lacks any signs of these, 'dropbears'." + prereq_ids = list("base") + design_ids = list("pin_explorer", "stun_boomerang") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + hidden = TRUE + experimental = TRUE + +/datum/techweb_node/interrogation + id = "interrogation" + display_name = "Enhanced Interrogation Technology" + description = "By cross-referencing several declassified documents from past dictatorial regimes, we were able to develop an incredibly effective interrogation device. \ + Ethical concerns about loss of free will do not apply to criminals, according to galactic law." + prereq_ids = list("base") + design_ids = list("hypnochair") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) + hidden = TRUE + experimental = TRUE +/* +/datum/techweb_node/tackle_advanced + id = "tackle_advanced" + display_name = "Advanced Grapple Technology" + description = "Nanotrasen would like to remind its researching staff that it is never acceptable to \"glomp\" your coworkers, and further \"scientific trials\" on the subject will no longer be accepted in its academic journals." + design_ids = list("tackle_dolphin", "tackle_rocket") + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + hidden = TRUE + experimental = TRUE +*/ \ No newline at end of file diff --git a/modular_dripstation/code/modules/bepis/bepis.dm b/modular_dripstation/code/modules/bepis/bepis.dm new file mode 100644 index 000000000000..360ddbee7d7a --- /dev/null +++ b/modular_dripstation/code/modules/bepis/bepis.dm @@ -0,0 +1,294 @@ +//This system is designed to act as an in-between for cargo and science, and the first major money sink in the game outside of just buying things from cargo (As of 10/9/19, anyway). + +//economics defined values, subject to change should anything be too high or low in practice. + +#define MACHINE_OPERATION 100000 +#define MACHINE_OVERLOAD 500000 +#define MAJOR_THRESHOLD (8*CARGO_CRATE_VALUE) +#define MINOR_THRESHOLD (4*CARGO_CRATE_VALUE) +#define STANDARD_DEVIATION (2*CARGO_CRATE_VALUE) +#define PART_CASH_OFFSET_AMOUNT (0.5*CARGO_CRATE_VALUE) + +/obj/machinery/rnd/bepis + name = "\improper B.E.P.I.S. Chamber" + desc = "A high fidelity testing device which unlocks the secrets of the known universe using the two most powerful substances available to man: excessive amounts of electricity and capital." + icon = 'modular_dripstation/icons/obj/bepis/bepis.dmi' + icon_state = "chamber" + base_icon_state = "chamber" + density = TRUE + layer = ABOVE_MOB_LAYER + circuit = /obj/item/circuitboard/machine/bepis + + ///How much cash the UI and machine are depositing at a time. + var/banking_amount = 100 + ///How much stored player cash exists within the machine. + var/banked_cash = 0 + ///Payer's bank account. + var/datum/bank_account/account + ///Name on the payer's bank account. + var/account_name + ///When the BEPIS fails to hand out any reward, the ERROR cause will be a randomly picked string displayed on the UI. + var/error_cause = null + + //Vars related to probability and chance of success for testing, using gaussian normal distribution. + ///How much cash you will need to obtain a Major Tech Disk reward. + var/major_threshold = MAJOR_THRESHOLD + ///How much cash you will need to obtain a minor invention reward. + var/minor_threshold = MINOR_THRESHOLD + ///The standard deviation of the BEPIS's gaussian normal distribution. + var/std = STANDARD_DEVIATION + + //Stock part variables + ///Multiplier that lowers how much the BEPIS' power costs are. Maximum of 1, upgraded to a minimum of 0.7. See RefreshParts. + var/power_saver = 1 + ///Variability on the money you actively spend on the BEPIS, with higher inaccuracy making the most change, good and bad to spent cash. + var/inaccuracy_percentage = 1.5 + ///How much "cash" is added to your inserted cash efforts for free. Based on manipulator stock part level. + var/positive_cash_offset = 0 + ///How much "cost" is removed from both the minor and major threshold costs. Based on laser stock part level. + var/negative_cash_offset = 0 + ///List of objects that constitute your minor rewards. All rewards are unique or rare outside of the BEPIS. + var/minor_rewards = list( + //To add a new minor reward, add it here. + /obj/item/stack/circuit_stack/full, + /obj/item/pen/fountain/survival, + /obj/item/circuitboard/machine/sleeper/party, + /obj/item/toy/sprayoncan, + ) + +/obj/machinery/rnd/bepis/attackby(obj/item/O, mob/user, params) + if(stat & (NOPOWER|BROKEN|MAINT)) + to_chat(user, span_notice("[src] can't accept money when it's not functioning.")) + return + if(istype(O, /obj/item/holochip) || istype(O, /obj/item/stack/spacecash)) + var/deposit_value = O.get_item_credit_value() + banked_cash += deposit_value + qdel(O) + say("Deposited [deposit_value] credits into storage.") + update_icon() + return + if(isidcard(O)) + var/obj/item/card/id/Card = O + if(Card.registered_account) + account = Card.registered_account + if(istype(Card, /obj/item/card/id/departmental_budget)) + var/obj/item/card/id/departmental_budget/DB = Card + account_name = DB.department_name + else + account_name = Card.registered_name + say("New account detected. Console Updated.") + else + say("No account detected on card. Aborting.") + return + return ..() + +/obj/machinery/rnd/bepis/screwdriver_act(mob/living/user, obj/item/tool) + return default_deconstruction_screwdriver(user, "chamber_open", "chamber", tool) + +/obj/machinery/rnd/bepis/RefreshParts() + . = ..() + var/C = 0 + var/M = 0 + var/L = 0 + var/S = 0 + for(var/obj/item/stock_parts/capacitor/capacitor in component_parts) + C += ((capacitor.rating - 1) * 0.1) + power_saver = 1 - C + for(var/obj/item/stock_parts/manipulator/manipulator in component_parts) + M += ((manipulator.rating - 1) * PART_CASH_OFFSET_AMOUNT) + positive_cash_offset = M + for(var/obj/item/stock_parts/micro_laser/Laser in component_parts) + L += ((Laser.rating - 1) * PART_CASH_OFFSET_AMOUNT) + negative_cash_offset = L + for(var/obj/item/stock_parts/scanning_module/scanning_module in component_parts) + S += ((scanning_module.rating - 1) * 0.25) + inaccuracy_percentage = (1.5 - S) + +/obj/machinery/rnd/bepis/update_icon() + if(panel_open == TRUE) + icon_state = "[base_icon_state]_open" + return ..() + if((use_power == ACTIVE_POWER_USE) && (banked_cash > 0) && !(stat & (NOPOWER|BROKEN|MAINT))) + icon_state = "[base_icon_state]_active_loaded" + return ..() + if (((use_power == IDLE_POWER_USE) && (banked_cash > 0)) || (banked_cash > 0) && (stat & (NOPOWER|BROKEN|MAINT))) + icon_state = "[base_icon_state]_loaded" + return ..() + if(use_power == ACTIVE_POWER_USE && !(stat & (NOPOWER|BROKEN|MAINT))) + icon_state = "[base_icon_state]_active" + return ..() + if(((use_power == IDLE_POWER_USE) && (banked_cash == 0)) || (stat & (NOPOWER|BROKEN|MAINT))) + icon_state = base_icon_state + return ..() + return ..() + +/obj/machinery/rnd/bepis/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Bepis", name) + ui.open() + RefreshParts() +// if(isliving(user)) +// var/mob/living/carbon/human/customer = user +// account = customer.get_bank_account() + +/obj/machinery/rnd/bepis/ui_data(mob/user) + var/list/data = list() + var/powered = FALSE + var/zvalue = ((banking_amount + banked_cash) - (major_threshold - positive_cash_offset - negative_cash_offset))/(std) + var/std_success = 0 + var/prob_success = 0 + //Admittedly this is messy, but not nearly as messy as the alternative, which is jury-rigging an entire Z-table into the code, or making an adaptive z-table. + var/z = abs(zvalue) + if(z > 0 && z <= 0.5) + std_success = 19.1 + else if(z > 0.5 && z <= 1.0) + std_success = 34.1 + else if(z > 1.0 && z <= 1.5) + std_success = 43.3 + else if(z > 1.5 && z <= 2.0) + std_success = 47.7 + else if(z > 2.0 && z <= 2.5) + std_success = 49.4 + else + std_success = 50 + if(zvalue > 0) + prob_success = 50 + std_success + else if(zvalue == 0) + prob_success = 50 + else + prob_success = 50 - std_success + + if(use_power == ACTIVE_POWER_USE) + powered = TRUE + data["account_owner"] = account_name + data["amount"] = banking_amount + data["stored_cash"] = account?.account_balance + data["mean_value"] = (major_threshold - positive_cash_offset - negative_cash_offset) + data["error_name"] = error_cause + data["power_saver"] = power_saver + data["accuracy_percentage"] = inaccuracy_percentage * 100 + data["positive_cash_offset"] = positive_cash_offset + data["negative_cash_offset"] = negative_cash_offset + data["manual_power"] = powered ? FALSE : TRUE + data["silicon_check"] = issilicon(user) + data["success_estimate"] = prob_success + return data + +/obj/machinery/rnd/bepis/ui_act(action,params) + . = ..() + if(.) + return + switch(action) + if("begin_experiment") + if(use_power == IDLE_POWER_USE) + return + depositcash() + if(banked_cash == 0) + say("Please select funds to deposit to begin testing.") + return + calcsuccess() + use_power(MACHINE_OPERATION * power_saver) //This thing should eat your APC battery if you're not careful. + use_power = IDLE_POWER_USE //Machine shuts off after use to prevent spam and look better visually. + update_icon() + if("amount") + var/input = text2num(params["amount"]) + if(input) + banking_amount = input + if("toggle_power") + if(use_power == ACTIVE_POWER_USE) + use_power = IDLE_POWER_USE + else + use_power = ACTIVE_POWER_USE + update_icon() + if("account_reset") + if(use_power == IDLE_POWER_USE) + return + account_name = "" + account = null + say("Account settings reset.") + . = TRUE + +/** + * Proc that handles the user's account to deposit credits for the BEPIS. + * Handles success and fail cases for transferring credits, then logs the transaction and uses small amounts of power. + **/ +/obj/machinery/rnd/bepis/proc/depositcash() + var/deposit_value = 0 + deposit_value = banking_amount + if(deposit_value == 0) + update_icon() + say("Attempting to deposit 0 credits. Aborting.") + return + deposit_value = clamp(round(deposit_value, 1), 1, 10000) + if(!account) + say("Cannot find user account. Please swipe a valid ID.") + return + if(!account.has_money(deposit_value)) + say("You do not possess enough credits.") + return + account.adjust_money(-deposit_value, "Vending: B.E.P.I.S. Chamber") //The money vanishes, not paid to any accounts. + SSblackbox.record_feedback("amount", "BEPIS_credits_spent", deposit_value) + log_message("[deposit_value] credits were inserted into [src] by [account.account_holder]", LOG_GAME) + banked_cash += deposit_value + use_power(1000 * power_saver) + return + +/** + * Proc used to determine the experiment math and results all in one. + * Uses banked_cash and stock part levels to determine minor, major, and real gauss values for the BEPIS to hold. + * If by the end real is larger than major, You get a tech disk. If all the disks are earned or you at least beat minor, you get a minor reward. + **/ + +/obj/machinery/rnd/bepis/proc/calcsuccess() + var/turf/dropturf = null + var/gauss_major = 0 + var/gauss_minor = 0 + var/gauss_real = 0 + + var/turf/open/floor/turfs = get_turf(src) + while(length(turfs)) + var/turf/T = pick_n_take(turfs) + if(T.is_blocked_turf()) + continue + else + dropturf = T + break + + if (!dropturf) + dropturf = drop_location() + gauss_major = (gaussian(major_threshold, std) - negative_cash_offset) //This is the randomized profit value that this experiment has to surpass to unlock a tech. + gauss_minor = (gaussian(minor_threshold, std) - negative_cash_offset) //And this is the threshold to instead get a minor prize. + gauss_real = (gaussian(banked_cash, std*inaccuracy_percentage) + positive_cash_offset) //this is the randomized profit value that your experiment expects to give. + say("Real: [gauss_real]. Minor: [gauss_minor]. Major: [gauss_major].") + flick("chamber_flash",src) + update_icon() + banked_cash = 0 + if((gauss_real >= gauss_major)) //Major Success. + if(SSresearch.techweb_nodes_experimental.len > 0) + say("Experiment concluded with major success. New technology node discovered on technology disc.") + new /obj/item/disk/design_disk/bepis/remove_tech(dropturf,1) + return + say("Expended all available experimental technology nodes. Resorting to minor rewards.") + if(gauss_real >= gauss_minor) //Minor Success. + var/reward = pick(minor_rewards) + new reward(dropturf) + say("Experiment concluded with partial success. Dispensing compiled research efforts.") + return + if(gauss_real <= -1) //Critical Failure + say("ERROR: CRITICAL MACHIME MALFUNCTI- ON. CURRENCY IS NOT CRASH. CANNOT COMPUTE COMMAND: 'make bucks'") //not a typo, for once. + new /mob/living/simple_animal/hostile/retaliate/frog(dropturf, 1) + use_power(MACHINE_OVERLOAD * power_saver) //To prevent gambling at low cost and also prevent spamming for infinite deer. + return + //Minor Failure + error_cause = pick("attempted to sell grey products to American dominated market.","attempted to sell gray products to British dominated market.","placed wild assumption that PDAs would go out of style.","simulated product #76 damaged brand reputation mortally.","simulated business model resembled 'pyramid scheme' by 98.7%.","product accidently granted override access to all station doors.") + say("Experiment concluded with zero product viability. Cause of error: [error_cause]") + return + + +#undef MACHINE_OPERATION +#undef MACHINE_OVERLOAD +#undef MAJOR_THRESHOLD +#undef MINOR_THRESHOLD +#undef STANDARD_DEVIATION +#undef PART_CASH_OFFSET_AMOUNT diff --git a/modular_dripstation/code/modules/bepis/bepis_board.dm b/modular_dripstation/code/modules/bepis/bepis_board.dm new file mode 100644 index 000000000000..0aa7b16b954f --- /dev/null +++ b/modular_dripstation/code/modules/bepis/bepis_board.dm @@ -0,0 +1,18 @@ +/datum/design/board/bepis + name = "B.E.P.I.S. Board" + desc = "The circuit board for a B.E.P.I.S." + id = "bepis" + build_path = /obj/item/circuitboard/machine/bepis + category = list("Research Machinery") + departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_CARGO + +/obj/item/circuitboard/machine/bepis + name = "BEPIS Chamber" + icon_state = "supply" + build_path = /obj/machinery/rnd/bepis + req_components = list( + /obj/item/stack/cable_coil = 5, + /obj/item/stock_parts/capacitor = 1, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/scanning_module = 1) \ No newline at end of file diff --git a/modular_dripstation/code/modules/bepis/bepis_designs.dm b/modular_dripstation/code/modules/bepis/bepis_designs.dm new file mode 100644 index 000000000000..028eeb2d1a8f --- /dev/null +++ b/modular_dripstation/code/modules/bepis/bepis_designs.dm @@ -0,0 +1,66 @@ +/datum/design/bright_helmet + name = "Workplace-Ready Firefighter Helmet" + desc = "By applying state of the art lighting technology to a fire helmet with industry standard photo-chemical hardening methods, this hardhat will protect you from robust workplace hazards." + id = "bright_helmet" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 4000, /datum/material/glass = 1000, /datum/material/plastic = 3000, /datum/material/silver = 500) + build_path = /obj/item/clothing/head/hardhat/red/upgraded + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/rld_mini + name = "Mini Rapid Light Device (MRLD)" + desc = "A tool that can deploy portable and standing lighting orbs and glowsticks." + id = "rld_mini" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 20000, /datum/material/glass = 10000, /datum/material/plastic = 8000, /datum/material/gold = 2000) + build_path = /obj/item/construction/rld/mini + category = list("Tool Designs") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_SERVICE + +/datum/design/eng_gloves + name = "Tinkers Gloves" + desc = "Overdesigned engineering gloves that have automated construction subroutines dialed in, allowing for faster construction while worn." + id = "eng_gloves" + build_type = PROTOLATHE + materials = list(/datum/material/iron= 2000, /datum/material/silver= 1500, /datum/material/gold = 1000) + build_path = /obj/item/clothing/gloves/tinkerer + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/lavarods + name = "Lava-Resistant Iron Rods" + id = "lava_rods" + build_type = PROTOLATHE + materials = list(/datum/material/iron= 1000, /datum/material/plasma= 500, /datum/material/titanium= 2000) + build_path = /obj/item/stack/rods/lava + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING + +/datum/design/pin_explorer + name = "Outback Firing Pin" + desc = "This firing pin only shoots while ya ain't on station, fair dinkum!" + id = "pin_explorer" + build_type = PROTOLATHE + materials = list(/datum/material/silver = 1000, /datum/material/gold = 1000, /datum/material/iron = 500) + build_path = /obj/item/firing_pin/explorer + category = list("Firing Pins") + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + +/datum/design/stun_boomerang + name = "OZtek Boomerang" + desc = "Uses reverse flow gravitodynamics to flip its personal gravity back to the thrower mid-flight. Also functions similar to a stun baton." + id = "stun_boomerang" + build_type = PROTOLATHE + materials = list(/datum/material/iron = 10000, /datum/material/glass = 4000, /datum/material/silver = 10000, /datum/material/gold = 2000) + build_path = /obj/item/melee/baton/boomerang + category = list("Weapons") + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + +/datum/design/board/hypnochair + name = "Enhanced Interrogation Chamber Board" + desc = "Allows for the construction of circuit boards used to build an Enhanced Interrogation Chamber." + id = "hypnochair" + build_path = /obj/item/circuitboard/machine/hypnochair + category = list("Misc. Machinery") + departmental_flags = DEPARTMENTAL_FLAG_SECURITY \ No newline at end of file diff --git a/modular_dripstation/code/modules/bepis/bepis_layout.dm b/modular_dripstation/code/modules/bepis/bepis_layout.dm new file mode 100644 index 000000000000..5f49659f1a35 --- /dev/null +++ b/modular_dripstation/code/modules/bepis/bepis_layout.dm @@ -0,0 +1,27 @@ +/datum/techweb_node/light_apps + ui_x = 32 + ui_y = -576 + +/datum/techweb_node/spec_eng + ui_x = -32 + ui_y = -576 + +/datum/techweb_node/aus_security + ui_x = -96 + ui_y = -576 + +/datum/techweb_node/interrogation + ui_x = -160 + ui_y = -576 + +///datum/techweb_node/free_space1 +// ui_x = -252 +// ui_y = -576 + +///datum/techweb_node/free_space2 +// ui_x = -352 +// ui_y = -576 + +///datum/techweb_node/free_space3 +// ui_x = -448 +// ui_y = -576 \ No newline at end of file diff --git a/modular_dripstation/code/modules/bepis/bounty.dm b/modular_dripstation/code/modules/bepis/bounty.dm new file mode 100644 index 000000000000..fec472a3659a --- /dev/null +++ b/modular_dripstation/code/modules/bepis/bounty.dm @@ -0,0 +1,5 @@ +/datum/bounty/item/science/bepis_disc + name = "Reformatted Tech Disk" + description = "It turns out the diskettes the BEPIS prints experimental nodes on are extremely space-efficient. Send us one of your spares when you're done with it." + reward = 10000 + wanted_types = list(/obj/item/disk/design_disk/bepis/remove_tech, /obj/item/disk/design_disk/bepis) \ No newline at end of file diff --git a/modular_dripstation/code/modules/bepis/designs.dm b/modular_dripstation/code/modules/bepis/designs.dm new file mode 100644 index 000000000000..13263134a24c --- /dev/null +++ b/modular_dripstation/code/modules/bepis/designs.dm @@ -0,0 +1,37 @@ +/obj/item/disk/design_disk/proc/on_upload(datum/techweb/stored_research) + return + +/obj/item/disk/design_disk/bepis + name = "Old experimental technology disk" + desc = "A disk containing some long-forgotten technology from a past age. You hope it still works after all these years. Upload the disk to an R&D Console to redeem the tech." + icon_state = "datadisk0" + max_blueprints = 0 + + ///The bepis node we have the design id's of + var/datum/techweb_node/bepis_node + +/obj/item/disk/design_disk/bepis/Initialize(mapload) + . = ..() + var/bepis_id = pick(SSresearch.techweb_nodes_experimental) + bepis_node = (SSresearch.techweb_node_by_id(bepis_id)) + + for(var/entry in bepis_node.design_ids) + var/datum/design/new_entry = SSresearch.techweb_design_by_id(entry) + blueprints += new_entry + +///Unhide and research our node so we show up in the R&D console. +/obj/item/disk/design_disk/bepis/on_upload(datum/techweb/stored_research) + stored_research.hidden_nodes -= bepis_node.id + stored_research.research_node(bepis_node, force = TRUE, auto_adjust_cost = FALSE) + +/** + * Subtype of Bepis tech disk + * Removes the tech disk that's held on it from the experimental node list, making them not show up in future disks. + */ +/obj/item/disk/design_disk/bepis/remove_tech + name = "Reformatted technology disk" + desc = "A disk containing a new, completed tech from the B.E.P.I.S. Upload the disk to an R&D Console to redeem the tech." + +/obj/item/disk/design_disk/bepis/remove_tech/Initialize(mapload) + . = ..() + SSresearch.techweb_nodes_experimental -= bepis_node.id \ No newline at end of file diff --git a/modular_dripstation/code/modules/cargo/bounties/progression.dm b/modular_dripstation/code/modules/cargo/bounties/progression.dm new file mode 100644 index 000000000000..085bd8b6f144 --- /dev/null +++ b/modular_dripstation/code/modules/cargo/bounties/progression.dm @@ -0,0 +1,15 @@ +/datum/bounty/item/progression/mining_advanced/reward_string() + return "[reward] Credits and clearance to order high quality plasmacutters" + +/* +/datum/bounty/item/progression/drakeslayer + name = "Hardsuit Initiatives" + description = "Strange dragon-like fauna detected in the area. Provide us a few examples of scaly material from this creatures and we`ll pay in reward." + reward = 20000 + required_count = 10 + wanted_types = list(/obj/item/stack/sheet/animalhide/ashdrake, /obj/item/stack/sheet/animalhide/carpdragon) //let`s get down some lizards + unlocked_crates = list(/datum/supply_pack/clearance/heavymining) + +/datum/bounty/item/progression/drakeslayer/reward_string() + return "[reward] Credits and clearance to order high quality mining gear." +*/ \ No newline at end of file diff --git a/modular_dripstation/code/modules/cargo/bounties/syndicate.dm b/modular_dripstation/code/modules/cargo/bounties/syndicate.dm new file mode 100644 index 000000000000..0f07736f676f --- /dev/null +++ b/modular_dripstation/code/modules/cargo/bounties/syndicate.dm @@ -0,0 +1,24 @@ +/datum/bounty/item/syndicate/secbudget + name = "!&@#DEFENCE BUDGET CARD!#@*$" + description = "!&@#WE ARE INTERESTED IN CRYPTO CODES OF NANOTRASEN BUDGET CARDS. WE WANT SECS ONE. DO NOT FAIL US IN THIS TASK.#@*$" + wanted_types = list(/obj/item/card/id/departmental_budget/sec) + reward = 5 //you gotta take it from armory +/datum/bounty/item/syndicate/combatmagboots + name = "!&@#COMBAT MAGBOOTS!#@*$" + description = "!&@#WE'RE LOOKING FOR NANOTRASEN ADVANCED MAGNETIC TECHNOLOGY. PROVIDE US SOME EXAMPLES FROM STATIONBOARD SECURITY DEPARTMENT.#@*$" + wanted_types = list(/obj/item/clothing/shoes/magboots/security) + required_count = 3 + reward = 4 +/datum/bounty/item/syndicate/hoshardsuit + name = "!&@#HEAD OF SECURITY HARDSUIT!#@*$" + description = "!&@#SOME PARTS OF SECURITY PLATESHIELDING ARE EXPENSIVE ENOUGH TO BE SOLD TO SOME COLLECTORS. YOU KNOW WHAT TO DO.#@*$" + wanted_types = list(/obj/item/clothing/suit/space/hardsuit/security/hos) + reward = 6 //you gotta take down a HoS +/datum/bounty/item/syndicate/gygaxboards + name = "!&@#GYGAX EXOSUIT BOARDS!#@*$" + description = "!&@#AFTER A RECENT OPERATION, SEVERAL OF OUR DARK GYGAX UNITS HAVE BEEN LEFT INOPERABLE. SEND SOME REPLACEMENT BOARDS TO US FOR A REWARD#@*$" + wanted_types = list(/obj/item/circuitboard/mecha/gygax/peripherals,/obj/item/circuitboard/mecha/gygax/targeting,/obj/item/circuitboard/mecha/gygax/main) + reward = 3 + required_count = 10 +/datum/bounty/item/syndicate/phazon + reward = 14 //you need an anomaly core and robotics for this one broski, it's gotta be worth a lot \ No newline at end of file diff --git a/modular_dripstation/code/modules/cargo/export_scaner.dm b/modular_dripstation/code/modules/cargo/export_scaner.dm new file mode 100644 index 000000000000..0d792f291c4f --- /dev/null +++ b/modular_dripstation/code/modules/cargo/export_scaner.dm @@ -0,0 +1,2 @@ +/obj/item/export_scanner + slot_flags = ITEM_SLOT_BELT \ No newline at end of file diff --git a/modular_dripstation/code/modules/cargo/markets/_market.dm b/modular_dripstation/code/modules/cargo/markets/_market.dm new file mode 100644 index 000000000000..3c264289cd2b --- /dev/null +++ b/modular_dripstation/code/modules/cargo/markets/_market.dm @@ -0,0 +1,61 @@ +/datum/market + /// Name for the market. + var/name = "huh?" + + /// Available shipping methods and prices, just leave the shipping method out that you don't want to have. + var/list/shipping + + // Automatic vars, do not touch these. + /// Items available from this market, populated by SSblackmarket on initialization. Automatically assigned, so don't manually adjust. + var/list/available_items = list() + /// Item categories available from this market, only items which are in these categories can be gotten from this market. Automatically assigned, so don't manually adjust. + var/list/categories = list() + +/// Adds item to the available items and add it's category if it is not in categories yet. +/datum/market/proc/add_item(datum/market_item/item) + if(!prob(initial(item.availability_prob))) + return FALSE + + if(ispath(item)) + item = new item() + + if(!(item.category in categories)) + categories += item.category + available_items[item.category] = list() + + available_items[item.category] += item + return TRUE + +/// Handles buying the item, this is mainly for future use and moving the code away from the uplink. +/datum/market/proc/purchase(item, category, method, obj/item/market_uplink/uplink, user) + if(!istype(uplink) || !(method in shipping)) + return FALSE + + for(var/datum/market_item/I in available_items[category]) + if(I.type != item) + continue + var/price = I.price + shipping[method] + + if(!uplink.current_user)///There is no ID card on the user, or the ID card has no account + to_chat(user, span_warning("The uplink sparks, as it can't identify an ID card with a bank account on you.")) + return FALSE + var/balance = uplink?.current_user.account_balance + + // I can't get the price of the item and shipping in a clean way to the UI, so I have to do this. + if(balance < price) + to_chat(user, span_warning("You don't have enough credits in [uplink] for [I] with [method] shipping.")) + return FALSE + + if(I.buy(uplink, user, method)) + uplink.current_user.adjust_money(-price, "Other: Third Party Transaction") + if(ismob(user)) + var/mob/m_user = user + m_user.playsound_local(get_turf(m_user), 'sound/machines/twobeep_high.ogg', 50, TRUE) + return TRUE + return FALSE + +/datum/market/blackmarket + name = "Black Market" + shipping = list(SHIPPING_METHOD_LTSRBT =50, + SHIPPING_METHOD_LAUNCH =10, + SHIPPING_METHOD_TELEPORT=75) diff --git a/modular_dripstation/code/modules/cargo/markets/market_item.dm b/modular_dripstation/code/modules/cargo/markets/market_item.dm new file mode 100644 index 000000000000..2113e1c846d5 --- /dev/null +++ b/modular_dripstation/code/modules/cargo/markets/market_item.dm @@ -0,0 +1,76 @@ +/datum/market_item + /// Name for the item entry used in the uplink. + var/name + /// Description for the item entry used in the uplink. + var/desc + /// The category this item belongs to, should be already declared in the market that this item is accessible in. + var/category + /// "/datum/market"s that this item should be in, used by SSblackmarket on init. + var/list/markets = list(/datum/market/blackmarket) + + /// Price for the item, if not set creates a price according to the *_min and *_max vars. + var/price + /// How many of this type of item is available, if not set creates a price according to the *_min and *_max vars. + var/stock + + /// Path to or the item itself what this entry is for, this should be set even if you override spawn_item to spawn your item. + var/item + + /// Minimum price for the item if generated randomly. + var/price_min = 0 + /// Maximum price for the item if generated randomly. + var/price_max = 0 + /// Minimum amount that there should be of this item in the market if generated randomly. This defaults to 1 as most items will have it as 1. + var/stock_min = 1 + /// Maximum amount that there should be of this item in the market if generated randomly. + var/stock_max = 0 + /// Probability for this item to be available. Used by SSblackmarket on init. + var/availability_prob = 0 + +/datum/market_item/New() + if(isnull(price)) + price = rand(price_min, price_max) + if(isnull(stock)) + stock = rand(stock_min, stock_max) + +/// Used for spawning the wanted item, override if you need to do something special with the item. +/datum/market_item/proc/spawn_item(loc) + return new item(loc) + +/// Buys the item and makes SSblackmarket handle it. +/datum/market_item/proc/buy(obj/item/market_uplink/uplink, mob/buyer, shipping_method) + // Sanity + if(!istype(uplink) || !istype(buyer)) + return FALSE + + // This shouldn't be able to happen unless there was some manipulation or admin fuckery. + if(!item || stock <= 0) + return FALSE + + // Alright, the item has been purchased. + var/datum/market_purchase/purchase = new(src, uplink, shipping_method) + + // SSblackmarket takes care of the shipping. + if(SSblackmarket.queue_item(purchase)) + stock-- + buyer.log_message("has succesfully purchased [name] using [shipping_method] for shipping.", LOG_GAME) + return TRUE + return FALSE + +// This exists because it is easier to keep track of all the vars this way. +/datum/market_purchase + /// The entry being purchased. + var/datum/market_item/entry + /// Instance of the item being sent. + var/item + /// The uplink where this purchase was done from. + var/obj/item/market_uplink/uplink + /// Shipping method used to buy this item. + var/method + +/datum/market_purchase/New(_entry, _uplink, _method) + entry = _entry + if(!ispath(entry.item)) + item = entry.item + uplink = _uplink + method = _method diff --git a/modular_dripstation/code/modules/cargo/markets/market_items/clothing.dm b/modular_dripstation/code/modules/cargo/markets/market_items/clothing.dm new file mode 100644 index 000000000000..42fd81856b51 --- /dev/null +++ b/modular_dripstation/code/modules/cargo/markets/market_items/clothing.dm @@ -0,0 +1,80 @@ +/datum/market_item/clothing + category = "Clothing" + +/datum/market_item/clothing/ninja_mask + name = "Space Ninja Mask" + desc = "Apart from being acid, lava, fireproof and being hard to take off someone it does nothing special on it's own." + item = /obj/item/clothing/mask/gas/space_ninja + + price_min = CARGO_CRATE_VALUE + price_max = CARGO_CRATE_VALUE * 2.5 + stock_max = 3 + availability_prob = 40 + +/datum/market_item/clothing/sunglasses + name = "Space Sunglasses" + desc = "Just cool sunglasses for all your needs." + item = /obj/item/clothing/glasses/sunglasses + + price_min = CARGO_CRATE_VALUE + price_max = CARGO_CRATE_VALUE * 2.5 + stock_max = 3 + availability_prob = 40 + +/datum/market_item/clothing/durathread_vest + name = "Durathread Vest" + desc = "Don't let them tell you this stuff is \"Like asbestos\" or \"Pulled from the market for safety concerns\". It could be the difference between a robusting and a retaliation." + item = /obj/item/clothing/suit/armor/vest/durathread + + price_min = CARGO_CRATE_VALUE + price_max = CARGO_CRATE_VALUE * 2 + stock_max = 4 + availability_prob = 50 + +/datum/market_item/clothing/durathread_helmet + name = "Durathread Helmet" + desc = "Customers ask why it's called a helmet when it's just made from armoured fabric and I always say the same thing: No refunds." + item = /obj/item/clothing/head/helmet/durathread + + price_min = CARGO_CRATE_VALUE * 0.5 + price_max = CARGO_CRATE_VALUE + stock_max = 4 + availability_prob = 50 + +/datum/market_item/clothing/full_spacesuit_set + name = "\improper Nanotrasen Branded Spacesuit Box" + desc = "A few boxes of \"Old Style\" space suits fell off the back of a space truck." + item = /obj/item/storage/box + + price_min = CARGO_CRATE_VALUE * 7.5 + price_max = CARGO_CRATE_VALUE * 20 + stock_max = 3 + availability_prob = 30 + +/datum/market_item/clothing/full_spacesuit_set/spawn_item(loc) + var/obj/item/storage/box/B = ..() + B.name = "Spacesuit Box" + B.desc = "It has an NT logo on it." + new /obj/item/clothing/suit/space(B) + new /obj/item/clothing/head/helmet/space(B) + return B + +/datum/market_item/clothing/chameleon_hat + name = "Chameleon Hat" + desc = "Pick any hat you want with this Handy device. Not Quality Tested." + item = /obj/item/clothing/head/chameleon/broken + + price_min = CARGO_CRATE_VALUE * 0.5 + price_max = CARGO_CRATE_VALUE + stock_max = 2 + availability_prob = 70 + +/datum/market_item/clothing/rocket_boots + name = "Rocket Boots" + desc = "We found a pair of jump boots and overclocked the hell out of them. No liability for grevious harm to or with a body." + item = /obj/item/clothing/shoes/bhop/rocket + + price_min = CARGO_CRATE_VALUE * 5 + price_max = CARGO_CRATE_VALUE * 15 + stock_max = 1 + availability_prob = 40 diff --git a/modular_dripstation/code/modules/cargo/markets/market_items/consumables.dm b/modular_dripstation/code/modules/cargo/markets/market_items/consumables.dm new file mode 100644 index 000000000000..e61c2bae1041 --- /dev/null +++ b/modular_dripstation/code/modules/cargo/markets/market_items/consumables.dm @@ -0,0 +1,53 @@ +/datum/market_item/consumable + category = "Consumables" + +/datum/market_item/consumable/donk_pocket_box + name = "Box of Donk Pockets" + desc = "A well packaged box containing the favourite snack of every spacefarer." + item = /obj/item/storage/box/donkpockets + + stock_min = 2 + stock_max = 5 + price_min = CARGO_CRATE_VALUE * 1.625 + price_max = CARGO_CRATE_VALUE * 2 + availability_prob = 80 + +/datum/market_item/consumable/suspicious_pills + name = "Bottle of Suspicious Pills" + desc = "A random cocktail of luxury drugs that are sure to put a smile on your face!" + item = /obj/item/storage/pill_bottle + + stock_min = 2 + stock_max = 3 + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 3.5 + availability_prob = 50 + +/datum/market_item/consumable/suspicious_pills/spawn_item(loc) + var/pillbottle = pick(list(/obj/item/storage/pill_bottle/zoom, + /obj/item/storage/pill_bottle/happy, + /obj/item/storage/pill_bottle/lsd, + /obj/item/storage/pill_bottle/aranesp, + /obj/item/storage/pill_bottle/stimulant)) + return new pillbottle(loc) + +/datum/market_item/consumable/floor_pill + name = "Strange Pill" + desc = "The Russian Roulette of the Maintenance Tunnels." + item = /obj/item/reagent_containers/pill/floorpill + + stock_min = 5 + stock_max = 35 + price_min = CARGO_CRATE_VALUE * 0.05 + price_max = CARGO_CRATE_VALUE * 0.3 + availability_prob = 50 + +/datum/market_item/consumable/pumpup + name = "Maintenance Pump-Up" + desc = "Resist any Baton stun with this handy device!" + item = /obj/item/reagent_containers/autoinjector/medipen/pumpup + + stock_max = 3 + price_min = CARGO_CRATE_VALUE * 0.25 + price_max = CARGO_CRATE_VALUE * 0.75 + availability_prob = 90 diff --git a/modular_dripstation/code/modules/cargo/markets/market_items/misc.dm b/modular_dripstation/code/modules/cargo/markets/market_items/misc.dm new file mode 100644 index 000000000000..70668d1c3b02 --- /dev/null +++ b/modular_dripstation/code/modules/cargo/markets/market_items/misc.dm @@ -0,0 +1,78 @@ +/datum/market_item/misc + category = "Miscellaneous" + +/datum/market_item/misc/Clear_PDA + name = "Clear PDA" + desc = "Show off your style with this limited edition clear PDA!." + item = /obj/item/modular_computer/tablet/pda/preset/basic + + price_min = CARGO_CRATE_VALUE * 1.25 + price_max = CARGO_CRATE_VALUE *3 + stock_max = 2 + availability_prob = 50 + +/datum/market_item/misc/jade_Lantern + name = "Jade Lantern" + desc = "Found in a box labeled 'Danger: Radioactive'. Probably safe." + item = /obj/item/flashlight/lantern/jade + + price_min = CARGO_CRATE_VALUE * 0.75 + price_max = CARGO_CRATE_VALUE * 2.5 + stock_max = 2 + availability_prob = 45 + +/datum/market_item/misc/cap_gun + name = "Cap Gun" + desc = "Prank your friends with this harmless gun! Harmlessness guranteed." + item = /obj/item/toy/gun + + price_min = CARGO_CRATE_VALUE * 0.25 + price_max = CARGO_CRATE_VALUE + stock_max = 6 + availability_prob = 80 + +/datum/market_item/misc/shoulder_holster + name = "Shoulder holster" + desc = "Yeehaw, hardboiled friends! This holster is the first step in your dream of becoming a detective and being allowed to shoot real guns!" + item = /obj/item/storage/belt/holster + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 4 + stock_max = 8 + availability_prob = 70 + +/datum/market_item/misc/holywater + name = "Flask of holy water" + desc = "Father Lootius' own brand of ready-made holy water." + item = /obj/item/reagent_containers/food/drinks/bottle/holywater + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 3 + stock_max = 3 + availability_prob = 40 + +/datum/market_item/misc/holywater/spawn_item(loc) + if (prob(6.66)) + return new /obj/item/reagent_containers/glass/beaker/unholywater(loc) + return ..() + +/datum/market_item/misc/strange_seed + name = "Strange Seeds" + desc = "An Exotic Variety of seed that can contain anything from glow to acid." + item = /obj/item/seeds/random + + price_min = CARGO_CRATE_VALUE * 1.6 + price_max = CARGO_CRATE_VALUE * 1.8 + stock_min = 2 + stock_max = 5 + availability_prob = 50 + +/datum/market_item/misc/smugglers_satchel + name = "Smuggler's Satchel" + desc = "This easily hidden satchel can become a versatile tool to anybody with the desire to keep certain items out of sight and out of mind." + item = /obj/item/storage/backpack/satchel/flat/empty + + price_min = CARGO_CRATE_VALUE * 3.75 + price_max = CARGO_CRATE_VALUE * 5 + stock_max = 2 + availability_prob = 30 diff --git a/modular_dripstation/code/modules/cargo/markets/market_items/tools.dm b/modular_dripstation/code/modules/cargo/markets/market_items/tools.dm new file mode 100644 index 000000000000..27aa49dcc130 --- /dev/null +++ b/modular_dripstation/code/modules/cargo/markets/market_items/tools.dm @@ -0,0 +1,82 @@ +/datum/market_item/tool + category = "Tools" + +/datum/market_item/tool/caravan_wrench + name = "Experimental Wrench" + desc = "The extra fast and handy wrench you always wanted!" + item = /obj/item/wrench/caravan + stock = 1 + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 4 + availability_prob = 20 + +/datum/market_item/tool/caravan_wirecutters + name = "Experimental Wirecutters" + desc = "The extra fast and handy wirecutters you always wanted!" + item = /obj/item/wirecutters/caravan + stock = 1 + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 4 + availability_prob = 20 + +/datum/market_item/tool/caravan_screwdriver + name = "Experimental Screwdriver" + desc = "The extra fast and handy screwdriver you always wanted!" + item = /obj/item/screwdriver/caravan + stock = 1 + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 4 + availability_prob = 20 + +/datum/market_item/tool/caravan_crowbar + name = "Experimental Crowbar" + desc = "The extra fast and handy crowbar you always wanted!" + item = /obj/item/crowbar/red/caravan + stock = 1 + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 4 + availability_prob = 20 + +/datum/market_item/tool/binoculars + name = "Binoculars" + desc = "Increase your sight by 150% with this handy Tool!" + item = /obj/item/binoculars + stock = 1 + + price_min = CARGO_CRATE_VALUE * 2 + price_max = CARGO_CRATE_VALUE * 4.8 + availability_prob = 30 + +/datum/market_item/tool/riot_shield + name = "Riot Shield" + desc = "Protect yourself from an unexpected Riot at your local Police department!" + item = /obj/item/shield/riot + + price_min = CARGO_CRATE_VALUE * 2.25 + price_max = CARGO_CRATE_VALUE * 3.25 + stock_max = 2 + availability_prob = 50 + +/datum/market_item/tool/thermite_bottle + name = "Thermite Bottle" + desc = "30u of Thermite to assist in creating a quick access point or get away!" + item = /obj/item/reagent_containers/glass/beaker/thermite + + price_min = CARGO_CRATE_VALUE * 2.5 + price_max = CARGO_CRATE_VALUE * 7.5 + stock_max = 3 + availability_prob = 30 + +/datum/market_item/tool/science_goggles + name = "Science Goggles" + desc = "These glasses scan the contents of containers and projects their contents to the user in an easy to read format." + item = /obj/item/clothing/glasses/science + + price_min = CARGO_CRATE_VALUE * 0.75 + price_max = CARGO_CRATE_VALUE + stock_max = 3 + availability_prob = 50 diff --git a/modular_dripstation/code/modules/cargo/markets/market_items/weapons.dm b/modular_dripstation/code/modules/cargo/markets/market_items/weapons.dm new file mode 100644 index 000000000000..2cb48a45b5ee --- /dev/null +++ b/modular_dripstation/code/modules/cargo/markets/market_items/weapons.dm @@ -0,0 +1,65 @@ +/datum/market_item/weapon + category = "Weapons" + +/datum/market_item/weapon/bear_trap + name = "Bear Trap" + desc = "Get the janitor back at his own game with this affordable prank kit." + item = /obj/item/restraints/legcuffs/beartrap + + price_min = CARGO_CRATE_VALUE * 1.5 + price_max = CARGO_CRATE_VALUE * 2.75 + stock_max = 3 + availability_prob = 50 + +/datum/market_item/weapon/shotgun_dart + name = "Shotgun Dart" + desc = "These handy darts can be filled up with any chemical and be shot with a shotgun! \ + Prank your friends by shooting them with laughter! \ + Not recommended for comercial use." + item = /obj/item/ammo_casing/shotgun/dart + + price_min = CARGO_CRATE_VALUE * 0.05 + price_max = CARGO_CRATE_VALUE * 0.25 + stock_min = 10 + stock_max = 60 + availability_prob = 40 + +/datum/market_item/weapon/bone_spear + name = "Bone Spear" + desc = "Authentic tribal spear, made from real bones! A steal at any price, especially if you're a caveman." + item = /obj/item/melee/spear/bonespear + + price_min = CARGO_CRATE_VALUE + price_max = CARGO_CRATE_VALUE * 1.5 + stock_max = 3 + availability_prob = 60 + +/datum/market_item/weapon/chainsaw + name = "Chainsaw" + desc = "A lumberjack's best friend, perfect for cutting trees or limbs efficiently." + item = /obj/item/melee/chainsaw + + price_min = CARGO_CRATE_VALUE * 1.75 + price_max = CARGO_CRATE_VALUE * 3 + stock_max = 1 + availability_prob = 35 + +/datum/market_item/weapon/switchblade + name = "Switchblade" + desc = "Tunnel Snakes rule!" + item = /obj/item/switchblade + + price_min = CARGO_CRATE_VALUE * 1.25 + price_max = CARGO_CRATE_VALUE * 1.75 + stock_max = 3 + availability_prob = 45 + +/datum/market_item/weapon/emp_grenade + name = "EMP Grenade" + desc = "Use this grenade for SHOCKING results!" + item = /obj/item/grenade/empgrenade + + price_min = CARGO_CRATE_VALUE * 0.5 + price_max = CARGO_CRATE_VALUE * 2 + stock_max = 2 + availability_prob = 50 diff --git a/modular_dripstation/code/modules/cargo/markets/market_telepad.dm b/modular_dripstation/code/modules/cargo/markets/market_telepad.dm new file mode 100644 index 000000000000..6b6dbab960c4 --- /dev/null +++ b/modular_dripstation/code/modules/cargo/markets/market_telepad.dm @@ -0,0 +1,120 @@ +/obj/item/circuitboard/machine/ltsrbt + name = "LTSRBT (Machine Board)" + icon_state = "bluespacearray" + icon = 'modular_dripstation/icons/obj/blackmarket/module.dmi' + build_path = /obj/machinery/ltsrbt + req_components = list( + /obj/item/stack/ore/bluespace_crystal = 2, + /obj/item/stock_parts/subspace/ansible = 1, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/scanning_module = 2) + def_components = list(/obj/item/stack/ore/bluespace_crystal = /obj/item/stack/ore/bluespace_crystal/artificial) + +/obj/machinery/ltsrbt + name = "Long-To-Short-Range-Bluespace-Transceiver" + desc = "The LTSRBT is a compact teleportation machine for receiving and sending items outside the station and inside the station.\nUsing teleportation frequencies stolen from NT it is near undetectable.\nEssential for any illegal market operations on NT stations.\n" + icon = 'modular_dripstation/icons/obj/blackmarket/telecoms.dmi' + icon_state = "exonet_node" + circuit = /obj/item/circuitboard/machine/ltsrbt + density = TRUE + + use_power = IDLE_POWER_USE + idle_power_usage = 200 + active_power_usage = 250 + + /// Divider for power_usage_per_teleport. + var/power_efficiency = 1 + /// Power used per teleported which gets divided by power_efficiency. + var/power_usage_per_teleport = 10000 + /// The time it takes for the machine to recharge before being able to send or receive items. + var/recharge_time = 0 + /// Current recharge progress. + var/recharge_cooldown = 0 + /// Base recharge time in seconds which is used to get recharge_time. + var/base_recharge_time = 100 + /// Current /datum/market_purchase being received. + var/receiving + /// Current /datum/market_purchase being sent to the target uplink. + var/transmitting + /// Queue for purchases that the machine should receive and send. + var/list/datum/market_purchase/queue = list() + +/obj/machinery/ltsrbt/Initialize(mapload) + . = ..() + SSblackmarket.telepads += src + +/obj/machinery/ltsrbt/Destroy() + SSblackmarket.telepads -= src + // Bye bye orders. + if(SSblackmarket.telepads.len) + for(var/datum/market_purchase/P in queue) + SSblackmarket.queue_item(P) + . = ..() + +/obj/machinery/ltsrbt/RefreshParts() + . = ..() + recharge_time = base_recharge_time + // On tier 4 recharge_time should be 20 and by default it is 80 as scanning modules should be tier 1. + for(var/obj/item/stock_parts/scanning_module/scanning_module in component_parts) + recharge_time -= scanning_module.rating * 10 + recharge_cooldown = recharge_time + + power_efficiency = 0 + for(var/obj/item/stock_parts/micro_laser/laser in component_parts) + power_efficiency += laser.rating + // Shouldn't happen but you never know. + if(!power_efficiency) + power_efficiency = 1 + +/// Adds /datum/market_purchase to queue unless the machine is free, then it sets the purchase to be instantly received +/obj/machinery/ltsrbt/proc/add_to_queue(datum/market_purchase/purchase) + if(!recharge_cooldown && !receiving && !transmitting) + receiving = purchase + return + queue += purchase + +/obj/machinery/ltsrbt/process(seconds_per_tick) + if(stat & NOPOWER) + return + + if(recharge_cooldown > 0) + recharge_cooldown -= seconds_per_tick + return + + var/turf/T = get_turf(src) + if(receiving) + var/datum/market_purchase/P = receiving + + if(!P.item || ispath(P.item)) + P.item = P.entry.spawn_item(T) + else + var/atom/movable/M = P.item + M.forceMove(T) + + use_power(power_usage_per_teleport / power_efficiency) + var/datum/effect_system/spark_spread/sparks = new + sparks.set_up(5, 1, get_turf(src)) + sparks.attach(P.item) + sparks.start() + + receiving = null + transmitting = P + + recharge_cooldown = recharge_time + return + else if(transmitting) + var/datum/market_purchase/P = transmitting + if(!P.item) + QDEL_NULL(transmitting) + if(!(P.item in T.contents)) + QDEL_NULL(transmitting) + return + do_teleport(P.item, get_turf(P.uplink)) + use_power(power_usage_per_teleport / power_efficiency) + QDEL_NULL(transmitting) + + recharge_cooldown = recharge_time + return + + if(queue.len) + receiving = pick_n_take(queue) diff --git a/modular_dripstation/code/modules/cargo/markets/market_uplink.dm b/modular_dripstation/code/modules/cargo/markets/market_uplink.dm new file mode 100644 index 000000000000..02a1ff7c877a --- /dev/null +++ b/modular_dripstation/code/modules/cargo/markets/market_uplink.dm @@ -0,0 +1,171 @@ +/obj/item/market_uplink + name = "\improper Market Uplink" + desc = "An market uplink. Usable with markets. You probably shouldn't have this!" + icon = 'modular_dripstation/icons/obj/blackmarket/blackmarket.dmi' + icon_state = "uplink" + + // UI variables. + /// What category is the current uplink viewing? + var/viewing_category + /// What market is currently being bought from by the uplink? + var/viewing_market + /// What item is the current uplink attempting to buy? + var/selected_item + /// Is the uplink in the process of buying the selected item? + var/buying + ///Reference to the currently logged in user's bank account. + var/datum/bank_account/current_user + /// List of typepaths for "/datum/market"s that this uplink can access. + var/list/accessible_markets = list(/datum/market/blackmarket) + +/obj/item/market_uplink/Initialize(mapload) + . = ..() + // We don't want to go through this at mapload because the SSblackmarket isn't initialized yet. + if(mapload) + return + + update_viewing_category() + +/// Simple internal proc for updating the viewing_category variable. +/obj/item/market_uplink/proc/update_viewing_category() + if(accessible_markets.len) + viewing_market = accessible_markets[1] + var/list/categories = SSblackmarket.markets[viewing_market].categories + if(categories?.len) + viewing_category = categories[1] + +/obj/item/market_uplink/ui_interact(mob/user, datum/tgui/ui) + if(!viewing_category) + update_viewing_category() + + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "BlackMarketUplink", name) + ui.open() + +/obj/item/market_uplink/ui_data(mob/user) + var/list/data = list() + var/datum/market/market = viewing_market ? SSblackmarket.markets[viewing_market] : null + var/obj/item/card/id/id_card + if(isliving(user)) + var/mob/living/livin = user + id_card = livin.get_idcard() + if(id_card?.registered_account) + current_user = id_card.registered_account + else + current_user = null + data["categories"] = market ? market.categories : null + data["delivery_methods"] = list() + if(market) + for(var/delivery in market.shipping) + data["delivery_methods"] += list(list("name" = delivery, "price" = market.shipping[delivery])) + data["money"] = "N/A cr" + if(current_user) + data["money"] = current_user.account_balance + data["buying"] = buying + data["items"] = list() + data["viewing_category"] = viewing_category + data["viewing_market"] = viewing_market + if(viewing_category && market) + if(market.available_items[viewing_category]) + for(var/datum/market_item/I in market.available_items[viewing_category]) + data["items"] += list(list( + "id" = I.type, + "name" = I.name, + "cost" = I.price, + "amount" = I.stock, + "desc" = I.desc || I.name + )) + return data + +/obj/item/market_uplink/ui_static_data(mob/user) + var/list/data = list() + data["delivery_method_description"] = SSblackmarket.shipping_method_descriptions + data["ltsrbt_built"] = SSblackmarket.telepads.len + data["markets"] = list() + for(var/M in accessible_markets) + var/datum/market/BM = SSblackmarket.markets[M] + data["markets"] += list(list( + "id" = M, + "name" = BM.name + )) + return data + +/obj/item/market_uplink/ui_act(action, params) + . = ..() + if(.) + return + switch(action) + if("set_category") + if(isnull(params["category"])) + return + if(isnull(viewing_market)) + return + if(!(params["category"] in SSblackmarket.markets[viewing_market].categories)) + return + viewing_category = params["category"] + . = TRUE + if("set_market") + if(isnull(params["market"])) + return + var/market = text2path(params["market"]) + if(!(market in accessible_markets)) + return + + viewing_market = market + + var/list/categories = SSblackmarket.markets[viewing_market].categories + if(categories?.len) + viewing_category = categories[1] + else + viewing_category = null + . = TRUE + if("select") + if(isnull(params["item"])) + return + var/item = text2path(params["item"]) + selected_item = item + buying = TRUE + . = TRUE + if("cancel") + selected_item = null + buying = FALSE + . = TRUE + if("buy") + if(isnull(params["method"])) + return + if(isnull(selected_item)) + buying = FALSE + return + var/datum/market/market = SSblackmarket.markets[viewing_market] + market.purchase(selected_item, viewing_category, params["method"], src, usr) + + buying = FALSE + selected_item = null + +/obj/item/market_uplink/blackmarket + name = "\improper Black Market Uplink" + desc = "An illegal black market uplink. If command wanted you to have these, they wouldn't have made it so hard to get one." + icon = 'modular_dripstation/icons/obj/blackmarket/blackmarket.dmi' + icon_state = "uplink" + //The original black market uplink + accessible_markets = list(/datum/market/blackmarket) + + +/datum/crafting_recipe/blackmarket_uplink + name = "Black Market Uplink" + result = /obj/item/market_uplink/blackmarket + time = 15 SECONDS + tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER, TOOL_MULTITOOL) + reqs = list( + /obj/item/stock_parts/micro_laser = 1, + /obj/item/assembly/signaler = 1, + /obj/item/stack/cable_coil = 15, + /obj/item/radio = 1, + /obj/item/analyzer = 1) + category = CAT_EQUIPMENT + +/datum/crafting_recipe/blackmarket_uplink/New() + ..() + blacklist |= typesof(/obj/item/radio/headset) // because we got shit like /obj/item/radio/off ... WHY!?! + blacklist |= typesof(/obj/item/radio/intercom) diff --git a/modular_dripstation/code/modules/cargo/packs.dm b/modular_dripstation/code/modules/cargo/packs.dm new file mode 100644 index 000000000000..4921dddcc3b7 --- /dev/null +++ b/modular_dripstation/code/modules/cargo/packs.dm @@ -0,0 +1,105 @@ +/datum/supply_pack + var/order_limit = -1 // The number of times one can order a cargo crate, before it becomes restricted. -1 for infinite + var/times_ordered = 0 // Number of times a crate has been ordered in a shift + var/order_limit_in_one_order = -1 // The number of times one can order a cargo crate, before it becomes restricted. -1 for infinite + var/times_ordered_in_one_order = 0 // Number of times a crate has been ordered in one package + +//specialops edit +/datum/supply_pack/emergency/specialops + desc = "(*!&@#TOO CHEAP FOR THAT NULL_ENTRY, HUH OPERATIVE? WELL, THIS LITTLE ORDER CAN STILL HELP YOU OUT IN A PINCH. CONTAINS A BOX OF FIVE EMP GRENADES, THREE SMOKEBOMBS, AN INCENDIARY GRENADE, A \"SLEEPY PEN\" FULL OF NICE TOXINS AND YOUR NEW GEAR!#@*$" + cost = 6000 + order_limit = 2 + contains = list(/obj/item/storage/box/emps, + /obj/item/grenade/smokebomb, + /obj/item/grenade/smokebomb, + /obj/item/grenade/smokebomb, + /obj/item/pen/blue/sleepy, + /obj/item/grenade/chem_grenade/incendiary, + /obj/item/clothing/glasses/night, + /obj/item/storage/belt/holster/syndicate, + /obj/item/clothing/mask/gas/syndicate, + /obj/item/clothing/under/syndicate/combat, + /obj/item/clothing/shoes/combat) + crate_name = "crate" + crate_type = /obj/structure/closet/crate + +//telepad for black market +/datum/supply_pack/costumes_toys/blackmarket_telepad + name = "Black Market LTSRBT" + desc = "Need a faster and better way of transporting your illegal goods from and to the \ + station? Fear not, the Long-To-Short-Range-Bluespace-Transceiver (LTSRBT for short) \ + is here to help. Contains a LTSRBT circuit, two bluespace crystals, and one ansible." + cost = 26000 + contraband = TRUE + contains = list(/obj/item/circuitboard/machine/ltsrbt, + /obj/item/stack/ore/bluespace_crystal/artificial = 2, + /obj/item/stock_parts/subspace/ansible) + crate_name = "crate" + +//nullcrate check +/datum/supply_pack/emergency/nullcrate + name = "NULL_ENTRY" + desc = "(#@&^$THIS IS YOUR LOVELY PACKAGE THAT CONTAINS SOME RANDOM SYNDICATE STUFF. GIVE EM HELL, OPERATIVE@&!*()" + hidden = TRUE + order_limit_in_one_order = 2 + order_limit = 10 + cost = 12000 + crate_name = "crate" + crate_type = /obj/structure/closet/crate + contains = list() + +/datum/supply_pack/emergency/nullcrate/fill(obj/structure/closet/crate/C) + switch (rand(0,3)) + if(0) + new /obj/item/gun/ballistic/automatic/pistol(C) + new /obj/item/ammo_box/magazine/m10mm(C) + new /obj/item/ammo_box/magazine/m10mm(C) + if(1) + new /obj/item/gun/ballistic/rifle/boltaction(C) + new /obj/item/ammo_box/a762(C) + if(2) + new /obj/item/gun/ballistic/automatic/toy/pistol/riot(C) + new /obj/item/ammo_box/magazine/toy/pistol/riot(C) + new /obj/item/ammo_box/foambox/riot(C) + if(3) + new /obj/item/pen/red/edagger(C) + new /obj/item/grenade/plastic/c4(C) + for(var/i in 1 to 2) + //Gear + var/item = pick(/obj/item/clothing/shoes/magboots/syndie, + /obj/item/clothing/gloves/fingerless/bigboss, + /obj/item/storage/backpack/duffelbag/syndie, + /obj/item/storage/belt/chameleon/syndicate, + /obj/item/clothing/under/chameleon, + /obj/item/clothing/suit/chameleon, + /obj/item/flashlight/emp, + /obj/item/syndicateReverseCard, + /obj/item/camera_bug, + /obj/item/storage/toolbox/syndicate) + new item(C) + //Misk + item = pick(/obj/item/storage/box/syndie_kit/cutouts, + /obj/item/disk/nuclear/fake, + /obj/item/toy/plush/carpplushie/dehy_carp, + /obj/item/storage/pill_bottle/gummies/omnizine, + /obj/item/storage/pill_bottle/gummies/sleepy, + /obj/item/storage/fancy/cigarettes/cigpack_syndicate, + /obj/item/stack/tape/guerrilla, + /obj/item/soap/syndie, + /obj/item/flashlight/lantern/syndicate, + /obj/item/storage/box/syndie_kit/bugs, + /obj/item/computer_hardware/hard_drive/portable/syndicate/ntnet_dos, + /obj/item/storage/box/syndie_kit/throwing_weapons, + /obj/item/multitool/ai_detect, + /obj/item/stamp/syndiround, + /obj/item/suppressor) + new item(C) + +/datum/supply_pack/security/armory/laser //dripstation mooving lethals to the armory + name = "Lasers Crate" + desc = "Contains three lethal, high-energy laser guns. Requires Armory access to open." + cost = 2000 + contains = list(/obj/item/gun/energy/laser, + /obj/item/gun/energy/laser, + /obj/item/gun/energy/laser) + crate_name = "laser crate" \ No newline at end of file diff --git a/modular_dripstation/code/modules/job/job_types/janitor.dm b/modular_dripstation/code/modules/job/job_types/janitor.dm new file mode 100644 index 000000000000..2898e9b82a3d --- /dev/null +++ b/modular_dripstation/code/modules/job/job_types/janitor.dm @@ -0,0 +1,2 @@ +/datum/job/janitor + base_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM, ACCESS_MAILSORTING, ACCESS_RESEARCH, ACCESS_MEDICAL, ACCESS_CONSTRUCTION) \ No newline at end of file diff --git a/modular_dripstation/code/modules/job/job_types/quartermaster.dm b/modular_dripstation/code/modules/job/job_types/quartermaster.dm new file mode 100644 index 000000000000..9b0a1dc7ebdb --- /dev/null +++ b/modular_dripstation/code/modules/job/job_types/quartermaster.dm @@ -0,0 +1,11 @@ +/datum/job/qm + mail_goodies = list( + /obj/item/stack/sheet/mineral/gold = 10, + /obj/item/circuitboard/machine/emitter = 5, + /obj/item/survivalcapsule/luxuryelite = 3, + /obj/item/construction/rcd = 3, + /obj/item/circuitboard/machine/vending/donksofttoyvendor = 2 + ) + +/datum/outfit/job/quartermaster + backpack_contents = list(/obj/item/melee/classic_baton/telescopic = 1) \ No newline at end of file diff --git a/modular_dripstation/icons/mob/clothing/belt.dmi b/modular_dripstation/icons/mob/clothing/belt.dmi new file mode 100644 index 000000000000..d2edeffb8753 Binary files /dev/null and b/modular_dripstation/icons/mob/clothing/belt.dmi differ diff --git a/modular_dripstation/icons/mob/clothing/guns_on_back.dmi b/modular_dripstation/icons/mob/clothing/guns_on_back.dmi new file mode 100644 index 000000000000..0e88c3e92c8b Binary files /dev/null and b/modular_dripstation/icons/mob/clothing/guns_on_back.dmi differ diff --git a/modular_dripstation/icons/mob/clothing/hands.dmi b/modular_dripstation/icons/mob/clothing/hands.dmi new file mode 100644 index 000000000000..c2f296c60b28 Binary files /dev/null and b/modular_dripstation/icons/mob/clothing/hands.dmi differ diff --git a/modular_dripstation/icons/mob/inhands/equipment/boxcutter_lefthand.dmi b/modular_dripstation/icons/mob/inhands/equipment/boxcutter_lefthand.dmi new file mode 100644 index 000000000000..73f563d66d61 Binary files /dev/null and b/modular_dripstation/icons/mob/inhands/equipment/boxcutter_lefthand.dmi differ diff --git a/modular_dripstation/icons/mob/inhands/equipment/boxcutter_righthand.dmi b/modular_dripstation/icons/mob/inhands/equipment/boxcutter_righthand.dmi new file mode 100644 index 000000000000..d83a9f2fe652 Binary files /dev/null and b/modular_dripstation/icons/mob/inhands/equipment/boxcutter_righthand.dmi differ diff --git a/modular_dripstation/icons/mob/inhands/equipment/cargo_teleporter_lefthand.dmi b/modular_dripstation/icons/mob/inhands/equipment/cargo_teleporter_lefthand.dmi new file mode 100644 index 000000000000..abde6177b576 Binary files /dev/null and b/modular_dripstation/icons/mob/inhands/equipment/cargo_teleporter_lefthand.dmi differ diff --git a/modular_dripstation/icons/mob/inhands/equipment/cargo_teleporter_righthand.dmi b/modular_dripstation/icons/mob/inhands/equipment/cargo_teleporter_righthand.dmi new file mode 100644 index 000000000000..804322b94a34 Binary files /dev/null and b/modular_dripstation/icons/mob/inhands/equipment/cargo_teleporter_righthand.dmi differ diff --git a/modular_dripstation/icons/mob/inhands/guns_lefthand.dmi b/modular_dripstation/icons/mob/inhands/guns_lefthand.dmi new file mode 100644 index 000000000000..87d9332db003 Binary files /dev/null and b/modular_dripstation/icons/mob/inhands/guns_lefthand.dmi differ diff --git a/modular_dripstation/icons/mob/inhands/guns_righthand.dmi b/modular_dripstation/icons/mob/inhands/guns_righthand.dmi new file mode 100644 index 000000000000..be3e720e8a37 Binary files /dev/null and b/modular_dripstation/icons/mob/inhands/guns_righthand.dmi differ diff --git a/modular_dripstation/icons/mob/inhands/security_lefthand.dmi b/modular_dripstation/icons/mob/inhands/security_lefthand.dmi new file mode 100644 index 000000000000..b3f49af053ef Binary files /dev/null and b/modular_dripstation/icons/mob/inhands/security_lefthand.dmi differ diff --git a/modular_dripstation/icons/mob/inhands/security_righthand.dmi b/modular_dripstation/icons/mob/inhands/security_righthand.dmi new file mode 100644 index 000000000000..65c48c22f7e6 Binary files /dev/null and b/modular_dripstation/icons/mob/inhands/security_righthand.dmi differ diff --git a/modular_dripstation/icons/mob/mecha/cargo_hauler.dmi b/modular_dripstation/icons/mob/mecha/cargo_hauler.dmi new file mode 100644 index 000000000000..4c549ac87bcc Binary files /dev/null and b/modular_dripstation/icons/mob/mecha/cargo_hauler.dmi differ diff --git a/modular_dripstation/icons/obj/bepis/bepis.dmi b/modular_dripstation/icons/obj/bepis/bepis.dmi new file mode 100644 index 000000000000..f348c2e1b055 Binary files /dev/null and b/modular_dripstation/icons/obj/bepis/bepis.dmi differ diff --git a/modular_dripstation/icons/obj/blackmarket/blackmarket.dmi b/modular_dripstation/icons/obj/blackmarket/blackmarket.dmi new file mode 100644 index 000000000000..99f4811ea6b9 Binary files /dev/null and b/modular_dripstation/icons/obj/blackmarket/blackmarket.dmi differ diff --git a/modular_dripstation/icons/obj/blackmarket/module.dmi b/modular_dripstation/icons/obj/blackmarket/module.dmi new file mode 100644 index 000000000000..ff9ce847d797 Binary files /dev/null and b/modular_dripstation/icons/obj/blackmarket/module.dmi differ diff --git a/modular_dripstation/icons/obj/blackmarket/telecoms.dmi b/modular_dripstation/icons/obj/blackmarket/telecoms.dmi new file mode 100644 index 000000000000..fb0da921d9d4 Binary files /dev/null and b/modular_dripstation/icons/obj/blackmarket/telecoms.dmi differ diff --git a/modular_dripstation/icons/obj/bureaucracy.dmi b/modular_dripstation/icons/obj/bureaucracy.dmi index d883cbecb413..bda80eb870de 100644 Binary files a/modular_dripstation/icons/obj/bureaucracy.dmi and b/modular_dripstation/icons/obj/bureaucracy.dmi differ diff --git a/modular_dripstation/icons/obj/cargo/boxcutter.dmi b/modular_dripstation/icons/obj/cargo/boxcutter.dmi new file mode 100644 index 000000000000..4f1c3ec30f55 Binary files /dev/null and b/modular_dripstation/icons/obj/cargo/boxcutter.dmi differ diff --git a/modular_dripstation/icons/obj/cargo/cargo_inducer.dmi b/modular_dripstation/icons/obj/cargo/cargo_inducer.dmi new file mode 100644 index 000000000000..3b027c6418fd Binary files /dev/null and b/modular_dripstation/icons/obj/cargo/cargo_inducer.dmi differ diff --git a/modular_dripstation/icons/obj/cargo/cargo_teleporter.dmi b/modular_dripstation/icons/obj/cargo/cargo_teleporter.dmi new file mode 100644 index 000000000000..75bafcbbea02 Binary files /dev/null and b/modular_dripstation/icons/obj/cargo/cargo_teleporter.dmi differ diff --git a/modular_dripstation/icons/obj/circuit_mess.dmi b/modular_dripstation/icons/obj/circuit_mess.dmi new file mode 100644 index 000000000000..559e67806617 Binary files /dev/null and b/modular_dripstation/icons/obj/circuit_mess.dmi differ diff --git a/modular_dripstation/icons/obj/clothing/gloves.dmi b/modular_dripstation/icons/obj/clothing/gloves.dmi new file mode 100644 index 000000000000..8ed1f72553f7 Binary files /dev/null and b/modular_dripstation/icons/obj/clothing/gloves.dmi differ diff --git a/modular_dripstation/icons/obj/clothing/shoes.dmi b/modular_dripstation/icons/obj/clothing/shoes.dmi new file mode 100644 index 000000000000..e878a1d33ed4 Binary files /dev/null and b/modular_dripstation/icons/obj/clothing/shoes.dmi differ diff --git a/modular_dripstation/icons/obj/device.dmi b/modular_dripstation/icons/obj/device.dmi index c4093e118bf0..1555a11664de 100644 Binary files a/modular_dripstation/icons/obj/device.dmi and b/modular_dripstation/icons/obj/device.dmi differ diff --git a/modular_dripstation/icons/obj/hypnochair.dmi b/modular_dripstation/icons/obj/hypnochair.dmi new file mode 100644 index 000000000000..c25e429c649b Binary files /dev/null and b/modular_dripstation/icons/obj/hypnochair.dmi differ diff --git a/modular_dripstation/icons/obj/partypod.dmi b/modular_dripstation/icons/obj/partypod.dmi new file mode 100644 index 000000000000..cb6f2a6dc1c3 Binary files /dev/null and b/modular_dripstation/icons/obj/partypod.dmi differ diff --git a/modular_dripstation/icons/obj/weapons/48x32.dmi b/modular_dripstation/icons/obj/weapons/48x32.dmi new file mode 100644 index 000000000000..7b7ee4064aa2 Binary files /dev/null and b/modular_dripstation/icons/obj/weapons/48x32.dmi differ diff --git a/modular_dripstation/icons/obj/weapons/security.dmi b/modular_dripstation/icons/obj/weapons/security.dmi new file mode 100644 index 000000000000..d510634d6f16 Binary files /dev/null and b/modular_dripstation/icons/obj/weapons/security.dmi differ diff --git a/modular_dripstation/includes.dm b/modular_dripstation/includes.dm index 333da863fe10..4c8915b0780a 100644 --- a/modular_dripstation/includes.dm +++ b/modular_dripstation/includes.dm @@ -1,3 +1,55 @@ +#include "code\controllers\subsystem\blackmarket.dm" +#include "code\datum\brain_damage\severe.dm" +#include "code\datum\component\transforming.dm" +#include "code\datum\reagent\baldium.dm" +#include "code\datum\reagent\chemoverride.dm" +#include "code\datum\reagent\leadacetate.dm" +#include "code\datum\strong_pull.dm" +#include "code\game\effects\effects_foam.dm" +#include "code\game\mecha\cargo_hauler.dm" +#include "code\game\objects\items\bepis_items\boomerang.dm" +#include "code\game\objects\items\bepis_items\eng_gloves.dm" +#include "code\game\objects\items\bepis_items\explorerpin.dm" +#include "code\game\objects\items\bepis_items\hypnochair.dm" +#include "code\game\objects\items\bepis_items\lava_rods.dm" +#include "code\game\objects\items\bepis_items\party_pod.dm" +#include "code\game\objects\items\bepis_items\polycircuit.dm" +#include "code\game\objects\items\bepis_items\rldmini.dm" +#include "code\game\objects\items\bepis_items\sprayoncan.dm" +#include "code\game\objects\items\bepis_items\survival_pen.dm" +#include "code\game\objects\items\blackmarketstuff.dm" +#include "code\game\objects\items\cargo_boxcutter.dm" +#include "code\game\objects\items\cargo_inducer.dm" +#include "code\game\objects\items\cargo_teleporter.dm" +#include "code\game\objects\items\clothing\gloves.dm" +#include "code\game\objects\items\devices\PDA\PDA_types.dm" +#include "code\game\objects\items\projectiles\guns\ballistic\rifle.dm" +#include "code\game\objects\items\tanks\watertank.dm" +#include "code\game\turfs\simulated\walls.dm" +#include "code\modules\antagonists\changeling\panacea.dm" +#include "code\modules\antagonists\horror\horror_chemicals.dm" +#include "code\modules\bepis\all_nodes.dm" +#include "code\modules\bepis\bepis.dm" +#include "code\modules\bepis\bepis_board.dm" +#include "code\modules\bepis\bepis_designs.dm" +#include "code\modules\bepis\bepis_layout.dm" +#include "code\modules\bepis\bounty.dm" +#include "code\modules\bepis\designs.dm" +#include "code\modules\cargo\bounties\progression.dm" +#include "code\modules\cargo\bounties\syndicate.dm" +#include "code\modules\cargo\export_scaner.dm" +#include "code\modules\cargo\markets\_market.dm" +#include "code\modules\cargo\markets\market_item.dm" +#include "code\modules\cargo\markets\market_items\clothing.dm" +#include "code\modules\cargo\markets\market_items\consumables.dm" +#include "code\modules\cargo\markets\market_items\misc.dm" +#include "code\modules\cargo\markets\market_items\tools.dm" +#include "code\modules\cargo\markets\market_items\weapons.dm" +#include "code\modules\cargo\markets\market_telepad.dm" +#include "code\modules\cargo\markets\market_uplink.dm" +#include "code\modules\cargo\packs.dm" +#include "code\modules\job\job_types\janitor.dm" +#include "code\modules\job\job_types\quartermaster.dm" #include "code\modules\antagonists\cult\cult_items.dm" #include "code\modules\antagonists\cult\cult_structures.dm" #include "code\modules\antagonists\wizard\equipment\wizard_spellbook.dm" diff --git a/modular_dripstation/sound/item/boxcutter_activate.ogg b/modular_dripstation/sound/item/boxcutter_activate.ogg new file mode 100644 index 000000000000..6700c6d03fde Binary files /dev/null and b/modular_dripstation/sound/item/boxcutter_activate.ogg differ diff --git a/tgui/packages/tgui/interfaces/Bepis.js b/tgui/packages/tgui/interfaces/Bepis.js index 8315e4c935cd..60468e7aaf83 100644 --- a/tgui/packages/tgui/interfaces/Bepis.js +++ b/tgui/packages/tgui/interfaces/Bepis.js @@ -2,7 +2,7 @@ import { useBackend } from '../backend'; import { Box, Button, Grid, LabeledList, NumberInput, Section } from '../components'; import { Window } from '../layouts'; -export const Bepis = (props, context) => { +export const Bepis_old = (props, context) => { const { act, data } = useBackend(context); const { amount, diff --git a/tgui/packages/tgui/interfaces/Bepis.tsx b/tgui/packages/tgui/interfaces/Bepis.tsx new file mode 100644 index 000000000000..822a178e5b3a --- /dev/null +++ b/tgui/packages/tgui/interfaces/Bepis.tsx @@ -0,0 +1,129 @@ +import { BooleanLike } from 'common/react'; +import { useBackend } from '../backend'; +import { Box, Button, Grid, LabeledList, NumberInput, Section } from '../components'; +import { Window } from '../layouts'; + +type Data = { + amount: number; + account_owner: string; + manual_power: BooleanLike; + stored_cash: number; + accuracy_percentage: number; + positive_cash_offset: number; + negative_cash_offset: number; + silicon_check: BooleanLike; + success_estimate: number; + mean_value: number; + error_name: string; +}; + +const BEPIS_SLOGAN = `All you need to know about the B.E.P.I.S. and you! The +B.E.P.I.S. performs hundreds of tests a second using +electrical and financial resources to invent new products, +or discover new technologies otherwise overlooked for being +too risky or too niche to produce!`; + +export const Bepis = (props, context) => { + const { act, data } = useBackend(context); + const { + amount, + account_owner, + manual_power, + stored_cash, + accuracy_percentage, + positive_cash_offset, + negative_cash_offset, + silicon_check, + success_estimate, + mean_value, + error_name, + } = data; + + return ( + + +
+
act('toggle_power')} + /> + }> + {BEPIS_SLOGAN} +
+
act('account_reset')} + /> + }> + Console is currently being linked to {' '}{account_owner ? account_owner : 'no one'}`s account. +
+ + +
+ + + {stored_cash} + + + {accuracy_percentage}% + + + {positive_cash_offset} + + + {negative_cash_offset} + + + + act('amount', { + amount: value, + }) + } + /> + + +
+ +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/Party.js b/tgui/packages/tgui/interfaces/Party.js new file mode 100644 index 000000000000..7896471dfbac --- /dev/null +++ b/tgui/packages/tgui/interfaces/Party.js @@ -0,0 +1,118 @@ +import { useBackend } from '../backend'; +import { Box, Button, LabeledList, ProgressBar, Section } from '../components'; +import { Window } from '../layouts'; + +const damageTypes = [ + { + label: 'Brute', + type: 'bruteLoss', + }, + { + label: 'Burn', + type: 'fireLoss', + }, + { + label: 'Toxin', + type: 'toxLoss', + }, + { + label: 'Oxygen', + type: 'oxyLoss', + }, +]; + +export const Party = (props, context) => { + const { act, data } = useBackend(context); + const { open, occupant = {}, occupied } = data; + const preSortChems = data.chems || []; + const chems = preSortChems.sort((a, b) => { + const descA = a.name.toLowerCase(); + const descB = b.name.toLowerCase(); + if (descA < descB) { + return -1; + } + if (descA > descB) { + return 1; + } + return 0; + }); + return ( + + +
+ {occupant.stat} + + ) + }> + {!!occupied && ( + <> + + + + {damageTypes.map((type) => ( + + + + ))} + + {occupant.cloneLoss ? 'Damaged' : 'Healthy'} + + + {occupant.brainLoss ? 'Abnormal' : 'Healthy'} + + + + )} +
+
act('door')} + /> + }> + {chems.map((chem) => ( +
+
+
+ ); +}; diff --git a/yogstation.dme b/yogstation.dme index df88d14d961f..916586a0e2e9 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -183,6 +183,9 @@ #include "code\__DEFINES\dcs\signals\signals_mob\signals_simplemob.dm" #include "code\__DEFINES\dcs\signals\signals_mob\signals_tools.dm" #include "code\__DEFINES\dcs\signals\signals_mob\signals_xenobiology.dm" +#include "code\__DEFINES\{dripstation_defines}\blackmarket.dm" +#include "code\__DEFINES\{dripstation_defines}\cargo.dm" +#include "code\__DEFINES\{dripstation_defines}\dcs\signals\signals_transform.dm" #include "code\__DEFINES\{yogs_defines}\admin.dm" #include "code\__DEFINES\{yogs_defines}\antagonists.dm" #include "code\__DEFINES\{yogs_defines}\atmospherics.dm"