diff --git a/_maps/map_files/AsteroidStation/AsteroidStation.dmm b/_maps/map_files/AsteroidStation/AsteroidStation.dmm index 0a85929d525e..7752dd3caa81 100644 --- a/_maps/map_files/AsteroidStation/AsteroidStation.dmm +++ b/_maps/map_files/AsteroidStation/AsteroidStation.dmm @@ -9307,6 +9307,14 @@ }, /turf/open/floor/plasteel, /area/crew_quarters/fitness) +"cdC" = ( +/obj/structure/closet/secure_closet/security/sec, +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 4 + }, +/obj/machinery/armaments_dispenser, +/turf/open/floor/plasteel/showroomfloor, +/area/security/main) "cdG" = ( /obj/machinery/door/airlock/highsecurity{ name = "Gravity Generator and SMES"; @@ -30965,6 +30973,14 @@ }, /turf/open/floor/plasteel, /area/engine/atmos_distro) +"jBf" = ( +/obj/item/gun/energy/disabler, +/obj/item/gun/energy/disabler{ + pixel_x = -3; + pixel_y = 3 + }, +/turf/open/floor/plasteel/dark, +/area/ai_monitored/security/armory) "jBm" = ( /obj/structure/table/wood, /obj/item/paper_bin{ @@ -45686,10 +45702,14 @@ dir = 8 }, /obj/structure/rack, -/obj/item/gun/energy/disabler{ +/obj/item/gun/ballistic/automatic/pistol/ntusp{ pixel_x = 3; pixel_y = -3 }, +/obj/item/ammo_box/magazine/recharge/ntusp{ + pixel_x = 9; + pixel_y = -7 + }, /obj/item/gun/energy/disabler, /obj/item/gun/energy/disabler{ pixel_x = -3; @@ -59786,6 +59806,13 @@ }, /turf/open/floor/plasteel/white, /area/science/research) +"tgz" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 4 + }, +/obj/structure/closet/secure_closet/security/sec, +/turf/open/floor/plasteel/showroomfloor, +/area/security/main) "tgD" = ( /obj/effect/landmark/start/atmospheric_technician, /obj/structure/chair/office/dark{ @@ -104939,7 +104966,7 @@ msb aHC cQp dSW -aJG +jBf oIh aJG uaZ @@ -106735,10 +106762,10 @@ adj fdg hFT hFT -hFT +tgz wIf tPH -tPH +cdC xnl lkG qya diff --git a/_maps/map_files/GaxStation/GaxStation.dmm b/_maps/map_files/GaxStation/GaxStation.dmm index 1605fc479c5e..733be15071a2 100644 --- a/_maps/map_files/GaxStation/GaxStation.dmm +++ b/_maps/map_files/GaxStation/GaxStation.dmm @@ -13287,7 +13287,8 @@ /turf/open/floor/plasteel, /area/quartermaster/storage) "guX" = ( -/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{ +/obj/effect/landmark/xeno_spawn, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{ dir = 4 }, /turf/open/floor/plasteel/showroomfloor, @@ -20899,10 +20900,14 @@ pixel_y = 3 }, /obj/item/gun/energy/disabler, -/obj/item/gun/energy/disabler{ +/obj/item/gun/ballistic/automatic/pistol/ntusp{ pixel_x = 3; pixel_y = -3 }, +/obj/item/ammo_box/magazine/recharge/ntusp{ + pixel_x = 9; + pixel_y = -7 + }, /turf/open/floor/plasteel/dark, /area/ai_monitored/security/armory) "kBk" = ( @@ -28702,9 +28707,6 @@ /turf/open/floor/plating, /area/crew_quarters/heads/cmo) "oqA" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{ - dir = 4 - }, /obj/machinery/light{ dir = 8 }, @@ -28712,7 +28714,7 @@ name = "Station Intercom (General)"; pixel_x = -29 }, -/obj/effect/landmark/xeno_spawn, +/obj/machinery/armaments_dispenser, /turf/open/floor/plasteel/showroomfloor, /area/security/main) "oqF" = ( diff --git a/_maps/map_files/YogStation/YogStation.dmm b/_maps/map_files/YogStation/YogStation.dmm index df34200cc949..7bd477fffafe 100644 --- a/_maps/map_files/YogStation/YogStation.dmm +++ b/_maps/map_files/YogStation/YogStation.dmm @@ -602,6 +602,7 @@ /obj/structure/reagent_dispensers/peppertank{ pixel_x = 30 }, +/obj/machinery/armaments_dispenser, /turf/open/floor/plasteel/showroomfloor, /area/security/main) "acV" = ( @@ -56358,12 +56359,10 @@ /turf/open/floor/plasteel, /area/engine/atmos_distro) "tin" = ( -/obj/item/radio/off, -/obj/structure/table, -/obj/structure/table, /obj/effect/turf_decal/trimline/red/filled/line{ dir = 6 }, +/obj/machinery/armaments_dispenser, /turf/open/floor/plasteel, /area/security/checkpoint/auxiliary) "tit" = ( @@ -60818,6 +60817,10 @@ /obj/item/crowbar, /obj/item/assembly/flash/handheld, /obj/effect/turf_decal/trimline/red/filled/line, +/obj/item/radio/off{ + pixel_x = 9; + pixel_y = 1 + }, /turf/open/floor/plasteel, /area/security/checkpoint/auxiliary) "vdm" = ( diff --git a/_maps/map_files/Yogsmeta/Yogsmeta.dmm b/_maps/map_files/Yogsmeta/Yogsmeta.dmm index 6483a343bd90..31c93c65b031 100644 --- a/_maps/map_files/Yogsmeta/Yogsmeta.dmm +++ b/_maps/map_files/Yogsmeta/Yogsmeta.dmm @@ -5270,10 +5270,7 @@ /turf/open/floor/plasteel/showroomfloor, /area/security/main) "anu" = ( -/obj/structure/table, -/obj/machinery/recharger{ - pixel_y = 4 - }, +/obj/machinery/armaments_dispenser, /turf/open/floor/plasteel/showroomfloor, /area/security/main) "anw" = ( @@ -5714,6 +5711,14 @@ /obj/effect/landmark/event_spawn, /obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2, /obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4, +/obj/machinery/recharger/wallrecharger{ + pixel_x = -22; + pixel_y = -8 + }, +/obj/machinery/recharger/wallrecharger{ + pixel_x = -22; + pixel_y = 2 + }, /turf/open/floor/plasteel/showroomfloor, /area/security/main) "aoH" = ( @@ -16726,6 +16731,8 @@ /obj/effect/turf_decal/tile/red{ dir = 8 }, +/obj/item/folder/red, +/obj/item/folder/red, /turf/open/floor/plasteel, /area/security/checkpoint/customs) "aOm" = ( @@ -17316,9 +17323,6 @@ /turf/open/floor/plasteel, /area/quartermaster/storage) "aPD" = ( -/obj/structure/table/reinforced, -/obj/item/folder/red, -/obj/item/folder/red, /obj/structure/cable/yellow{ icon_state = "4-8" }, @@ -17328,6 +17332,7 @@ /obj/effect/turf_decal/tile/red{ dir = 8 }, +/obj/machinery/armaments_dispenser, /turf/open/floor/plasteel, /area/security/checkpoint/customs) "aPE" = ( diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index 7aa087fbbdee..c2c219e895f0 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -293,6 +293,12 @@ InsertAll("", each, GLOB.alldirs) ..() +/datum/asset/simple/security_armaments + assets = list( + "disablerbig.png" = 'icons/vending_icons/disablerbig.png', + "ntuspbig.png" = 'icons/vending_icons/ntuspbig.png', + ) + // Representative icons for each research design /datum/asset/spritesheet/research_designs name = "design" diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 1aaf71853d19..9cb87606be80 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -308,6 +308,19 @@ /obj/item/gun/energy/disabler) crate_name = "disabler crate" +/datum/supply_pack/security/ntusp + name = "NT-USP Crate" + desc = "Three stamina-draining ballistic weapons, along with 3 extra clips. Requires Security access to open." + cost = 2000 + access_view = ACCESS_SECURITY + contains = list(/obj/item/gun/ballistic/automatic/pistol/ntusp, + /obj/item/gun/ballistic/automatic/pistol/ntusp, + /obj/item/gun/ballistic/automatic/pistol/ntusp, + /obj/item/ammo_box/magazine/recharge/ntusp, + /obj/item/ammo_box/magazine/recharge/ntusp, + /obj/item/ammo_box/magazine/recharge/ntusp) + crate_name = "nt-usp crate" + /datum/supply_pack/security/forensics name = "Forensics Crate" desc = "Stay hot on the criminal's heels with Nanotrasen's Detective Essentials(tm). Contains a forensics scanner, six evidence bags, camera, tape recorder, white crayon, and of course, a fedora. Requires Security access to open." diff --git a/code/modules/economy/account.dm b/code/modules/economy/account.dm index e9bc3118072a..708172d985c4 100644 --- a/code/modules/economy/account.dm +++ b/code/modules/economy/account.dm @@ -12,6 +12,7 @@ var/withdrawDelay = 0 var/is_bourgeois = FALSE // Marks whether we've tried giving them the achievement already, this round. var/bounties_claimed = 0 // Marks how many bounties this person has successfully claimed + var/sec_weapon_claimed = FALSE // If this account has claimed a weapon \code\modules\vending\security_armaments.dm /datum/bank_account/New(newname, job, modifier = 1) var/limiter = 0 diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index 40f7d7705040..161da3a807ab 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -163,7 +163,6 @@ GLOBAL_LIST_INIT(available_depts_sec, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICA digitigrade_shoes = /obj/item/clothing/shoes/xeno_wraps/jackboots l_pocket = /obj/item/restraints/handcuffs r_pocket = /obj/item/assembly/flash/handheld - suit_store = /obj/item/gun/energy/disabler backpack_contents = list(/obj/item/melee/baton/loaded=1) backpack = /obj/item/storage/backpack/security diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index 81320e14d9e8..8b8552620f4b 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -73,7 +73,6 @@ glasses = /obj/item/clothing/glasses/hud/security/sunglasses r_pocket = /obj/item/assembly/flash/handheld l_pocket = /obj/item/restraints/handcuffs - suit_store = /obj/item/gun/energy/disabler backpack_contents = list(/obj/item/melee/baton/loaded=1) //yogs - ~~added departmental budget ID~~ removes sec budget backpack = /obj/item/storage/backpack/security diff --git a/code/modules/projectiles/boxes_magazines/external/rechargable.dm b/code/modules/projectiles/boxes_magazines/external/rechargable.dm index 571020e225e1..f070027a2491 100644 --- a/code/modules/projectiles/boxes_magazines/external/rechargable.dm +++ b/code/modules/projectiles/boxes_magazines/external/rechargable.dm @@ -3,7 +3,7 @@ /obj/item/ammo_box/magazine/recharge name = "power pack" desc = "A rechargeable, detachable battery that serves as a magazine for laser rifles." - icon_state = "oldrifle" + icon_state = "powerpack" ammo_type = /obj/item/ammo_casing/caseless/laser caliber = LASER max_ammo = 20 @@ -11,10 +11,63 @@ /obj/item/ammo_box/magazine/recharge/update_icon() ..() desc = "[initial(desc)] It has [stored_ammo.len] shot\s left." - if(ammo_count()) - icon_state = "oldrifle" - else - icon_state = "oldrifle_empty" + cut_overlays() + var/cur_ammo = ammo_count() + if(cur_ammo) + if(cur_ammo >= max_ammo) + add_overlay("[icon_state]_o_full") + else + add_overlay("[icon_state]_o_mid") + /obj/item/ammo_box/magazine/recharge/attack_self() //No popping out the "bullets" return + +/obj/item/gun/ballistic/automatic/pistol/ntusp + name = "NT-USP pistol" + desc = "A small pistol that uses hardlight technology to synthesize bullets. Due to its low power, it doesn't have much use besides tiring out criminals." + icon_state = "ntusp" + w_class = WEIGHT_CLASS_SMALL + mag_type = /obj/item/ammo_box/magazine/recharge/ntusp + can_suppress = FALSE + can_flashlight = TRUE + bolt_type = BOLT_TYPE_LOCKING + fire_sound = "sound/weapons/gunshot.ogg" + vary_fire_sound = FALSE + fire_sound_volume = 80 + rack_sound = "sound/weapons/pistolrack.ogg" + bolt_drop_sound = "sound/weapons/pistolslidedrop.ogg" + bolt_wording = "slide" + feedback_types = list( + "fire" = 2 + ) + +//NT-USP Clip +/obj/item/ammo_box/magazine/recharge/ntusp + name = "small power pack" + desc = "A small rechargable power pack that synthesizes .22HL bullets, used in the NT-USP." + icon_state = "powerpack_small" + ammo_type = /obj/item/ammo_casing/caseless/c22hl + max_ammo = 9 + +/obj/item/ammo_box/magazine/recharge/ntusp/emp_act(severity) //shooting physical bullets wont stop you dying to an EMP + . = ..() + if(!(. & EMP_PROTECT_CONTENTS)) + var/bullet_count = ammo_count() + var/bullets_to_remove = round(bullet_count / severity) + for(var/i = 0; i < bullets_to_remove, i++) + qdel(get_round()) + update_icon() + +/obj/item/ammo_casing/caseless/c22hl + caliber = ENERGY + projectile_type = /obj/item/projectile/bullet/c22hl + +/obj/item/projectile/bullet/c22hl //.22 HL + name = "NT-USP beam" + icon_state = "disabler_bullet" + flag = ENERGY + damage = 2 //ouch ouch my skin ouchie + damage_type = BURN + stamina = 25 + diff --git a/code/modules/vending/security_armaments.dm b/code/modules/vending/security_armaments.dm new file mode 100644 index 000000000000..0427222ce8ad --- /dev/null +++ b/code/modules/vending/security_armaments.dm @@ -0,0 +1,120 @@ +// An armaments dispenser that gives security officers their roundstart weapon +/obj/machinery/armaments_dispenser + name = "armaments dispenser" + desc = "A standard issue security armaments dispenser." + icon = 'icons/obj/vending.dmi' + icon_state = "armament" // BAIOMU REPLACE THIS WITH YOUR SPRITE + layer = 2.9 + density = TRUE + var/list/inventory = list() + + contents = newlist(/obj/item/gun/energy/disabler, + /obj/item/gun/ballistic/automatic/pistol/ntusp) + + +/obj/machinery/armaments_dispenser/Initialize() + . = ..() + inventory = contents.Copy() + +/obj/machinery/armaments_dispenser/ui_assets(mob/user) + return list( + get_asset_datum(/datum/asset/simple/security_armaments), + ) + +/obj/machinery/armaments_dispenser/ui_act(action, params) + if(..()) + return TRUE + + var/allowed = FALSE + var/can_claim = FALSE + var/obj/item/card/id/C = usr?.get_idcard() + // Security officers and wardens + if(istype(C) && (ACCESS_SECURITY in C.access) && (ACCESS_WEAPONS in C.access) && !(ACCESS_HOS in C.access)) + allowed = TRUE + // Hasn't claimed a weapon yet + if(!C?.registered_account?.sec_weapon_claimed) + can_claim = TRUE + + if(!allowed) + return FALSE + + if(!can_claim) + return FALSE + + switch(action) + if("dispense_weapon") + if(params["weapon"] && ispath(text2path(params["weapon"]))) + var/wep = text2path(params["weapon"]) + new wep(loc) + if(params["magazine"] && ispath(text2path(params["magazine"]))) + var/mag = text2path(params["magazine"]) + new mag(loc) + else + return FALSE + C.registered_account.sec_weapon_claimed = TRUE + return TRUE + return FALSE + +/obj/machinery/armaments_dispenser/ui_interact(mob/user, datum/tgui/ui) + if(stat & (BROKEN | NOPOWER | MAINT)) + if(ui) + ui.close() + return 0 + + ui = SStgui.try_update_ui(user, src, ui) + if (!ui) + ui = new(user, src, "ArmamentsDispenser") + ui.open() + +/obj/machinery/armaments_dispenser/ui_static_data(mob/user) + var/list/data = ..() + var/list/items = list() + for(var/obj/item/wep in inventory) + var/obj/item/gun/weapon = wep + weapon.update_icon(TRUE) + var/icon/gun_icon = getFlatIcon(wep) + + var/list/details = list() + details["name"] = weapon.name + details["description"] = weapon.desc + details["path"] = weapon.type + + var/md5 = md5(fcopy_rsc(gun_icon)) + + if(!SSassets.cache["photo_[md5]_icon.png"]) + SSassets.transport.register_asset("photo_[md5]_icon.png", gun_icon) + + SSassets.transport.send_assets(user, list("photo_[md5]_icon.png" = gun_icon)) + details["gun_icon"] = SSassets.transport.get_asset_url("photo_[md5]_icon.png") + if(istype(weapon, /obj/item/gun/ballistic)) + var/obj/item/gun/ballistic/gun = wep + var/icon/mag_icon = getFlatIcon(gun.magazine) + md5 = md5(fcopy_rsc(mag_icon)) + + if(!SSassets.cache["photo_[md5]_icon.png"]) + SSassets.transport.register_asset("photo_[md5]_icon.png", mag_icon) + SSassets.transport.send_assets(user, list("photo_[md5]_icon.png" = mag_icon)) + details["mag_icon"] = SSassets.transport.get_asset_url("photo_[md5]_icon.png") + details["mag_path"] = gun.mag_type + items += list(details) + + data["inventory"] = items + return data + +/obj/machinery/armaments_dispenser/ui_data(mob/user) + var/list/data = ..() + + var/allowed = FALSE + var/can_claim = FALSE + var/obj/item/card/id/C = user?.get_idcard() + // Security officers and wardens + if(istype(C) && (ACCESS_SECURITY in C.access) && (ACCESS_WEAPONS in C.access) && !(ACCESS_HOS in C.access)) + allowed = TRUE + // Hasn't claimed a weapon yet + if(!C?.registered_account?.sec_weapon_claimed) + can_claim = TRUE + + data["allowed"] = allowed + data["can_claim"] = can_claim + + return data diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi index 033405c1e458..34cf348bbf87 100644 Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi index 95bc571605d8..f5ff0de42319 100644 Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 8ffece5f6397..ed134b5f47a5 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/icons/obj/vending.dmi b/icons/obj/vending.dmi index e91e7352a95c..ce1a0e36f5c4 100644 Binary files a/icons/obj/vending.dmi and b/icons/obj/vending.dmi differ diff --git a/icons/vending_icons/disablerbig.png b/icons/vending_icons/disablerbig.png new file mode 100644 index 000000000000..470fb9b8c94e Binary files /dev/null and b/icons/vending_icons/disablerbig.png differ diff --git a/icons/vending_icons/ntuspbig.png b/icons/vending_icons/ntuspbig.png new file mode 100644 index 000000000000..f43d52957594 Binary files /dev/null and b/icons/vending_icons/ntuspbig.png differ diff --git a/tgui/packages/tgui/interfaces/ArmamentsDispenser.js b/tgui/packages/tgui/interfaces/ArmamentsDispenser.js new file mode 100644 index 000000000000..a39ceefaff5e --- /dev/null +++ b/tgui/packages/tgui/interfaces/ArmamentsDispenser.js @@ -0,0 +1,81 @@ +import { resolveAsset } from '../assets'; +import { useBackend } from '../backend'; +import { NoticeBox, Button, Flex, Box } from '../components'; +import { Window } from '../layouts'; + +export const ArmamentsDispenser = (props, context) => { + const { act, data } = useBackend(context); + const { inventory = [] } = data; + return ( + + + {(data.allowed === 1 && data.can_claim === 1) && ( + + Please select your preferred weapon. + + )} + {data.allowed !== 1 && ( + + You are not a security officer or warden! + + )} + {(data.can_claim !== 1 && data.allowed === 1) && ( + + You have already claimed a weapon or do not have a registered account! + + )} + + {inventory.map(weapon => ( + + + + ))} + + + + + ); +}; diff --git a/yogstation.dme b/yogstation.dme index 8c68cfbac232..791a5b500abc 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -3416,6 +3416,7 @@ #include "code\modules\vending\plasmaresearch.dm" #include "code\modules\vending\robotics.dm" #include "code\modules\vending\security.dm" +#include "code\modules\vending\security_armaments.dm" #include "code\modules\vending\snack.dm" #include "code\modules\vending\sovietsoda.dm" #include "code\modules\vending\sustenance.dm"