diff --git a/code/__DEFINES/storage.dm b/code/__DEFINES/storage.dm new file mode 100644 index 00000000000..cb657520e33 --- /dev/null +++ b/code/__DEFINES/storage.dm @@ -0,0 +1,88 @@ +// storage_flags variable on /datum/component/storage + +// Storage limits. These can be combined (and usually are combined). +/// Check max_items and contents.len when trying to insert +#define STORAGE_LIMIT_MAX_ITEMS (1<<0) +/// Check max_combined_w_class. +#define STORAGE_LIMIT_COMBINED_W_CLASS (1<<1) +/// Use the new volume system. Will automatically force rendering to use the new volume/baystation scaling UI so this is kind of incompatible with stuff like stack storage etc etc. +#define STORAGE_LIMIT_VOLUME (1<<2) +/// Use max_w_class +#define STORAGE_LIMIT_MAX_W_CLASS (1<<3) + +#define STORAGE_FLAGS_LEGACY_DEFAULT (STORAGE_LIMIT_MAX_ITEMS | STORAGE_LIMIT_COMBINED_W_CLASS | STORAGE_LIMIT_MAX_W_CLASS) +#define STORAGE_FLAGS_VOLUME_DEFAULT (STORAGE_LIMIT_VOLUME | STORAGE_LIMIT_MAX_W_CLASS) + +// UI defines +/// Size of volumetric box icon +#define VOLUMETRIC_STORAGE_BOX_ICON_SIZE 32 +/// Size of EACH left/right border icon for volumetric boxes +#define VOLUMETRIC_STORAGE_BOX_BORDER_SIZE 1 +/// Minimum pixels an item must have in volumetric scaled storage UI +#define MINIMUM_PIXELS_PER_ITEM 8 +/// Maximum number of objects that will be allowed to be displayed using the volumetric display system. Arbitrary number to prevent server lockups. +#define MAXIMUM_VOLUMETRIC_ITEMS 256 +/// How much padding to give between items +#define VOLUMETRIC_STORAGE_ITEM_PADDING 3 +/// How much padding to give to edges +#define VOLUMETRIC_STORAGE_EDGE_PADDING 1 + +//ITEM INVENTORY WEIGHT, FOR w_class +/// Usually items smaller then a human hand, ex: Playing Cards, Lighter, Scalpel, Coins/Money +#define WEIGHT_CLASS_TINY 1 +/// Fits within a small pocket, ex: Flashlight, Multitool, Grenades, GPS Device +#define WEIGHT_CLASS_SMALL 2 +/// Can be carried in one hand comfortably, ex: Fire extinguisher, Stunbaton, Gas Mask, Metal Sheets +#define WEIGHT_CLASS_NORMAL 3 +/// Items that can be wielded or equipped, (e.g. defibrillator, space suits). Often fits inside backpacks. +#define WEIGHT_CLASS_BULKY 4 +/// Usually represents objects that require two hands to operate, (e.g. shotgun, two-handed melee weapons) May fit on some inventory slots +#define WEIGHT_CLASS_HUGE 5 +/// Essentially means it cannot be picked up or placed in an inventory, ex: Mech Parts, Safe - Can not fit in Boh +#define WEIGHT_CLASS_GIGANTIC 6 + +// PLEASE KEEP ALL VOLUME DEFINES IN THIS FILE, it's going to be hell to keep track of them later. +#define DEFAULT_VOLUME_TINY 1 +#define DEFAULT_VOLUME_SMALL 2 +#define DEFAULT_VOLUME_NORMAL 6 +#define DEFAULT_VOLUME_BULKY 12 +#define DEFAULT_VOLUME_HUGE 24 +#define DEFAULT_VOLUME_GIGANTIC 48 + +GLOBAL_LIST_INIT(default_weight_class_to_volume, list( + "[WEIGHT_CLASS_TINY]" = DEFAULT_VOLUME_TINY, + "[WEIGHT_CLASS_SMALL]" = DEFAULT_VOLUME_SMALL, + "[WEIGHT_CLASS_NORMAL]" = DEFAULT_VOLUME_NORMAL, + "[WEIGHT_CLASS_BULKY]" = DEFAULT_VOLUME_BULKY, + "[WEIGHT_CLASS_HUGE]" = DEFAULT_VOLUME_HUGE, + "[WEIGHT_CLASS_GIGANTIC]" = DEFAULT_VOLUME_GIGANTIC + )) + +/// Macro for automatically getting the volume of an item from its w_class. +#define AUTO_SCALE_VOLUME(w_class) (GLOB.default_weight_class_to_volume["[w_class]"]) +/// Macro for automatically getting the volume of a storage item from its max_w_class and max_combined_w_class. +#define AUTO_SCALE_STORAGE_VOLUME(w_class, max_combined_w_class) (AUTO_SCALE_VOLUME(w_class) * (max_combined_w_class / w_class)) + +// Let's keep all of this in one place. given what we put above anyways.. + +// volume amount for items +#define ITEM_VOLUME_DISK DEFAULT_VOLUME_TINY +#define ITEM_VOLUME_CONTAINER_M 12 //makes nested toolboxes & toolbelts less efficient +#define ITEM_VOLUME_MOB 40//prevents mob stacking + +// #define SAMPLE_VOLUME_AMOUNT 2 + +// max_weight_class for storages +// +#define MAX_WEIGHT_CLASS_S_CONTAINER WEIGHT_CLASS_SMALL +#define MAX_WEIGHT_CLASS_M_CONTAINER WEIGHT_CLASS_NORMAL +#define MAX_WEIGHT_CLASS_BACKPACK WEIGHT_CLASS_NORMAL +#define MAX_WEIGHT_CLASS_DUFFEL WEIGHT_CLASS_BULKY + +// max_volume for storages +#define STORAGE_VOLUME_CONTAINER_S DEFAULT_VOLUME_NORMAL //3 small items +#define STORAGE_VOLUME_CONTAINER_M (DEFAULT_VOLUME_NORMAL * 2) //6 small items +#define STORAGE_VOLUME_SATCHEL (DEFAULT_VOLUME_NORMAL * 4) //4 normal items +#define STORAGE_VOLUME_BACKPACK (DEFAULT_VOLUME_NORMAL * 6) //6 normal items, or 3 bulky items +#define STORAGE_VOLUME_DUFFLEBAG (DEFAULT_VOLUME_NORMAL * 8) // 2 huge items, or 4 bulky items +#define STORAGE_VOLUME_BAG_OF_HOLDING (DEFAULT_VOLUME_NORMAL * 9) //1.5X backpack diff --git a/code/_onclick/hud/storage.dm b/code/_onclick/hud/storage.dm new file mode 100644 index 00000000000..c10375df4e8 --- /dev/null +++ b/code/_onclick/hud/storage.dm @@ -0,0 +1,198 @@ +/atom/movable/screen/storage + name = "storage" + var/insertion_click = FALSE + +/atom/movable/screen/storage/Initialize(mapload, new_master) + . = ..() + master = new_master + +/atom/movable/screen/storage/Click(location, control, params) + if(!insertion_click) + return ..() + if(hud?.mymob && (hud.mymob != usr)) + return + // just redirect clicks + if(master) + var/obj/item/I = usr.get_active_held_item() + if(I) + master.attackby(null, I, usr, params) + return TRUE + +/atom/movable/screen/storage/boxes + name = "storage" + icon_state = "block" + screen_loc = "7,7 to 10,8" + layer = HUD_LAYER + plane = HUD_PLANE + insertion_click = TRUE + +/atom/movable/screen/storage/close + name = "close" + layer = ABOVE_HUD_LAYER + plane = ABOVE_HUD_PLANE + icon_state = "backpack_close" + +/atom/movable/screen/storage/close/Click() + var/datum/component/storage/S = master + S.close(usr) + return TRUE + +/atom/movable/screen/storage/left + icon_state = "storage_start" + insertion_click = TRUE + +/atom/movable/screen/storage/right + icon_state = "storage_end" + insertion_click = TRUE + +/atom/movable/screen/storage/continuous + icon_state = "storage_continue" + insertion_click = TRUE + +/atom/movable/screen/storage/volumetric_box + icon_state = "stored_continue" + layer = VOLUMETRIC_STORAGE_BOX_LAYER + plane = VOLUMETRIC_STORAGE_BOX_PLANE + var/obj/item/our_item + +/atom/movable/screen/storage/volumetric_box/Initialize(mapload, new_master, obj/item/our_item) + src.our_item = our_item + RegisterSignal(our_item, COMSIG_ITEM_MOUSE_ENTER, PROC_REF(on_item_mouse_enter)) + RegisterSignal(our_item, COMSIG_ITEM_MOUSE_EXIT, PROC_REF(on_item_mouse_exit)) + return ..() + +/atom/movable/screen/storage/volumetric_box/Destroy() + makeItemInactive() + our_item = null + return ..() + +/atom/movable/screen/storage/volumetric_box/Click(location, control, params) + return our_item.Click(location, control, params) + +/atom/movable/screen/storage/volumetric_box/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) + return our_item.MouseDrop(over, src_location, over_location, src_control, over_control, params) + +/atom/movable/screen/storage/volumetric_box/MouseExited(location, control, params) + makeItemInactive() + +/atom/movable/screen/storage/volumetric_box/MouseEntered(location, control, params) + . = ..() + makeItemActive() + +/atom/movable/screen/storage/volumetric_box/proc/on_item_mouse_enter() + makeItemActive() + +/atom/movable/screen/storage/volumetric_box/proc/on_item_mouse_exit() + makeItemInactive() + +/atom/movable/screen/storage/volumetric_box/proc/makeItemInactive() + return + +/atom/movable/screen/storage/volumetric_box/proc/makeItemActive() + return + +/atom/movable/screen/storage/volumetric_box/center + icon_state = "stored_continue" + var/atom/movable/screen/storage/volumetric_edge/stored_left/left + var/atom/movable/screen/storage/volumetric_edge/stored_right/right + var/atom/movable/screen/storage/item_holder/holder + var/pixel_size + +/atom/movable/screen/storage/volumetric_box/center/Initialize(mapload, new_master, our_item) + left = new(null, src, our_item) + right = new(null, src, our_item) + return ..() + +/atom/movable/screen/storage/volumetric_box/center/Destroy() + QDEL_NULL(left) + QDEL_NULL(right) + vis_contents.Cut() + if(holder) + QDEL_NULL(holder) + return ..() + +/atom/movable/screen/storage/volumetric_box/center/proc/on_screen_objects() + return list(src) + + +//Sets the size of this box screen object and regenerates its left/right borders. This includes the actual border's size! +/atom/movable/screen/storage/volumetric_box/center/proc/set_pixel_size(pixels) + if(pixel_size == pixels) + return + pixel_size = pixels + cut_overlays() + vis_contents.Cut() + //our icon size is 32 pixels. + var/multiplier = (pixels - (VOLUMETRIC_STORAGE_BOX_BORDER_SIZE * 2)) / VOLUMETRIC_STORAGE_BOX_ICON_SIZE + transform = matrix(multiplier, 0, 0, 0, 1, 0) + if(our_item) + if(holder) + qdel(holder) + holder = new(null, src, our_item) + holder.transform = matrix(1 / multiplier, 0, 0, 0, 1, 0) + holder.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + holder.appearance_flags &= ~RESET_TRANSFORM + makeItemInactive() + vis_contents += holder + left.pixel_x = -((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) - VOLUMETRIC_STORAGE_BOX_BORDER_SIZE + right.pixel_x = ((pixels - VOLUMETRIC_STORAGE_BOX_ICON_SIZE) * 0.5) + VOLUMETRIC_STORAGE_BOX_BORDER_SIZE + add_overlay(left) + add_overlay(right) + +/atom/movable/screen/storage/volumetric_box/center/makeItemInactive() + if(!holder) + return + holder.layer = VOLUMETRIC_STORAGE_ITEM_LAYER + holder.plane = VOLUMETRIC_STORAGE_ITEM_PLANE + +/atom/movable/screen/storage/volumetric_box/center/makeItemActive() + if(!holder) + return + holder.our_item.layer = VOLUMETRIC_STORAGE_ACTIVE_ITEM_LAYER //make sure we display infront of the others! + holder.our_item.plane = VOLUMETRIC_STORAGE_ACTIVE_ITEM_PLANE + +/atom/movable/screen/storage/volumetric_edge + layer = VOLUMETRIC_STORAGE_BOX_LAYER + plane = VOLUMETRIC_STORAGE_BOX_PLANE + +/atom/movable/screen/storage/volumetric_edge/Initialize(mapload, master, our_item) + src.master = master + return ..() + +/atom/movable/screen/storage/volumetric_edge/Click(location, control, params) + return master.Click(location, control, params) + +/atom/movable/screen/storage/volumetric_edge/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) + return master.MouseDrop(over, src_location, over_location, src_control, over_control, params) + +/atom/movable/screen/storage/volumetric_edge/MouseExited(location, control, params) + return master.MouseExited(location, control, params) + +/atom/movable/screen/storage/volumetric_edge/MouseEntered(location, control, params) + . = ..() + return master.MouseEntered(location, control, params) + +/atom/movable/screen/storage/volumetric_edge/stored_left + icon_state = "stored_start" + appearance_flags = APPEARANCE_UI | KEEP_APART | RESET_TRANSFORM // Yes I know RESET_TRANSFORM is in APPEARANCE_UI but we're hard-asserting this incase someone changes it. + +/atom/movable/screen/storage/volumetric_edge/stored_right + icon_state = "stored_end" + appearance_flags = APPEARANCE_UI | KEEP_APART | RESET_TRANSFORM + +/atom/movable/screen/storage/item_holder + var/obj/item/our_item + vis_flags = NONE + +/atom/movable/screen/storage/item_holder/Initialize(mapload, new_master, obj/item/I) + . = ..() + our_item = I + vis_contents += I + +/atom/movable/screen/storage/item_holder/Destroy() + vis_contents.Cut() + our_item = null + return ..() + +/atom/movable/screen/storage/item_holder/Click(location, control, params) + return our_item.Click(location, control, params) diff --git a/code/controllers/subsystem/processing/movable_physics.dm b/code/controllers/subsystem/processing/movable_physics.dm new file mode 100644 index 00000000000..65015edbd66 --- /dev/null +++ b/code/controllers/subsystem/processing/movable_physics.dm @@ -0,0 +1,24 @@ +///Real fast ticking subsystem for moving movables via modifying pixel_x/y/z +PROCESSING_SUBSYSTEM_DEF(movablephysics) + name = "Movable Physics" + wait = 0.05 SECONDS + stat_tag = "MP" + priority = FIRE_PRIORITY_MOVABLE_PHYSICS + +/datum/controller/subsystem/processing/movablephysics/fire(resumed = FALSE) + if (!resumed) + currentrun = processing.Copy() + //cache for sanic speed (lists are references anyways) + var/list/current_run = currentrun + + while(current_run.len) + var/datum/component/thing = current_run[current_run.len] + current_run.len-- + if(QDELETED(thing)) + processing -= thing + else + if(thing.process(wait * 0.1) == PROCESS_KILL) + // fully stop so that a future START_PROCESSING will work + STOP_PROCESSING(src, thing) + if (MC_TICK_CHECK) + return diff --git a/code/datums/components/crafting/recipes/clothing.dm b/code/datums/components/crafting/recipes/clothing.dm new file mode 100644 index 00000000000..95b37502bca --- /dev/null +++ b/code/datums/components/crafting/recipes/clothing.dm @@ -0,0 +1,192 @@ +// Please separate them based on categories. Made this easier for all of us, god damn it! #Lianvee + +// Durathread +/datum/crafting_recipe/durathread_vest + name = "Durathread Vest" + result = /obj/item/clothing/suit/armor/vest/durathread + reqs = list( + /obj/item/stack/sheet/durathread = 5, + /obj/item/stack/sheet/leather = 4 + ) + time = 50 + category = CAT_CLOTHING + +/datum/crafting_recipe/durathread_helmet + name = "Durathread Helmet" + result = /obj/item/clothing/head/helmet/durathread + reqs = list( + /obj/item/stack/sheet/durathread = 4, + /obj/item/stack/sheet/leather = 5 + ) + time = 40 + category = CAT_CLOTHING + +/datum/crafting_recipe/durathread_jumpsuit + name = "Durathread Jumpsuit" + result = /obj/item/clothing/under/misc/durathread + reqs = list(/obj/item/stack/sheet/durathread = 4) + time = 40 + category = CAT_CLOTHING + +/datum/crafting_recipe/durathread_beret + name = "Durathread Beret" + result = /obj/item/clothing/head/beret/durathread + reqs = list(/obj/item/stack/sheet/durathread = 2) + time = 40 + category = CAT_CLOTHING + +/datum/crafting_recipe/durathread_beanie + name = "Durathread Beanie" + result = /obj/item/clothing/head/beanie/durathread + reqs = list(/obj/item/stack/sheet/durathread = 2) + time = 40 + category = CAT_CLOTHING + +/datum/crafting_recipe/durathread_bandana + name = "Durathread Bandana" + result = /obj/item/clothing/mask/bandana/durathread + reqs = list(/obj/item/stack/sheet/durathread = 1) + time = 25 + category = CAT_CLOTHING + +// Belts +/datum/crafting_recipe/fannypack + name = "Fannypack" + result = /obj/item/storage/belt/fannypack + reqs = list( + /obj/item/stack/sheet/cotton/cloth = 2, + /obj/item/stack/sheet/leather = 1 + ) + time = 20 + category = CAT_CLOTHING + +// Eyewear +/datum/crafting_recipe/hudsunsec + name = "Security HUDsunglasses" + result = /obj/item/clothing/glasses/hud/security/sunglasses + time = 20 + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list( + /obj/item/clothing/glasses/hud/security = 1, + /obj/item/clothing/glasses/sunglasses = 1, + /obj/item/stack/cable_coil = 5 + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/hudsunmed + name = "Medical HUDsunglasses" + result = /obj/item/clothing/glasses/hud/health/sunglasses + time = 20 + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list( + /obj/item/clothing/glasses/hud/health = 1, + /obj/item/clothing/glasses/sunglasses = 1, + /obj/item/stack/cable_coil = 5 + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/hudsundiag + name = "Diagnostic HUDsunglasses" + result = /obj/item/clothing/glasses/hud/diagnostic/sunglasses + time = 20 + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list( + /obj/item/clothing/glasses/hud/diagnostic = 1, + /obj/item/clothing/glasses/sunglasses = 1, + /obj/item/stack/cable_coil = 5 + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/sciencesunglasses + name = "Science Sunglasses" + result = /obj/item/clothing/glasses/sunglasses/chemical + time = 20 + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list( + /obj/item/clothing/glasses/science = 1, + /obj/item/clothing/glasses/sunglasses = 1, + /obj/item/stack/cable_coil = 5 + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/medhudglasses // The prescription HUD glasses. This long to have them... #Lianvee + name = "MedicalHUD Prescription Glasses" + result = /obj/item/clothing/glasses/hud/health/prescription + time = 20 + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list( + /obj/item/clothing/glasses/hud/health = 1, + /obj/item/clothing/glasses/regular = 1, + /obj/item/stack/cable_coil = 5 + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/sechudglasses + name = "SecurityHUD Prescription Glasses" + result = /obj/item/clothing/glasses/hud/security/prescription + time = 20 + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list( + /obj/item/clothing/glasses/hud/security = 1, + /obj/item/clothing/glasses/regular = 1, + /obj/item/stack/cable_coil = 5 + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/mesonglasses + name = "Meson Prescription Glasses" + result = /obj/item/clothing/glasses/meson/prescription + time = 20 + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list( + /obj/item/clothing/glasses/meson = 1, + /obj/item/clothing/glasses/regular = 1, + /obj/item/stack/cable_coil = 5 + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/scienceglasses + name = "Science Prescription Glasses" + result = /obj/item/clothing/glasses/science/prescription + time = 20 + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + reqs = list( + /obj/item/clothing/glasses/science = 1, + /obj/item/clothing/glasses/regular = 1, + /obj/item/stack/cable_coil = 5 + ) + category = CAT_CLOTHING + +// Misc. +/datum/crafting_recipe/ghostsheet + name = "Ghost Sheet" + result = /obj/item/clothing/suit/ghost_sheet + time = 5 + tools = list(TOOL_WIRECUTTER) + reqs = list(/obj/item/bedsheet = 1) + category = CAT_CLOTHING + +/datum/crafting_recipe/cowboyboots + name = "Cowboy Boots" + result = /obj/item/clothing/shoes/cowboy + reqs = list(/obj/item/stack/sheet/leather = 2) + time = 45 + category = CAT_CLOTHING + +/datum/crafting_recipe/gripperoffbrand + name = "Improvised Gripper Gloves" + reqs = list( + /obj/item/clothing/gloves/fingerless = 1, + /obj/item/stack/tape = 1) + result = /obj/item/clothing/gloves/tackler/offbrand + category = CAT_CLOTHING + +/datum/crafting_recipe/scrap_armor + name = "Scrap Armor" + result = /obj/item/clothing/suit/armor/vest/scrap_armor + time = 60 + reqs = list( + /obj/item/stack/sheet/metal = 10, + /obj/item/stack/cable_coil = 20, + ) + category = CAT_CLOTHING diff --git a/code/datums/components/crafting/recipes/drink.dm b/code/datums/components/crafting/recipes/drink.dm new file mode 100644 index 00000000000..5ca6d14814c --- /dev/null +++ b/code/datums/components/crafting/recipes/drink.dm @@ -0,0 +1,52 @@ +/datum/crafting_recipe/umbrellared + name = "Red Drink Umbrella" + result = /obj/item/garnish/umbrellared + time = 1 SECONDS + tools = list(/obj/item/toy/crayon/spraycan) + reqs = list( + /obj/item/paper = 1, + /obj/item/stack/rods = 1) + category = CAT_DRINK + +/datum/crafting_recipe/umbrellablue + name = "Blue Drink Umbrella" + result = /obj/item/garnish/umbrellablue + time = 1 SECONDS + tools = list(/obj/item/toy/crayon/spraycan) + reqs = list( + /obj/item/paper = 1, + /obj/item/stack/rods = 1) + category = CAT_DRINK + +/datum/crafting_recipe/umbrellagreen + name = "Green Drink Umbrella" + result = /obj/item/garnish/umbrellagreen + time = 1 SECONDS + tools = list(/obj/item/toy/crayon/spraycan) + reqs = list( + /obj/item/paper = 1, + /obj/item/stack/rods = 1) + category = CAT_DRINK + +/datum/crafting_recipe/ash_garnish + name = "Ash Garnish" + result = /obj/item/garnish/ash + reqs = list(/datum/reagent/ash = 10) + time = 5 + category = CAT_DRINK + +/datum/crafting_recipe/salt_garnish + name = "Salt Garnish" + result = /obj/item/garnish/salt + reqs = list(/datum/reagent/consumable/sodiumchloride = 10) + time = 5 + category = CAT_DRINK + +/datum/crafting_recipe/breakawayflask + name = "Breakaway Flask" + result = /obj/item/reagent_containers/food/drinks/breakawayflask + time = 5 SECONDS + reqs = list(/obj/item/stack/sheet/glass = 5, + /obj/item/stack/sheet/mineral/plasma = 1) + tools = list(TOOL_WELDER) + category = CAT_DRINK diff --git a/code/datums/components/crafting/recipes/misc.dm b/code/datums/components/crafting/recipes/misc.dm new file mode 100644 index 00000000000..0ed4acb5be7 --- /dev/null +++ b/code/datums/components/crafting/recipes/misc.dm @@ -0,0 +1,220 @@ +/datum/crafting_recipe/skateboard + name = "Skateboard" + result = /obj/vehicle/ridden/scooter/skateboard + time = 60 + reqs = list(/obj/item/stack/sheet/metal = 5, + /obj/item/stack/rods = 10) + category = CAT_MISC + +/datum/crafting_recipe/scooter + name = "Scooter" + result = /obj/vehicle/ridden/scooter + time = 65 + reqs = list(/obj/item/stack/sheet/metal = 5, + /obj/item/stack/rods = 12) + category = CAT_MISC + +/datum/crafting_recipe/wheelchair + name = "Wheelchair" + result = /obj/vehicle/ridden/wheelchair + reqs = list(/obj/item/stack/sheet/metal = 4, + /obj/item/stack/rods = 6) + time = 100 + category = CAT_MISC + +/datum/crafting_recipe/motorized_wheelchair + name = "Motorized Wheelchair" + result = /obj/vehicle/ridden/wheelchair/motorized + reqs = list(/obj/item/stack/sheet/metal = 10, + /obj/item/stack/rods = 8, + /obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/capacitor = 1) + parts = list(/obj/item/stock_parts/manipulator = 2, + /obj/item/stock_parts/capacitor = 1) + tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH) + time = 200 + category = CAT_MISC + +/datum/crafting_recipe/mousetrap + name = "Mouse Trap" + result = /obj/item/assembly/mousetrap + time = 10 + reqs = list(/obj/item/stack/sheet/cardboard = 1, + /obj/item/stack/rods = 1) + category = CAT_MISC + +/datum/crafting_recipe/papersack + name = "Paper Sack" + result = /obj/item/storage/box/papersack + time = 10 + reqs = list(/obj/item/paper = 5) + category = CAT_MISC + +/datum/crafting_recipe/flashlight_eyes + name = "Flashlight Eyes" + result = /obj/item/organ/eyes/robotic/flashlight + time = 10 + reqs = list( + /obj/item/flashlight = 2, + /obj/item/restraints/handcuffs/cable = 1 + ) + category = CAT_MISC + +/datum/crafting_recipe/paperframes + name = "Paper Frames" + result = /obj/item/stack/sheet/paperframes/five + time = 10 + reqs = list(/obj/item/stack/sheet/mineral/wood = 5, /obj/item/paper = 20) + category = CAT_MISC + +/datum/crafting_recipe/naturalpaper + name = "Hand-Pressed Paper" + time = 30 + reqs = list(/datum/reagent/water = 50, /obj/item/stack/sheet/mineral/wood = 1) + tools = list(/obj/item/hatchet) + result = /obj/item/paper_bin/bundlenatural + category = CAT_MISC + +/datum/crafting_recipe/curtain + name = "Curtains" + reqs = list(/obj/item/stack/sheet/cotton/cloth = 4, /obj/item/stack/rods = 1) + result = /obj/structure/curtain/cloth + category = CAT_MISC + +/datum/crafting_recipe/showercurtain + name = "Shower Curtains" + reqs = list(/obj/item/stack/sheet/cotton/cloth = 2, /obj/item/stack/sheet/plastic = 2, /obj/item/stack/rods = 1) + result = /obj/structure/curtain + category = CAT_MISC + +/datum/crafting_recipe/extendohand + name = "Extendo-Hand" + reqs = list(/obj/item/bodypart/r_arm/robot = 1, /obj/item/clothing/gloves/boxing = 1) + result = /obj/item/extendohand + category = CAT_MISC + +/datum/crafting_recipe/pressureplate + name = "Pressure Plate" + result = /obj/item/pressure_plate + time = 5 + reqs = list(/obj/item/stack/sheet/metal = 1, + /obj/item/stack/tile/plasteel = 1, + /obj/item/stack/cable_coil = 2, + /obj/item/assembly/igniter = 1) + category = CAT_MISC + +/datum/crafting_recipe/rcl + name = "Makeshift Rapid Pipe Cleaner Layer" + result = /obj/item/rcl/ghetto + time = 40 + tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH) + reqs = list(/obj/item/stack/sheet/metal = 15) + category = CAT_MISC + +/datum/crafting_recipe/guillotine + name = "Guillotine" + result = /obj/structure/guillotine + time = 150 // Building a functioning guillotine takes time + reqs = list(/obj/item/stack/sheet/plasteel = 3, + /obj/item/stack/sheet/mineral/wood = 20, + /obj/item/stack/cable_coil = 10) + tools = list(TOOL_SCREWDRIVER, TOOL_WRENCH, TOOL_WELDER) + category = CAT_MISC + +/datum/crafting_recipe/ghettojetpack + name = "Improvised Jetpack" + result = /obj/item/tank/jetpack/improvised + time = 30 + reqs = list(/obj/item/tank/internals/oxygen = 2, /obj/item/extinguisher = 1, /obj/item/pipe = 3, /obj/item/stack/cable_coil = MAXCOIL) + category = CAT_MISC + tools = list(TOOL_WRENCH, TOOL_WELDER, TOOL_WIRECUTTER) + +/datum/crafting_recipe/multiduct + name = "Multi-layer duct" + result = /obj/machinery/duct/multilayered + time = 5 + reqs = list(/obj/item/stack/ducts = 5) + category = CAT_MISC + tools = list(TOOL_WELDER) + +/datum/crafting_recipe/ipickaxe + name = "Improvised Pickaxe" + reqs = list( + /obj/item/crowbar = 1, + /obj/item/kitchen/knife = 1, + /obj/item/stack/tape = 1) + result = /obj/item/pickaxe/improvised + category = CAT_MISC + +/datum/crafting_recipe/chem_scanner + name = "Reagent Scanner" + time = 30 + tools = list(TOOL_WIRECUTTER, TOOL_SCREWDRIVER) + reqs = list( + /obj/item/healthanalyzer = 1, + /obj/item/stack/cable_coil = 5, + /obj/item/stock_parts/scanning_module = 1) + result = /obj/item/reagent_scanner + category = CAT_MISC + +/datum/crafting_recipe/filter + name = "Seperatory Funnel" + time = 40 + tools = list(TOOL_WELDER, TOOL_WIRECUTTER) + reqs = list( + /obj/item/stack/cable_coil = 1, + /obj/item/reagent_containers/glass/beaker = 3) + result = /obj/item/reagent_containers/glass/filter + category = CAT_MISC + +/datum/crafting_recipe/splint + name = "Makeshift Splint" + reqs = list( + /obj/item/stack/rods = 2, + /obj/item/stack/sheet/cotton/cloth = 4) + result = /obj/item/stack/medical/splint/ghetto + category = CAT_MISC + +/datum/crafting_recipe/portableseedextractor + name = "Portable seed extractor" + reqs = list( + /obj/item/storage/bag/plants = 1, + /obj/item/plant_analyzer = 1, + /obj/item/stock_parts/manipulator = 1, + /obj/item/stack/cable_coil = 2) + result = /obj/item/storage/bag/plants/portaseeder //this will probably mean that you can craft portable seed extractors into themselves, sending the other materials into the void, but we still don't have a solution for recipes involving radios stealing your headset, so this is officially not my problem. "no, Tills-The-Soil, adding more analyzers and micro-manipulators to your portable seed extractor does not make it make more seeds. in fact it does exactly nothing." + time = 20 + tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER) + category = CAT_MISC + +/datum/crafting_recipe/freezer + name = "Freezer" + result = /obj/structure/closet/crate/freezer + time = 2 SECONDS + reqs = list(/datum/reagent/consumable/ice = 25, + /obj/item/stack/sheet/metal = 2) + category = CAT_MISC + +/datum/crafting_recipe/aquarium + name = "Aquarium" + result = /obj/structure/aquarium + time = 10 SECONDS + reqs = list(/obj/item/stack/sheet/metal = 15, + /obj/item/stack/sheet/glass = 10, + /obj/item/aquarium_kit = 1) + category = CAT_MISC + +/datum/crafting_recipe/mothplush + name = "Moth Plushie" + result = /obj/item/toy/plush/moth + reqs = list(/obj/item/stack/sheet/animalhide/mothroach = 1, + /obj/item/organ/heart = 1, + /obj/item/stack/sheet/cotton/cloth = 3) + category = CAT_MISC + +/datum/crafting_recipe/candorupgrade + name = "Candor Upgrade" + result = /obj/item/gun/ballistic/automatic/pistol/candor/phenex + reqs = list(/obj/item/stack/sheet/mineral/hidden = 4, + /obj/item/gun/ballistic/automatic/pistol/candor = 1) + category = CAT_MISC diff --git a/code/datums/components/crafting/recipes/robot.dm b/code/datums/components/crafting/recipes/robot.dm new file mode 100644 index 00000000000..a5558682e86 --- /dev/null +++ b/code/datums/components/crafting/recipes/robot.dm @@ -0,0 +1,86 @@ +/datum/crafting_recipe/ed209 + name = "ED209" + result = /mob/living/simple_animal/bot/secbot/ed209 + reqs = list(/obj/item/robot_suit = 1, + /obj/item/clothing/head/helmet = 1, + /obj/item/clothing/suit/armor/vest = 1, + /obj/item/bodypart/leg/left/robot = 1, + /obj/item/bodypart/leg/right/robot = 1, + /obj/item/stack/sheet/metal = 1, + /obj/item/stack/cable_coil = 1, + /obj/item/gun/energy/disabler = 1, + /obj/item/assembly/prox_sensor = 1) + tools = list(TOOL_WELDER, TOOL_SCREWDRIVER) + time = 60 + category = CAT_ROBOT + +/datum/crafting_recipe/secbot + name = "Secbot" + result = /mob/living/simple_animal/bot/secbot + reqs = list(/obj/item/assembly/signaler = 1, + /obj/item/clothing/head/helmet/sec = 1, + /obj/item/melee/baton = 1, + /obj/item/assembly/prox_sensor = 1, + /obj/item/bodypart/r_arm/robot = 1) + tools = list(TOOL_WELDER) + time = 60 + category = CAT_ROBOT + +/datum/crafting_recipe/cleanbot + name = "Cleanbot" + result = /mob/living/simple_animal/bot/cleanbot + reqs = list(/obj/item/reagent_containers/glass/bucket = 1, + /obj/item/assembly/prox_sensor = 1, + /obj/item/bodypart/r_arm/robot = 1) + time = 40 + category = CAT_ROBOT + +/datum/crafting_recipe/floorbot + name = "Floorbot" + result = /mob/living/simple_animal/bot/floorbot + reqs = list(/obj/item/storage/toolbox = 1, + /obj/item/stack/tile/plasteel = 10, + /obj/item/assembly/prox_sensor = 1, + /obj/item/bodypart/r_arm/robot = 1) + time = 40 + category = CAT_ROBOT + +/datum/crafting_recipe/medbot + name = "Medbot" + result = /mob/living/simple_animal/bot/medbot + reqs = list(/obj/item/healthanalyzer = 1, + /obj/item/storage/firstaid = 1, + /obj/item/assembly/prox_sensor = 1, + /obj/item/bodypart/r_arm/robot = 1) + time = 40 + category = CAT_ROBOT + +/datum/crafting_recipe/honkbot + name = "Honkbot" + result = /mob/living/simple_animal/bot/honkbot + reqs = list(/obj/item/storage/box/clown = 1, + /obj/item/bodypart/r_arm/robot = 1, + /obj/item/assembly/prox_sensor = 1, + /obj/item/bikehorn/ = 1) + time = 40 + category = CAT_ROBOT + +/datum/crafting_recipe/Firebot + name = "Firebot" + result = /mob/living/simple_animal/bot/firebot + reqs = list(/obj/item/extinguisher = 1, + /obj/item/bodypart/r_arm/robot = 1, + /obj/item/assembly/prox_sensor = 1, + /obj/item/clothing/head/hardhat/red = 1) + time = 40 + category = CAT_ROBOT + +/datum/crafting_recipe/Vibebot + name = "Vibebot" + result = /mob/living/simple_animal/bot/vibebot + reqs = list(/obj/item/light/bulb = 2, + /obj/item/bodypart/head/robot = 1, + /obj/item/assembly/prox_sensor = 1, + /obj/item/toy/crayon = 1) + time = 40 + category = CAT_ROBOT diff --git a/code/datums/components/crafting/recipes/tribal.dm b/code/datums/components/crafting/recipes/tribal.dm new file mode 100644 index 00000000000..83e5c03722b --- /dev/null +++ b/code/datums/components/crafting/recipes/tribal.dm @@ -0,0 +1,236 @@ +/datum/crafting_recipe/bonetalisman + name = "Bone Talisman" + result = /obj/item/clothing/accessory/talisman + time = 20 + reqs = list(/obj/item/stack/sheet/bone = 2, + /obj/item/stack/sheet/sinew = 1) + category = CAT_PRIMAL + +/datum/crafting_recipe/bonenecklace + name = "Hunter's Necklace" + result = /obj/item/clothing/accessory/wolftalisman + time = 35 + reqs = list(/obj/item/stack/sheet/bone = 2, + /obj/item/stack/sheet/sinew = 3, + /obj/item/mob_trophy/wolf_ear = 2, + /obj/item/mob_trophy/fang = 1) + category = CAT_PRIMAL + +/datum/crafting_recipe/bonecodpiece + name = "Skull Codpiece" + result = /obj/item/clothing/accessory/skullcodpiece + time = 20 + reqs = list(/obj/item/stack/sheet/bone = 2, + /obj/item/mob_trophy/legion_skull = 1, + /obj/item/stack/sheet/animalhide/goliath_hide = 1) + category = CAT_PRIMAL + +/datum/crafting_recipe/skilt + name = "Sinew Kilt" + result = /obj/item/clothing/accessory/skilt + time = 20 + reqs = list(/obj/item/stack/sheet/bone = 1, + /obj/item/stack/sheet/sinew = 2) + category = CAT_PRIMAL + +/datum/crafting_recipe/bracers + name = "Bone Bracers" + result = /obj/item/clothing/gloves/bracer + time = 20 + reqs = list(/obj/item/stack/sheet/bone = 2, + /obj/item/stack/sheet/sinew = 1) + category = CAT_PRIMAL + +/datum/crafting_recipe/goliathcloak + name = "Goliath Cloak" + result = /obj/item/clothing/suit/hooded/cloak/goliath + time = 50 + reqs = list(/obj/item/stack/sheet/leather = 2, + /obj/item/stack/sheet/sinew = 2, + /obj/item/stack/sheet/animalhide/goliath_hide = 2) //it takes 4 goliaths to make 1 cloak if the plates are skinned + category = CAT_PRIMAL + +/datum/crafting_recipe/drakecloak + name = "Ash Drake Armour" + result = /obj/item/clothing/suit/hooded/cloak/drake + time = 60 + reqs = list(/obj/item/stack/sheet/bone = 10, + /obj/item/stack/sheet/sinew = 2, + /obj/item/stack/sheet/animalhide/ashdrake = 5) + category = CAT_PRIMAL + +/datum/crafting_recipe/bonespear + name = "Bone Spear" + result = /obj/item/spear/bonespear + time = 30 + reqs = list(/obj/item/stack/sheet/bone = 4, + /obj/item/stack/sheet/sinew = 1) + category = CAT_PRIMAL + +/datum/crafting_recipe/boneaxe + name = "Bone Axe" + result = /obj/item/fireaxe/boneaxe + time = 50 + reqs = list(/obj/item/stack/sheet/bone = 6, + /obj/item/stack/sheet/sinew = 3) + category = CAT_PRIMAL + +/datum/crafting_recipe/bonfire + name = "Bonfire" + time = 60 + reqs = list(/obj/item/grown/log = 5) + parts = list(/obj/item/grown/log = 5) + blacklist = list(/obj/item/grown/log/steel) + result = /obj/structure/bonfire + category = CAT_PRIMAL + +/datum/crafting_recipe/headpike + name = "Spike Head (Glass Spear)" + time = 65 + reqs = list(/obj/item/spear = 1, + /obj/item/bodypart/head = 1) + parts = list(/obj/item/bodypart/head = 1, + /obj/item/spear = 1) + blacklist = list(/obj/item/spear/explosive, /obj/item/spear/bonespear) + result = /obj/structure/headpike + category = CAT_PRIMAL + +/datum/crafting_recipe/headpikebone + name = "Spike Head (Bone Spear)" + time = 65 + reqs = list(/obj/item/spear/bonespear = 1, + /obj/item/bodypart/head = 1) + parts = list(/obj/item/bodypart/head = 1, + /obj/item/spear/bonespear = 1) + result = /obj/structure/headpike/bone + category = CAT_PRIMAL + +/datum/crafting_recipe/lasso + name = "Bone Lasso" + reqs = list( + /obj/item/stack/sheet/bone = 1, + /obj/item/stack/sheet/sinew = 5) + result = /obj/item/key/lasso + category = CAT_PRIMAL + +/datum/crafting_recipe/heavybonearmor + name = "Heavy Bone Armor" + result = /obj/item/clothing/suit/hooded/cloak/bone + time = 60 + reqs = list(/obj/item/stack/sheet/bone = 8, + /obj/item/stack/sheet/sinew = 3) + category = CAT_PRIMAL + +/datum/crafting_recipe/watcherbola + name = "Watcher Bola" + result = /obj/item/restraints/legcuffs/bola/watcher + time = 30 + reqs = list(/obj/item/stack/sheet/animalhide/goliath_hide = 2, + /obj/item/restraints/handcuffs/cable/sinew = 1) + category = CAT_PRIMAL + +/datum/crafting_recipe/goliathshield + name = "Goliath shield" + result = /obj/item/shield/riot/goliath + time = 60 + reqs = list(/obj/item/stack/sheet/bone = 4, + /obj/item/stack/sheet/animalhide/goliath_hide = 3) + category = CAT_PRIMAL + +/datum/crafting_recipe/bonesword + name = "Bone Sword" + result = /obj/item/claymore/bone + time = 40 + reqs = list(/obj/item/stack/sheet/bone = 3, + /obj/item/stack/sheet/sinew = 2) + category = CAT_PRIMAL + +/datum/crafting_recipe/hunterbelt + name = "Hunters Belt" + result = /obj/item/storage/belt/mining/primitive + time = 20 + reqs = list(/obj/item/stack/sheet/sinew = 2, + /obj/item/stack/sheet/animalhide/goliath_hide = 2) + category = CAT_PRIMAL + +/datum/crafting_recipe/quiver + name = "Quiver" + result = /obj/item/storage/bag/quiver/empty + time = 80 + reqs = list(/obj/item/stack/sheet/leather = 3, + /obj/item/stack/sheet/sinew = 4) + category = CAT_PRIMAL + +/datum/crafting_recipe/bone_bow + name = "Bone Bow" + result = /obj/item/gun/ballistic/bow/ashen + time = 200 + reqs = list(/obj/item/stack/sheet/bone = 8, + /obj/item/stack/sheet/sinew = 4) + category = CAT_PRIMAL + +/datum/crafting_recipe/polarbearcloak + name = "Polar Cloak" + result = /obj/item/clothing/suit/hooded/cloak/goliath/polar + time = 50 + reqs = list(/obj/item/stack/sheet/leather = 2, + /obj/item/stack/sheet/sinew = 2, + /obj/item/stack/sheet/animalhide/goliath_hide/polar_bear_hide = 2) + blacklist = list(/obj/item/stack/sheet/animalhide/goliath_hide) + category = CAT_PRIMAL + +/datum/crafting_recipe/distiller + name = "Distiller" + result = /obj/structure/fermenting_barrel/distiller + reqs = list(/obj/item/stack/sheet/mineral/wood = 8, /obj/item/stack/sheet/metal = 5, /datum/reagent/srm_bacteria = 30) + time = 50 + category = CAT_PRIMAL + +/datum/crafting_recipe/crystalamulet + name = "Crystal Amulet" + result = /obj/item/clothing/neck/crystal_amulet + time = 4 SECONDS + reqs = list(/obj/item/strange_crystal = 3) + category = CAT_PRIMAL + +/datum/crafting_recipe/crystalspear + name = "Crystal Spear" + result = /obj/item/spear/crystal + time = 4 SECONDS + reqs = list(/obj/item/strange_crystal = 2) + category = CAT_PRIMAL + +/datum/crafting_recipe/mushroom_bowl + name = "Mushroom Bowl" + result = /obj/item/reagent_containers/glass/bowl/mushroom_bowl + reqs = list(/obj/item/reagent_containers/food/snacks/grown/ash_flora/shavings = 5) + time = 30 + category = CAT_PRIMAL + +/datum/crafting_recipe/charcoal_stylus + name = "Charcoal Stylus" + result = /obj/item/pen/charcoal + reqs = list(/obj/item/stack/sheet/mineral/wood = 1, /datum/reagent/ash = 30) + time = 30 + category = CAT_PRIMAL + +/datum/crafting_recipe/mushroom_mortar + name = "Mushroom Mortar" + result = /obj/item/reagent_containers/glass/mortar/mushroom + reqs = list(/obj/item/reagent_containers/food/snacks/grown/ash_flora/shavings = 5) + time = 30 + category = CAT_PRIMAL + +/datum/crafting_recipe/oar + name = "Goliath Bone Oar" + result = /obj/item/oar + reqs = list(/obj/item/stack/sheet/bone = 2) + time = 15 + category = CAT_PRIMAL + +/datum/crafting_recipe/boat + name = "Goliath Hide Boat" + result = /obj/vehicle/ridden/lavaboat + reqs = list(/obj/item/stack/sheet/animalhide/goliath_hide = 3) + time = 50 + category = CAT_PRIMAL diff --git a/code/datums/components/crafting/recipes/weapon.dm b/code/datums/components/crafting/recipes/weapon.dm new file mode 100644 index 00000000000..c1dde04b365 --- /dev/null +++ b/code/datums/components/crafting/recipes/weapon.dm @@ -0,0 +1,317 @@ +/datum/crafting_recipe/IED + name = "IED" + result = /obj/item/grenade/iedcasing + reqs = list(/datum/reagent/fuel = 50, + /obj/item/stack/cable_coil = 1, + /obj/item/assembly/igniter = 1, + /obj/item/reagent_containers/food/drinks/soda_cans = 1) + parts = list(/obj/item/reagent_containers/food/drinks/soda_cans = 1) + time = 15 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/lance + name = "Explosive Lance (Grenade)" + result = /obj/item/spear/explosive + reqs = list(/obj/item/spear = 1, + /obj/item/grenade = 1) + blacklist = list(/obj/item/spear/bonespear) + parts = list(/obj/item/spear = 1, + /obj/item/grenade = 1) + time = 15 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/strobeshield + name = "Strobe Shield" + result = /obj/item/shield/riot/flash + reqs = list(/obj/item/wallframe/flasher = 1, + /obj/item/assembly/flash/handheld = 1, + /obj/item/shield/riot = 1) + time = 40 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/strobeshield/New() + ..() + blacklist |= subtypesof(/obj/item/shield/riot/) + +/datum/crafting_recipe/molotov + name = "Molotov" + result = /obj/item/reagent_containers/food/drinks/bottle/molotov + reqs = list(/obj/item/reagent_containers/glass/rag = 1, + /obj/item/reagent_containers/food/drinks/bottle = 1) + parts = list(/obj/item/reagent_containers/food/drinks/bottle = 1) + time = 40 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/stunprod + name = "Stunprod" + result = /obj/item/melee/baton/cattleprod + reqs = list(/obj/item/restraints/handcuffs/cable = 1, + /obj/item/stack/rods = 1, + /obj/item/assembly/igniter = 1) + time = 40 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/teleprod + name = "Teleprod" + result = /obj/item/melee/baton/cattleprod/teleprod + reqs = list(/obj/item/restraints/handcuffs/cable = 1, + /obj/item/stack/rods = 1, + /obj/item/assembly/igniter = 1, + /obj/item/stack/ore/bluespace_crystal = 1) + time = 40 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/bola + name = "Bola" + result = /obj/item/restraints/legcuffs/bola + reqs = list(/obj/item/restraints/handcuffs/cable = 1, + /obj/item/stack/sheet/metal = 6) + time = 20//15 faster than crafting them by hand! + category= CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/gonbola + name = "Gonbola" + result = /obj/item/restraints/legcuffs/bola/gonbola + reqs = list(/obj/item/restraints/handcuffs/cable = 1, + /obj/item/stack/sheet/metal = 6, + /obj/item/stack/sheet/animalhide/gondola = 1) + time = 40 + category= CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/improvised_pneumatic_cannon //Pretty easy to obtain but + name = "Pneumatic Cannon" + result = /obj/item/pneumatic_cannon/ghetto + tools = list(TOOL_WELDER, TOOL_WRENCH) + reqs = list(/obj/item/stack/sheet/metal = 4, + /obj/item/stack/packageWrap = 8, + /obj/item/pipe = 2) + time = 50 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/flamethrower + name = "Flamethrower" + result = /obj/item/flamethrower + reqs = list(/obj/item/weldingtool = 1, + /obj/item/assembly/igniter = 1, + /obj/item/stack/rods = 1) + parts = list(/obj/item/assembly/igniter = 1, + /obj/item/weldingtool = 1) + tools = list(TOOL_SCREWDRIVER) + time = 10 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/meteorslug + name = "Meteorslug Shell" + result = /obj/item/ammo_casing/shotgun/meteorslug + reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1, + /obj/item/rcd_ammo = 1, + /obj/item/stock_parts/manipulator = 2) + tools = list(TOOL_SCREWDRIVER) + time = 5 + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/pulseslug + name = "Pulse Slug Shell" + result = /obj/item/ammo_casing/shotgun/pulseslug + reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1, + /obj/item/stock_parts/capacitor = 3, + /obj/item/stock_parts/micro_laser = 1, + /obj/item/stock_parts/cell = 1, + /datum/reagent/lithium = 5) + tools = list(TOOL_SCREWDRIVER) + time = 5 + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/dragonsbreath + name = "Dragonsbreath Shell" + result = /obj/item/ammo_casing/shotgun/dragonsbreath + reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1, /datum/reagent/phosphorus = 10) + tools = list(TOOL_SCREWDRIVER) + time = 5 + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/frag12 + name = "FRAG-12 Shell" + result = /obj/item/ammo_casing/shotgun/frag12 + reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1, + /datum/reagent/glycerol = 5, + /datum/reagent/toxin/acid = 5, + /datum/reagent/toxin/acid/fluacid = 5) + tools = list(TOOL_SCREWDRIVER) + time = 5 + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/ionslug + name = "Ion Scatter Shell" + result = /obj/item/ammo_casing/shotgun/ion + reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1, + /obj/item/stock_parts/micro_laser = 2, + /obj/item/stock_parts/capacitor = 2, + /obj/item/stock_parts/scanning_module = 1, + /datum/reagent/iron = 5, + /datum/reagent/uranium = 5) + tools = list(TOOL_SCREWDRIVER) + time = 5 + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/improvisedslug + name = "Improvised Shotgun Shell" + result = /obj/item/ammo_casing/shotgun/improvised + reqs = list(/obj/item/stack/sheet/metal = 2, + /obj/item/stack/cable_coil = 1, + /datum/reagent/fuel = 10) + tools = list(TOOL_SCREWDRIVER) + time = 12 + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/laserscatter + name = "Scatter Laser Shell" + result = /obj/item/ammo_casing/shotgun/laserscatter + reqs = list(/obj/item/ammo_casing/shotgun/techshell = 1, + /obj/item/stock_parts/capacitor = 1, + /obj/item/stock_parts/micro_laser = 3, + /obj/item/stock_parts/cell = 1, + /datum/reagent/lithium = 5) + tools = list(TOOL_SCREWDRIVER) + time = 5 + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/ishotgun + name = "Improvised Shotgun" + result = /obj/item/gun/ballistic/shotgun/doublebarrel/improvised + reqs = list(/obj/item/weaponcrafting/receiver = 1, + /obj/item/pipe = 1, + /obj/item/weaponcrafting/stock = 1, + /obj/item/stack/packageWrap = 5) + tools = list(TOOL_SCREWDRIVER) + time = 100 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/chainsaw + name = "Chainsaw" + result = /obj/item/chainsaw + reqs = list(/obj/item/circular_saw = 1, + /obj/item/stack/cable_coil = 3, + /obj/item/stack/sheet/plasteel = 5) + tools = list(TOOL_WELDER) + time = 50 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/spear + name = "Spear" + result = /obj/item/spear + reqs = list(/obj/item/restraints/handcuffs/cable = 1, + /obj/item/shard = 1, + /obj/item/stack/rods = 1) + parts = list(/obj/item/shard = 1) + time = 40 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/chemical_payload + name = "Chemical Payload (C4)" + result = /obj/item/bombcore/chemical + reqs = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/grenade/c4 = 1, + /obj/item/grenade/chem_grenade = 2 + ) + parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2) + time = 30 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/chemical_payload2 + name = "Chemical Payload (Gibtonite)" + result = /obj/item/bombcore/chemical + reqs = list( + /obj/item/stock_parts/matter_bin = 1, + /obj/item/gibtonite = 1, + /obj/item/grenade/chem_grenade = 2 + ) + parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2) + time = 50 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/pipebow + name = "Pipe Bow" + result = /obj/item/gun/ballistic/bow/pipe + reqs = list(/obj/item/pipe = 5, + /obj/item/stack/sheet/plastic = 15, + /obj/item/weaponcrafting/silkstring = 10) + time = 450 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON + +/datum/crafting_recipe/arrow + name = "Arrow" + result = /obj/item/ammo_casing/caseless/arrow/wood + time = 30 + reqs = list(/obj/item/stack/sheet/mineral/wood = 1, + /obj/item/stack/sheet/silk = 1, + /obj/item/stack/rods = 1) //1 metal sheet = 2 rods= 2 arrows + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/bone_arrow + name = "Bone Arrow" + result = /obj/item/ammo_casing/caseless/arrow/bone + time = 30 + reqs = list(/obj/item/stack/sheet/bone = 1, + /obj/item/stack/sheet/sinew = 1, + /obj/item/ammo_casing/caseless/arrow/ash = 1) + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/ashen_arrow + name = "Fire hardened arrow" + result = /obj/item/ammo_casing/caseless/arrow/ash + tools = list(TOOL_WELDER) + time = 30 + reqs = list(/obj/item/ammo_casing/caseless/arrow/wood = 1) + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/bronze_arrow + name = "Bronze arrow" + result = /obj/item/ammo_casing/caseless/arrow/bronze + time = 30 + reqs = list(/obj/item/stack/sheet/mineral/wood = 1, + /obj/item/stack/tile/bronze = 1, + /obj/item/stack/sheet/silk = 1) + category = CAT_WEAPONRY + subcategory = CAT_AMMO + +/datum/crafting_recipe/zip_pistol + name = "Zip Pistol" + result = /obj/item/gun/ballistic/automatic/zip_pistol + reqs = list(/obj/item/stack/rods = 4, + /obj/item/pipe = 1, + /obj/item/stack/cable_coil = 15, + /obj/item/weaponcrafting/receiver = 1, + /obj/item/floor_painter = 1, + /obj/item/stack/packageWrap = 10) + tools = list(TOOL_SCREWDRIVER) + time = 100 + category = CAT_WEAPONRY + subcategory = CAT_WEAPON diff --git a/code/datums/components/movable_physics.dm b/code/datums/components/movable_physics.dm new file mode 100644 index 00000000000..114cac29f24 --- /dev/null +++ b/code/datums/components/movable_physics.dm @@ -0,0 +1,151 @@ +#define PHYSICS_GRAV_STANDARD 9.80665 + +///Remove the component as soon as there's zero velocity, useful for movables that will no longer move after being initially moved (blood splatters) +#define QDEL_WHEN_NO_MOVEMENT (1<<0) + +///Stores information related to the movable's physics and keeping track of relevant signals to trigger movement +/datum/component/movable_physics + ///Modifies the pixel_x/pixel_y of an object every process() + var/horizontal_velocity + ///Modifies the pixel_z of an object every process(), movables aren't Move()'d into another turf if pixel_z exceeds 16, so try not to supply a super high vertical value if you don't want the movable to clip through multiple turfs + var/vertical_velocity + ///The horizontal_velocity is reduced by this every process(), this doesn't take into account the object being in the air vs gravity pushing it against the ground + var/horizontal_friction + ///The vertical_velocity is reduced by this every process() + var/z_gravity + ///The pixel_z that the object will no longer be influenced by gravity for a 32x32 turf, keep this value between -16 to 0 so it's visuals matches up with it physically being in the turf + var/z_floor + ///The angle of the path the object takes on the x/y plane + var/angle_of_movement + ///Flags for turning on certain physic properties, see the top of the file for more information on flags + var/physic_flags + ///The cached animate_movement of the parent; any kind of gliding when doing Move() makes the physics look derpy, so we'll just make Move() be instant + var/cached_animate_movement + ///The sound effect to play when bouncing off of something + var/bounce_sound + + var/numbounce = 1 + +/datum/component/movable_physics/Initialize(_horizontal_velocity = 0, _vertical_velocity = 0, _horizontal_friction = 0, _z_gravity = 0, _z_floor = 0, _angle_of_movement = 0, _physic_flags = 0, _bounce_sound) + . = ..() + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + RegisterSignal(parent, COMSIG_MOVABLE_IMPACT, PROC_REF(throw_impact_ricochet), override = TRUE) + horizontal_velocity = _horizontal_velocity + vertical_velocity = _vertical_velocity + horizontal_friction = _horizontal_friction + z_gravity = _z_gravity + z_floor = _z_floor + angle_of_movement = _angle_of_movement + physic_flags = _physic_flags + bounce_sound = _bounce_sound + if(vertical_velocity || horizontal_velocity) + start_movement() + +///Let's get moving +/datum/component/movable_physics/proc/start_movement() + var/atom/movable/moving_atom = parent + cached_animate_movement = moving_atom.animate_movement + moving_atom.animate_movement = NO_STEPS + START_PROCESSING(SSmovablephysics, src) + moving_atom.SpinAnimation(speed = 1 SECONDS, loops = 1) + +///Alright it's time to stop +/datum/component/movable_physics/proc/stop_movement() + var/atom/movable/moving_atom = parent + moving_atom.animate_movement = cached_animate_movement + STOP_PROCESSING(SSmovablephysics, src) + if(physic_flags & QDEL_WHEN_NO_MOVEMENT) + qdel(src) + +/datum/component/movable_physics/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_MOVABLE_IMPACT) + +/datum/component/movable_physics/proc/throw_impact_ricochet(datum/source, atom/hit_atom, datum/thrownthing/throwingdatum) + SIGNAL_HANDLER + var/atom/movable/atom_source = source + ricochet(atom_source, Get_Angle(atom_source, throwingdatum.target_turf)) + +/datum/component/movable_physics/proc/z_floor_bounce(atom/movable/moving_atom) + angle_of_movement += rand(-3000, 3000) / 100 + var/turf/a_turf = get_turf(moving_atom) + if(istype(moving_atom, /obj/item/ammo_casing) && !bounce_sound) + playsound(moving_atom, a_turf.bullet_bounce_sound, 50, TRUE) + else + playsound(moving_atom, bounce_sound, 50, TRUE) + moving_atom.SpinAnimation(speed = 1 SECONDS / numbounce, loops = 1) + moving_atom.pixel_z = z_floor + horizontal_velocity = max(0, horizontal_velocity + (vertical_velocity * -0.8)) + vertical_velocity = max(0, ((vertical_velocity * -0.8) - 0.2)) + numbounce += 0.5 + +/datum/component/movable_physics/proc/ricochet(atom/movable/moving_atom, bounce_angle) + angle_of_movement = ((180 - bounce_angle) - angle_of_movement) + if(angle_of_movement < 0) + angle_of_movement += 360 + //var/turf/a_turf = get_turf(moving_atom) + //playsound(src, a_turf.bullet_bounce_sound, 50, TRUE) + +/datum/component/movable_physics/proc/fix_angle(angle, atom/moving_atom)//fixes an angle below 0 or above 360 + if(!(angle_of_movement > 360) && !(angle_of_movement < 0)) + return angle //early return if it doesn't need to change + var/new_angle + if(angle_of_movement > 360) + new_angle = angle_of_movement - 360 + if(angle_of_movement < 0) + new_angle = angle_of_movement + 360 + return new_angle + +/datum/component/movable_physics/process(delta_time) + var/atom/movable/moving_atom = parent + var/turf/location = get_turf(moving_atom) + + angle_of_movement = fix_angle(angle_of_movement, moving_atom) + if(horizontal_velocity <= 0 && moving_atom.pixel_z == 0) + horizontal_velocity = 0 + stop_movement() + return + + moving_atom.pixel_x += (horizontal_velocity * (sin(angle_of_movement))) + moving_atom.pixel_y += (horizontal_velocity * (cos(angle_of_movement))) + + horizontal_velocity = max(0, horizontal_velocity - horizontal_friction) + + moving_atom.pixel_z = max(z_floor, moving_atom.pixel_z + vertical_velocity) + if(moving_atom.pixel_z > z_floor) + vertical_velocity -= (z_gravity * 0.05) + + if(moving_atom.pixel_z <= z_floor && (vertical_velocity != 0) && moving_atom.has_gravity(location)) //z bounce + z_floor_bounce(moving_atom) + + if(moving_atom.pixel_x > 16) + if(moving_atom.Move(get_step(moving_atom, EAST))) + moving_atom.pixel_x = -16 + else + moving_atom.pixel_x = 16 + ricochet(moving_atom, 0) + return + + if(moving_atom.pixel_x < -16) + if(moving_atom.Move(get_step(moving_atom, WEST))) + moving_atom.pixel_x = 16 + else + moving_atom.pixel_x = -16 + ricochet(moving_atom, 0) + return + + if(moving_atom.pixel_y > 16) + if(moving_atom.Move(get_step(moving_atom, NORTH))) + moving_atom.pixel_y = -16 + else + moving_atom.pixel_y = 16 + ricochet(moving_atom, 180) + return + + if(moving_atom.pixel_y < -16) + if(moving_atom.Move(get_step(moving_atom, SOUTH))) + moving_atom.pixel_y = 16 + else + moving_atom.pixel_y = -16 + ricochet(moving_atom, 180) + diff --git a/code/datums/components/storage/ui.dm b/code/datums/components/storage/ui.dm new file mode 100644 index 00000000000..e3e4c126d73 --- /dev/null +++ b/code/datums/components/storage/ui.dm @@ -0,0 +1,253 @@ +// Generates a list of numbered_display datums for the numerical display system. +/datum/component/storage/proc/_process_numerical_display() + . = list() + for(var/obj/item/I in accessible_items()) + if(QDELETED(I)) + continue + if(!.[I.type]) + .[I.type] = new /datum/numbered_display(I, 1, src) + else + var/datum/numbered_display/ND = .[I.type] + ND.number++ + +// Orients all objects in legacy mode, and returns the objects to show to the user. +/datum/component/storage/proc/orient2hud_legacy(mob/user, maxcolumns) + . = list() + var/list/accessible_contents = accessible_items() + var/adjusted_contents = length(accessible_contents) + var/atom/movable/screen/storage/close/ui_close + var/atom/movable/screen/storage/boxes/ui_boxes + + //Numbered contents display + var/list/datum/numbered_display/numbered_contents + if(display_numerical_stacking) + numbered_contents = _process_numerical_display() + adjusted_contents = numbered_contents.len + + var/columns = limited_random_access_stack_position == 0 ? clamp(max_items, 1, maxcolumns ? maxcolumns : screen_max_columns) : clamp(limited_random_access_stack_position, 1, maxcolumns ? maxcolumns : screen_max_columns) + var/rows = clamp(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows) + + // First, boxes. + ui_boxes = get_ui_boxes() + ui_boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+columns-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]" + . += ui_boxes + // Then, closer. + ui_close = get_ui_close() + ui_close.screen_loc = "[screen_start_x + columns]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]" + . += ui_close + // Then orient the actual items. + var/cx = screen_start_x + var/cy = screen_start_y + if(islist(numbered_contents)) + for(var/type in numbered_contents) + var/datum/numbered_display/ND = numbered_contents[type] + ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE + ND.sample_object.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]" + ND.sample_object.maptext = "[(ND.number > 1)? "[ND.number]" : ""]" + ND.sample_object.layer = ABOVE_HUD_LAYER + ND.sample_object.plane = ABOVE_HUD_PLANE + . += ND.sample_object + cx++ + if(cx - screen_start_x >= columns) + cx = screen_start_x + cy++ + if(cy - screen_start_y >= rows) + break + else + for(var/obj/O in accessible_items()) + if(QDELETED(O)) + continue + var/atom/movable/screen/storage/item_holder/D = new(null, src, O) + D.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip" + D.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]" + O.maptext = "" + O.layer = ABOVE_HUD_LAYER + O.plane = ABOVE_HUD_PLANE + . += D + cx++ + if(cx - screen_start_x >= columns) + cx = screen_start_x + cy++ + if(cy - screen_start_y >= rows) + break + +// Orients all objects in .. volumetric mode. Does not support numerical display! +/datum/component/storage/proc/orient2hud_volumetric(mob/user, maxcolumns) + . = list() + var/atom/movable/screen/storage/left/ui_left + var/atom/movable/screen/storage/continuous/ui_continuous + var/atom/movable/screen/storage/close/ui_close + + // Generate ui_item_blocks for missing ones and render+orient. + var/list/atom/contents = accessible_items() + // our volume + var/our_volume = get_max_volume() + var/horizontal_pixels = (maxcolumns * world.icon_size) - (VOLUMETRIC_STORAGE_EDGE_PADDING * 2) + var/max_horizontal_pixels = horizontal_pixels * screen_max_rows + // sigh loopmania time + var/used = 0 + // define outside for performance + var/volume + var/list/volume_by_item = list() + var/list/percentage_by_item = list() + for(var/obj/item/I in contents) + if(QDELETED(I)) + continue + volume = I.get_w_volume() + used += volume + volume_by_item[I] = volume + percentage_by_item[I] = volume / get_max_volume() + var/padding_pixels = ((length(percentage_by_item) - 1) * VOLUMETRIC_STORAGE_ITEM_PADDING) + VOLUMETRIC_STORAGE_EDGE_PADDING * 2 + var/min_pixels = (MINIMUM_PIXELS_PER_ITEM * length(percentage_by_item)) + padding_pixels + // do the check for fallback for when someone has too much gamer gear + if((min_pixels) > (max_horizontal_pixels + 4)) // 4 pixel grace zone + to_chat(user, "[parent] was showed to you in legacy mode due to your items overrunning the three row limit! Consider not carrying too much or bugging a maintainer to raise this limit!") + return orient2hud_legacy(user, maxcolumns) + // after this point we are sure we can somehow fit all items into our max number of rows. + + // determine rows + var/rows = clamp(CEILING(min_pixels / horizontal_pixels, 1), 1, screen_max_rows) + + var/overrun = FALSE + if(used > our_volume) + // congratulations we are now in overrun mode. everything will be crammed to minimum storage pixels. + to_chat(user, "[parent] rendered in overrun mode due to more items inside than the maximum volume supports.") + overrun = TRUE + + // how much we are using + var/using_horizontal_pixels = horizontal_pixels * rows + + // item padding + using_horizontal_pixels -= padding_pixels + + // define outside for marginal performance boost + var/obj/item/I + // start at this pixel from screen_start_x. + var/current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING + var/first = TRUE + var/row = 1 + + for(var/i in percentage_by_item) + I = i + var/percent = percentage_by_item[I] + var/atom/movable/screen/storage/volumetric_box/center/B = new /atom/movable/screen/storage/volumetric_box/center(null, src, I) + // SNOWFLAKE: force it to icon until we unfuck storage/click passing + I.mouse_opacity = MOUSE_OPACITY_ICON + var/pixels_to_use = overrun? MINIMUM_PIXELS_PER_ITEM : max(using_horizontal_pixels * percent, MINIMUM_PIXELS_PER_ITEM) + var/addrow = FALSE + if(CEILING(pixels_to_use, 1) >= FLOOR(horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING, 1)) + pixels_to_use = horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING + addrow = TRUE + + // now that we have pixels_to_use, place our thing and add it to the returned list. + B.screen_loc = "[screen_start_x]:[round(current_pixel + (pixels_to_use * 0.5) + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING), 1)],[screen_start_y+row-1]:[screen_pixel_y]" + // add the used pixels to pixel after we place the object + current_pixel += pixels_to_use + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING) + first = FALSE //apply padding to everything after this + + // set various things + B.set_pixel_size(pixels_to_use) + B.name = I.name + + // finally add our things. + . += B.on_screen_objects() + + // go up a row if needed + if(addrow) + row++ + first = TRUE //first in the row, don't apply between-item padding. + current_pixel = VOLUMETRIC_STORAGE_EDGE_PADDING + + // Then, continuous section. + ui_continuous = get_ui_continuous() + ui_continuous.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+maxcolumns-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]" + . += ui_continuous + // Then, left. + ui_left = get_ui_left() + ui_left.screen_loc = "[screen_start_x]:[screen_pixel_x - 2],[screen_start_y]:[screen_pixel_y] to [screen_start_x]:[screen_pixel_x - 2],[screen_start_y+rows-1]:[screen_pixel_y]" + . += ui_left + // Then, closer, which is also our right element. + ui_close = get_ui_close() + ui_close.screen_loc = "[screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x + maxcolumns]:[screen_pixel_x],[screen_start_y + row - 1]:[screen_pixel_y]" + . += ui_close + + +// Shows our UI to a mob. +/datum/component/storage/proc/ui_show(mob/M) + if(!M.client) + return FALSE + if(ui_by_mob[M] || LAZYFIND(is_using, M)) + // something went horribly wrong + // hide first + ui_hide(M) + var/list/cview = getviewsize(M.client.view) + // in tiles + var/maxallowedscreensize = cview[1]-8 + // we got screen size, register signal + RegisterSignal(M, COMSIG_PARENT_QDELETING, PROC_REF(on_logout), override = TRUE) + if(M.active_storage != src) + if(M.active_storage) + M.active_storage.ui_hide(M) + M.active_storage = src + LAZYOR(is_using, M) + if(volumetric_ui()) + //new volumetric ui bay-style + var/list/objects = orient2hud_volumetric(M, maxallowedscreensize) + M.client.screen |= objects + ui_by_mob[M] = objects + else + //old ui + var/list/objects = orient2hud_legacy(M, maxallowedscreensize) + M.client.screen |= objects + ui_by_mob[M] = objects + return TRUE + +// VV hooked to ensure no lingering screen objects. +/datum/component/storage/vv_edit_var(var_name, var_value) + var/list/old + if(var_name == NAMEOF(src, storage_flags)) + old = is_using.Copy() + for(var/i in is_using) + ui_hide(i) + . = ..() + if(old) + for(var/i in old) + ui_show(i) + +// Proc triggered by signal to ensure logging out clients don't linger. +/datum/component/storage/proc/on_logout(datum/source, client/C) + ui_hide(source) + +// Hides our UI from a mob +/datum/component/storage/proc/ui_hide(mob/M) + if(!M.client) + return TRUE + UnregisterSignal(M, list(COMSIG_PARENT_QDELETING)) + M.client.screen -= ui_by_mob[M] + var/list/objects = ui_by_mob[M] + QDEL_LIST(objects) + if(M.active_storage == src) + M.active_storage = null + LAZYREMOVE(is_using, M) + return TRUE + +// Returns TRUE if we are using volumetric UI instead of box UI +/datum/component/storage/proc/volumetric_ui() + var/atom/real_location = real_location() + return (storage_flags & STORAGE_LIMIT_VOLUME) && (length(real_location.contents) <= MAXIMUM_VOLUMETRIC_ITEMS) && !display_numerical_stacking + +// Gets our ui_boxes, making it if it doesn't exist. +/datum/component/storage/proc/get_ui_boxes() + return new /atom/movable/screen/storage/boxes(null, src) + +// Gets our ui_left, making it if it doesn't exist. +/datum/component/storage/proc/get_ui_left() + return new /atom/movable/screen/storage/left(null, src) + +// Gets our ui_close, making it if it doesn't exist. +/datum/component/storage/proc/get_ui_close() + return new /atom/movable/screen/storage/close(null, src) + +// Gets our ui_continuous, making it if it doesn't exist. +/datum/component/storage/proc/get_ui_continuous() + return new /atom/movable/screen/storage/continuous(null, src) diff --git a/code/datums/elements/world_icon.dm b/code/datums/elements/world_icon.dm new file mode 100644 index 00000000000..bcb0129c6c6 --- /dev/null +++ b/code/datums/elements/world_icon.dm @@ -0,0 +1,121 @@ +///////////////////////////////////////////////////////////// +////////// WORLD ICON ELEMENT DIRECTORY ////////// +///////////////////////////////////////////////////////////// +//PORTED FROM MOJAVE SUN// + +// Slap onto something to give it a world icon that differs from the inventory one (allows for realistically sized objects and all that) // +// To fix 25/06/2021 : Blood Decals, Mutable Overlays and other baked in bitch ass overlays that need to be remade when the icon changes // +// Fixed 07/05/2022: Now you can deal with the above by handling everything with attached_proc instead +// Fixed 12/04/2023: Icon states, Needs major tuning up by someone who can properly make it work + +/datum/element/world_icon + id_arg_index = 2 + element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH + //If we want COMPLEX world icon behavior, this proc will handle icon updating when the item is NOT in the inventory. + //I just assumed that the default update_icon is for inventory sprites because ss13 basically focuses on how the sprites + //look on your hand, not how they realistically look in the world. + var/attached_proc + /// Only used if attached_proc doesn't exist, simply changes the icon of target to this when it's in the inventory + var/inventory_icon + /// Only used if attached_proc doesn't exist, simply changes the icon of target to this when it's NOT in the inventory + var/world_icon + /// Only used when inventory state icon is different from original + var/inventory_icon_state + /// Only used when world state icon is different from original, pretty much just the original "icon_state" but if you for some reason need to flip the standard icon states for this element around you can use this + var/world_icon_state + +/datum/element/world_icon/Attach(obj/item/target, attached_proc, world_icon, inventory_icon, world_icon_state, inventory_icon_state) + . = ..() + if(!istype(target)) + return ELEMENT_INCOMPATIBLE + + src.attached_proc = attached_proc + src.world_icon = world_icon + src.world_icon_state = world_icon_state + src.inventory_icon = inventory_icon + src.inventory_icon_state = inventory_icon_state + RegisterSignal(target, COMSIG_ATOM_UPDATE_ICON, PROC_REF(update_icon)) + RegisterSignal(target, COMSIG_ATOM_UPDATE_ICON_STATE, PROC_REF(update_icon_state)) + RegisterSignal(target, list(COMSIG_ITEM_EQUIPPED, COMSIG_STORAGE_ENTERED, COMSIG_ITEM_DROPPED, COMSIG_STORAGE_EXITED), PROC_REF(inventory_updated)) + target.update_appearance(UPDATE_ICON) + target.update_appearance(UPDATE_ICON_STATE) + +/datum/element/world_icon/Detach(obj/item/source) + . = ..() + UnregisterSignal(source, COMSIG_ATOM_UPDATE_ICON) + UnregisterSignal(source, COMSIG_ATOM_UPDATE_ICON_STATE, PROC_REF(update_icon_state)) + UnregisterSignal(source, list(COMSIG_ITEM_EQUIPPED, COMSIG_STORAGE_ENTERED, COMSIG_ITEM_DROPPED, COMSIG_STORAGE_EXITED)) + source.update_appearance(UPDATE_ICON) + source.update_appearance(UPDATE_ICON_STATE) + +/datum/element/world_icon/proc/update_icon(obj/item/source, updates) + SIGNAL_HANDLER + + if((source.item_flags & IN_INVENTORY) || (source.loc && SEND_SIGNAL(source.loc, COMSIG_CONTAINS_STORAGE))) + if(attached_proc) + return + return default_inventory_icon(source) + + if(attached_proc) + return call(source, attached_proc)(updates) + else + return default_world_icon(source) + +/datum/element/world_icon/proc/update_icon_state(obj/item/source, updates) + SIGNAL_HANDLER + + if((source.item_flags & IN_INVENTORY) || (source.loc && SEND_SIGNAL(source.loc, COMSIG_CONTAINS_STORAGE))) + if(attached_proc) + return + return default_inventory_icon_state(source) + + if(attached_proc) + return call(source, attached_proc)(updates) + else + return default_world_icon_state(source) + +/datum/element/world_icon/proc/inventory_updated(obj/item/source) + SIGNAL_HANDLER + + source.update_appearance(UPDATE_ICON) + source.update_appearance(UPDATE_ICON_STATE) + +/datum/element/world_icon/proc/default_inventory_icon(obj/item/source) + SIGNAL_HANDLER + + source.icon = inventory_icon + +/datum/element/world_icon/proc/default_world_icon(obj/item/source) + SIGNAL_HANDLER + + source.icon = world_icon + +/datum/element/world_icon/proc/default_inventory_icon_state(obj/item/source) + SIGNAL_HANDLER + + if(!inventory_icon_state) + source.icon_state = source.icon_state + return + + INVOKE_ASYNC(src, PROC_REF(check_inventory_state), source) + +/datum/element/world_icon/proc/default_world_icon_state(obj/item/source) + SIGNAL_HANDLER + + if(!world_icon_state) + source.icon_state = source.icon_state + return + + INVOKE_ASYNC(src, PROC_REF(check_world_icon_state), source) + +/datum/element/world_icon/proc/check_inventory_state(obj/item/source) + SIGNAL_HANDLER + + inventory_icon_state = source.inventory_state + source.icon_state = inventory_icon_state + +/datum/element/world_icon/proc/check_world_icon_state(obj/item/source) + SIGNAL_HANDLER + + world_icon_state = source.world_state + source.icon_state = world_icon_state diff --git a/code/modules/autowiki/pages/reactions.dm b/code/modules/autowiki/pages/reactions.dm new file mode 100644 index 00000000000..2e1a07b806e --- /dev/null +++ b/code/modules/autowiki/pages/reactions.dm @@ -0,0 +1,65 @@ +/* +Templates: + +Autowiki/Reaction +{{{chems|ERROR}}} {{#if: {{{temperature|}}} |
Temperature {{{temperature}}} | }} {{#if: {{{container|}}} |
Needs container "{{{container}}}" | }}
Makes {{{volume|1}}}u + +Autowiki/Reagent +{{#if: {{{tooltip|}}} | {{Tooltip|{{{volume}}} part [[#{{{name}}}|{{{name}}}]]|{{{tooltip}}}|FEF6E7}} | {{{volume}}} part {{{name}}} }} + +*/ + +/datum/autowiki/reactions + page = "Template:Autowiki/Content/Reactions" + +/datum/autowiki/reactions/generate() + var/list/output = list() + + var/list/mixable_reagents = list() + var/list/all_reactions = list() + for(var/type in subtypesof(/datum/chemical_reaction)) + var/datum/chemical_reaction/reaction = new type + all_reactions += reaction + mixable_reagents |= reaction.results + + for(var/datum/chemical_reaction/reaction as anything in all_reactions) + var/required_chems = "" + for(var/datum/reagent/required_chem_type as anything in reaction.required_reagents) + var/has_tooltip = (required_chem_type in mixable_reagents) && !(required_chem_type in reaction.results) && !(required_chem_type in GLOB.base_reagents) + required_chems += format_required_reagent(required_chem_type, reaction.required_reagents[required_chem_type], has_tooltip) + + for(var/datum/reagent/required_catalyst_type as anything in reaction.required_catalysts) + var/has_tooltip = (required_catalyst_type in mixable_reagents) && !(required_catalyst_type in reaction.results) && !(required_catalyst_type in GLOB.base_reagents) + required_chems += format_required_reagent(required_catalyst_type, reaction.required_catalysts[required_catalyst_type], has_tooltip, "Catalyst") + + for(var/datum/reagent/result_chem_type as anything in reaction.results) + var/result_name = escape_value(initial(result_chem_type.name)) + var/list/details = list("volume" = reaction.results[result_chem_type], "chems" = required_chems, "name" = result_name) + + if(reaction.required_temp > 0) + details["temperature"] = "[reaction.is_cold_recipe ? "below" : "above"] [reaction.required_temp]K" + + if(reaction.required_container) + details["container"] = "[escape_value(initial(reaction.required_container.name))]" + + var/description = include_template("Autowiki/Reaction", details) + if(result_name in output) + output[result_name] += "
OR
[description]" + else + output[result_name] = description + + return output + +/datum/autowiki/reactions/proc/format_required_reagent(datum/reagent/required_reagent_type, volume, has_tooltip = FALSE, type) + var/list/details = list( + "volume" = volume, + "name" = escape_value(initial(required_reagent_type.name)) + ) + + if(has_tooltip) + details["tooltip"] = include_template("Autowiki/Content/Reactions/[initial(required_reagent_type.name)]") + + if(type) + details["type"] = type + + return include_template("Autowiki/Reagent", details) diff --git a/code/modules/cargo/blackmarket/blackmarket_items/emergency.dm b/code/modules/cargo/blackmarket/blackmarket_items/emergency.dm new file mode 100644 index 00000000000..b609da87945 --- /dev/null +++ b/code/modules/cargo/blackmarket/blackmarket_items/emergency.dm @@ -0,0 +1,52 @@ +/datum/blackmarket_item/emergency + category = "Emergency" + +/datum/blackmarket_item/emergency/plasma + name = "Ten Plasma Sheets" + desc = "Low on fuel? We can part with some plasma... for a reasonable price." + item = /obj/item/stack/sheet/mineral/plasma/ten + + price_min = 1750 + price_max = 2250 + availability_prob = 100 + unlimited = TRUE + +/datum/blackmarket_item/emergency/uranium + name = "Ten Uranium Sheets" + desc = "Fuel? Dirty Bomb? Fancy nightlight? Doesn't matter, we'll supply." + item = /obj/item/stack/sheet/mineral/uranium/ten + + price_min = 1750 + price_max = 2250 + availability_prob = 100 + unlimited = TRUE + +/datum/blackmarket_item/emergency/ion_thruster + name = "Ion Thruster" + desc = "Need a boost? We have a leftover engine board or two from a ship we happened to find. If you're lucky, you won't be the next." + item = /obj/item/circuitboard/machine/shuttle/engine/electric + + price_min = 2000 + price_max = 3000 + stock_max = 5 + availability_prob = 100 + +/datum/blackmarket_item/emergency/oyxgen + name = "Oxygen Canister" + desc = "What keeps us all breathing. It'll keep you breathing too, if you know what's good for you." + item = /obj/machinery/portable_atmospherics/canister/oxygen + + price_min = 2000 + price_max = 3000 + stock_max = 3 + availability_prob = 100 + +/datum/blackmarket_item/emergency/metal_foam + name = "Metal Foam Grenade" + desc = "Poor piloting blow a hole in the side of your hull? These metal foam grenades should keep everything important in." + item = /obj/item/grenade/chem_grenade/metalfoam + + price_min = 300 + price_max = 750 + availability_prob = 100 + unlimited = TRUE diff --git a/code/modules/cargo/blackmarket/blackmarket_items/explosives.dm b/code/modules/cargo/blackmarket/blackmarket_items/explosives.dm new file mode 100644 index 00000000000..7fe78cdcd05 --- /dev/null +++ b/code/modules/cargo/blackmarket/blackmarket_items/explosives.dm @@ -0,0 +1,88 @@ +/datum/blackmarket_item/explosive + category = "Explosives" + +/datum/blackmarket_item/explosive/emp_grenade + name = "EMP Grenade" + desc = "Use this grenade for SHOCKING results!" + item = /obj/item/grenade/empgrenade + + price_min = 100 + price_max = 400 + stock_max = 5 + availability_prob = 50 + +/datum/blackmarket_item/explosive/h_e + name = "HE Grenade" + desc = "These high explosive grenades are sure to get some bang for your buck." + item = /obj/item/grenade/syndieminibomb/concussion + + price_min = 100 + price_max = 500 + stock_min = 2 + stock_max = 5 + availability_prob = 25 + +/datum/blackmarket_item/explosive/frag + name = "Fragmentation Grenade" + desc = "Pull the pin, count to three, and throw for best results." + item = /obj/item/grenade/frag + + price_min = 100 + price_max = 500 + stock_min = 3 + stock_max = 5 + availability_prob = 40 + +/datum/blackmarket_item/explosive/c4 + name = "C4" + desc = "Looking to make an explosive entrance? These plastic explosives are perfect for the job." + item = /obj/item/grenade/c4 + + price_min = 100 + price_max = 400 + stock_min = 5 + stock_max = 10 + availability_prob = 50 + +/datum/blackmarket_item/explosive/x4 + name = "X4" + desc = "X4 Plastic Explosives! Better than W4, worse than Y4." + item = /obj/item/grenade/c4/x4 + + price_min = 400 + price_max = 700 + stock_min = 2 + stock_max = 4 + availability_prob = 25 + +/datum/blackmarket_item/explosive/slipocalypse + name = "Slipocalyse Cluster Bomb" + desc = "Wash away the opposition with sudstastic grenade!" + item = /obj/item/grenade/clusterbuster/soap + + price_min = 500 + price_max = 1500 + stock = 1 + availability_prob = 10 + +/datum/blackmarket_item/explosive/rusted_mine + name = "Landmine" + desc = "Recovered from a decades old ICW battlefield by our best EOD tech, Nicky Nine Fingers." + item = /obj/item/mine/pressure/explosive/rusty + + price_min = 250 + price_max = 500 + stock_max = 7 + availability_prob = 50 + +/datum/blackmarket_item/explosive/rpg + name = "PML-9 RPG" + desc = "Offically, it's an anti-armor RPG launcher. Technically, it's anti-everything. Most things don't enjoy being hit in the face with high explosives." + item = /obj/item/gun/ballistic/rocketlauncher + + price_min = 3500 + price_max = 6500 + stock_min = 2 + stock_max = 5 + availability_prob = 20 + diff --git a/code/modules/clothing/factions/ngr.dm b/code/modules/clothing/factions/ngr.dm new file mode 100644 index 00000000000..7892a098b50 --- /dev/null +++ b/code/modules/clothing/factions/ngr.dm @@ -0,0 +1,244 @@ +////////////// +//Jumpsuits// +///////////// + +/obj/item/clothing/under/syndicate/ngr + name = "\improper NGR uniform" + desc = "A button-up in a tasteful beige with black pants, used as the basic uniform of the New Gorlex Republic." + icon_state = "ngr" + item_state = "ngr" + armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 40) + can_adjust = FALSE + icon = 'icons/obj/clothing/faction/ngr/uniforms.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/uniforms.dmi' + +/obj/item/clothing/under/syndicate/ngr/fatigues + name = "\improper NGR fatigues" + desc = "Beige fatigues used primarily by the ship and mech pilots of the New Gorlex Republic." + icon_state = "ngr_fatigues" + item_state = "ngr_fatigues" + +/obj/item/clothing/under/syndicate/ngr/jumpsuit + name = "\improper NGR jumpsuit" + desc = "A beige jumpsuit with black overalls used by wreckers of the New Gorlex Republic. A reminder of Gorlex VII's history as a mining colony, prior to its destruction." + icon_state = "ngr_jumpsuit" + item_state = "ngr_jumpsuit" + +/obj/item/clothing/under/syndicate/ngr/officer + name = "\improper NGR officer uniform" + desc = "A button-up in a tasteful black with beige pants, used by officers of the New Gorlex Republic." + icon_state = "ngr_officer" + item_state = "ngr_officer" + +/obj/item/clothing/under/plasmaman/ngr + name = "\improper NGR phorid envirosuit" + desc = "A button-up envirosuit with use intended for phorids of the New Gorlex Republic. Ensures they don't die of combustion." + icon_state = "ngr_envirosuit" + item_state = "ngr_envirosuit" + icon = 'icons/obj/clothing/faction/ngr/uniforms.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/uniforms.dmi' + + +//////////////////// +//Unarmored suits// +/////////////////// + +/obj/item/clothing/suit/ngr + name = "foreman's jacket" + desc = "A beige high-visibility jacket worn by the Foreman of the New Gorlex Republic." + icon = 'icons/obj/clothing/faction/ngr/suits.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/suits.dmi' + icon_state = "ngr_foreman" + item_state = "blackcloth" + +/obj/item/clothing/suit/ngr/smock + name = "blood red smock" + desc = "A blood-red surgical smock typically worn by field medics of the New Gorlex Republic. It hides red blood really well!" + icon_state = "ngr_apron" + item_state = "redcloth" + +/obj/item/clothing/suit/hazardvest/ngr + name = "blood-red hazard vest" + desc = "A blood-red high-visibility vest typically used in work zones by the New Gorlex Republic." + icon = 'icons/obj/clothing/faction/ngr/suits.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/suits.dmi' + icon_state = "ngr_hazard" + item_state = "redcloth" + +////////////////// +//Armored suits// +///////////////// + +/obj/item/clothing/suit/armor/ngr + name = "NGR armor vest" + desc = "A slim Type I armored vest, utilized by the 2nd Battlegroup of the New Gorlex Republic that provides decent protection against most types of damage." + icon_state = "ngr_vest" + item_state = "armor" + icon = 'icons/obj/clothing/faction/ngr/suits.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/suits.dmi' + blood_overlay_type = "armor" + +/obj/item/clothing/suit/armor/ngr/lieutenant + name = "\improper 2nd Battlegroup overcoat" + desc = "An armored overcoat worn by the lieutenants of the New Gorlex Republic's 2nd Battlegroup." + body_parts_covered = CHEST|GROIN|ARMS + icon_state = "ngr_lieutenant" + item_state = "ngr_lieutenant" + blood_overlay_type = "coat" + armor = list("melee" = 35, "bullet" = 30, "laser" = 30, "energy" = 40, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) + +/obj/item/clothing/suit/armor/ngr/captain + name = "\improper 2nd Battlegroup coat" + desc = "An armored coat worn by captains the New Gorlex Republic's 2nd Battlegroup." + body_parts_covered = CHEST|GROIN|ARMS + icon_state = "ngr_captain" + item_state = "ngr_captain" + blood_overlay_type = "coat" + armor = list("melee" = 35, "bullet" = 30, "laser" = 30, "energy" = 40, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) + +/////////////// +//Spacesuits// +////////////// + +/obj/item/clothing/head/helmet/space/hardsuit/syndi/ngr + name = "beige-red hardsuit helmet" + desc = "A standardized dual-mode helmet derived from ICW-era advanced special operations helmets, its red partly replaced by beige. It is in EVA mode. Manufactured by Second Battlegroup." + alt_desc = "A standardized dual-mode helmet derived from ICW-era advanced special operations helmets, its red partly replaced by beige. It is in combat mode. Manufactured by Second Battlegroup." + icon_state = "hardsuit1-ngr" + item_state = "hardsuit1-ngr" + icon = 'icons/obj/clothing/faction/ngr/head.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/head.dmi' + hardsuit_type = "ngr" + +/obj/item/clothing/suit/space/hardsuit/syndi/ngr + name = "beige-red hardsuit" + desc = "A standardized dual-mode hardsuit derived from ICW-era advanced special operations hardsuits, its red partly replaced by beige. It is in EVA mode. Manufactured by Second Battlegroup." + alt_desc = "A standardized dual-mode hardsuit derived from ICW-era advanced special operations hardsuits, its red partly replaced by beige. It is in combat mode. Manufactured by the Second Battlegroup." + icon_state = "hardsuit1-ngr" + item_state = "hardsuit1-ngr" + hardsuit_type = "ngr" + icon = 'icons/obj/clothing/faction/ngr/suits.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/suits.dmi' + helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi/ngr + lightweight = 1 + jetpack = null + +/obj/item/clothing/head/helmet/space/plasmaman/ngr + name = "NGR phorid envirosuit helmet" + desc = "An envirohelmet designed for phorids of the New Gorlex Republic, with intimidating blood-red stripes." + icon_state = "ngr_envirohelm" + item_state = "ngr_envirohelm" + icon = 'icons/obj/clothing/faction/ngr/head.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/head.dmi' + +///////// +//Hats// +//////// + +/obj/item/clothing/head/ngr + name = "beige garrison cap" + desc = "A garrison cap used by low-ranking members of the New Gorlex Republic's 2nd Battlegroup when off-duty." + icon_state = "ngr_garrison" + icon = 'icons/obj/clothing/faction/ngr/head.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/head.dmi' + armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) + +/obj/item/clothing/head/ngr/flap + name = "beige flap cap" + desc = "A flap cap used by soldiers of the New Gorlex Republic's 2nd Battlegroup in desert environments." + icon_state = "ngr_flap" + +/obj/item/clothing/head/ngr/surgical + name = "blood-red surgical cap" + desc = "A surgical cap used by field medics of the New Gorlex Republic's 2nd Battlegroup." + icon_state = "ngr_surgery" + +/obj/item/clothing/head/hardhat/ngr + name = "blood-red hard hat" + desc = "A blood-red hardhat typically used by Wreckers and Ship Engineers of the New Gorlex Republic." + icon_state = "ngr_hardhat" + icon = 'icons/obj/clothing/faction/ngr/head.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/head.dmi' + +/obj/item/clothing/head/hardhat/ngr/foreman + name = "beige hard hat" + desc = "A beige hardhat used exclusively by the Foreman of the New Gorlex Republic." + icon_state = "ngr_foreman" + +/obj/item/clothing/head/ngr/peaked + name = "2nd Battlegroup peaked cap" + desc = "A cap worn by officers of the New Gorlex Republic's 2nd Battlegroup." + icon_state = "ngr_officer" + item_state = "ngr_officer" + +/obj/item/clothing/head/helmet/ngr + name = "\improper NGR X-11 helmet" + desc = "A well-armored helmet utilized by the New Gorlex Republic's 2nd Battlegroup, far better at protecting one's head than the softer caps." + icon = 'icons/obj/clothing/faction/ngr/head.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/head.dmi' + armor = list("melee" = 40, "bullet" = 60, "laser" = 35, "energy" = 35, "bomb" = 40, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50) // The guys who specialize in ballistics would probably have better bullet armor. Maybe. + icon_state = "ngr_x11" + item_state = "ngr_x11" + +/obj/item/clothing/head/helmet/ngr/swat + name = "\improper NGR pilot helmet" + desc = "A modified X-11 helmet utilized by the pilots of the New Gorlex Republic's 2nd Battlegroup. The attached visor helps protect against sudden flashes from explosions." + flash_protect = FLASH_PROTECTION_WELDER + icon_state = "ngr_pilot" + item_state = "ngr_pilot" + +//////////// +//Glasses// +/////////// + +/obj/item/clothing/glasses/hud/security/sunglasses/ngr + name = "NGR modified mesons" + desc = "A modified version of widely-used optical meson scanners, with a flash-proof tint and integrated security HUD. Unfortunately, the opaque visor disables the meson functionality." + icon_state = "ngr_goggles" + item_state = "ngr_goggles" + icon = 'icons/obj/clothing/faction/ngr/eyes.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/eyes.dmi' + glass_colour_type = /datum/client_colour/glass_colour/green + +////////// +//Masks// +///////// + +/obj/item/clothing/mask/gas/sechailer/balaclava/ngr + name = "NGR combat balaclava" + desc = "A surprisingly advanced balaclava. while it doesn't muffle your voice it has a miniature rebreather for internals. Comfy to boot! This version is commonly used by the soldiers of the New Gorlex Republic to protect against sandstorms." + icon_state = "ngr_balaclava" + item_state = "ngr_balaclava" + icon = 'icons/obj/clothing/faction/ngr/mask.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/mask.dmi' + +/obj/item/clothing/mask/gas/syndicate/ngr + name = "NGR face mask" + desc = "A face mask that covers the nose, mouth and neck of those who wear it. Favored by field medics over the balaclava due to lessened heat while wearing." + icon_state = "ngr_facemask" + item_state = "ngr_facemask" + icon = 'icons/obj/clothing/faction/ngr/mask.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/mask.dmi' + +////////// +//Neck// +///////// + +/obj/item/clothing/neck/shemagh/ngr + name = "shemagh" + desc = "An oversized shemagh, in a tacticool blood-red for use in the 2nd Battlegroup." + icon_state = "ngr_shemagh" + icon = 'icons/obj/clothing/faction/ngr/neck.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/neck.dmi' + +////////// +//Belts// +///////// + +/obj/item/storage/belt/security/webbing/ngr + name = "NGR webbing" + desc = "A set of tactical webbing for operators of the New Gorlex Republic, can hold security gear." + icon_state = "ngr_webbing" + item_state = "ngr_webbing" + icon = 'icons/obj/clothing/faction/ngr/belt.dmi' + mob_overlay_icon = 'icons/mob/clothing/faction/ngr/belt.dmi' diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord_outfits.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord_outfits.dm new file mode 100644 index 00000000000..0dca4c21dad --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord_outfits.dm @@ -0,0 +1,479 @@ +/datum/outfit/generic/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) + . = ..() + uniform = pickweight(list( + /obj/item/clothing/under/utility = 5, + /obj/item/clothing/under/utility/skirt = 5, + /obj/item/clothing/under/color/black = 1, + /obj/item/clothing/under/color/white = 1, + /obj/item/clothing/under/color/random = 1, + /obj/item/clothing/under/suit/white = 1, + /obj/item/clothing/under/suit/tan = 1, + /obj/item/clothing/under/suit/black_really = 1, + /obj/item/clothing/under/suit/navy = 1, + /obj/item/clothing/under/suit/burgundy = 1, + /obj/item/clothing/under/suit/charcoal = 1, + /obj/item/clothing/under/rank/civilian/lawyer/galaxy = 1, + /obj/item/clothing/under/suit/black/skirt = 1, + /obj/item/clothing/under/suit/black = 1, + /obj/item/clothing/under/dress/sailor = 1, + /obj/item/clothing/under/dress/striped = 1, + /obj/item/clothing/under/dress/skirt/blue = 1, + /obj/item/clothing/under/syndicate/tacticool = 1, + ) + ) + suit = pickweight(list( + /obj/item/clothing/suit/hooded/wintercoat = 1, + /obj/item/clothing/suit/jacket = 1, + /obj/item/clothing/suit/jacket/leather = 1, + /obj/item/clothing/suit/jacket/leather/overcoat = 1, + /obj/item/clothing/suit/jacket/leather/duster = 1, + /obj/item/clothing/suit/jacket/miljacket = 1, + /obj/item/clothing/suit/jacket/puffer = 1, + /obj/item/clothing/suit/gothcoat = 1, + /obj/item/clothing/suit/toggle/industrial = 1, + /obj/item/clothing/suit/toggle/hazard = 1, + ) + ) + back = pickweight(list( + /obj/item/storage/backpack = 1, + /obj/item/storage/backpack/satchel = 1, + /obj/item/storage/backpack/duffelbag = 1, + /obj/item/storage/backpack/messenger = 1, + /obj/item/storage/backpack/satchel/leather = 1 + ) + ) + if (prob(10)) + belt = pickweight(list( + /obj/item/gun/ballistic/automatic/pistol/candor = 2, + /obj/item/gun/ballistic/automatic/pistol/commander = 1, + /obj/item/gun/ballistic/automatic/pistol = 1, + /obj/item/gun/ballistic/revolver = 1, + /obj/item/gun/ballistic/revolver/firebrand = 1, + ) + ) + if(prob(50)) + gloves = pickweight(list( + /obj/item/clothing/gloves/color/black = 1, + /obj/item/clothing/gloves/fingerless = 1, + /obj/item/clothing/gloves/color/white = 1, + ) + ) + shoes = pickweight(list( + /obj/item/clothing/shoes/laceup = 1, + /obj/item/clothing/shoes/sandal = 1, + /obj/item/clothing/shoes/winterboots = 1, + /obj/item/clothing/shoes/workboots/mining = 1, + /obj/item/clothing/shoes/workboots = 1, + /obj/item/clothing/shoes/sneakers/black = 1, + /obj/item/clothing/shoes/sneakers/brown = 1, + /obj/item/clothing/shoes/sneakers/white = 1 + ) + ) + if(prob(50)) + head = pickweight(list( + /obj/item/clothing/head/beret = 3, + /obj/item/clothing/head/beret/grey = 3, + /obj/item/clothing/head/flatcap = 3, + /obj/item/clothing/head/beanie = 3, + /obj/item/clothing/head/cowboy = 3, + /obj/item/clothing/head/trapper = 2, + /obj/item/clothing/head/hardhat = 2, + /obj/item/clothing/head/hardhat/orange = 2, + /obj/item/clothing/head/hardhat/dblue = 2, + /obj/item/clothing/head/pirate = 1, + /obj/item/clothing/head/foilhat = 1 + ) + ) + if(prob(50)) + mask = pickweight(list( + /obj/item/clothing/mask/balaclava = 1, + /obj/item/clothing/mask/bandana/red = 1, + /obj/item/clothing/mask/gas = 3, + /obj/item/clothing/mask/breath = 3, + ) + ) + if(prob(25)) + neck = pickweight(list( + /obj/item/clothing/neck/scarf/red = 1, + /obj/item/clothing/neck/scarf/green = 1, + /obj/item/clothing/neck/scarf/darkblue = 1, + /obj/item/clothing/neck/shemagh = 1, + /obj/item/clothing/neck/stripedredscarf = 1, + /obj/item/clothing/neck/stripedgreenscarf = 1, + /obj/item/clothing/neck/stripedbluescarf = 1 + ) + ) + ears = pick(/obj/item/radio/headset, /obj/item/radio/headset/alt) + if(prob(50)) + glasses = pickweight(list( + /obj/item/clothing/glasses/regular = 1, + /obj/item/clothing/glasses/regular/circle = 1, + /obj/item/clothing/glasses/regular/jamjar = 1, + /obj/item/clothing/glasses/eyepatch = 1, + /obj/item/clothing/glasses/cheapsuns = 1, + /obj/item/clothing/glasses/regular/hipster = 1, + /obj/item/clothing/glasses/cold = 1, + /obj/item/clothing/glasses/heat = 1, + /obj/item/clothing/glasses/orange = 1, + ) + ) + if(prob(75)) + r_pocket = /obj/item/tank/internals/emergency_oxygen + if(prob(75)) + l_pocket = pick(/obj/item/radio, /obj/item/flashlight) + id = /obj/item/card/id + backpack_contents = list() + backpack_contents += pickweight(list( + /obj/item/dice/d20 = 1, + /obj/item/lipstick = 1, + /obj/item/clothing/mask/vape = 1, + /obj/item/clothing/mask/vape/cigar = 1, + /obj/item/reagent_containers/food/drinks/flask = 1, + /obj/item/lighter = 1, + /obj/item/toy/cards/deck = 1, + /obj/item/toy/eightball = 1, + /obj/item/storage/wallet = 1, + /obj/item/paicard = 1, + /obj/item/pen/fourcolor = 1, + /obj/item/paper_bin = 1, + /obj/item/cane = 1, + /obj/item/radio = 1, + /obj/item/dyespray = 1, + /obj/item/table_bell/brass = 1, + /obj/item/flashlight = 1, + /obj/item/crowbar/red = 1 + ) + ) + +/datum/outfit/generic + name = "Generic (Legion)" + box = /obj/item/storage/box/survival + random = TRUE + +/datum/outfit/generic/miner/pre_equip(mob/living/carbon/human/H, visualsOnly) + . = ..() + if(prob(75)) + uniform = pickweight(list( + /obj/item/clothing/under/rank/cargo/miner/lavaland = 5, + /obj/item/clothing/under/rank/cargo/miner = 4, + /obj/item/clothing/under/rank/cargo/miner/lavaland/old = 1, + ) + ) + if(prob(25)) + suit = pickweight(list( + /obj/item/clothing/suit/hooded/explorer = 18, + /obj/item/clothing/suit/hooded/explorer/old = 1, + /obj/item/clothing/suit/hooded/cloak/goliath = 1 + ) + ) + if(prob(75)) + back = /obj/item/storage/backpack/explorer + if(prob(75)) + belt = pickweight(list( + /obj/item/storage/belt/mining = 2, + /obj/item/storage/belt/mining/alt = 2 + ) + ) + else if(prob(75)) + belt = pickweight(list( + /obj/item/pickaxe = 16, + /obj/item/pickaxe/mini = 8, + /obj/item/pickaxe/silver = 4, + /obj/item/pickaxe/diamond = 2, + /obj/item/gun/energy/kinetic_accelerator = 2, + /obj/item/kinetic_crusher/old = 1 + ) + ) + if(prob(75)) + gloves = pickweight(list( + /obj/item/clothing/gloves/color/black = 9, + /obj/item/clothing/gloves/explorer/old = 1 + ) + ) + if(prob(75)) + shoes = /obj/item/clothing/shoes/workboots/mining + if(prob(75)) + mask = pickweight(list( + /obj/item/clothing/mask/gas/explorer = 9, + /obj/item/clothing/mask/gas/explorer/old = 1 + ) + ) + if(prob(50)) + glasses = /obj/item/clothing/glasses/meson + if(prob(50)) + r_pocket = pickweight(list( + /obj/item/stack/marker_beacon = 20, + /obj/item/spacecash/bundle/mediumrand = 7, + /obj/item/reagent_containers/hypospray/medipen/survival = 2, + /obj/item/borg/upgrade/modkit/damage = 1 + ) + ) + if(prob(25)) + l_pocket = pickweight(list( + /obj/item/spacecash/bundle/mediumrand = 5, + /obj/item/reagent_containers/hypospray/medipen/survival = 2, + /obj/item/borg/upgrade/modkit/cooldown = 1 + ) + ) + if(prob(75)) + for(var/count in 1 to 3) + if(prob(70)) + backpack_contents += pickweight(list( + /obj/item/borg/upgrade/modkit/damage = 1, + /obj/item/borg/upgrade/modkit/trigger_guard = 1, + /obj/item/soap/nanotrasen = 1, + /obj/item/wormhole_jaunter = 1, + /obj/item/fulton_core = 1, + /obj/item/extraction_pack = 2, + /obj/item/stack/sheet/animalhide/goliath_hide = 3, + /obj/item/hivelordstabilizer = 2, + /obj/item/stack/marker_beacon/ten = 2, + /obj/item/mining_scanner = 2, + /obj/item/extinguisher/mini = 2, + /obj/item/kitchen/knife/combat/survival = 3, + /obj/item/flashlight/seclite = 3, + /obj/item/stack/sheet/sinew = 3, + /obj/item/stack/sheet/bone = 3 + ) + ) + if(prob(30)) + backpack_contents += list( + /obj/item/reagent_containers/hypospray/medipen/survival = pickweight(list( + 1 = 3, + 2 = 2, + 3 = 1 + ) + ) + ) + else if (prob(75)) + backpack_contents = list() + back = pickweight(list( + /obj/item/kinetic_crusher = 9, + /obj/item/kinetic_crusher/old = 1 + ) + ) + +/datum/outfit/generic/miner + name = "Miner (Legion)" + +/datum/outfit/generic/engineer/pre_equip(mob/living/carbon/human/H, visualsOnly) + . = ..() + if(prob(75)) + uniform = pick(/obj/item/clothing/under/rank/engineering/engineer, /obj/item/clothing/under/rank/engineering/engineer/hazard, /obj/item/clothing/under/rank/security/officer/military/eng) + if(prob(75)) + suit = pick(/obj/item/clothing/suit/toggle/hazard, /obj/item/clothing/suit/hazardvest, /obj/item/clothing/suit/hooded/wintercoat/engineering) + if(prob(75)) + gloves = pick(/obj/item/clothing/gloves/color/yellow, /obj/item/clothing/gloves/color/fyellow, /obj/item/clothing/gloves/color/fyellow/old) + if(prob(75)) + belt = pick(/obj/item/storage/belt/utility/full, /obj/item/storage/belt/utility) + if(prob(50)) + head = /obj/item/clothing/head/welding + if(prob(75)) + ears = /obj/item/radio/headset/headset_eng + else if(prob(50)) + glasses = /obj/item/clothing/glasses/welding + if(prob(75)) + back = pick(/obj/item/storage/backpack/industrial, /obj/item/storage/backpack/satchel/eng, /obj/item/storage/backpack/duffelbag/engineering, /obj/item/storage/backpack/messenger/engi) + if(prob(10)) + back = /obj/item/fireaxe + for(var/i = 1 to 3) + if(prob(75)) + backpack_contents += pickweight(list( + /obj/item/stack/tape/industrial/electrical = 1, + /obj/item/electronics/apc = 1, + /obj/item/multitool = 1, + /obj/item/pipe_dispenser = 1, + /obj/item/tank/internals/emergency_oxygen/engi = 1, + /obj/item/holosign_creator/engineering = 1, + /obj/item/extinguisher/advanced = 1, + /obj/item/stack/sheet/metal/twenty = 1 + ) + ) + if(prob(75)) + accessory = /obj/item/clothing/accessory/armband/engine + +/datum/outfit/generic/engineer + name = "Mechanic (Legion)" + box = /obj/item/storage/box/survival/engineer + +/datum/outfit/generic/doctor/pre_equip(mob/living/carbon/human/H, visualsOnly) + . = ..() + if(prob(75)) + uniform = pick(/obj/item/clothing/under/rank/medical/doctor, /obj/item/clothing/under/rank/medical/doctor/blue) + if(prob(75)) + suit = pick(/obj/item/clothing/suit/toggle/labcoat, /obj/item/clothing/suit/apron/surgical ,/obj/item/clothing/suit/hooded/wintercoat/medical) + if(prob(75)) + back = pick(/obj/item/storage/backpack/medic, /obj/item/storage/backpack/satchel/med, /obj/item/storage/backpack/duffelbag/med, /obj/item/storage/backpack/messenger/med) + else if (prob(75)) + back = /obj/item/defibrillator/loaded + if(prob(75)) + belt = pickweight(list(/obj/item/storage/belt/medical = 5, /obj/item/defibrillator/compact/loaded = 1)) + if(prob(75)) + gloves = pick(/obj/item/clothing/gloves/color/white, /obj/item/clothing/gloves/color/latex/nitrile) + if(prob(75)) + mask = /obj/item/clothing/mask/surgical + if(prob(75)) + shoes = /obj/item/clothing/shoes/sneakers/white + if(prob(75)) + head = /obj/item/clothing/head/beret/med + if(prob(75)) + ears = /obj/item/radio/headset/headset_med + if(prob(75)) + glasses = pick(/obj/item/clothing/glasses/hud/health, /obj/item/clothing/glasses/hud/health/prescription) + for(var/i = 1 to 3) + if(prob(75)) + backpack_contents += pickweight(list( + /obj/item/reagent_containers/pill/patch/styptic = 5, + /obj/item/reagent_containers/pill/patch/silver_sulf = 5, + /obj/item/storage/firstaid/medical = 3, + /obj/item/reagent_containers/syringe = 3, + /obj/item/reagent_containers/glass/beaker = 2, + /obj/item/reagent_containers/dropper = 2, + /obj/item/reagent_containers/pill/charcoal = 2, + /obj/item/reagent_containers/medigel/styptic = 2, + /obj/item/reagent_containers/medigel/silver_sulf = 2, + /obj/item/reagent_containers/medigel/sterilizine = 1, + /obj/item/flashlight/pen = 1, + /obj/item/hypospray/mkii = 1, + /obj/item/healthanalyzer = 1, + ) + ) + if(prob(75)) + accessory = /obj/item/clothing/accessory/armband/medblue + +/datum/outfit/generic/doctor + name = "Medical Doctor (Legion)" + box = /obj/item/storage/box/survival/medical + +/datum/outfit/generic/science/pre_equip(mob/living/carbon/human/H) + ..() + if(prob(75)) + uniform = pick(/obj/item/clothing/under/rank/rnd/scientist, /obj/item/clothing/under/rank/rnd/roboticist) + if(prob(75)) + suit = pick(/obj/item/clothing/suit/toggle/labcoat/science, /obj/item/clothing/suit/hooded/wintercoat/science) + if(prob(75)) + back = pick(/obj/item/storage/backpack/science, /obj/item/storage/backpack/satchel/tox, /obj/item/storage/backpack/messenger/tox) + if(prob(75)) + shoes = /obj/item/clothing/shoes/sneakers/white + if(prob(75)) + gloves = /obj/item/clothing/gloves/color/white + if(prob(75)) + head = /obj/item/clothing/head/beret/sci + if(prob(75)) + ears = /obj/item/radio/headset/headset_sci + if(prob(75)) + glasses = pick(/obj/item/clothing/glasses/hud/diagnostic, /obj/item/clothing/glasses/science) + if(prob(1)) + neck = /obj/item/clothing/neck/tie/horrible + for(var/i = 1 to 3) + if(prob(75)) + backpack_contents += pickweight(list( + /obj/item/research_notes/loot/tiny = 3, + /obj/item/research_notes/loot/small = 3, + /obj/item/reagent_scanner = 3, + /obj/item/assembly/flash/handheld = 3, + /obj/item/stock_parts/capacitor/adv = 2, + /obj/item/stock_parts/scanning_module/adv = 2, + /obj/item/stock_parts/manipulator/nano = 2, + /obj/item/stock_parts/micro_laser/high = 2, + /obj/item/stock_parts/matter_bin/adv = 2, + /obj/item/survey_handheld = 1, + /obj/item/weldingtool/experimental = 1, + /obj/item/mmi/posibrain = 1, + /obj/item/reagent_containers/glass/beaker/plastic = 1, + /obj/item/organ/eyes/robotic/shield = 1, + /obj/item/organ/eyes/robotic/glow = 1, + ) + ) + if(prob(75)) + accessory = /obj/item/clothing/accessory/armband/science + + +/datum/outfit/generic/science + name = "Scientist (Legion)" + +/datum/outfit/generic/cargo/pre_equip(mob/living/carbon/human/H, visualsOnly) + . = ..() + if(prob(75)) + uniform = pick(/obj/item/clothing/under/rank/cargo/tech, /obj/item/clothing/under/shorts/grey) + if(prob(75)) + suit = pick(/obj/item/clothing/suit/hazardvest, /obj/item/clothing/suit/hooded/wintercoat/cargo) + if(prob(25)) + belt = /obj/item/gun/ballistic/automatic/zip_pistol + if(prob(75)) + gloves = /obj/item/clothing/gloves/fingerless + if(prob(75)) + shoes = /obj/item/clothing/shoes/sneakers/black + if(prob(75)) + head = /obj/item/clothing/head/soft + if(prob(75)) + ears = /obj/item/radio/headset/headset_cargo + for(var/i = 1 to 3) + if(prob(75)) + backpack_contents += pickweight(list( + /obj/item/spacecash/bundle/mediumrand = 5, + /obj/item/ammo_box/magazine/illestren_a850r = 5, + /obj/item/ammo_box/magazine/zip_ammo_9mm = 5, + /obj/item/modular_computer/tablet/preset/cargo = 3, + /obj/item/stack/tape = 3, + /obj/item/stack/tape/industrial = 3, + /obj/item/stack/sheet/plastic/five = 3, + /obj/item/grenade/frag = 1 + ) + ) + if(prob(75)) + accessory = /obj/item/clothing/accessory/armband/cargo + if(prob(25)) + suit = /obj/item/clothing/suit/armor/vest/scrap_armor + suit_store = /obj/item/gun/ballistic/rifle/illestren + +/datum/outfit/generic/cargo + name = "Cargo Technician (Legion)" + +/datum/outfit/generic/security/pre_equip(mob/living/carbon/human/H, visualsOnly) + . = ..() + if(prob(75)) + uniform = /obj/item/clothing/under/rank/security/officer + if(prob(75)) + suit = pick(/obj/item/clothing/suit/armor/vest, /obj/item/clothing/suit/armor/vest/security/officer, /obj/item/clothing/suit/armor/vest/bulletproof, /obj/item/clothing/suit/armor/vest/blueshirt) + if(prob(75)) + back = pick(/obj/item/storage/backpack/security, /obj/item/storage/backpack/satchel/sec, /obj/item/storage/backpack/duffelbag/sec, /obj/item/storage/backpack/messenger/sec) + if(prob(75)) + belt = pick(/obj/item/storage/belt/security, /obj/item/storage/belt/security/webbing) + if(prob(75)) + gloves = pick(/obj/item/clothing/gloves/color/black, /obj/item/clothing/gloves/tackler) + if(prob(75)) + shoes = /obj/item/clothing/shoes/jackboots + if(prob(75)) + head = pick(/obj/item/clothing/head/helmet/sec, /obj/item/clothing/head/helmet/blueshirt, /obj/item/clothing/head/helmet/bulletproof) + if(prob(75)) + mask = /obj/item/clothing/mask/gas/sechailer + if(prob(75)) + ears = /obj/item/radio/headset/headset_sec + if(prob(75)) + glasses = pick(/obj/item/clothing/glasses/hud/security, /obj/item/clothing/glasses/sunglasses) + if(prob(75)) + r_pocket = pick(/obj/item/flashlight/seclite, /obj/item/assembly/flash/handheld, /obj/item/restraints/handcuffs) + if(prob(50)) + suit_store = pick(/obj/item/gun/energy/e_gun, /obj/item/gun/energy/e_gun/smg, /obj/item/gun/energy/e_gun/iot) + for(var/i = 1 to 3) + if(prob(75)) + backpack_contents += pickweight(list( + /obj/item/restraints/handcuffs = 8, + /obj/item/assembly/flash/handheld = 5, + /obj/item/storage/box/evidence = 6, + /obj/item/flashlight/seclite = 4, + /obj/item/ammo_box/c9mm/rubbershot = 3, + /obj/item/ammo_box/c9mm = 1, + /obj/item/stock_parts/cell/gun = 3, + /obj/item/coin/antagtoken = 1, + /obj/item/grenade/stingbang = 1 + ) + ) + if(prob(75)) + accessory = /obj/item/clothing/accessory/armband/deputy + +/datum/outfit/generic/security + name = "Security Officer (Legion)" + box = /obj/item/storage/box/survival/security + diff --git a/code/modules/projectiles/boxes_magazines/generic_ammo_box.dm b/code/modules/projectiles/boxes_magazines/generic_ammo_box.dm new file mode 100644 index 00000000000..2c88824623e --- /dev/null +++ b/code/modules/projectiles/boxes_magazines/generic_ammo_box.dm @@ -0,0 +1,53 @@ +/obj/item/ammo_box/generic + name = "generic ammo box" + desc = "A generic, unbranded box of ammo. It doesn't have great capacity, but it can hold a variety of different calibers." + max_ammo = 20 + start_empty = TRUE + icon_state = "generic-ammo" + /// Does the box currently have an ammo type set? + var/ammo_set = FALSE + /// Name of the currently set ammo type + var/ammo_name + +/obj/item/ammo_box/generic/update_ammo_count() + . = ..() + if(LAZYLEN(stored_ammo) == 0) + ammo_set = FALSE + ammo_type = /obj/item/ammo_casing + +/obj/item/ammo_box/generic/proc/update_max_ammo(obj/item/ammo_casing/ammo) + if(ammo.bullet_per_box) + max_ammo = round(ammo.bullet_per_box) + else + max_ammo = 10 + + return + +/obj/item/ammo_box/generic/attackby(obj/item/attacking_obj, mob/user, params, silent, replace_spent) + . = ..() + + if(!ammo_set && istype(attacking_obj, /obj/item/ammo_casing)) + var/obj/item/ammo_casing/ammo_load = attacking_obj.type + ammo_type = ammo_load + ammo_set = TRUE + ammo_name = attacking_obj.name + update_max_ammo(attacking_obj) + to_chat(user, span_notice("You set the box to hold [attacking_obj]!")) + + if(istype(attacking_obj, /obj/item/pen)) + if(!user.is_literate()) + to_chat(user, span_notice("You scribble illegibly on the cover of [src]!")) + return + var/inputvalue = stripped_input(user, "What would you like to label the box?", "Box Labelling", "", MAX_NAME_LEN) + + if(!inputvalue) + return + + if(user.canUseTopic(src, BE_CLOSE)) + name = "[initial(src.name)][(inputvalue ? " - '[inputvalue]'" : null)]" + +/obj/item/ammo_box/generic/examine(mob/user) + . = ..() + . += span_notice("[ammo_set ? "It's set to hold [ammo_name]\s. The box can hold up to [max_ammo] rounds." : "It doesn't have an ammo type set. Use a bullet on the box to set it."]") + . += span_notice("You can use a pen on it to rename the box.") + diff --git a/code/modules/ruins/lavalandruin_code/biodome_winter.dm b/code/modules/ruins/lavalandruin_code/biodome_winter.dm new file mode 100644 index 00000000000..85fed2a7432 --- /dev/null +++ b/code/modules/ruins/lavalandruin_code/biodome_winter.dm @@ -0,0 +1,9 @@ + +/obj/item/paper/pamphlet/biodomelore + name = "Solarian Frontier Project Pamphlet" + default_raw_text = "

Extrasolar Biodome Project



The Most Serene Solar and Intersolar Confederation welcomes you to one of our many experimental biodomes out in the frontier.
These facilities are developed and built as a collaboration with the Pionierskompanien and are to serve as extrasolar research bases for our most accomplished scientists and scribes. These facilities utilize breakthroughs in terraforming technology to create a comfortable, habitable environment in even the harshest of locales. Your purpose here is to research and report on the effectiveness of the technology utilized within the central dome, as well as maintain and protect the facility." + +/obj/item/paper/crumpled/bloody/winterbiodome + name = "hastily written note" + default_raw_text = "Scheiße, I knew this would happen eventually. Legions have been piling up outside for days, and one of my former coworkers was unwise enough to let them in.

...They're all dead. I can hear the legions outside. The display case with the Claris is locked tight, and I cant find anything to break the glass with.

Please forgive me. My time is up. If anyone finds this, the Claris is yours. Just avenge us.
" + diff --git a/tools/autowiki/autowiki.js b/tools/autowiki/autowiki.js index 6aaf25d80e5..24ad6e35217 100644 --- a/tools/autowiki/autowiki.js +++ b/tools/autowiki/autowiki.js @@ -38,7 +38,7 @@ async function main() { const bot = new MWBot(); await bot.loginGetEditToken({ - apiUrl: "https://shiptest.net/w/api.php", + apiUrl: "https://wiki.starfly.space/api.php", username: USERNAME, password: PASSWORD, });