diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index ee4219635db..00867c4ac0e 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -543,3 +543,40 @@ icon_state = "light_ash" icon = 'icons/effects/weather_effects.dmi' duration = 3.2 SECONDS + +/obj/effect/temp_visual/sonar_ping + duration = 3 SECONDS + resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF + anchored = TRUE + randomdir = FALSE + /// The image shown to modsuit users + var/image/modsuit_image + /// The person in the modsuit at the moment, really just used to remove this from their screen + var/datum/weakref/mod_man + /// The icon state applied to the image created for this ping. + var/real_icon_state = "sonar_ping" + +/obj/effect/temp_visual/sonar_ping/Initialize(mapload, mob/living/looker, mob/living/creature) + . = ..() + if(!looker || !creature) + return INITIALIZE_HINT_QDEL + modsuit_image = image(icon = icon, loc = looker.loc, icon_state = real_icon_state, layer = ABOVE_ALL_MOB_LAYER, pixel_x = ((creature.x - looker.x) * 32), pixel_y = ((creature.y - looker.y) * 32)) + modsuit_image.plane = ABOVE_LIGHTING_PLANE + mod_man = WEAKREF(looker) + add_mind(looker) + +/obj/effect/temp_visual/sonar_ping/Destroy() + var/mob/living/previous_user = mod_man?.resolve() + if(previous_user) + remove_mind(previous_user) + // Null so we don't shit the bed when we delete + modsuit_image = null + return ..() + +/// Add the image to the modsuit wearer's screen +/obj/effect/temp_visual/sonar_ping/proc/add_mind(mob/living/looker) + looker?.client?.images |= modsuit_image + +/// Remove the image from the modsuit wearer's screen +/obj/effect/temp_visual/sonar_ping/proc/remove_mind(mob/living/looker) + looker?.client?.images -= modsuit_image diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index f27fbb872d9..4f987c1b18d 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -337,3 +337,32 @@ projectile.damage /= damage_multiplier projectile.speed /= speed_multiplier projectile.cut_overlay(projectile_effect) + +///Active Sonar - Displays a hud circle on the turf of any living creatures in the given radius +/obj/item/mod/module/active_sonar + name = "MOD active sonar" + desc = "Ancient tech from the 20th century, this module uses sonic waves to detect living creatures within the user's radius. \ + Its loud ping is much harder to hide in an indoor station than in the outdoor operations it was designed for." + icon_state = "active_sonar" + module_type = MODULE_USABLE + use_power_cost = DEFAULT_CHARGE_DRAIN * 5 + complexity = 3 + incompatible_modules = list(/obj/item/mod/module/active_sonar) + cooldown_time = 25 SECONDS + +/obj/item/mod/module/active_sonar/on_use() + . = ..() + if(!.) + return + balloon_alert(mod.wearer, "readying sonar...") + playsound(mod.wearer, 'sound/mecha/skyfall_power_up.ogg', vol = 20, vary = TRUE, extrarange = SHORT_RANGE_SOUND_EXTRARANGE) + if(!do_after(mod.wearer, 1.1 SECONDS)) + return + var/creatures_detected = 0 + for(var/mob/living/creature in range(9, mod.wearer)) + if(creature == mod.wearer || creature.stat == DEAD) + continue + new /obj/effect/temp_visual/sonar_ping(mod.wearer.loc, mod.wearer, creature) + creatures_detected++ + playsound(mod.wearer, 'sound/effects/ping_hit.ogg', vol = 75, vary = TRUE, extrarange = MEDIUM_RANGE_SOUND_EXTRARANGE) // Should be audible for the radius of the sonar + to_chat(mod.wearer, span_notice("You slam your fist into the ground, sending out a sonic wave that detects [creatures_detected] living beings nearby!")) diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 095fbf10796..dd90c20c2eb 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -1389,6 +1389,13 @@ build_path = /obj/item/mod/module/anomaly_locked/kinesis department_type = MODULE_ENGINEERING +/datum/design/module/mod_sonar + name = "MOD Module: Active Sonar" + id = "mod_sonar" + materials = list(/datum/material/titanium = 250, /datum/material/glass = 1000, /datum/material/gold = 500, /datum/material/uranium = 250) + build_path = /obj/item/mod/module/active_sonar + department_type = MODULE_SECURITY + /datum/design/module/projectile_dampener name = "MOD Module: Projectile Dampener" id = "mod_projectile_dampener" diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index ff3f301a80f..e65db0e55ff 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -899,7 +899,7 @@ "paladin_module", "robocop_module", "corporate_module", - "drone_module", + "drone_module", "oxygen_module", "safeguard_module", "protectstation_module", @@ -908,7 +908,7 @@ "remove_module", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) - + /datum/techweb_node/ai_adv id = "ai_adv" display_name = "Advanced Artificial Intelligence" @@ -1566,7 +1566,8 @@ "mod_mag_harness", "mod_pathfinder", "mod_holster", - "mod_projectile_dampener" + "mod_sonar", + "mod_projectile_dampener", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index f8e1c9f6929..8beb91e6b3a 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/obj/clothing/modsuit/mod_modules.dmi b/icons/obj/clothing/modsuit/mod_modules.dmi index 0e0121b33d9..69affa3fa49 100644 Binary files a/icons/obj/clothing/modsuit/mod_modules.dmi and b/icons/obj/clothing/modsuit/mod_modules.dmi differ diff --git a/sound/effects/ping_hit.ogg b/sound/effects/ping_hit.ogg new file mode 100644 index 00000000000..729bd7efa88 Binary files /dev/null and b/sound/effects/ping_hit.ogg differ