diff --git a/code/__DEFINES/objects.dm b/code/__DEFINES/objects.dm
index 33b6c3d1af88..30f9b8f04577 100644
--- a/code/__DEFINES/objects.dm
+++ b/code/__DEFINES/objects.dm
@@ -169,6 +169,7 @@ GLOBAL_LIST_INIT(RESTRICTED_CAMERA_NETWORKS, list( //Those networks can only be
#define FLAMESHAPE_IRREGULAR "irregular"
#define FLAMESHAPE_TRIANGLE "triangle"
#define FLAMESHAPE_LINE "line"
+#define FLAMESHAPE_SQUARE "square"
#define FLAME_REAGENT_USE_AMOUNT 1
diff --git a/code/game/objects/items/explosives/mine.dm b/code/game/objects/items/explosives/mine.dm
index bf718cadf122..12601ce28c0f 100644
--- a/code/game/objects/items/explosives/mine.dm
+++ b/code/game/objects/items/explosives/mine.dm
@@ -397,19 +397,24 @@
layer = ABOVE_OBJ_LAYER
shrapnel_spread = 360
health = 50
+ ignore_small_xeno = TRUE
+
var/disarmed = FALSE
- var/explosion_size = 100
+ var/explosion_strength = 100
var/explosion_falloff = 50
var/mine_level = 1
var/deploy_time = 0
var/mine_state = ""
- var/timer_id
+ var/mine_safety = FALSE
+ var/setup_timer // initialized in sharp.dm drop_dart
+ var/upgrade_timer // used here
+ var/disarm_timer // initialized in sharp.dm drop_dart
/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)
+ upgrade_timer = 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
@@ -417,19 +422,40 @@
/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
+ if(!disarmed)
+ 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, 3 SECONDS, 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()
+ else
+ if(HAS_TRAIT(W, TRAIT_TOOL_MULTITOOL))
+ 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 rearm \the [src]..."))
+ return
+ var/turf = get_turf(src)
+ for(var/obj/item/explosive/mine/existing_mine in turf)
+ if(existing_mine != src)
+ to_chat(user, SPAN_WARNING("There is already a mine deployed here!"))
+ return
+ user.visible_message(SPAN_NOTICE("[user] starts rearming [src]."), \
+ SPAN_NOTICE("You start rearming [src]."))
+ if(!do_after(user, 1 SECONDS, INTERRUPT_NO_NEEDHAND, BUSY_ICON_FRIENDLY))
+ user.visible_message(SPAN_WARNING("[user] stops rearming [src]."), \
+ SPAN_WARNING("You stop rearming [src]."))
+ return
+ if(active)//someone beat us to it
+ return
+ user.visible_message(SPAN_NOTICE("[user] finishes rearming [src]."), \
+ SPAN_NOTICE("You finish rearming [src]."))
+ rearm(user)
/obj/item/explosive/mine/sharp/set_tripwire()
if(!active && !tripwire)
@@ -441,22 +467,33 @@
/obj/item/explosive/mine/sharp/prime(mob/user)
set waitfor = FALSE
+ if (disarmed)
+ qdel(src)
+ return
if(!cause_data)
cause_data = create_cause_data(initial(name), user, src)
else if(user)
cause_data.weak_mob = WEAKREF(user)
+
if(mine_level == 1)
- explosion_size = 100
+ explosion_strength = 100
+ explosion_falloff = 50
else if(mine_level == 2)
- explosion_size = 100
+ explosion_strength = 100
explosion_falloff = 25
else if(mine_level == 3)
- explosion_size = 125
+ explosion_strength = 125
explosion_falloff = 30
else
- explosion_size = 125
+ explosion_strength = 125
explosion_falloff = 25
- cell_explosion(loc, explosion_size, explosion_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, CARDINAL_ALL_DIRS, cause_data, enviro=map_deployed)
+
+ if (mine_safety)
+ for(var/mob/living/carbon/human in range((explosion_strength / explosion_falloff) - 1, src))
+ if (human.get_target_lock(iff_signal))
+ disarm()
+ return
+ cell_explosion(loc, explosion_strength, explosion_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, CARDINAL_ALL_DIRS, cause_data, enviro=map_deployed)
playsound(loc, 'sound/weapons/gun_sharp_explode.ogg', 100)
qdel(src)
@@ -465,12 +502,19 @@
active = FALSE
triggered = FALSE
icon_state = "sharp_mine_disarmed"
- desc = "A disarmed P9 SHARP rifle dart, useless now."
+ desc = "A disarmed P9 SHARP rifle dart. With the right training, it can potentially be rearmed with a security access tuner."
QDEL_NULL(tripwire)
disarmed = TRUE
- deltimer(timer_id)
- add_to_garbage(src)
+ deltimer(upgrade_timer)
+ deltimer(disarm_timer)
+ playsound(src, 'sound/weapons/smartgun_fail.ogg', src, 25)
+/obj/item/explosive/mine/sharp/proc/rearm(mob/user)
+ disarmed = FALSE
+ mine_level = 1
+ 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."
+ deploy_mine(user)
+ disarm_timer = addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, disarm)), 5 MINUTES, TIMER_DELETE_ME | TIMER_STOPPABLE)
/obj/item/explosive/mine/sharp/attack_self(mob/living/user)
if(disarmed)
@@ -482,18 +526,17 @@
return
if(!hard_iff_lock && user)
iff_signal = user.faction
+ if(user && src.loc == user)
+ user.drop_inv_item_on_ground(src)
cause_data = create_cause_data(initial(name), user, src)
- 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)
+ upgrade_timer = addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, upgrade_mine)), 30 SECONDS, TIMER_DELETE_ME | TIMER_STOPPABLE)
+ anchored = TRUE
/obj/item/explosive/mine/sharp/attack_alien()
if(disarmed)
@@ -518,33 +561,67 @@
if(health <= 0)
prime()
+/obj/item/explosive/mine/sharp/get_examine_text(mob/user)
+ . = ..()
+ var/extended_description = ""
+ if(!ishuman(user))
+ return
+ if(skillcheck(user, SKILL_SPEC_WEAPONS, SKILL_SPEC_GRENADIER))
+ extended_description = mine_safety ? "SAFE" : "DANGER"
+ . += SPAN_INFO("Your training allows you to discern what mode this mine was fired in: it appears to be set to [extended_description] mode.")
+ if(disarmed)
+ . += SPAN_INFO("The dart's internal timer has already expired, but you are trained in resetting the clock with a multitool.")
+ else if(deploy_time)
+ var/remaining_ds = max(0, (deploy_time + 5 MINUTES) - world.time)
+ var/remaining_mins = round(remaining_ds / 600, 1)
+ . += SPAN_INFO("Your training allows you to determine how much time is approximately left on the mine: ~[remaining_mins] [remaining_mins == 1 ? "minute" : "minutes"] remaining before auto-disarm.")
+
/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"
+ var/incendiary_radius
+ var/is_smoke
+ var/datum/incendiary_reagent
/obj/item/explosive/mine/sharp/incendiary/prime(mob/user)
set waitfor = FALSE
+ if (disarmed)
+ qdel(src)
+ return
if(!cause_data)
cause_data = create_cause_data(initial(name), user, src)
else if(user)
cause_data.weak_mob = WEAKREF(user)
+
if(mine_level == 1)
+ incendiary_radius = 2
+ is_smoke = TRUE
+ else if(mine_level == 2)
+ incendiary_radius = 2
+ is_smoke = FALSE
+ incendiary_reagent = new /datum/reagent/napalm/green()
+ else if(mine_level == 3)
+ incendiary_radius = 2
+ is_smoke = FALSE
+ incendiary_reagent = new /datum/reagent/napalm/ut()
+ else
+ incendiary_radius = 3
+ is_smoke = FALSE
+ incendiary_reagent = new /datum/reagent/napalm/ut()
+
+ if (mine_safety)
+ for(var/mob/living/carbon/human in range(is_smoke ? incendiary_radius : incendiary_radius - 1, src))
+ if (human.get_target_lock(iff_signal))
+ disarm()
+ return
+
+ if(is_smoke)
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.set_up(incendiary_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)
+ new /obj/flamer_fire(loc, cause_data, incendiary_reagent, incendiary_radius, null, FLAMESHAPE_SQUARE)
playsound(loc, 'sound/weapons/gun_flamethrower3.ogg', 45)
+
qdel(src)
diff --git a/code/modules/cm_marines/equipment/kit_boxes.dm b/code/modules/cm_marines/equipment/kit_boxes.dm
index 5093c68a490f..1d3e7b320da6 100644
--- a/code/modules/cm_marines/equipment/kit_boxes.dm
+++ b/code/modules/cm_marines/equipment/kit_boxes.dm
@@ -225,6 +225,7 @@
new /obj/item/ammo_magazine/pistol/vp78(src)
new /obj/item/ammo_magazine/pistol/vp78(src)
new /obj/item/device/binoculars(src)
+ new /obj/item/device/multitool(src)
//maybe put in req for later use?
diff --git a/code/modules/projectiles/guns/flamer/flameshape.dm b/code/modules/projectiles/guns/flamer/flameshape.dm
index fffcf1a53ee3..d11504e3a56c 100644
--- a/code/modules/projectiles/guns/flamer/flameshape.dm
+++ b/code/modules/projectiles/guns/flamer/flameshape.dm
@@ -257,6 +257,38 @@
if(F.to_call)
F.to_call.Invoke()
+/datum/flameshape/square
+ name = "Square"
+ id = FLAMESHAPE_SQUARE
+
+/datum/flameshape/square/handle_fire_spread(obj/flamer_fire/F, fire_spread_amount, burn_dam, fuel_pressure = 1)
+ var/turf/source_turf = get_turf(F.loc)
+ var/radius = fire_spread_amount - 1
+
+ for(var/turf/T in range(radius, source_turf))
+ if(T == source_turf)
+ continue
+ if(istype(T, /turf/open/space))
+ continue
+
+ var/obj/flamer_fire/foundflame = locate() in T
+ if(foundflame && foundflame.tied_reagent == F.tied_reagent)
+ continue
+
+ if(T.density)
+ T.flamer_fire_act(burn_dam, F.weapon_cause_data)
+ continue
+
+ var/obj/flamer_fire/temp = new()
+ var/atom/A = LinkBlocked(temp, source_turf, T)
+
+ if(A)
+ A.flamer_fire_act(burn_dam, F.weapon_cause_data)
+ if(A.flags_atom & ON_BORDER)
+ continue
+
+ var/ring = get_dist(source_turf, T)
+ addtimer(CALLBACK(src, PROC_REF(generate_fire), T, F, 0, FLAMESHAPE_SQUARE, null, FALSE, fuel_pressure), ring)
GLOBAL_LIST_INIT(flameshapes, list(
FLAMESHAPE_DEFAULT = new /datum/flameshape/default(),
@@ -265,4 +297,5 @@ GLOBAL_LIST_INIT(flameshapes, list(
FLAMESHAPE_MINORSTAR = new /datum/flameshape/star/minor(),
FLAMESHAPE_TRIANGLE = new /datum/flameshape/triangle(),
FLAMESHAPE_LINE = new /datum/flameshape/line(),
+ FLAMESHAPE_SQUARE = new /datum/flameshape/square()
))
diff --git a/code/modules/projectiles/guns/specialist/sharp.dm b/code/modules/projectiles/guns/specialist/sharp.dm
index 270674e4b597..3491b08b6d4d 100644
--- a/code/modules/projectiles/guns/specialist/sharp.dm
+++ b/code/modules/projectiles/guns/specialist/sharp.dm
@@ -20,20 +20,21 @@
aim_slowdown = SLOWDOWN_ADS_SPECIALIST
wield_delay = WEAPON_DELAY_VERY_SLOW
- flags_gun_features = GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER
+ flags_gun_features = GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_AUTO_EJECTOR
flags_item = TWOHANDED|NO_CRYO_STORE
map_specific_decoration = TRUE
- var/explosion_delay_sharp = TRUE
+ var/current_mine_safety = TRUE
/obj/item/weapon/gun/rifle/sharp/Initialize()
- . = ..()
AddElement(/datum/element/corp_label/armat)
+ LAZYADD(actions_types, list(/datum/action/item_action/specialist/sharp_firemode_ability))
+ return ..()
/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.")
+ . += SPAN_INFO("Switching firemodes will toggle SAFE mode operation, with much greater IFF-logic of fired mines when activated.")
/obj/item/weapon/gun/rifle/sharp/set_bullet_traits()
LAZYADD(traits_to_give, list(
@@ -52,7 +53,6 @@
damage_mult = BASE_BULLET_DAMAGE_MULT
recoil = RECOIL_OFF
-
/obj/item/weapon/gun/rifle/sharp/unload_chamber(mob/user)
if(!in_chamber)
return
@@ -74,14 +74,58 @@
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
+//code for changing mine modes
+
+/datum/action/item_action/specialist/sharp_firemode_ability
+ ability_primacy = SPEC_PRIMARY_ACTION_1
+
+/datum/action/item_action/specialist/sharp_firemode_ability/New(mob/living/user, obj/item/holder)
+ . = ..()
+ name = "Toggle SHARP Firemode"
+ button.name = name
+ update_button_icon()
+ update_ability_icon()
+
+/datum/action/item_action/specialist/sharp_firemode_ability/proc/update_ability_icon()
+ var/obj/item/weapon/gun/rifle/sharp/sharp_rifle = holder_item
+ var/icon = 'icons/mob/hud/actions.dmi'
+ var/icon_state
+ if(sharp_rifle.current_mine_safety)
+ icon_state = "sharp_safe"
+ else
+ icon_state = "sharp_danger"
+ button.overlays.Cut()
+ var/image/IMG = image(icon, button, icon_state)
+ button.overlays += IMG
+
+/datum/action/item_action/specialist/sharp_firemode_ability/can_use_action()
+ if(owner.is_mob_incapacitated())
+ return FALSE
+ return TRUE
+
+/datum/action/item_action/specialist/sharp_firemode_ability/action_activate()
+ . = ..()
+ var/obj/item/weapon/gun/rifle/sharp/sharp_rifle = holder_item
+ if(!ishuman(owner))
+ return
+ sharp_rifle.do_toggle_firemode(owner)
/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, "explosion delay [explosion_delay_sharp ? "5 seconds" : "2.5 seconds"].")
+ var/mine_mode_notice = ""
+ if(current_mine_safety)
+ current_mine_safety = FALSE
+ mine_mode_notice += "[icon2html(src, user)] You set [src]'s mine mode to DANGER mode. Explosive ammo will blow up regardless of friendly presence."
+ user.balloon_alert(user, "activated DANGER mode")
+ else
+ current_mine_safety = TRUE
+ mine_mode_notice += "[icon2html(src, user)] You set [src]'s mine mode to SAFE mode. Explosive ammo will NEVER blow up near detected friendly targets."
+ user.balloon_alert(user, "activated SAFE mode")
+ to_chat(user, SPAN_NOTICE(mine_mode_notice))
+
+ var/datum/action/item_action/specialist/sharp_firemode_ability/SFA = locate(/datum/action/item_action/specialist/sharp_firemode_ability) in actions
+ SFA.update_ability_icon()
@@ -108,6 +152,7 @@
shell_speed = AMMO_SPEED_TIER_2
var/embed_object = /obj/item/sharp/explosive
var/mine_level = 0
+ var/mine_safety = FALSE
/datum/ammo/rifle/sharp/on_embed(mob/embedded_mob, obj/limb/target_organ)
if(!ishuman(embedded_mob))
@@ -138,36 +183,46 @@
return
var/mob/shooter = shot_dart.firer
+ var/obj/item/weapon/gun/rifle/sharp/weapon = shot_dart.shot_from
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
+ if(weapon)
+ mine_safety = weapon.current_mine_safety
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)
+ var/obj/item/explosive/mine/sharp/mine = new /obj/item/explosive/mine/sharp(loc)
+ var/obj/item/weapon/gun/rifle/sharp/weapon = shot_dart.shot_from
+ if(weapon)
+ mine.mine_safety = weapon.current_mine_safety
// 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)
+ INVOKE_ASYNC(mine, 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)
+ mine.anchored = TRUE
+ mine.setup_timer = addtimer(CALLBACK(mine, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, deploy_mine), shooter, weapon), 3 SECONDS, TIMER_DELETE_ME | TIMER_STOPPABLE)
+ mine.disarm_timer = addtimer(CALLBACK(mine, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, disarm)), 5 MINUTES, TIMER_DELETE_ME | TIMER_STOPPABLE)
/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/explosion_strength = 60
+ var/explosion_falloff = 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)
+ if (mine_safety)
+ for(var/mob/living/carbon/human in range((explosion_strength / explosion_falloff) - 1, target))
+ if (human.get_target_lock(shooter.faction_group))
+ playsound(target, 'sound/weapons/smartgun_fail.ogg', target, 25)
+ to_chat(target, SPAN_WARNING("[shot_dart] releases itself from you!"))
+ target.balloon_alert(target, "an attached explosive dart releases itself from you!")
+ to_chat(shooter, SPAN_WARNING("[shot_dart] recognized an IFF marked target and did not detonate!"))
+ return
+ cell_explosion(get_turf(target), explosion_strength, explosion_falloff, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data)
/datum/ammo/rifle/sharp/incendiary
@@ -180,34 +235,44 @@
if(!target || target == shot_dart.firer)
return
var/mob/shooter = shot_dart.firer
+ var/obj/item/weapon/gun/rifle/sharp/weapon = shot_dart.shot_from
shake_camera(target, 2, 1)
if(shooter && ismob(shooter))
- target.balloon_alert(target, "you have been hit by an incendiary dart!", text_color = "#ce1e1e")
+ target.balloon_alert(target, "you have been hit by an incendiary dart!", text_color = "#ce7c1e")
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
+ if(weapon)
+ mine_safety = weapon.current_mine_safety
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)
+ var/obj/item/explosive/mine/sharp/incendiary/mine = new /obj/item/explosive/mine/sharp/incendiary(loc)
+ var/obj/item/weapon/gun/rifle/sharp/weapon = shot_dart.shot_from
+ if(weapon)
+ mine.mine_safety = weapon.current_mine_safety
// 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)
+ INVOKE_ASYNC(mine, 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)
+ mine.anchored = TRUE
+ mine.setup_timer = addtimer(CALLBACK(mine, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, deploy_mine), shooter, weapon), 3 SECONDS, TIMER_DELETE_ME | TIMER_STOPPABLE)
+ mine.disarm_timer = addtimer(CALLBACK(mine, TYPE_PROC_REF(/obj/item/explosive/mine/sharp, disarm)), 5 MINUTES, TIMER_DELETE_ME | TIMER_STOPPABLE)
/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
+ if(mine_safety)
+ for(var/mob/living/carbon/human in range(smoke_radius, target))
+ if (human.get_target_lock(shooter.faction_group))
+ playsound(target, 'sound/weapons/smartgun_fail.ogg', target, 25)
+ to_chat(target, SPAN_WARNING("[shot_dart] releases itself from you!"))
+ target.balloon_alert(target, "an attached incendiary dart releases itself from you!")
+ to_chat(shooter, SPAN_WARNING("[shot_dart] recognized an IFF marked target and did not detonate!"))
+ return
smoke.set_up(smoke_radius, 0, get_turf(target))
smoke.start()
diff --git a/code/modules/projectiles/magazines/rifles.dm b/code/modules/projectiles/magazines/rifles.dm
index 0a03c799f7f8..9a61d79173d4 100644
--- a/code/modules/projectiles/magazines/rifles.dm
+++ b/code/modules/projectiles/magazines/rifles.dm
@@ -734,17 +734,17 @@
/obj/item/ammo_magazine/rifle/sharp/explosive
name = "\improper 9X-E sticky explosive dart magazine"
- desc = "A specialized explosive sticky dart magazine for the SHARP rifle."
+ desc = "A specialized explosive dart magazine for the P9 SHARP rifle. Darts either embed into targets and detonate after a short delay, or stay behind as proximity-triggered explosive mines."
/obj/item/ammo_magazine/rifle/sharp/incendiary
name = "\improper 9X-T sticky incendiary dart magazine"
- desc = "A specialized incendiary dart magazine for the SHARP rifle."
+ desc = "A specialized incendiary dart magazine for the P9 SHARP rifle. Darts either embed into targets and release an incendiary concoction after a short delay, or stay behind as proximity-triggered incendiary mines."
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 for the SHARP rifle."
+ desc = "A specialized flechette dart magazine for the P9 SHARP rifle. Unlike their explosive and incendiary counterparts, the darts detonate on contact without delay, dispersing a concentrated cone of metal shards that shred anything in their path."
icon_state = "sharp_flechette_mag"
default_ammo = /datum/ammo/rifle/sharp/flechette
diff --git a/icons/mob/hud/actions.dmi b/icons/mob/hud/actions.dmi
index 4a754815243b..ad963d0a951c 100644
Binary files a/icons/mob/hud/actions.dmi and b/icons/mob/hud/actions.dmi differ