Automatic firemode for guns (#4730)

* New gun firemode: automatic

Full-auto destruction at the tip of your fingers! If you're an admin. Switch the automatic var to 1 to make any gun automatic.

This code is largely donated by Mport and the SS:CM project. Relevant modifcations are located in automatic.dm, special.dm, and automagical.dm

* Removes '/blue's

* Removes a block of pseudocode.

* Welp. Missed some things.

* Automatic removed from the Suppression gun, as requested by @Anewbe in #4730

* Requested changes.
This commit is contained in:
Andromeda-K22
2018-02-06 23:57:53 -05:00
committed by Anewbe
parent d4a1abbcf2
commit 58cf8000ba
5 changed files with 117 additions and 13 deletions

View File

@@ -51,6 +51,7 @@
attack_verb = list("struck", "hit", "bashed")
zoomdevicename = "scope"
var/automatic = 0
var/burst = 1
var/fire_delay = 6 //delay after shooting before the gun can be used again
var/burst_delay = 2 //delay between shots, if firing in bursts
@@ -68,7 +69,8 @@
var/requires_two_hands
var/wielded_icon = "gun_wielded"
var/one_handed_penalty = 0 // Penalty applied if someone fires a two-handed gun with one hand.
var/obj/screen/auto_target/auto_target
var/shooting = 0
var/next_fire_time = 0
var/sel_mode = 1 //index of the currently selected mode
@@ -87,7 +89,6 @@
var/obj/item/dnalockingchip/attached_lock
var/last_shot = 0 //records the last shot fired
/obj/item/weapon/gun/New()
..()
for(var/i in 1 to firemodes.len)
@@ -177,8 +178,23 @@
if(user && user.a_intent == I_HELP && user.is_preference_enabled(/datum/client_preference/safefiring)) //regardless of what happens, refuse to shoot if help intent is on
user << "<span class='warning'>You refrain from firing your [src] as your intent is set to help.</span>"
else
Fire(A,user,params) //Otherwise, fire normally.
return
if(automatic == 1)//Are we are going to be using automatic shooting
//We check to make sure they can fire
if(!special_check(user))
return
if(auto_target)//If they already have one then update it
auto_target.loc = get_turf(A)
auto_target.delay_del = 1//And reset the del so its like they got a new one and doesnt instantly vanish
to_chat(user, "<span class='notice'>You ready \the [src]! Click and drag the target around to shoot.</span>")
else//Otherwise just make a new one
auto_target = new/obj/screen/auto_target(get_turf(A), src)
visible_message("<span class='danger'>\[user] readies the [src]!</span>")
playsound(src, 'sound/weapons/TargetOn.ogg', 50, 1)
to_chat(user, "<span class='notice'>You ready \the [src]! Click and drag the target around to shoot.</span>")
return
Fire(A,user,params) //Otherwise, fire normally.
/obj/item/weapon/gun/attack(atom/A, mob/living/user, def_zone)
if (A == user && user.zone_sel.selecting == O_MOUTH && !mouthshoot)
@@ -278,8 +294,8 @@
return
var/shoot_time = (burst - 1)* burst_delay
user.setClickCooldown(shoot_time) //no clicking on things while shooting
user.setMoveCooldown(shoot_time) //no moving while shooting either
//user.setClickCooldown(shoot_time) //no clicking on things while shooting //These are currently disabled to allow for the automatic system to function without causing near-permanant paralysis.
//user.setMoveCooldown(shoot_time) //no moving while shooting either
next_fire_time = world.time + shoot_time
var/held_acc_mod = 0
@@ -291,7 +307,23 @@
//actually attempt to shoot
var/turf/targloc = get_turf(target) //cache this in case target gets deleted during shooting, e.g. if it was a securitron that got destroyed.
shooting = 1
if(automatic == 1 && auto_target && auto_target.active)//When we are going to shoot and have an auto_target AND its active meaning we clicked on it we tell it to burstfire 1000 rounds
burst = 1000//Yes its not EXACTLY full auto but when are we shooting more than 1000 normally and it can easily be made higher
for(var/i in 1 to burst)
if(!reflex && automatic)//If we are shooting automatic then check our target, however if we are shooting reflex we dont use automatic
//extra sanity checking.
if(user.paralysis >= 1)
return
if(user.get_active_hand() != src)
break
if(!auto_target) break//Stopped shooting
else if(auto_target.loc)
target = auto_target.loc
//Lastly just update our dir if needed
if(user.dir != get_dir(user, auto_target))
user.face_atom(auto_target)
var/obj/projectile = consume_next_projectile(user)
if(!projectile)
handle_click_empty(user)
@@ -316,7 +348,7 @@
pointblank = 0
last_shot = world.time
shooting = 0
// We do this down here, so we don't get the message if we fire an empty gun.
if(requires_two_hands)
if(user.item_is_in_hands(src) && user.hands_are_full())

View File

@@ -0,0 +1,70 @@
//True automagic gun modes. Dakka dakka.
//A significant portion of this code was donated by Mport from SS:CM
//This is used by guns shooting in automatic mode
/obj/screen/auto_target
name = "targeter"
icon = null//We dont want people to see this guy
density = 0
anchored = 1
var/obj/item/weapon/gun/gun
var/active = 0//Just tells us that it was clicked on so we should start shooting
var/delay_del = 0//Delays the del if we retarget without shooting
/obj/screen/auto_target/New(loc, var/obj/item/weapon/gun/G)
..()
gun = G
var/image/I = image('icons/effects/Targeted.dmi', src, "locked")
I.override = 1
usr << I
//autodel() //Currently doesn't really work right.
return
/obj/screen/auto_target/CanPass()//Everything should ignore this guy and just pass by
return 1
//Used to get rid of this if they target but dont actually shoot or stop shooting (no ammo) yet are still dragging us around
/obj/screen/auto_target/proc/autodel()
set waitfor=0
if(active == 1)
return
sleep(20)
if(!src) return//Might not really be needed
if(delay_del)//This says we want to wait another X seconds before trying to del
delay_del = 0
autodel()
return
if(gun.shooting == 0)
del(src)
else
autodel()//Yes in theory this could hit the inf loop
return
//When the player clicks on the target it will disable the autodel and tell the gun to shoot
/obj/screen/auto_target/MouseDown(location,control,params)
active += 1//Tell the autodel that we are actually using this now
if(gun.shooting == 0)//If we are not shooting start shooting, we need this here or they have to drag to a new turf before it starts shooting, felt weird
gun.Fire(loc, usr, params)
return
//Called when they drag the object somewhere else
//If its not already shooting (should be though due to the above, but this does let it click at you when it runs dry) then start shooting,
/obj/screen/auto_target/MouseDrag(over_object,src_location,over_location,src_control,over_control,params)
if(gun.shooting == 0)//If we are not shooting start shooting
gun.Fire(loc, usr, params)
if(over_location != loc)//This updates the loc to our new location when we drag it to a new turf
loc = over_location
if((usr.get_active_hand() != gun))
del(src)
//This gets rid of us when they let go of the click, but only after they actually drag the target to a new turf which is why the below also has to exist
/obj/screen/auto_target/MouseDrop(over_object,src_location,over_location,src_control,over_control,params)
del(src)
return
//This is needed so if they just MouseDown and then let go it will stop shooting, otherwise we stick around till they run out of bullets
/obj/screen/auto_target/MouseUp(object,location,control,params)
del(src)
return
//This pseudo code is being left in place to serve as references to the modifications to gun.dm, the Fire() proc, and the afterattack() proc. -k22
//Code donated by Mport.

View File

@@ -209,5 +209,5 @@ obj/item/weapon/gun/energy/staff/focus
firemodes = list(
list(mode_name="single shot", burst = 1, burst_accuracy = list(5), dispersion = list(0), charge_cost = 24),
list(mode_name="five shot burst", burst = 5, burst_accuracy = list(5,5,5,5,5), dispersion = list(1,1,1,1,1)),
list(mode_name="ten shot burst", burst = 10, burst_accuracy = list(5,5,5,5,5,5,5,5,5,5), dispersion = list(2,2,2,2,2,2,2,2,2,2)),
)
list(mode_name="ten shot burst", burst = 10, burst_accuracy = list(5,5,5,5,5,5,5,5,5,5), dispersion = list(2,2,2,2,2,2,2,2,2,2))
)

View File

@@ -191,9 +191,10 @@
one_handed_penalty = 6
firemodes = list(
list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, burst_accuracy=null, dispersion=null),
list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=4, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0)),
list(mode_name="short bursts", burst=5, move_delay=6, burst_accuracy = list(0,-1,-1,-2,-2), dispersion = list(0.6, 1.0, 1.0, 1.0, 1.2))
list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, burst_accuracy=null, dispersion=null, automatic = 0),
list(mode_name="3-round bursts", burst=3, fire_delay=null, move_delay=4, burst_accuracy=list(0,-1,-1), dispersion=list(0.0, 0.6, 1.0), automatic = 0),
list(mode_name="short bursts", burst=5, move_delay=6, burst_accuracy = list(0,-1,-1,-2,-2), dispersion = list(0.6, 1.0, 1.0, 1.0, 1.2), automatic = 0),
list(mode_name="automatic", burst=1, fire_delay=-1, move_delay=null, burst_accuracy=null, dispersion=null, automatic = 1),
)
var/cover_open = 0
@@ -370,4 +371,4 @@
icon_state = "bullpup"
else
item_state = "bullpup-empty"
if(!ignore_inhands) update_held_icon()
if(!ignore_inhands) update_held_icon()