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