diff --git a/code/datums/components/deployable.dm b/code/datums/components/deployable.dm new file mode 100644 index 00000000000..f652c25de74 --- /dev/null +++ b/code/datums/components/deployable.dm @@ -0,0 +1,74 @@ +/** + * Deployable - Bring your big guns with you, and smack em' down where you want. + * + * Allows items to spawn other items (usually objects) in front of the user after a short delay. + * If attaching this to something: + * Set deploy_time to a number in seconds for the deploy delay + * Set thing_to_be_deployed to an obj path for the thing that gets spawned + * Lastly, set delete_on_use to TRUE or FALSE if you want the object you're deploying with to get deleted when used + */ + +/datum/component/deployable + /// The time it takes to deploy the object + var/deploy_time = 5 SECONDS + /// The object that gets spawned if deployed successfully + var/obj/thing_to_be_deployed + /// Used in getting the name of the deployed object + var/deployed_name + /// If the item used to deploy gets deleted on use or not + var/delete_on_use = TRUE + +/datum/component/deployable/Initialize(deploy_time, thing_to_be_deployed, delete_on_use) + . = ..() + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + src.deploy_time = deploy_time + src.thing_to_be_deployed = thing_to_be_deployed + src.delete_on_use = delete_on_use + + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine) + RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/on_attack_hand) + + var/obj/item/typecast = thing_to_be_deployed + deployed_name = initial(typecast.name) + +/datum/component/deployable/proc/examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + examine_list += span_notice("[source.p_they()] look[source.p_s()] like [source.p_they()] can be deployed into \a [deployed_name].") + +/datum/component/deployable/proc/on_attack_hand(datum/source, mob/user, location, direction) + SIGNAL_HANDLER + INVOKE_ASYNC(src, .proc/deploy, source, user, location, direction) + +/datum/component/deployable/proc/deploy(obj/source, mob/user, location, direction) //If there's no user, location and direction are used + var/obj/deployed_object //Used for spawning the deployed object + var/turf/deploy_location //Where our deployed_object gets put + var/new_direction //What direction do we want our deployed object in + if(user) + if(!ishuman(user)) + return + + deploy_location = get_step(user, user.dir) //Gets spawn location for thing_to_be_deployed if there is a user + if(deploy_location.is_blocked_turf(TRUE)) + source.balloon_alert(user, "insufficient room to deploy here.") + return + new_direction = user.dir //Gets the direction for thing_to_be_deployed if there is a user + source.balloon_alert(user, "deploying...") + playsound(source, 'sound/items/ratchet.ogg', 50, TRUE) + if(!do_after(user, deploy_time)) + return + else //If there is for some reason no user, then the location and direction are set here + deploy_location = location + new_direction = direction + + deployed_object = new thing_to_be_deployed(deploy_location) + deployed_object.setDir(new_direction) + + //Sets the integrity of the new deployed machine to that of the object it came from + deployed_object.modify_max_integrity(source.max_integrity) + deployed_object.update_icon_state() + + if(delete_on_use) + qdel(source) diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 8c2897a7fd3..70f9c3e9eb5 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -196,6 +196,18 @@ /obj/item/grenade/barrier/ui_action_click(mob/user) toggle_mode(user) +/obj/item/deployable_turret_folded + name = "folded heavy machine gun" + desc = "A folded and unloaded heavy machine gun, ready to be deployed and used." + icon = 'icons/obj/turrets.dmi' + icon_state = "folded_hmg" + max_integrity = 250 + w_class = WEIGHT_CLASS_BULKY + slot_flags = ITEM_SLOT_BACK + +/obj/item/deployable_turret_folded/Initialize() + . = ..() + AddComponent(/datum/component/deployable, 5 SECONDS, /obj/machinery/deployable_turret/hmg, delete_on_use = TRUE) #undef SINGLE #undef VERTICAL diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index 0b3bcba1a24..a0a0e16199f 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -109,6 +109,15 @@ new /obj/item/extinguisher/mini(src) new /obj/item/stack/cable_coil(src) +/obj/item/storage/belt/utility/full/powertools/rcd/PopulateContents() + new /obj/item/screwdriver/power(src) + new /obj/item/crowbar/power(src) + new /obj/item/weldingtool/experimental(src) + new /obj/item/multitool(src) + new /obj/item/construction/rcd/loaded/upgraded(src) + new /obj/item/extinguisher/mini(src) + new /obj/item/stack/cable_coil(src) + /obj/item/storage/belt/utility/full/engi/PopulateContents() new /obj/item/screwdriver(src) new /obj/item/wrench(src) diff --git a/code/game/objects/structures/manned_turret.dm b/code/game/objects/structures/deployable_turret.dm similarity index 55% rename from code/game/objects/structures/manned_turret.dm rename to code/game/objects/structures/deployable_turret.dm index 00db0bf6867..72a35b7e9e6 100644 --- a/code/game/objects/structures/manned_turret.dm +++ b/code/game/objects/structures/deployable_turret.dm @@ -1,6 +1,7 @@ -/////// MANNED TURRET //////// +/// DEPLOYABLE TURRET (FORMERLY MANNED TURRET) +//All of this file is five year old shitcode, and I'm too scared to touch more than I have to -/obj/machinery/manned_turret +/obj/machinery/deployable_turret name = "machine gun turret" desc = "While the trigger is held down, this gun will redistribute recoil to allow its user to easily shift targets." icon = 'icons/obj/turrets.dmi' @@ -13,23 +14,53 @@ layer = ABOVE_MOB_LAYER var/view_range = 2.5 var/cooldown = 0 + /// The projectile that the turret fires var/projectile_type = /obj/projectile/bullet/manned_turret + /// Delay between shots in a burst var/rate_of_fire = 1 + /// Number of shots fired from one click var/number_of_shots = 40 - var/cooldown_duration = 90 + /// How long it takes for the gun to allow firing after a burst + var/cooldown_duration = 9 SECONDS var/atom/target var/turf/target_turf var/warned = FALSE var/list/calculated_projectile_vars + /// Sound to play at the end of a burst + var/overheatsound = 'sound/weapons/sear.ogg' + /// Sound to play when firing + var/firesound = 'sound/weapons/gun/smg/shot.ogg' + /// If using a wrench on the turret will start undeploying it + var/can_be_undeployed = FALSE + /// What gets spawned if the object is undeployed + var/obj/spawned_on_undeploy + /// How long it takes for a wrench user to undeploy the object + var/undeploy_time = 3 SECONDS -/obj/machinery/manned_turret/Destroy() +/obj/machinery/deployable_turret/Destroy() target = null target_turf = null ..() +/// Undeploying, for when you want to move your big dakka around +/obj/machinery/deployable_turret/wrench_act(mob/living/user, obj/item/wrench/used_wrench) + . = ..() + if(!can_be_undeployed) + return + if(!ishuman(user)) + return + used_wrench.play_tool_sound(user) + user.balloon_alert(user, "undeploying...") + if(!do_after(user, undeploy_time)) + return + var/obj/undeployed_object = new spawned_on_undeploy(src) + //Keeps the health the same even if you redeploy the gun + undeployed_object.modify_max_integrity(max_integrity) + qdel(src) + //BUCKLE HOOKS -/obj/machinery/manned_turret/unbuckle_mob(mob/living/buckled_mob,force = FALSE) +/obj/machinery/deployable_turret/unbuckle_mob(mob/living/buckled_mob,force = FALSE) playsound(src,'sound/mecha/mechmove01.ogg', 50, TRUE) for(var/obj/item/I in buckled_mob.held_items) if(istype(I, /obj/item/gun_control)) @@ -43,7 +74,7 @@ . = ..() STOP_PROCESSING(SSfastprocess, src) -/obj/machinery/manned_turret/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) +/obj/machinery/deployable_turret/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE) if(user.incapacitated() || !istype(user)) return M.forceMove(get_turf(src)) @@ -68,25 +99,26 @@ M.client.view_size.setTo(view_range) START_PROCESSING(SSfastprocess, src) -/obj/machinery/manned_turret/process() +/obj/machinery/deployable_turret/process() if (!update_positioning()) return PROCESS_KILL -/obj/machinery/manned_turret/proc/update_positioning() +/obj/machinery/deployable_turret/proc/update_positioning() if (!LAZYLEN(buckled_mobs)) return FALSE var/mob/living/controller = buckled_mobs[1] if(!istype(controller)) return FALSE - var/client/C = controller.client - if(C) - var/atom/A = C.mouseObject - var/turf/T = get_turf(A) - if(istype(T)) //They're hovering over something in the map. - direction_track(controller, T) - calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(controller, C.mouseParams) + var/client/controlling_client = controller.client + if(controlling_client) + var/modifiers = params2list(controlling_client.mouseParams) + var/atom/target_atom = controlling_client.mouseObject + var/turf/target_turf = get_turf(target_atom) + if(istype(target_turf)) //They're hovering over something in the map. + direction_track(controller, target_turf) + calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(controller, modifiers) -/obj/machinery/manned_turret/proc/direction_track(mob/user, atom/targeted) +/obj/machinery/deployable_turret/proc/direction_track(mob/user, atom/targeted) if(user.incapacitated()) return setDir(get_dir(src,targeted)) @@ -125,56 +157,63 @@ user.pixel_x = 8 user.pixel_y = -4 -/obj/machinery/manned_turret/proc/checkfire(atom/targeted_atom, mob/user) +/obj/machinery/deployable_turret/proc/checkfire(atom/targeted_atom, mob/user) target = targeted_atom if(target == user || user.incapacitated() || target == get_turf(src)) return if(world.time < cooldown) if(!warned && world.time > (cooldown - cooldown_duration + rate_of_fire*number_of_shots)) // To capture the window where one is done firing warned = TRUE - playsound(src, 'sound/weapons/sear.ogg', 100, TRUE) + playsound(src, overheatsound, 100, TRUE) return else cooldown = world.time + cooldown_duration warned = FALSE volley(user) -/obj/machinery/manned_turret/proc/volley(mob/user) +/obj/machinery/deployable_turret/proc/volley(mob/user) target_turf = get_turf(target) for(var/i in 1 to number_of_shots) - addtimer(CALLBACK(src, /obj/machinery/manned_turret/.proc/fire_helper, user), i*rate_of_fire) + addtimer(CALLBACK(src, /obj/machinery/deployable_turret/.proc/fire_helper, user), i*rate_of_fire) -/obj/machinery/manned_turret/proc/fire_helper(mob/user) +/obj/machinery/deployable_turret/proc/fire_helper(mob/user) if(user.incapacitated() || !(user in buckled_mobs)) return update_positioning() //REFRESH MOUSE TRACKING!! var/turf/targets_from = get_turf(src) if(QDELETED(target)) target = target_turf - var/obj/projectile/P = new projectile_type(targets_from) - P.starting = targets_from - P.firer = user - P.original = target - playsound(src, 'sound/weapons/gun/smg/shot.ogg', 75, TRUE) - P.xo = target.x - targets_from.x - P.yo = target.y - targets_from.y - P.Angle = calculated_projectile_vars[1] + rand(-9, 9) - P.p_x = calculated_projectile_vars[2] - P.p_y = calculated_projectile_vars[3] - P.fire() + var/obj/projectile/projectile_to_fire = new projectile_type + playsound(src, firesound, 75, TRUE) + projectile_to_fire.preparePixelProjectile(target, targets_from) + projectile_to_fire.fire() -/obj/machinery/manned_turret/ultimate // Admin-only proof of concept for autoclicker automatics +/obj/machinery/deployable_turret/ultimate // Admin-only proof of concept for autoclicker automatics name = "Infinity Gun" view_range = 12 - projectile_type = /obj/projectile/bullet/manned_turret -/obj/machinery/manned_turret/ultimate/checkfire(atom/targeted_atom, mob/user) +/obj/machinery/deployable_turret/ultimate/checkfire(atom/targeted_atom, mob/user) target = targeted_atom if(target == user || target == get_turf(src)) return target_turf = get_turf(target) fire_helper(user) +/obj/machinery/deployable_turret/hmg + name = "heavy machine gun turret" + desc = "A heavy calibre machine gun commonly used by Nanotrasen forces, famed for it's ability to give people on the recieving end more holes than normal." + icon_state = "hmg" + max_integrity = 250 + projectile_type = /obj/projectile/bullet/manned_turret/hmg + anchored = TRUE + number_of_shots = 3 + cooldown_duration = 2 SECONDS + rate_of_fire = 2 + firesound = 'sound/weapons/gun/hmg/hmg.ogg' + overheatsound = 'sound/weapons/gun/smg/smgrack.ogg' + can_be_undeployed = TRUE + spawned_on_undeploy = /obj/item/deployable_turret_folded + /obj/item/gun_control name = "turret controls" icon = 'icons/obj/items_and_weapons.dmi' @@ -182,7 +221,7 @@ w_class = WEIGHT_CLASS_HUGE item_flags = ABSTRACT | NOBLUDGEON | DROPDEL resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF - var/obj/machinery/manned_turret/turret + var/obj/machinery/deployable_turret/turret /obj/item/gun_control/Initialize() . = ..() @@ -210,7 +249,8 @@ /obj/item/gun_control/afterattack(atom/targeted_atom, mob/user, flag, params) . = ..() - var/obj/machinery/manned_turret/E = user.buckled - E.calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(user, params) + var/modifiers = params2list(params) + var/obj/machinery/deployable_turret/E = user.buckled + E.calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(user, modifiers) E.direction_track(user, targeted_atom) E.checkfire(targeted_atom, user) diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm index bbed5f60d04..3f99f89ffbc 100644 --- a/code/modules/clothing/outfits/ert.dm +++ b/code/modules/clothing/outfits/ert.dm @@ -619,16 +619,10 @@ suit_store = /obj/item/gun/ballistic/shotgun/lethal mask = /obj/item/clothing/mask/cigarette/robustgold head = /obj/item/clothing/head/helmet/marine/engineer - back = /obj/item/storage/backpack/ert/engineer - backpack_contents = list( - /obj/item/construction/rcd/loaded/upgraded = 1, - /obj/item/pipe_dispenser = 1, - /obj/item/storage/box/lethalshot = 1, - /obj/item/grenade/c4 = 3, -) + back = /obj/item/deployable_turret_folded uniform = /obj/item/clothing/under/syndicate/camo - belt = /obj/item/storage/belt/utility/full/powertools - glasses = /obj/item/clothing/glasses/welding + belt = /obj/item/storage/belt/utility/full/powertools/rcd + glasses = /obj/item/clothing/glasses/hud/diagnostic/sunglasses r_pocket = /obj/item/rcd_ammo/large /datum/outfit/centcom/ert/marine/engineer/post_equip(mob/living/carbon/human/equipper, visualsOnly = FALSE) diff --git a/code/modules/projectiles/projectile/bullets/lmg.dm b/code/modules/projectiles/projectile/bullets/lmg.dm index 4b0e2cdd862..f6081c7b070 100644 --- a/code/modules/projectiles/projectile/bullets/lmg.dm +++ b/code/modules/projectiles/projectile/bullets/lmg.dm @@ -18,6 +18,9 @@ /obj/projectile/bullet/manned_turret damage = 20 +/obj/projectile/bullet/manned_turret/hmg + icon_state = "redtrac" + /obj/projectile/bullet/syndicate_turret damage = 20 diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index 09b69094adf..7f643df4bd5 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index 6483e901698..ddcfd7d0780 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index b3d9ed37734..4ac249f2eb3 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/obj/guns/projectiles.dmi b/icons/obj/guns/projectiles.dmi index 28546c5576f..7a0509129cb 100644 Binary files a/icons/obj/guns/projectiles.dmi and b/icons/obj/guns/projectiles.dmi differ diff --git a/icons/obj/turrets.dmi b/icons/obj/turrets.dmi index 60f076be052..1153e70ea1e 100644 Binary files a/icons/obj/turrets.dmi and b/icons/obj/turrets.dmi differ diff --git a/sound/weapons/gun/hmg/hmg.ogg b/sound/weapons/gun/hmg/hmg.ogg new file mode 100644 index 00000000000..44886d59aba Binary files /dev/null and b/sound/weapons/gun/hmg/hmg.ogg differ diff --git a/tgstation.dme b/tgstation.dme index a967a008311..7c44020ed14 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -553,6 +553,7 @@ #include "code\datums\components\customizable_reagent_holder.dm" #include "code\datums\components\deadchat_control.dm" #include "code\datums\components\dejavu.dm" +#include "code\datums\components\deployable.dm" #include "code\datums\components\earprotection.dm" #include "code\datums\components\edit_complainer.dm" #include "code\datums\components\egg_layer.dm" @@ -1436,6 +1437,7 @@ #include "code\game\objects\structures\barsigns.dm" #include "code\game\objects\structures\bedsheet_bin.dm" #include "code\game\objects\structures\chess.dm" +#include "code\game\objects\structures\deployable_turret.dm" #include "code\game\objects\structures\destructible_structures.dm" #include "code\game\objects\structures\displaycase.dm" #include "code\game\objects\structures\divine.dm" @@ -1467,7 +1469,6 @@ #include "code\game\objects\structures\life_candle.dm" #include "code\game\objects\structures\loom.dm" #include "code\game\objects\structures\maintenance.dm" -#include "code\game\objects\structures\manned_turret.dm" #include "code\game\objects\structures\memorial.dm" #include "code\game\objects\structures\mineral_doors.dm" #include "code\game\objects\structures\mirror.dm"