diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm
index 17fd8b32c280..5ba67f34ca57 100644
--- a/code/__DEFINES/conflict.dm
+++ b/code/__DEFINES/conflict.dm
@@ -41,6 +41,8 @@
#define AMMO_MP (1<<21)
/// Handles sentry flamers glob
#define AMMO_FLAME (1<<22)
+// If the projectile hits a dense turf it'll do on_hit_turf on the turf just in front of the turf instead of on the turf itself (This one does not work on mobs)
+#define AMMO_STRIKES_SURFACE_ONLY (1<<23)
// NOTE: Don't add flags past 1<<23, it'll break things due to BYOND limitations. You can usually use a Component instead.
/// Projectile is shrpanel which allow it to skip some collisions
diff --git a/code/__DEFINES/weapon_stats.dm b/code/__DEFINES/weapon_stats.dm
index 1c3c09e9b28d..6c7cfeed541d 100644
--- a/code/__DEFINES/weapon_stats.dm
+++ b/code/__DEFINES/weapon_stats.dm
@@ -136,6 +136,7 @@ As such, don't expect any values assigned to common firearms to even consider ho
//How many ticks you have to wait between firing. Burst delay uses the same variable!
*/
+#define FIRE_DELAY_TIER_SHARP 40
#define FIRE_DELAY_TIER_AMR 30
#define FIRE_DELAY_TIER_VULTURE 20
#define FIRE_DELAY_TIER_SNIPER 15
diff --git a/code/datums/supply_packs/spec_ammo.dm b/code/datums/supply_packs/spec_ammo.dm
index 889d2e25b8af..259cb7a6e7a2 100644
--- a/code/datums/supply_packs/spec_ammo.dm
+++ b/code/datums/supply_packs/spec_ammo.dm
@@ -178,6 +178,65 @@
containername = "M4RA Scout Impact Magazine Crate"
group = "Weapons Specialist Ammo"
+//SHARP
+
+/datum/supply_packs/ammo_grenadier_sharp_mix
+ name = "SHARP Operator Mixed Magazine Crate (explosive x2, flechette x2, incendiary x2)"
+ contains = list(
+ /obj/item/ammo_magazine/rifle/sharp/explosive,
+ /obj/item/ammo_magazine/rifle/sharp/explosive,
+ /obj/item/ammo_magazine/rifle/sharp/flechette,
+ /obj/item/ammo_magazine/rifle/sharp/flechette,
+ /obj/item/ammo_magazine/rifle/sharp/incendiary,
+ /obj/item/ammo_magazine/rifle/sharp/incendiary,
+ )
+ cost = 40
+ containertype = /obj/structure/closet/crate/ammo
+ containername = "SHARP Operator Mixed Magazine Crate"
+ group = "Weapons Specialist Ammo"
+
+/datum/supply_packs/ammo_grenadier_sharp_explosive
+ name = "SHARP Operator Explosive Magazine Crate (x5)"
+ contains = list(
+ /obj/item/ammo_magazine/rifle/sharp/explosive,
+ /obj/item/ammo_magazine/rifle/sharp/explosive,
+ /obj/item/ammo_magazine/rifle/sharp/explosive,
+ /obj/item/ammo_magazine/rifle/sharp/explosive,
+ /obj/item/ammo_magazine/rifle/sharp/explosive,
+ )
+ cost = 30
+ containertype = /obj/structure/closet/crate/ammo
+ containername = "SHARP Operator Explosive Magazine Crate"
+ group = "Weapons Specialist Ammo"
+
+/datum/supply_packs/ammo_grenadier_sharp_flechette
+ name = "SHARP Operator Flechette Magazine Crate (x5)"
+ contains = list(
+ /obj/item/ammo_magazine/rifle/sharp/flechette,
+ /obj/item/ammo_magazine/rifle/sharp/flechette,
+ /obj/item/ammo_magazine/rifle/sharp/flechette,
+ /obj/item/ammo_magazine/rifle/sharp/flechette,
+ /obj/item/ammo_magazine/rifle/sharp/flechette,
+ )
+ cost = 30
+ containertype = /obj/structure/closet/crate/ammo
+ containername = "SHARP Operator Flechette Magazine Crate"
+ group = "Weapons Specialist Ammo"
+
+/datum/supply_packs/ammo_grenadier_sharp_incendiary
+ name = "SHARP Operator incendiary Magazine Crate (x5)"
+ contains = list(
+ /obj/item/ammo_magazine/rifle/sharp/incendiary,
+ /obj/item/ammo_magazine/rifle/sharp/incendiary,
+ /obj/item/ammo_magazine/rifle/sharp/incendiary,
+ /obj/item/ammo_magazine/rifle/sharp/incendiary,
+ /obj/item/ammo_magazine/rifle/sharp/incendiary,
+ )
+ cost = 30
+ containertype = /obj/structure/closet/crate/ammo
+ containername = "SHARP Operator incendiary Magazine Crate"
+ group = "Weapons Specialist Ammo"
+
//M240-T
/datum/supply_packs/ammo_pyro_mix
diff --git a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm
index cfe67465df07..7554bb781f6d 100644
--- a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm
+++ b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm
@@ -612,6 +612,7 @@
var/list/supplies = list(
"10x24mm, slugs, buckshot, and 10x20mm rounds",
"Explosives and grenades",
+ "SHARP ammo",
"Rocket ammo",
"Sniper ammo",
"Anti-Material Sniper ammo",
@@ -641,11 +642,14 @@
if("Explosives and grenades")
supply_drop = 5
to_chat(usr, SPAN_NOTICE("Explosives and grenades will now drop!"))
- if("Pyrotechnician tanks")
+ if("SHARP ammo")
supply_drop = 6
+ to_chat(usr, SPAN_NOTICE("SHARP ammo will now drop!"))
+ if("Pyrotechnician tanks")
+ supply_drop = 7
to_chat(usr, SPAN_NOTICE("Pyrotechnician tanks will now drop!"))
if("Scout ammo")
- supply_drop = 7
+ supply_drop = 8
to_chat(usr, SPAN_NOTICE("Scout ammo will now drop!"))
else
return
@@ -747,12 +751,17 @@
if(5) // Give them explosives + Grenades for the Grenade spec. Might be too many grenades, but we'll find out.
spawnitems = list(/obj/item/storage/box/explosive_mines,
/obj/item/storage/belt/grenade/full)
- if(6) // Pyrotech
+ if(6) // SHARP ammo
+ spawnitems = list(/obj/item/ammo_magazine/rifle/sharp/explosive,
+ /obj/item/ammo_magazine/rifle/sharp/explosive,
+ /obj/item/ammo_magazine/rifle/sharp/incendiary,
+ /obj/item/ammo_magazine/rifle/sharp/flechette,)
+ if(7) // Pyrotech
var/fuel = pick(/obj/item/ammo_magazine/flamer_tank/large/B, /obj/item/ammo_magazine/flamer_tank/large/X)
spawnitems = list(/obj/item/ammo_magazine/flamer_tank/large,
/obj/item/ammo_magazine/flamer_tank/large,
fuel)
- if(7) // Scout
+ if(8) // Scout
spawnitems = list(/obj/item/ammo_magazine/rifle/m4ra/custom,
/obj/item/ammo_magazine/rifle/m4ra/custom,
/obj/item/ammo_magazine/rifle/m4ra/custom/incendiary,
diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm
index 8e84f7556b50..bcdce351f746 100644
--- a/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm
+++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_specialist.dm
@@ -4,6 +4,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_spec, list(
list("WEAPONS SPECIALIST SETS (CHOOSE 1)", 0, null, null, null),
list("Demolitionist Set", 0, /obj/item/storage/box/spec/demolitionist, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR),
list("Heavy Grenadier Set", 0, /obj/item/storage/box/spec/heavy_grenadier, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR),
+ list("SHARP Operator Set", 0, /obj/item/storage/box/spec/sharp_operator, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR),
list("Pyro Set", 0, /obj/item/storage/box/spec/pyro, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR),
list("Scout Set", 0, /obj/item/storage/box/spec/scout, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_REGULAR),
list("Sniper Set", 0, /obj/item/storage/box/spec/sniper, MARINE_CAN_BUY_ESSENTIALS, VENDOR_ITEM_RECOMMENDED),
@@ -25,6 +26,11 @@ GLOBAL_LIST_INIT(cm_vending_gear_spec, list(
list("84mm High-Explosive Rocket", 40, /obj/item/ammo_magazine/rocket, null, VENDOR_ITEM_REGULAR),
list("84mm White-Phosphorus Rocket", 40, /obj/item/ammo_magazine/rocket/wp, null, VENDOR_ITEM_REGULAR),
+ list("EXTRA SHARP AMMUNITION", 0, null, null, null),
+ list("SHARP 9X-E Sticky Explosive Dart magazine (darts)", 40, /obj/item/ammo_magazine/rifle/sharp/explosive, null, VENDOR_ITEM_REGULAR),
+ list("SHARP 9X-T Sticky incendiary Dart magazine (darts)", 40, /obj/item/ammo_magazine/rifle/sharp/incendiary, null, VENDOR_ITEM_REGULAR),
+ list("SHARP 9X-F Flechette Dart Magazine (darts)", 40, /obj/item/ammo_magazine/rifle/sharp/flechette, null, VENDOR_ITEM_REGULAR),
+
list("EXTRA GRENADES", 0, null, null, null),
list("M40 HEDP Grenades x6", 40, /obj/effect/essentials_set/hedp_6_pack, null, VENDOR_ITEM_REGULAR),
list("M40 HIDP Incendiary Grenades x6", 40, /obj/effect/essentials_set/hidp_6_pack, null, VENDOR_ITEM_REGULAR),
diff --git a/code/game/machinery/vending/vendor_types/wo_vendors.dm b/code/game/machinery/vending/vendor_types/wo_vendors.dm
index ce0b098ed9e5..a93ae7433a84 100644
--- a/code/game/machinery/vending/vendor_types/wo_vendors.dm
+++ b/code/game/machinery/vending/vendor_types/wo_vendors.dm
@@ -185,6 +185,11 @@
list("84mm High-Explosive Rocket", floor(scale * 1), /obj/item/ammo_magazine/rocket, VENDOR_ITEM_REGULAR),
list("84mm White-Phosphorus Rocket", floor(scale * 1), /obj/item/ammo_magazine/rocket/wp, VENDOR_ITEM_REGULAR),
+ list("EXTRA SHARP AMMUNITION", -1, null, null, null),
+ list("SHARP 9X-E Sticky Explosive Dart magazine (darts)", round(scale * 1.5), /obj/item/ammo_magazine/rifle/sharp/explosive, null, VENDOR_ITEM_REGULAR),
+ list("SHARP 9X-T Sticky incendiary Dart magazine (darts)", round(scale * 1), /obj/item/ammo_magazine/rifle/sharp/incendiary, null, VENDOR_ITEM_REGULAR),
+ list("SHARP 9X-F Flechette Dart Magazine (darts)", round(scale * 1), /obj/item/ammo_magazine/rifle/sharp/flechette, null, VENDOR_ITEM_REGULAR),
+
list("EXTRA GRENADES", -1, null, null, null),
list("M40 HEDP Grenade Pack (x6)", floor(scale * 1.5), /obj/effect/essentials_set/hedp_6_pack, VENDOR_ITEM_REGULAR),
list("M40 HIDP Grenade Pack (x6)", floor(scale * 1.5), /obj/effect/essentials_set/hidp_6_pack, VENDOR_ITEM_REGULAR),
diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm
index 45fbd5d4ba2b..7373464595c2 100644
--- a/code/game/objects/effects/aliens.dm
+++ b/code/game/objects/effects/aliens.dm
@@ -103,6 +103,10 @@
W.acid_spray_act()
continue
+ if(istype(atm, /obj/item/explosive/mine/sharp))
+ var/obj/item/explosive/mine/sharp/sharp_mine = atm
+ sharp_mine.prime()
+
// Humans?
if(isliving(atm)) //For extinguishing mobs on fire
var/mob/living/M = atm
diff --git a/code/game/objects/effects/effect_system/smoke.dm b/code/game/objects/effects/effect_system/smoke.dm
index 1efe8e5e3b66..e6a43da22197 100644
--- a/code/game/objects/effects/effect_system/smoke.dm
+++ b/code/game/objects/effects/effect_system/smoke.dm
@@ -314,6 +314,7 @@
var/burn_damage = 40
var/applied_fire_stacks = 5
var/xeno_yautja_reduction = 0.75
+ var/reagent = new /datum/reagent/napalm/ut()
/obj/effect/particle_effect/smoke/phosphorus/weak
time_to_live = 2
@@ -321,6 +322,9 @@
burn_damage = 30
xeno_yautja_reduction = 0.5
+/obj/effect/particle_effect/smoke/phosphorus/sharp
+ reagent = new /datum/reagent/napalm/blue()
+
/obj/effect/particle_effect/smoke/phosphorus/Move()
. = ..()
for(var/mob/living/carbon/affected_mob in get_turf(src))
@@ -351,7 +355,6 @@
if(isyautja(affected_mob) || isxeno(affected_mob))
damage *= xeno_yautja_reduction
- var/reagent = new /datum/reagent/napalm/ut()
affected_mob.burn_skin(damage)
affected_mob.adjust_fire_stacks(applied_fire_stacks, reagent)
affected_mob.IgniteMob()
@@ -761,6 +764,9 @@
/datum/effect_system/smoke_spread/phosphorus/weak
smoke_type = /obj/effect/particle_effect/smoke/phosphorus/weak
+/datum/effect_system/smoke_spread/phosphorus/sharp
+ smoke_type = /obj/effect/particle_effect/smoke/phosphorus/sharp
+
/datum/effect_system/smoke_spread/cn20
smoke_type = /obj/effect/particle_effect/smoke/cn20
diff --git a/code/game/objects/items/explosives/mine.dm b/code/game/objects/items/explosives/mine.dm
index 6e7aa2bdccc3..04be8c2f2f0b 100644
--- a/code/game/objects/items/explosives/mine.dm
+++ b/code/game/objects/items/explosives/mine.dm
@@ -157,7 +157,7 @@
if(!customizable)
set_tripwire()
- return;
+ return
if(!detonator)
active = TRUE
@@ -339,3 +339,153 @@
/obj/item/explosive/mine/sebb/prime()
new /obj/item/explosive/grenade/sebb/primed(get_turf(src))
qdel(src)
+
+/obj/item/explosive/mine/sharp
+ name = "\improper P9 SHARP explosive dart"
+ desc = "An experimental P9 SHARP proximity triggered explosive dart designed by Armat Systems for use by the United States Colonial Marines. This one has full 360 detection range."
+ icon_state = "sharp_explosive_mine"
+ layer = ABOVE_OBJ_LAYER
+ angle = 360
+ health = 50
+ var/disarmed = FALSE
+ var/explosion_size = 100
+ var/explosion_falloff = 50
+ var/mine_level = 1
+ var/deploy_time = 0
+ var/mine_state = ""
+ var/timer_id
+
+/obj/item/explosive/mine/sharp/proc/upgrade_mine()
+ mine_level++
+ icon_state = mine_state + "_[mine_level]"
+ if(mine_level < 4)
+ timer_id = addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, upgrade_mine)), 30 SECONDS, TIMER_DELETE_ME | TIMER_STOPPABLE)
+
+/obj/item/explosive/mine/sharp/check_for_obstacles(mob/living/user)
+ return FALSE
+
+/obj/item/explosive/mine/sharp/attackby(obj/item/W, mob/user)
+ if(user.action_busy)
+ return
+ else if(HAS_TRAIT(W, TRAIT_TOOL_MULTITOOL))
+ user.visible_message(SPAN_NOTICE("[user] starts disarming [src]."), \
+ SPAN_NOTICE("You start disarming [src]."))
+ if(!do_after(user, 30, INTERRUPT_NO_NEEDHAND, BUSY_ICON_FRIENDLY))
+ user.visible_message(SPAN_WARNING("[user] stops disarming [src]."), \
+ SPAN_WARNING("You stop disarming [src]."))
+ return
+ if(!active)//someone beat us to it
+ return
+ user.visible_message(SPAN_NOTICE("[user] finishes disarming [src]."), \
+ SPAN_NOTICE("You finish disarming [src]."))
+ disarm()
+ return
+
+/obj/item/explosive/mine/sharp/set_tripwire()
+ if(!active && !tripwire)
+ for(var/direction in CARDINAL_ALL_DIRS)
+ var/tripwire_loc = get_turf(get_step(loc,direction))
+ tripwire = new(tripwire_loc)
+ tripwire.linked_claymore = src
+ active = TRUE
+
+/obj/item/explosive/mine/sharp/prime(mob/user)
+ set waitfor = FALSE
+ if(!cause_data)
+ cause_data = create_cause_data(initial(name), user)
+ if(mine_level == 1)
+ explosion_size = 100
+ else if(mine_level == 2)
+ explosion_size = 100
+ explosion_falloff = 25
+ else if(mine_level == 3)
+ explosion_size = 125
+ explosion_falloff = 30
+ else
+ explosion_size = 125
+ explosion_falloff = 25
+ cell_explosion(loc, explosion_size, explosion_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, CARDINAL_ALL_DIRS, cause_data)
+ playsound(loc, 'sound/weapons/gun_sharp_explode.ogg', 100)
+ qdel(src)
+
+/obj/item/explosive/mine/sharp/disarm()
+ anchored = FALSE
+ active = FALSE
+ triggered = FALSE
+ icon_state = "sharp_mine_disarmed"
+ desc = "A disarmed P9 SHARP rifle dart, useless now."
+ QDEL_NULL(tripwire)
+ disarmed = TRUE
+ deltimer(timer_id)
+ add_to_garbage(src)
+
+
+/obj/item/explosive/mine/sharp/attack_self(mob/living/user)
+ if(disarmed)
+ return
+ . = ..()
+
+/obj/item/explosive/mine/sharp/deploy_mine(mob/user)
+ if(disarmed)
+ return
+ if(!hard_iff_lock && user)
+ iff_signal = user.faction
+
+ cause_data = create_cause_data(initial(name), user)
+ if(user)
+ user.drop_inv_item_on_ground(src)
+ setDir(user ? user.dir : dir) //The direction it is planted in is the direction the user faces at that time
+ activate_sensors()
+ update_icon()
+ deploy_time = world.time
+ mine_state = icon_state
+ timer_id = addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, upgrade_mine)), 30 SECONDS, TIMER_DELETE_ME | TIMER_STOPPABLE)
+ for(var/mob/living/carbon/mob in range(1, src))
+ try_to_prime(mob)
+
+/obj/item/explosive/mine/sharp/attack_alien()
+ if(disarmed)
+ ..()
+ else
+ return
+
+//basically copy pasted from welding kit code
+/obj/item/explosive/mine/sharp/bullet_act(obj/projectile/bullet)
+ var/damage = bullet.damage
+ health -= damage
+ ..()
+ healthcheck()
+ return TRUE
+
+/obj/item/explosive/mine/sharp/proc/healthcheck()
+ if(health <= 0)
+ prime()
+
+/obj/item/explosive/mine/sharp/incendiary
+ name = "\improper P9 SHARP incendiary dart"
+ desc = "An experimental P9 SHARP proximity triggered explosive dart designed by Armat Systems for use by the United States Colonial Marines. This one has full 360 detection range."
+ icon_state = "sharp_incendiary_mine"
+
+/obj/item/explosive/mine/sharp/incendiary/prime(mob/user)
+ set waitfor = FALSE
+ if(!cause_data)
+ cause_data = create_cause_data(initial(name), user)
+ if(mine_level == 1)
+ var/datum/effect_system/smoke_spread/phosphorus/smoke = new /datum/effect_system/smoke_spread/phosphorus/sharp
+ var/smoke_radius = 2
+ smoke.set_up(smoke_radius, 0, loc)
+ smoke.start()
+ playsound(loc, 'sound/weapons/gun_sharp_explode.ogg', 100)
+ else if(mine_level == 2)
+ var/datum/reagent/napalm/green/reagent = new()
+ new /obj/flamer_fire(loc, cause_data, reagent, 2)
+ playsound(loc, 'sound/weapons/gun_flamethrower3.ogg', 45)
+ else if(mine_level == 3)
+ var/datum/reagent/napalm/ut/reagent = new()
+ new /obj/flamer_fire(loc, cause_data, reagent, 2)
+ playsound(loc, 'sound/weapons/gun_flamethrower3.ogg', 45)
+ else
+ var/datum/reagent/napalm/ut/reagent = new()
+ new /obj/flamer_fire(loc, cause_data, reagent, 3)
+ playsound(loc, 'sound/weapons/gun_flamethrower3.ogg', 45)
+ qdel(src)
diff --git a/code/game/objects/items/shards.dm b/code/game/objects/items/shards.dm
index dab573e6f5a5..86631b10982d 100644
--- a/code/game/objects/items/shards.dm
+++ b/code/game/objects/items/shards.dm
@@ -73,7 +73,6 @@
icon_state = "phoron"
source_sheet_type = /obj/item/stack/sheet/glass/phoronglass
-
// Shrapnel.
// on_embed is called from projectile.dm, bullet_act(obj/projectile/P).
// on_embedded_movement is called from human.dm, handle_embedded_objects().
@@ -265,3 +264,56 @@
/obj/item/shard/shrapnel/tutorial
damage_on_move = 0
+
+/obj/item/sharp
+ name = "sharp dart shrapnel"
+ desc = "It looks like a used 9X-E Sticky Explosive Dart, useless now."
+ icon = 'icons/obj/items/weapons/projectiles.dmi'
+ icon_state = "sharp_explosive_dart"
+ sharp = IS_SHARP_ITEM_BIG
+ w_class = SIZE_SMALL
+ edge = TRUE
+ force = 0
+ throwforce = 0
+ garbage = TRUE
+ var/damage_on_move = 3
+ var/count = 1
+
+/obj/item/sharp/Initialize(mapload, dir)
+ . = ..()
+ if(dir && dir <= 6)
+ turn_object(90)
+ else
+ turn_object(270)
+
+/obj/item/sharp/proc/on_embed(mob/embedded_mob, obj/limb/target_organ)
+ return
+
+/obj/item/sharp/proc/on_embedded_movement(mob/living/embedded_mob)
+ if(!ishuman(embedded_mob))
+ return
+ var/mob/living/carbon/human/H = embedded_mob
+ if(H.species.flags & NO_SHRAPNEL)
+ return
+ var/obj/limb/organ = embedded_organ
+ if(istype(organ))
+ organ.take_damage(damage_on_move * count, 0, 0, no_limb_loss = TRUE)
+ embedded_mob.pain.apply_pain(damage_on_move * count)
+
+/obj/item/sharp/proc/turn_object(amount)
+ var/matrix/initial_matrix = matrix(transform)
+ initial_matrix.Turn(amount)
+ apply_transform(initial_matrix)
+
+/obj/item/sharp/explosive
+ name = "\improper 9X-E Sticky Explosive Dart"
+
+/obj/item/sharp/incendiary
+ name = "\improper 9X-T Sticky Incendiary Dart"
+ desc = "It looks like a used 9X-T Sticky Incendiary Dart, useless now."
+ icon_state = "sharp_incendiary_dart"
+
+/obj/item/sharp/flechette
+ name = "\improper 9X-F Flechette Dart"
+ desc = "It looks like a used 9X-F Flechette Dart, useless now."
+ icon_state = "sharp_flechette_dart"
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 139d90ff33ce..283826fd81ca 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -665,6 +665,24 @@
new /obj/item/ammo_magazine/smartgun(src)
new /obj/item/ammo_magazine/smartgun(src)
+/obj/item/storage/belt/marine/sharp
+ name = "\improper M103 pattern SHARP magazine belt"
+ desc = "A specially modified M103 pattern rig designed to hold P9 SHARP rifle magazines, instead of tank shells."
+ icon_state = "tankbelt"
+ item_state = "tankbelt"
+ item_state_slots = list(
+ WEAR_L_HAND = "utility",
+ WEAR_R_HAND = "utility")
+ storage_slots = 8
+ max_storage_space = 8
+ can_hold = list(
+ /obj/item/ammo_magazine/rifle/sharp/explosive,
+ /obj/item/ammo_magazine/rifle/sharp/flechette,
+ /obj/item/ammo_magazine/rifle/sharp/incendiary,
+ )
+ has_gamemode_skin = FALSE
+ flags_atom = NO_NAME_OVERRIDE|NO_SNOW_TYPE
+
/obj/item/storage/belt/marine/quackers
name = "Mr. Quackers"
desc = "What are we going to do today, Mr. Quackers?"
diff --git a/code/modules/cm_marines/equipment/kit_boxes.dm b/code/modules/cm_marines/equipment/kit_boxes.dm
index 7be519896097..80b701f38875 100644
--- a/code/modules/cm_marines/equipment/kit_boxes.dm
+++ b/code/modules/cm_marines/equipment/kit_boxes.dm
@@ -121,7 +121,6 @@
else
new /obj/item/device/binoculars/range/designator/scout(src)
-
/obj/item/storage/box/spec/pyro
name = "\improper Pyrotechnician equipment case"
desc = "A large case containing M240-T incinerator unit, M35 pyrotechnician armor and helmet, Broiler-T flexible refueling system and additional pieces of equipment.\nDrag this sprite onto yourself to open it up! NOTE: You cannot put items back inside this case."
@@ -160,6 +159,30 @@
new /obj/item/ammo_magazine/pistol/vp78(src)
new /obj/item/device/binoculars(src)
+/obj/item/storage/box/spec/sharp_operator
+ name = "\improper SHARP Operator equipment case"
+ desc = "A large case containing a P9 SHARP rifle, M3-G4 Grenadier armor and helmet, and various pieces of additional equipment.\nDrag this sprite onto yourself to open it up!"
+ kit_overlay = "grenadier"
+
+/obj/item/storage/box/spec/sharp_operator/fill_preset_inventory()
+ new /obj/item/weapon/gun/rifle/sharp(src)
+ new /obj/item/storage/belt/marine/sharp(src)
+ new /obj/item/ammo_magazine/rifle/sharp/explosive(src)
+ new /obj/item/ammo_magazine/rifle/sharp/explosive(src)
+ new /obj/item/ammo_magazine/rifle/sharp/explosive(src)
+ new /obj/item/ammo_magazine/rifle/sharp/explosive(src)
+ new /obj/item/ammo_magazine/rifle/sharp/flechette(src)
+ new /obj/item/ammo_magazine/rifle/sharp/flechette(src)
+ new /obj/item/ammo_magazine/rifle/sharp/incendiary(src)
+ new /obj/item/ammo_magazine/rifle/sharp/incendiary(src)
+ new /obj/item/clothing/gloves/marine/M3G(src)
+ new /obj/item/clothing/suit/storage/marine/M3G(src)
+ new /obj/item/clothing/head/helmet/marine/grenadier(src)
+ new /obj/item/weapon/gun/pistol/vp78(src)
+ new /obj/item/ammo_magazine/pistol/vp78(src)
+ new /obj/item/ammo_magazine/pistol/vp78(src)
+ new /obj/item/device/binoculars(src)
+
//maybe put in req for later use?
/obj/item/storage/box/spec/B18
@@ -271,6 +294,7 @@
return GLOB.specialist_set_name_dict[selection].redeem_set(user, TRUE)
+
//******************************************PFC Kits****************************************************************/
/obj/item/storage/box/kit
diff --git a/code/modules/cm_marines/specialist.dm b/code/modules/cm_marines/specialist.dm
index 72247641c488..b1d429138834 100644
--- a/code/modules/cm_marines/specialist.dm
+++ b/code/modules/cm_marines/specialist.dm
@@ -185,6 +185,18 @@
skill_to_give = SKILL_SPEC_GRENADIER
trait_to_give = "grenadier"
kit_typepath = /obj/item/storage/box/spec/heavy_grenadier
+ incompatible_sets = list(
+ /datum/specialist_set/sharp_operator,
+ )
+
+/datum/specialist_set/sharp_operator
+ name = "SHARP Operator Set"
+ role_name = "SHARP Operator"
+ skill_to_give = SKILL_SPEC_GRENADIER
+ kit_typepath = /obj/item/storage/box/spec/sharp_operator
+ incompatible_sets = list(
+ /datum/specialist_set/grenadier,
+ )
/datum/specialist_set/pyro
name = "Pyro Set"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 0a6a42d09ba5..6ba315a160c1 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -980,6 +980,9 @@
else if(istype(W, /obj/item/shard/shrapnel))
var/obj/item/shard/shrapnel/embedded = W
embedded.on_embedded_movement(src)
+ else if(istype(W, /obj/item/sharp))
+ var/obj/item/sharp/embedded = W
+ embedded.on_embedded_movement(src)
// Check if its a sharp weapon
else if(is_sharp(W))
if(organ.status & LIMB_SPLINTED) //Splints prevent movement.
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index e032d3ebbe55..c576a4af62b7 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -32,6 +32,7 @@ They're all essentially identical when it comes to getting the job done.
var/base_mag_item //the default mag item (inhand) state.
var/transfer_handful_amount = 8 //amount of bullets to transfer, 5 for 12g, 9 for 45-70
var/handful_state = "bullet" //used for generating handfuls from boxes and setting their sprite when loading/unloading
+ var/description_ammo = "rounds"
/// If this and ammo_band_icon aren't null, run update_ammo_band(). Is the color of the band, such as green on AP.
var/ammo_band_color
@@ -98,7 +99,7 @@ They're all essentially identical when it comes to getting the job done.
. += "Something went horribly wrong. Ahelp the following: ERROR CODE R1: negative current_rounds on examine."
log_debug("ERROR CODE R1: negative current_rounds on examine. User: [usr] Magazine: [src]")
else
- . += "[src] has [current_rounds] rounds out of [max_rounds]."
+ . += "[src] has [current_rounds] [description_ammo] out of [max_rounds]."
/obj/item/ammo_magazine/attack_hand(mob/user)
if(flags_magazine & AMMUNITION_REFILLABLE) //actual refillable magazine, not just a handful of bullets or a fuel tank.
diff --git a/code/modules/projectiles/guns/specialist/sharp.dm b/code/modules/projectiles/guns/specialist/sharp.dm
new file mode 100644
index 000000000000..54082a409b8d
--- /dev/null
+++ b/code/modules/projectiles/guns/specialist/sharp.dm
@@ -0,0 +1,244 @@
+//-------------------------------------------------------
+//P9 Sonic Harpoon Artillery Remote Projectile(SHARP) Rifle
+
+/obj/item/weapon/gun/rifle/sharp
+ name = "\improper P9 SHARP rifle"
+ desc = "An experimental harpoon launcher rifle with an inbuilt magnetic harness manufactured by Armat Systems. It's specialized for specific ammo types out of a 10-round magazine, best used for area denial and disruption."
+ icon_state = "sharprifle"
+ item_state = "sharp"
+ fire_sound = 'sound/weapons/gun_sharp.ogg'
+ reload_sound = 'sound/weapons/handling/m41_reload.ogg'
+ unload_sound = 'sound/weapons/handling/m41_unload.ogg'
+ unacidable = TRUE
+ indestructible = TRUE
+ muzzle_flash = null
+
+ current_mag = /obj/item/ammo_magazine/rifle/sharp/explosive
+ attachable_allowed = list()
+ auto_retrieval_slot = WEAR_J_STORE
+
+ aim_slowdown = SLOWDOWN_ADS_SPECIALIST
+ wield_delay = WIELD_DELAY_VERY_SLOW
+ flags_gun_features = GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER
+
+ flags_item = TWOHANDED|NO_CRYO_STORE
+ map_specific_decoration = TRUE
+
+ var/explosion_delay_sharp = TRUE
+
+/obj/item/weapon/gun/rifle/sharp/get_examine_text(mob/user)
+ . = ..()
+ . += SPAN_INFO("Switching firemodes will toggle the explosion delay timer between 1 second and 5 seconds")
+
+/obj/item/weapon/gun/rifle/sharp/set_gun_attachment_offsets()
+ attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 17,"rail_x" = 12, "rail_y" = 22, "under_x" = 23, "under_y" = 13, "stock_x" = 24, "stock_y" = 13)
+
+/obj/item/weapon/gun/rifle/sharp/set_gun_config_values()
+ ..()
+ set_burst_amount(BURST_AMOUNT_TIER_1)
+ fire_delay = FIRE_DELAY_TIER_AMR
+ accuracy_mult = BASE_ACCURACY_MULT
+ scatter = SCATTER_AMOUNT_NONE
+ damage_mult = BASE_BULLET_DAMAGE_MULT
+ recoil = RECOIL_OFF
+
+
+/obj/item/weapon/gun/rifle/sharp/unload_chamber(mob/user)
+ if(!in_chamber)
+ return
+ var/found_handful
+ for(var/obj/item/ammo_magazine/handful/handful in user.loc)
+ if(handful.default_ammo == in_chamber.ammo.type && handful.caliber == caliber && handful.current_rounds < handful.max_rounds)
+ found_handful = TRUE
+ handful.current_rounds++
+ handful.update_icon()
+ break
+ if(!found_handful)
+ var/obj/item/ammo_magazine/handful/new_handful = new(get_turf(src))
+ new_handful.generate_handful(in_chamber.ammo.type, caliber, 5, 1, type)
+
+/obj/item/weapon/gun/rifle/sharp/able_to_fire(mob/living/user)
+ . = ..()
+ if (. && istype(user))
+ if(!skillcheck(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_ALL) && user.skills.get_skill_level(SKILL_SPEC_WEAPONS) != SKILL_SPEC_GRENADIER)
+ to_chat(user, SPAN_WARNING("You don't seem to know how to use \the [src]..."))
+ return FALSE
+
+//code for changing explosion delay on direct hits
+
+/obj/item/weapon/gun/rifle/sharp/do_toggle_firemode(mob/user)
+ . = ..()
+ explosion_delay_sharp = !explosion_delay_sharp
+ playsound(user, 'sound/weapons/handling/gun_burst_toggle.ogg', 15, 1)
+ to_chat(user, SPAN_NOTICE("[icon2html(src, user)] You [explosion_delay_sharp ? SPAN_BOLD("enable") : SPAN_BOLD("disable")] [src]'s delayed fire mode. Explosive ammo will blow up in [explosion_delay_sharp ? SPAN_BOLD("5 seconds") : SPAN_BOLD("2.5 seconds")]."))
+ user.balloon_alert(user, "explosive ammo will blow up in [explosion_delay_sharp ? SPAN_BOLD("5 seconds") : SPAN_BOLD("2.5 seconds")].")
+
+
+
+/*
+//========
+ SHARP Dart Ammo
+//========
+*/
+/datum/ammo/rifle/sharp
+ name = "dart"
+ ping = null //no bounce off.
+ damage_type = BRUTE
+ shrapnel_type = /obj/item/sharp
+ flags_ammo_behavior = AMMO_SPECIAL_EMBED|AMMO_NO_DEFLECT|AMMO_STRIKES_SURFACE_ONLY|AMMO_HITS_TARGET_TURF
+ icon_state = "sharp_explosive_dart"
+ handful_state = "sharp_explosive"
+
+
+ shrapnel_chance = 100
+ accuracy = HIT_ACCURACY_TIER_MAX
+ accurate_range = 12
+ max_range = 7
+ damage = 35
+ shell_speed = AMMO_SPEED_TIER_2
+ var/embed_object = /obj/item/sharp/explosive
+ var/mine_level = 0
+
+/datum/ammo/rifle/sharp/on_embed(mob/embedded_mob, obj/limb/target_organ)
+ if(!ishuman(embedded_mob))
+ return
+ var/mob/living/carbon/human/humano = embedded_mob
+ if(humano.species.flags & NO_SHRAPNEL)
+ return
+ if(istype(target_organ))
+ target_organ.embed(new embed_object)
+
+/datum/ammo/rifle/sharp/on_hit_obj(obj/O, obj/projectile/P)
+ drop_dart(P.loc, P)
+
+/datum/ammo/rifle/sharp/on_hit_turf(turf/T, obj/projectile/P)
+ drop_dart(T, P)
+
+/datum/ammo/rifle/sharp/do_at_max_range(obj/projectile/P)
+ drop_dart(P.loc, P)
+
+/datum/ammo/rifle/sharp/proc/drop_dart(loc, obj/projectile/P)
+ new embed_object(loc, P.dir)
+
+/datum/ammo/rifle/sharp/explosive
+ name = "9X-E sticky explosive dart"
+
+/datum/ammo/rifle/sharp/explosive/on_hit_mob(mob/living/target, obj/projectile/shot_dart)
+ if(!target || target == shot_dart.firer)
+ return
+
+ var/mob/shooter = shot_dart.firer
+ shake_camera(target, 2, 1)
+ if(shooter && ismob(shooter))
+ target.balloon_alert(target, "you have been hit by an explosive dart!", text_color = "#ce1e1e")
+ if(!target.get_target_lock(shooter.faction_group))
+ var/obj/item/weapon/gun/rifle/sharp/weapon = shot_dart.shot_from
+ playsound(get_turf(target), 'sound/weapons/gun_sharp_explode.ogg', 100)
+ if(weapon && weapon.explosion_delay_sharp)
+ addtimer(CALLBACK(src, PROC_REF(delayed_explosion), shot_dart, target, shooter), 5 SECONDS)
+ else
+ addtimer(CALLBACK(src, PROC_REF(delayed_explosion), shot_dart, target, shooter), 2.5 SECONDS)
+
+/datum/ammo/rifle/sharp/explosive/drop_dart(loc, obj/projectile/shot_dart, mob/shooter)
+ var/signal_explosion = FALSE
+ if(locate(/obj/item/explosive/mine) in get_turf(loc))
+ signal_explosion = TRUE
+ var/obj/item/explosive/mine/sharp/dart = new /obj/item/explosive/mine/sharp(loc)
+ // if no darts on tile, don't arm, explode instead.
+ if(signal_explosion)
+ INVOKE_ASYNC(dart, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, prime), shooter)
+ else
+ dart.anchored = TRUE
+ addtimer(CALLBACK(dart, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, deploy_mine), shooter), 3 SECONDS, TIMER_DELETE_ME)
+ addtimer(CALLBACK(dart, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, disarm)), 5 MINUTES, TIMER_DELETE_ME)
+
+/datum/ammo/rifle/sharp/explosive/proc/delayed_explosion(obj/projectile/shot_dart, mob/target, mob/shooter)
+ if(ismob(target))
+ var/explosion_size = 60
+ var/falloff_size = 35
+ var/cause_data = create_cause_data("P9 SHARP Rifle", shooter)
+ cell_explosion(get_turf(target), explosion_size, falloff_size, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data)
+
+
+/datum/ammo/rifle/sharp/incendiary
+ name = "9X-T sticky incendiary dart"
+ icon_state = "sharp_incendiary_dart"
+ handful_state = "sharp_incendiary"
+ embed_object = /obj/item/sharp/incendiary
+
+/datum/ammo/rifle/sharp/incendiary/on_hit_mob(mob/living/target, obj/projectile/shot_dart)
+ if(!target || target == shot_dart.firer)
+ return
+ var/mob/shooter = shot_dart.firer
+ shake_camera(target, 2, 1)
+ if(shooter && ismob(shooter))
+ target.balloon_alert(target, "you have been hit by an incendiary dart!", text_color = "#ce1e1e")
+ if(!target.get_target_lock(shooter.faction_group))
+ var/obj/item/weapon/gun/rifle/sharp/weapon = shot_dart.shot_from
+ playsound(get_turf(target), 'sound/weapons/gun_sharp_explode.ogg', 100)
+ if(weapon && weapon.explosion_delay_sharp)
+ addtimer(CALLBACK(src, PROC_REF(delayed_fire), shot_dart, target, shooter), 5 SECONDS)
+ else
+ addtimer(CALLBACK(src, PROC_REF(delayed_fire), shot_dart, target, shooter), 2.5 SECONDS)
+
+/datum/ammo/rifle/sharp/incendiary/drop_dart(loc, obj/projectile/shot_dart, mob/shooter)
+ var/signal_explosion = FALSE
+ if(locate(/obj/item/explosive/mine) in get_turf(loc))
+ signal_explosion = TRUE
+ var/obj/item/explosive/mine/sharp/incendiary/dart = new /obj/item/explosive/mine/sharp/incendiary(loc)
+ // if no darts on tile, don't arm, explode instead.
+ if(signal_explosion)
+ INVOKE_ASYNC(dart, TYPE_PROC_REF(/obj/item/explosive/mine/sharp/incendiary, prime), shooter)
+ else
+ dart.anchored = TRUE
+ addtimer(CALLBACK(dart, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, deploy_mine), shooter), 3 SECONDS, TIMER_DELETE_ME)
+ addtimer(CALLBACK(dart, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, disarm)), 5 MINUTES, TIMER_DELETE_ME)
+
+/datum/ammo/rifle/sharp/incendiary/proc/delayed_fire(obj/projectile/shot_dart, mob/target, mob/shooter)
+ if(ismob(target))
+ var/datum/effect_system/smoke_spread/phosphorus/smoke = new /datum/effect_system/smoke_spread/phosphorus/sharp
+ var/smoke_radius = 2
+ smoke.set_up(smoke_radius, 0, get_turf(target))
+ smoke.start()
+
+/datum/ammo/rifle/sharp/flechette
+ name = "9X-F flechette dart"
+ icon_state = "sharp_flechette_dart"
+ handful_state = "sharp_flechette"
+ embed_object = /obj/item/sharp/flechette
+ shrapnel_type = /datum/ammo/bullet/shotgun/flechette_spread
+
+/datum/ammo/rifle/sharp/flechette/on_hit_mob(mob/living/target, obj/projectile/shot_dart)
+ if(!target || target == shot_dart.firer)
+ return
+ var/mob/shooter = shot_dart.firer
+ shake_camera(target, 2, 1)
+ if(shooter && ismob(shooter))
+ if(!target.get_target_lock(shooter.faction_group))
+ create_flechette(target.loc, shot_dart)
+
+/datum/ammo/rifle/sharp/flechette/on_pointblank(mob/living/target, obj/projectile/shot_dart)
+ if(!target) return
+ shot_dart.dir = get_dir(shot_dart.firer, target)
+
+/datum/ammo/rifle/sharp/flechette/on_hit_obj(obj/O, obj/projectile/P)
+ create_flechette(O.loc, P)
+
+/datum/ammo/rifle/sharp/flechette/on_hit_turf(turf/T, obj/projectile/P)
+ create_flechette(T, P)
+
+/datum/ammo/rifle/sharp/flechette/do_at_max_range(obj/projectile/P)
+ create_flechette(P.loc, P)
+
+/datum/ammo/rifle/sharp/flechette/proc/create_flechette(loc, obj/projectile/shot_dart)
+ var/shrapnel_count = 8
+ var/dispersion_angle = 20
+ create_shrapnel(loc, shrapnel_count, shot_dart.dir, dispersion_angle, shrapnel_type, shot_dart.weapon_cause_data, FALSE, 1)
+ apply_explosion_overlay(loc)
+
+/datum/ammo/rifle/sharp/flechette/proc/apply_explosion_overlay(turf/loc)
+ var/obj/effect/overlay/sharp_overlay = new /obj/effect/overlay(loc)
+ sharp_overlay.name = "grenade"
+ sharp_overlay.icon = 'icons/effects/explosion.dmi'
+ flick("grenade", sharp_overlay)
+ QDEL_IN(sharp_overlay, 7)
diff --git a/code/modules/projectiles/magazines/rifles.dm b/code/modules/projectiles/magazines/rifles.dm
index 60be8ed6c1ad..8c8ebc2cc3e5 100644
--- a/code/modules/projectiles/magazines/rifles.dm
+++ b/code/modules/projectiles/magazines/rifles.dm
@@ -528,3 +528,35 @@
max_rounds = 12
gun_type = /obj/item/weapon/gun/rifle/xm51
transfer_handful_amount = 6
+//-------------------------------------------------------
+//P9 SHARP Rifle
+
+/obj/item/ammo_magazine/rifle/sharp
+ name = "sharp rifle magazine"
+ icon_state = "sharp_explosive_mag"
+ item_state = "sharprifle"
+ caliber = "Dart"
+ w_class = SIZE_MEDIUM
+ max_rounds = 10
+ default_ammo = /datum/ammo/rifle/sharp/explosive
+ gun_type = /obj/item/weapon/gun/rifle/sharp
+ transfer_handful_amount = 5
+
+
+ description_ammo = "darts"
+
+/obj/item/ammo_magazine/rifle/sharp/explosive
+ name = "\improper 9X-E sticky explosive dart magazine"
+ desc = "A specialized sticky explosive dart magazine."
+
+/obj/item/ammo_magazine/rifle/sharp/incendiary
+ name = "\improper 9X-T sticky incendiary dart magazine"
+ desc = "A specialized incendiary dart magazine."
+ icon_state = "sharp_incendiary_mag"
+ default_ammo = /datum/ammo/rifle/sharp/incendiary
+
+/obj/item/ammo_magazine/rifle/sharp/flechette
+ name = "\improper 9X-F flechette dart magazine"
+ desc = "A specialized flechette dart magazine."
+ icon_state = "sharp_flechette_mag"
+ default_ammo = /datum/ammo/rifle/sharp/flechette
diff --git a/code/modules/projectiles/magazines/specialist.dm b/code/modules/projectiles/magazines/specialist.dm
index 38b9137be54f..de568c731703 100644
--- a/code/modules/projectiles/magazines/specialist.dm
+++ b/code/modules/projectiles/magazines/specialist.dm
@@ -385,3 +385,4 @@
default_ammo = /datum/ammo/rocket/wp/upp
gun_type = /obj/item/weapon/gun/launcher/rocket/upp
reload_delay = 85
+
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index cdc23da1a940..8c6178ab8207 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -417,7 +417,7 @@
// If the ammo should hit the surface of the target and the next turf is dense
// The current turf is the "surface" of the target
- if(ammo_flags & AMMO_STRIKES_SURFACE)
+ if(ammo_flags & (AMMO_STRIKES_SURFACE|AMMO_STRIKES_SURFACE_ONLY))
// We "hit" the current turf but strike the actual blockage
ammo.on_hit_turf(get_turf(src),src)
else
@@ -478,7 +478,7 @@
// If the ammo should hit the surface of the target and there is an object blocking
// The current turf is the "surface" of the target
- if(ammo_flags & AMMO_STRIKES_SURFACE)
+ if(ammo_flags & (AMMO_STRIKES_SURFACE|AMMO_STRIKES_SURFACE_ONLY))
var/turf/T = get_turf(O)
// We "hit" the current turf but strike the actual blockage
diff --git a/code/modules/vehicles/interior/interactable/vendors.dm b/code/modules/vehicles/interior/interactable/vendors.dm
index 4ad837169fba..f0565e118580 100644
--- a/code/modules/vehicles/interior/interactable/vendors.dm
+++ b/code/modules/vehicles/interior/interactable/vendors.dm
@@ -219,6 +219,9 @@
list("A19 High Velocity Impact Magazine (10x24mm)", 0, /obj/item/ammo_magazine/rifle/m4ra/custom/impact, VENDOR_ITEM_REGULAR),
list("A19 High Velocity Incendiary Magazine (10x24mm)", 0, /obj/item/ammo_magazine/rifle/m4ra/custom/incendiary, VENDOR_ITEM_REGULAR),
list("A19 High Velocity Magazine (10x24mm)", 0, /obj/item/ammo_magazine/rifle/m4ra/custom, VENDOR_ITEM_REGULAR),
+ list("SHARP 9X-E Sticky Explosive Dart magazine (darts)", 0, /obj/item/ammo_magazine/rifle/sharp/explosive, VENDOR_ITEM_REGULAR),
+ list("SHARP 9X-T Sticky Incendiary Dart magazine (darts)", 0, /obj/item/ammo_magazine/rifle/sharp/incendiary, VENDOR_ITEM_REGULAR),
+ list("SHARP 9X-F Flechette Dart Magazine (darts)", 0, /obj/item/ammo_magazine/rifle/sharp/flechette, VENDOR_ITEM_REGULAR),
list("M42A Flak Magazine (10x28mm)", 0, /obj/item/ammo_magazine/sniper/flak, VENDOR_ITEM_REGULAR),
list("M42A Incendiary Magazine (10x28mm)", 0, /obj/item/ammo_magazine/sniper/incendiary, VENDOR_ITEM_REGULAR),
list("M42A Marksman Magazine (10x28mm Caseless)", 0, /obj/item/ammo_magazine/sniper, VENDOR_ITEM_REGULAR),
diff --git a/colonialmarines.dme b/colonialmarines.dme
index f728c9a38c26..f1b1b0ca2aa8 100644
--- a/colonialmarines.dme
+++ b/colonialmarines.dme
@@ -2244,6 +2244,7 @@
#include "code\modules\projectiles\guns\flamer\flamer.dm"
#include "code\modules\projectiles\guns\flamer\flameshape.dm"
#include "code\modules\projectiles\guns\specialist\scout.dm"
+#include "code\modules\projectiles\guns\specialist\sharp.dm"
#include "code\modules\projectiles\guns\specialist\sniper.dm"
#include "code\modules\projectiles\guns\specialist\launcher\grenade_launcher.dm"
#include "code\modules\projectiles\guns\specialist\launcher\launcher.dm"
diff --git a/icons/obj/items/weapons/grenade.dmi b/icons/obj/items/weapons/grenade.dmi
index 61c9707e43df..231ff9e3d177 100644
Binary files a/icons/obj/items/weapons/grenade.dmi and b/icons/obj/items/weapons/grenade.dmi differ
diff --git a/icons/obj/items/weapons/guns/ammo_by_faction/uscm.dmi b/icons/obj/items/weapons/guns/ammo_by_faction/uscm.dmi
index 8b3b5e0f1c80..ff8123237204 100644
Binary files a/icons/obj/items/weapons/guns/ammo_by_faction/uscm.dmi and b/icons/obj/items/weapons/guns/ammo_by_faction/uscm.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi b/icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi
index a22810024717..edbf9d9938d0 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi and b/icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/classic/back.dmi b/icons/obj/items/weapons/guns/guns_by_map/classic/back.dmi
index fb21be90f8a7..99d4e1ec1655 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/classic/back.dmi and b/icons/obj/items/weapons/guns/guns_by_map/classic/back.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/classic/guns_lefthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/classic/guns_lefthand.dmi
index df823405fac3..06f4cdb74f61 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/classic/guns_lefthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/classic/guns_lefthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/classic/guns_obj.dmi b/icons/obj/items/weapons/guns/guns_by_map/classic/guns_obj.dmi
index 4a31d29042d4..ba31b75a50e6 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/classic/guns_obj.dmi and b/icons/obj/items/weapons/guns/guns_by_map/classic/guns_obj.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/classic/guns_righthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/classic/guns_righthand.dmi
index 21d7b04f6f05..a990fb4d26e8 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/classic/guns_righthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/classic/guns_righthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/classic/suit_slot.dmi b/icons/obj/items/weapons/guns/guns_by_map/classic/suit_slot.dmi
index 0d3b1f715571..ad458d686080 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/classic/suit_slot.dmi and b/icons/obj/items/weapons/guns/guns_by_map/classic/suit_slot.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/desert/back.dmi b/icons/obj/items/weapons/guns/guns_by_map/desert/back.dmi
index 9e5e8d4c9c59..4ed596878b7a 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/desert/back.dmi and b/icons/obj/items/weapons/guns/guns_by_map/desert/back.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/desert/guns_lefthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/desert/guns_lefthand.dmi
index 02021756a805..75cbff28bca3 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/desert/guns_lefthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/desert/guns_lefthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/desert/guns_obj.dmi b/icons/obj/items/weapons/guns/guns_by_map/desert/guns_obj.dmi
index a91d071754ad..8da305ba8285 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/desert/guns_obj.dmi and b/icons/obj/items/weapons/guns/guns_by_map/desert/guns_obj.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/desert/guns_righthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/desert/guns_righthand.dmi
index e408fff750da..26e7fd1d2eca 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/desert/guns_righthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/desert/guns_righthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/desert/suit_slot.dmi b/icons/obj/items/weapons/guns/guns_by_map/desert/suit_slot.dmi
index 764a51e8b390..5e6c53be187c 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/desert/suit_slot.dmi and b/icons/obj/items/weapons/guns/guns_by_map/desert/suit_slot.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/jungle/back.dmi b/icons/obj/items/weapons/guns/guns_by_map/jungle/back.dmi
index 5cc73c3e9ec5..a6024c32b3db 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/jungle/back.dmi and b/icons/obj/items/weapons/guns/guns_by_map/jungle/back.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_lefthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_lefthand.dmi
index 25f8b823289c..9ae002fda26b 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_lefthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_lefthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_obj.dmi b/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_obj.dmi
index c5b3b3f3fe73..ee98004abc55 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_obj.dmi and b/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_obj.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_righthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_righthand.dmi
index 9c2562d5a921..b85933e79f8b 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_righthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/jungle/guns_righthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/jungle/suit_slot.dmi b/icons/obj/items/weapons/guns/guns_by_map/jungle/suit_slot.dmi
index 0aa7f686a749..78150dc86bec 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/jungle/suit_slot.dmi and b/icons/obj/items/weapons/guns/guns_by_map/jungle/suit_slot.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/snow/back.dmi b/icons/obj/items/weapons/guns/guns_by_map/snow/back.dmi
index 8ad5352cc440..2345c34c3c3c 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/snow/back.dmi and b/icons/obj/items/weapons/guns/guns_by_map/snow/back.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/snow/guns_lefthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/snow/guns_lefthand.dmi
index a837e7061417..daa066645804 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/snow/guns_lefthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/snow/guns_lefthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/snow/guns_obj.dmi b/icons/obj/items/weapons/guns/guns_by_map/snow/guns_obj.dmi
index 171d0d0eca03..2a9db67d1faf 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/snow/guns_obj.dmi and b/icons/obj/items/weapons/guns/guns_by_map/snow/guns_obj.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/snow/guns_righthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/snow/guns_righthand.dmi
index 1de053b6f969..dfa98d65f01a 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/snow/guns_righthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/snow/guns_righthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/snow/suit_slot.dmi b/icons/obj/items/weapons/guns/guns_by_map/snow/suit_slot.dmi
index 1555703bfb94..90a8abc9cbcd 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/snow/suit_slot.dmi and b/icons/obj/items/weapons/guns/guns_by_map/snow/suit_slot.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/urban/back.dmi b/icons/obj/items/weapons/guns/guns_by_map/urban/back.dmi
index 5996089a64d6..6c642f8bd49a 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/urban/back.dmi and b/icons/obj/items/weapons/guns/guns_by_map/urban/back.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/urban/guns_lefthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/urban/guns_lefthand.dmi
index ea84f3e69e21..88d228bc0593 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/urban/guns_lefthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/urban/guns_lefthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/urban/guns_obj.dmi b/icons/obj/items/weapons/guns/guns_by_map/urban/guns_obj.dmi
index 78e322e3db8b..b81e51cfd185 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/urban/guns_obj.dmi and b/icons/obj/items/weapons/guns/guns_by_map/urban/guns_obj.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/urban/guns_righthand.dmi b/icons/obj/items/weapons/guns/guns_by_map/urban/guns_righthand.dmi
index 1b2c96fb9518..954a6bc132d7 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/urban/guns_righthand.dmi and b/icons/obj/items/weapons/guns/guns_by_map/urban/guns_righthand.dmi differ
diff --git a/icons/obj/items/weapons/guns/guns_by_map/urban/suit_slot.dmi b/icons/obj/items/weapons/guns/guns_by_map/urban/suit_slot.dmi
index 738add8e1df4..ee04fb95e4ac 100644
Binary files a/icons/obj/items/weapons/guns/guns_by_map/urban/suit_slot.dmi and b/icons/obj/items/weapons/guns/guns_by_map/urban/suit_slot.dmi differ
diff --git a/icons/obj/items/weapons/guns/handful.dmi b/icons/obj/items/weapons/guns/handful.dmi
index e3fe380c9dfe..150118b9733d 100644
Binary files a/icons/obj/items/weapons/guns/handful.dmi and b/icons/obj/items/weapons/guns/handful.dmi differ
diff --git a/icons/obj/items/weapons/guns/lineart.dmi b/icons/obj/items/weapons/guns/lineart.dmi
index 52ed68016313..3cb9ec85fd18 100644
Binary files a/icons/obj/items/weapons/guns/lineart.dmi and b/icons/obj/items/weapons/guns/lineart.dmi differ
diff --git a/icons/obj/items/weapons/projectiles.dmi b/icons/obj/items/weapons/projectiles.dmi
index 21c210c14910..3d91eb3eac3b 100644
Binary files a/icons/obj/items/weapons/projectiles.dmi and b/icons/obj/items/weapons/projectiles.dmi differ
diff --git a/sound/weapons/gun_sharp.ogg b/sound/weapons/gun_sharp.ogg
new file mode 100644
index 000000000000..9fd6fe029a20
Binary files /dev/null and b/sound/weapons/gun_sharp.ogg differ
diff --git a/sound/weapons/gun_sharp_explode.ogg b/sound/weapons/gun_sharp_explode.ogg
new file mode 100644
index 000000000000..d97608d21d9a
Binary files /dev/null and b/sound/weapons/gun_sharp_explode.ogg differ