From 6df27ef2a330ea843bfe24818505ea74754661b9 Mon Sep 17 00:00:00 2001 From: BurgerLua Date: Thu, 9 May 2019 15:25:48 -0700 Subject: [PATCH] Updated integrated circuits --- .../subtypes/manipulation.dm | 216 +---------- .../subtypes/reagents.dm | 11 +- .../subtypes/weaponized.dm | 344 ++++++++++++++++++ .../subtypes/manipulation.dm | 1 - tgstation.dme | 1 + 5 files changed, 359 insertions(+), 214 deletions(-) create mode 100644 code/modules/integrated_electronics/subtypes/weaponized.dm diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm index c187f49473..682e76a46e 100644 --- a/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -1,139 +1,6 @@ /obj/item/integrated_circuit/manipulation category_text = "Manipulation" -/obj/item/integrated_circuit/manipulation/weapon_firing - name = "weapon firing mechanism" - desc = "This somewhat complicated system allows one to slot in a gun, direct it towards a position, and remotely fire it." - extended_desc = "The firing mechanism can slot in any energy weapon. \ - The first and second inputs need to be numbers which correspond to coordinates for the gun to fire at relative to the machine itself. \ - The 'fire' activator will cause the mechanism to attempt to fire the weapon at the coordinates, if possible. Mode will switch between \ - lethal (TRUE) or stun (FALSE) modes. It uses the internal battery of the weapon itself, not the assembly. If you wish to fire the gun while the circuit is in \ - hand, you will need to use an assembly that is a gun." - complexity = 20 - w_class = WEIGHT_CLASS_SMALL - size = 3 - inputs = list( - "target X rel" = IC_PINTYPE_NUMBER, - "target Y rel" = IC_PINTYPE_NUMBER, - "mode" = IC_PINTYPE_BOOLEAN - ) - outputs = list("reference to gun" = IC_PINTYPE_REF) - activators = list( - "fire" = IC_PINTYPE_PULSE_IN - - ) - var/obj/item/gun/energy/installed_gun = null - spawn_flags = IC_SPAWN_RESEARCH - action_flags = IC_ACTION_COMBAT - power_draw_per_use = 0 - ext_cooldown = 1 - var/mode = FALSE - - var/stun_projectile = null //stun mode projectile type - var/stun_projectile_sound - var/lethal_projectile = null //lethal mode projectile type - var/lethal_projectile_sound - - demands_object_input = TRUE // You can put stuff in once the circuit is in assembly,passed down from additem and handled by attackby() - - - -/obj/item/integrated_circuit/manipulation/weapon_firing/Destroy() - qdel(installed_gun) - return ..() - -/obj/item/integrated_circuit/manipulation/weapon_firing/attackby(var/obj/O, var/mob/user) - if(istype(O, /obj/item/gun/energy)) - var/obj/item/gun/gun = O - if(installed_gun) - to_chat(user, "There's already a weapon installed.") - return - user.transferItemToLoc(gun,src) - installed_gun = gun - var/list/gun_properties = gun.get_turret_properties() - to_chat(user, "You slide \the [gun] into the firing mechanism.") - playsound(src, 'sound/items/Crowbar.ogg', 50, 1) - stun_projectile = gun_properties["stun_projectile"] - stun_projectile_sound = gun_properties["stun_projectile_sound"] - lethal_projectile = gun_properties["lethal_projectile"] - lethal_projectile_sound = gun_properties["lethal_projectile_sound"] - if(gun_properties["shot_delay"]) - cooldown_per_use = gun_properties["shot_delay"]*10 - if(cooldown_per_use<30) - cooldown_per_use = 30 - if(gun_properties["reqpower"]) - power_draw_per_use = gun_properties["reqpower"] - set_pin_data(IC_OUTPUT, 1, WEAKREF(installed_gun)) - push_data() - else - ..() - -/obj/item/integrated_circuit/manipulation/weapon_firing/attack_self(var/mob/user) - if(installed_gun) - installed_gun.forceMove(drop_location()) - to_chat(user, "You slide \the [installed_gun] out of the firing mechanism.") - size = initial(size) - playsound(src, 'sound/items/Crowbar.ogg', 50, 1) - installed_gun = null - set_pin_data(IC_OUTPUT, 1, WEAKREF(null)) - push_data() - else - to_chat(user, "There's no weapon to remove from the mechanism.") - -/obj/item/integrated_circuit/manipulation/weapon_firing/do_work() - if(!installed_gun || !installed_gun.handle_pins()) - return - if(!isturf(assembly.loc) && !(assembly.can_fire_equipped && ishuman(assembly.loc))) - return - set_pin_data(IC_OUTPUT, 1, WEAKREF(installed_gun)) - push_data() - var/datum/integrated_io/xo = inputs[1] - var/datum/integrated_io/yo = inputs[2] - var/datum/integrated_io/mode1 = inputs[3] - - mode = mode1.data - if(assembly) - if(isnum(xo.data)) - xo.data = round(xo.data, 1) - if(isnum(yo.data)) - yo.data = round(yo.data, 1) - - var/turf/T = get_turf(assembly) - var/target_x = CLAMP(T.x + xo.data, 0, world.maxx) - var/target_y = CLAMP(T.y + yo.data, 0, world.maxy) - - assembly.visible_message("[assembly] fires [installed_gun]!") - shootAt(locate(target_x, target_y, T.z)) - -/obj/item/integrated_circuit/manipulation/weapon_firing/proc/shootAt(turf/target) - var/turf/T = get_turf(src) - var/turf/U = target - if(!istype(T) || !istype(U)) - return - if(!installed_gun.cell) - return - if(!installed_gun.cell.charge) - return - var/obj/item/ammo_casing/energy/shot = installed_gun.ammo_type[mode?2:1] - if(installed_gun.cell.charge < shot.e_cost) - return - if(!shot) - return - update_icon() - var/obj/item/projectile/A - if(!mode) - A = new stun_projectile(T) - playsound(loc, stun_projectile_sound, 75, 1) - else - A = new lethal_projectile(T) - playsound(loc, lethal_projectile_sound, 75, 1) - installed_gun.cell.use(shot.e_cost) - //Shooting Code: - A.preparePixelProjectile(target, src) - A.fire() - log_attack("[assembly] [REF(assembly)] has fired [installed_gun].") - return A - /obj/item/integrated_circuit/manipulation/locomotion name = "locomotion circuit" desc = "This allows a machine to move in a given direction." @@ -171,80 +38,6 @@ return FALSE return FALSE -/obj/item/integrated_circuit/manipulation/grenade - name = "grenade primer" - desc = "This circuit comes with the ability to attach most types of grenades and prime them at will." - extended_desc = "The time between priming and detonation is limited to between 1 to 12 seconds, but is optional. \ - If the input is not set, not a number, or a number less than 1, the grenade's built-in timing will be used. \ - Beware: Once primed, there is no aborting the process!" - icon_state = "grenade" - complexity = 30 - cooldown_per_use = 10 - inputs = list("detonation time" = IC_PINTYPE_NUMBER) - outputs = list() - activators = list("prime grenade" = IC_PINTYPE_PULSE_IN) - spawn_flags = IC_SPAWN_RESEARCH - action_flags = IC_ACTION_COMBAT - var/obj/item/grenade/attached_grenade - var/pre_attached_grenade_type - demands_object_input = TRUE // You can put stuff in once the circuit is in assembly,passed down from additem and handled by attackby() - -/obj/item/integrated_circuit/manipulation/grenade/Initialize() - . = ..() - if(pre_attached_grenade_type) - var/grenade = new pre_attached_grenade_type(src) - attach_grenade(grenade) - -/obj/item/integrated_circuit/manipulation/grenade/Destroy() - if(attached_grenade && !attached_grenade.active) - attached_grenade.forceMove(loc) - detach_grenade() - return ..() - -/obj/item/integrated_circuit/manipulation/grenade/attackby(var/obj/item/grenade/G, var/mob/user) - if(istype(G)) - if(attached_grenade) - to_chat(user, "There is already a grenade attached!") - else if(user.transferItemToLoc(G,src)) - user.visible_message("\The [user] attaches \a [G] to \the [src]!", "You attach \the [G] to \the [src].") - attach_grenade(G) - G.forceMove(src) - else - return ..() - -/obj/item/integrated_circuit/manipulation/grenade/attack_self(var/mob/user) - if(attached_grenade) - user.visible_message("\The [user] removes \an [attached_grenade] from \the [src]!", "You remove \the [attached_grenade] from \the [src].") - user.put_in_hands(attached_grenade) - detach_grenade() - else - return ..() - -/obj/item/integrated_circuit/manipulation/grenade/do_work() - if(attached_grenade && !attached_grenade.active) - var/datum/integrated_io/detonation_time = inputs[1] - var/dt - if(isnum(detonation_time.data) && detonation_time.data > 0) - dt = CLAMP(detonation_time.data, 1, 12)*10 - else - dt = 15 - addtimer(CALLBACK(attached_grenade, /obj/item/grenade.proc/prime), dt) - var/atom/holder = loc - message_admins("activated a grenade assembly. Last touches: Assembly: [holder.fingerprintslast] Circuit: [fingerprintslast] Grenade: [attached_grenade.fingerprintslast]") - -// These procs do not relocate the grenade, that's the callers responsibility -/obj/item/integrated_circuit/manipulation/grenade/proc/attach_grenade(var/obj/item/grenade/G) - attached_grenade = G - G.forceMove(src) - desc += " \An [attached_grenade] is attached to it!" - -/obj/item/integrated_circuit/manipulation/grenade/proc/detach_grenade() - if(!attached_grenade) - return - attached_grenade.forceMove(drop_location()) - attached_grenade = null - desc = initial(desc) - /obj/item/integrated_circuit/manipulation/plant_module name = "plant manipulation module" desc = "Used to uproot weeds and harvest/plant trays." @@ -478,7 +271,7 @@ /obj/item/integrated_circuit/manipulation/thrower name = "thrower" - desc = "A compact launcher to throw things from inside or nearby tiles." + desc = "A compact launcher to throw things from inside or nearby tiles at a low enough velocity not to harm someone." extended_desc = "The first and second inputs need to be numbers which correspond to the coordinates to throw objects at relative to the machine itself. \ The 'fire' activator will cause the mechanism to attempt to throw objects at the coordinates, if possible. Note that the \ projectile needs to be inside the machine, or on an adjacent tile, and must be medium sized or smaller. The assembly \ @@ -544,7 +337,7 @@ A.embedding = list("embed_chance" = 0) //throw it assembly.visible_message("[assembly] has thrown [A]!") - log_attack("[assembly] [REF(assembly)] has thrown [A].") + log_attack("[assembly] [REF(assembly)] has thrown [A] with non-lethal force.") A.forceMove(drop_location()) A.throw_at(locate(x_abs, y_abs, T.z), range, 3, , , , CALLBACK(src, .proc/post_throw, A)) @@ -813,4 +606,7 @@ set_pin_data(IC_OUTPUT, 1, assembly.detail_color) push_data() - activate_pin(3) \ No newline at end of file + activate_pin(3) + + + diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm index 0d8bf96afc..fb8fce10b2 100644 --- a/code/modules/integrated_electronics/subtypes/reagents.dm +++ b/code/modules/integrated_electronics/subtypes/reagents.dm @@ -548,9 +548,12 @@ desc = "Unlike most electronics, creating smoke is completely intentional." icon_state = "smoke" extended_desc = "This smoke generator creates clouds of smoke on command. It can also hold liquids inside, which will go \ - into the smoke clouds when activated. The reagents are consumed when the smoke is made." + into the smoke clouds when activated. The reagents are consumed when the smoke is made. Requires at least 10 units of reagents to generate smoke." ext_cooldown = 1 + volume = 100 + container_type = OPENCONTAINER + complexity = 20 cooldown_per_use = 1 SECONDS inputs = list() @@ -573,6 +576,7 @@ if(changetype == ADD_REAGENT) notified = FALSE push_vol() + /obj/item/integrated_circuit/reagent/smoke/do_work(ord) switch(ord) if(1) @@ -598,9 +602,10 @@ name = "integrated extinguisher" desc = "This circuit sprays any of its contents out like an extinguisher." icon_state = "injector" - extended_desc = "This circuit can hold up to 30 units of any given chemicals. On each use, it sprays these reagents like a fire extinguisher." + extended_desc = "This circuit can hold up to 30 units of any given chemicals. On each use, it sprays these reagents like a fire extinguisher. Requires at least 10 units of reagents to work." volume = 30 + container_type = OPENCONTAINER complexity = 20 cooldown_per_use = 6 SECONDS @@ -631,7 +636,7 @@ /obj/item/integrated_circuit/reagent/extinguisher/do_work() //Check if enough volume set_pin_data(IC_OUTPUT, 1, reagents.total_volume) - if(!reagents || reagents.total_volume < 5 || busy) + if(!reagents || reagents.total_volume < IC_SMOKE_REAGENTS_MINIMUM_UNITS || busy) push_data() activate_pin(3) return diff --git a/code/modules/integrated_electronics/subtypes/weaponized.dm b/code/modules/integrated_electronics/subtypes/weaponized.dm new file mode 100644 index 0000000000..086b53f417 --- /dev/null +++ b/code/modules/integrated_electronics/subtypes/weaponized.dm @@ -0,0 +1,344 @@ +/obj/item/integrated_circuit/weaponized + category_text = "Weaponized" + +/obj/item/integrated_circuit/weaponized/weapon_firing + name = "weapon firing mechanism" + desc = "This somewhat complicated system allows one to slot in a gun, direct it towards a position, and remotely fire it." + extended_desc = "The firing mechanism can slot in any energy weapon. \ + The first and second inputs need to be numbers which correspond to coordinates for the gun to fire at relative to the machine itself. \ + The 'fire' activator will cause the mechanism to attempt to fire the weapon at the coordinates, if possible. Mode will switch between \ + lethal (TRUE) or stun (FALSE) modes. It uses the internal battery of the weapon itself, not the assembly. If you wish to fire the gun while the circuit is in \ + hand, you will need to use an assembly that is a gun." + complexity = 20 + w_class = WEIGHT_CLASS_SMALL + size = 3 + inputs = list( + "target X rel" = IC_PINTYPE_NUMBER, + "target Y rel" = IC_PINTYPE_NUMBER, + "mode" = IC_PINTYPE_BOOLEAN + ) + outputs = list("reference to gun" = IC_PINTYPE_REF) + activators = list( + "fire" = IC_PINTYPE_PULSE_IN + + ) + var/obj/item/gun/energy/installed_gun = null + spawn_flags = IC_SPAWN_RESEARCH + action_flags = IC_ACTION_COMBAT + power_draw_per_use = 0 + ext_cooldown = 1 + var/mode = FALSE + + var/stun_projectile = null //stun mode projectile type + var/stun_projectile_sound + var/lethal_projectile = null //lethal mode projectile type + var/lethal_projectile_sound + + demands_object_input = TRUE // You can put stuff in once the circuit is in assembly,passed down from additem and handled by attackby() + + + +/obj/item/integrated_circuit/weaponized/weapon_firing/Destroy() + qdel(installed_gun) + return ..() + +/obj/item/integrated_circuit/weaponized/weapon_firing/attackby(var/obj/O, var/mob/user) + if(istype(O, /obj/item/gun/energy)) + var/obj/item/gun/gun = O + if(installed_gun) + to_chat(user, "There's already a weapon installed.") + return + user.transferItemToLoc(gun,src) + installed_gun = gun + var/list/gun_properties = gun.get_turret_properties() + to_chat(user, "You slide \the [gun] into the firing mechanism.") + playsound(src, 'sound/items/Crowbar.ogg', 50, 1) + stun_projectile = gun_properties["stun_projectile"] + stun_projectile_sound = gun_properties["stun_projectile_sound"] + lethal_projectile = gun_properties["lethal_projectile"] + lethal_projectile_sound = gun_properties["lethal_projectile_sound"] + if(gun_properties["shot_delay"]) + cooldown_per_use = gun_properties["shot_delay"]*10 + if(cooldown_per_use<30) + cooldown_per_use = 30 + if(gun_properties["reqpower"]) + power_draw_per_use = gun_properties["reqpower"] + set_pin_data(IC_OUTPUT, 1, WEAKREF(installed_gun)) + push_data() + else + ..() + +/obj/item/integrated_circuit/weaponized/weapon_firing/attack_self(var/mob/user) + if(installed_gun) + installed_gun.forceMove(drop_location()) + to_chat(user, "You slide \the [installed_gun] out of the firing mechanism.") + size = initial(size) + playsound(src, 'sound/items/Crowbar.ogg', 50, 1) + installed_gun = null + set_pin_data(IC_OUTPUT, 1, WEAKREF(null)) + push_data() + else + to_chat(user, "There's no weapon to remove from the mechanism.") + +/obj/item/integrated_circuit/weaponized/weapon_firing/do_work() + if(!installed_gun || !installed_gun.handle_pins()) + return + if(!isturf(assembly.loc) && !(assembly.can_fire_equipped && ishuman(assembly.loc))) + return + set_pin_data(IC_OUTPUT, 1, WEAKREF(installed_gun)) + push_data() + var/datum/integrated_io/xo = inputs[1] + var/datum/integrated_io/yo = inputs[2] + var/datum/integrated_io/mode1 = inputs[3] + + mode = mode1.data + if(assembly) + if(isnum(xo.data)) + xo.data = round(xo.data, 1) + if(isnum(yo.data)) + yo.data = round(yo.data, 1) + + var/turf/T = get_turf(assembly) + var/target_x = CLAMP(T.x + xo.data, 0, world.maxx) + var/target_y = CLAMP(T.y + yo.data, 0, world.maxy) + + assembly.visible_message("[assembly] fires [installed_gun]!") + shootAt(locate(target_x, target_y, T.z)) + +/obj/item/integrated_circuit/weaponized/weapon_firing/proc/shootAt(turf/target) + var/turf/T = get_turf(src) + var/turf/U = target + if(!istype(T) || !istype(U)) + return + if(!installed_gun.cell) + return + if(!installed_gun.cell.charge) + return + var/obj/item/ammo_casing/energy/shot = installed_gun.ammo_type[mode?2:1] + if(installed_gun.cell.charge < shot.e_cost) + return + if(!shot) + return + update_icon() + var/obj/item/projectile/A + if(!mode) + A = new stun_projectile(T) + playsound(loc, stun_projectile_sound, 75, 1) + else + A = new lethal_projectile(T) + playsound(loc, lethal_projectile_sound, 75, 1) + installed_gun.cell.use(shot.e_cost) + //Shooting Code: + A.preparePixelProjectile(target, src) + A.fire() + log_attack("[assembly] [REF(assembly)] has fired [installed_gun].") + return A + +/obj/item/integrated_circuit/weaponized/grenade + name = "grenade primer" + desc = "This circuit comes with the ability to attach most types of grenades and prime them at will." + extended_desc = "The time between priming and detonation is limited to between 1 to 12 seconds, but is optional. \ + If the input is not set, not a number, or a number less than 1, the grenade's built-in timing will be used. \ + Beware: Once primed, there is no aborting the process!" + icon_state = "grenade" + complexity = 30 + cooldown_per_use = 10 + inputs = list("detonation time" = IC_PINTYPE_NUMBER) + outputs = list() + activators = list("prime grenade" = IC_PINTYPE_PULSE_IN) + spawn_flags = IC_SPAWN_RESEARCH + action_flags = IC_ACTION_COMBAT + var/obj/item/grenade/attached_grenade + var/pre_attached_grenade_type + demands_object_input = TRUE // You can put stuff in once the circuit is in assembly,passed down from additem and handled by attackby() + +/obj/item/integrated_circuit/weaponized/grenade/Initialize() + . = ..() + if(pre_attached_grenade_type) + var/grenade = new pre_attached_grenade_type(src) + attach_grenade(grenade) + +/obj/item/integrated_circuit/weaponized/grenade/Destroy() + if(attached_grenade && !attached_grenade.active) + attached_grenade.forceMove(loc) + detach_grenade() + return ..() + +/obj/item/integrated_circuit/weaponized/grenade/attackby(var/obj/item/grenade/G, var/mob/user) + if(istype(G)) + if(attached_grenade) + to_chat(user, "There is already a grenade attached!") + else if(user.transferItemToLoc(G,src)) + user.visible_message("\The [user] attaches \a [G] to \the [src]!", "You attach \the [G] to \the [src].") + attach_grenade(G) + G.forceMove(src) + else + return ..() + +/obj/item/integrated_circuit/weaponized/grenade/attack_self(var/mob/user) + if(attached_grenade) + user.visible_message("\The [user] removes \an [attached_grenade] from \the [src]!", "You remove \the [attached_grenade] from \the [src].") + user.put_in_hands(attached_grenade) + detach_grenade() + else + return ..() + +/obj/item/integrated_circuit/weaponized/grenade/do_work() + if(attached_grenade && !attached_grenade.active) + var/datum/integrated_io/detonation_time = inputs[1] + var/dt + if(isnum(detonation_time.data) && detonation_time.data > 0) + dt = CLAMP(detonation_time.data, 1, 12)*10 + else + dt = 15 + addtimer(CALLBACK(attached_grenade, /obj/item/grenade.proc/prime), dt) + var/atom/holder = loc + message_admins("activated a grenade assembly. Last touches: Assembly: [holder.fingerprintslast] Circuit: [fingerprintslast] Grenade: [attached_grenade.fingerprintslast]") + +// These procs do not relocate the grenade, that's the callers responsibility +/obj/item/integrated_circuit/weaponized/grenade/proc/attach_grenade(var/obj/item/grenade/G) + attached_grenade = G + G.forceMove(src) + desc += " \An [attached_grenade] is attached to it!" + +/obj/item/integrated_circuit/weaponized/grenade/proc/detach_grenade() + if(!attached_grenade) + return + attached_grenade.forceMove(drop_location()) + attached_grenade = null + desc = initial(desc) + +/obj/item/integrated_circuit/weaponized/air_cannon + name = "pneumatic cannon" + desc = "A compact pneumatic cannon to throw things from inside or nearby tiles at a high enough velocity to cause damage. Requires air from a canister to fire." + extended_desc = "The first and second inputs need to be numbers which correspond to the coordinates to throw objects at relative to the machine itself. \ + The 'fire' activator will cause the mechanism to attempt to launch objects at the coordinates, if possible. Note that the \ + projectile needs to be inside the machine, or on an adjacent tile, and must be medium sized or smaller. The assembly \ + must also be a gun if you wish to launch something while the assembly is in hand." + complexity = 75 + w_class = WEIGHT_CLASS_SMALL + size = 4 + cooldown_per_use = 30 + ext_cooldown = 15 + inputs = list( + "target X rel" = IC_PINTYPE_NUMBER, + "target Y rel" = IC_PINTYPE_NUMBER, + "projectile" = IC_PINTYPE_REF, + "canister" = IC_PINTYPE_REF + ) + outputs = list() + activators = list( + "fire" = IC_PINTYPE_PULSE_IN + ) + spawn_flags = IC_SPAWN_RESEARCH + action_flags = IC_ACTION_COMBAT + power_draw_per_use = 50 + var/mole_requirement = 1 + +/obj/item/integrated_circuit/weaponized/air_cannon/do_work() + + var/max_w_class = assembly.w_class + var/target_x_rel = round(get_pin_data(IC_INPUT, 1)) + var/target_y_rel = round(get_pin_data(IC_INPUT, 2)) + var/obj/item/A = get_pin_data_as_type(IC_INPUT, 3, /obj/item) + var/obj/item/integrated_circuit/atmospherics/AT = get_pin_data_as_type(IC_INPUT, 4, /obj/item/integrated_circuit/atmospherics) + + if(!A || A.anchored || A.throwing || A == assembly || istype(A, /obj/item/twohanded) || istype(A, /obj/item/transfer_valve)) + return + + if(!AT || !AT.air_contents) + return + + if (istype(assembly.loc, /obj/item/implant/storage)) //Prevents the more abusive form of chestgun. + return + + if(max_w_class && (A.w_class > max_w_class)) + return + + if(!assembly.can_fire_equipped && ishuman(assembly.loc)) + return + + // Is the target inside the assembly or close to it? + if(!check_target(A, exclude_components = TRUE)) + return + + var/turf/T = get_turf(get_object()) + if(!T) + return + + // If the item is in mob's inventory, try to remove it from there. + if(ismob(A.loc)) + var/mob/living/M = A.loc + if(!M.temporarilyRemoveItemFromInventory(A)) + return + + var/datum/gas_mixture/source_air = AT.return_air() + var/datum/gas_mixture/target_air = T.return_air() + + if(!source_air || !target_air) + return + + if(source_air.total_moles() <= mole_requirement) + return + + // If the item is in a grabber circuit we'll update the grabber's outputs after we've thrown it. + var/obj/item/integrated_circuit/manipulation/grabber/G = A.loc + + var/x_abs = CLAMP(T.x + target_x_rel, 0, world.maxx) + var/y_abs = CLAMP(T.y + target_y_rel, 0, world.maxy) + var/range = round(CLAMP(sqrt(target_x_rel*target_x_rel+target_y_rel*target_y_rel),0,8),1) + assembly.visible_message("[assembly] has thrown [A]!") + log_attack("[assembly] [REF(assembly)] has thrown [A] with lethal force.") + A.forceMove(drop_location()) + A.throw_at(locate(x_abs, y_abs, T.z), range, 3) + + var/datum/gas_mixture/removed = source_air.remove(mole_requirement) + target_air.merge(removed) + + air_update_turf() + + // If the item came from a grabber now we can update the outputs since we've thrown it. + if(istype(G)) + G.update_outputs() + + +/obj/item/integrated_circuit/weaponized/stun + name = "electronic stun module" + desc = "Used to stun a target holding the device via electricity." + icon_state = "power_relay" + extended_desc = "Attempts to stun the holder of this device, with the strength input being the strength of the stun, from 1 to 70." + complexity = 60 + size = 4 + inputs = list("strength" = IC_PINTYPE_NUMBER) + activators = list("stun" = IC_PINTYPE_PULSE_IN, "on success" = IC_PINTYPE_PULSE_OUT, "on fail" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_RESEARCH + power_draw_per_use = 2000 + cooldown_per_use = 50 + ext_cooldown = 25 + + +/obj/item/integrated_circuit/weaponized/stun/do_work() + var/stunforce = CLAMP(get_pin_data(IC_INPUT, 1),1,70) + var/mob/living/L = assembly.loc + if(attempt_stun(L,stunforce)) + activate_pin(2) + else + activate_pin(3) + +/obj/item/integrated_circuit/weaponized/proc/attempt_stun(var/mob/living/L,var/stunforce = 70) //Copied from stunbaton code. + + if(!L || !isliving(L)) + return 0 + + L.Knockdown(stunforce) + SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK) + + message_admins("stunned someone with an assembly. Last touches: Assembly: [assembly.fingerprintslast] Circuit: [fingerprintslast]") + + L.visible_message("\The [assembly] has stunned \the [L] with \the [src]!", "\The [assembly] has stunned you with \the [src]!") + playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + H.forcesay(GLOB.hit_appends) + + return 1 \ No newline at end of file diff --git a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm index 246205f7b6..547c1a5768 100644 --- a/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm +++ b/modular_citadel/code/modules/integrated_electronics/subtypes/manipulation.dm @@ -14,7 +14,6 @@ ext_cooldown = 25 /obj/item/integrated_circuit/manipulation/electric_stimulator/do_work() - ..() set_pin_data(IC_OUTPUT, 1, 0) var/mob/living/M = get_pin_data_as_type(IC_INPUT, 1, /mob/living) if(!check_target(M)) diff --git a/tgstation.dme b/tgstation.dme index 9e9c6fe593..b792852358 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -1753,6 +1753,7 @@ #include "code\modules\integrated_electronics\subtypes\text.dm" #include "code\modules\integrated_electronics\subtypes\time.dm" #include "code\modules\integrated_electronics\subtypes\trig.dm" +#include "code\modules\integrated_electronics\subtypes\weaponized.dm" #include "code\modules\jobs\access.dm" #include "code\modules\jobs\job_exp.dm" #include "code\modules\jobs\jobs.dm"