mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-12 03:02:54 +00:00
Rewrites gun.dm. Reorganizes the firing procedure into logical procs and cleans up some unnecessary variables or demotes them to the subtypes that actually care. Energy weapons that create their own projectiles no longer care about in_chamber. Launcher support is much more natural now. Cleans up duplicated cyborg energy weapon power supply code. Adds support for energy weapons to recharge from external power sources, unifying cyborg and hardsuit mounted weapons. Incorporates the cyborg taser recharging mechanism. Cleans up laser tag gun duplication Changes path strings to actual paths. Changes relative paths to absolute paths. Renamed several targeting vars to make their purposes more clear. Fixed targeting not handling firing correctly for certain subtypes.
376 lines
12 KiB
Plaintext
376 lines
12 KiB
Plaintext
/obj/item/weapon/gun/verb/toggle_firerate()
|
|
set name = "Toggle Continue Aiming"
|
|
set category = "Object"
|
|
|
|
keep_aim = !keep_aim
|
|
|
|
if (keep_aim)
|
|
loc << "You will now continue firing when your target moves."
|
|
else
|
|
loc << "You will now only fire once, then lower your aim, when your target moves."
|
|
|
|
/obj/item/weapon/gun/verb/lower_aim()
|
|
set name = "Lower Aim"
|
|
set category = "Object"
|
|
if(aim_targets)
|
|
stop_aim()
|
|
usr.visible_message("\blue \The [usr] lowers \the [src]...")
|
|
|
|
//Clicking gun will still lower aim for guns that don't overwrite this
|
|
/obj/item/weapon/gun/attack_self()
|
|
lower_aim()
|
|
|
|
//Removing the lock and the buttons.
|
|
/obj/item/weapon/gun/dropped(mob/user as mob)
|
|
stop_aim()
|
|
if (user.client)
|
|
user.client.remove_gun_icons()
|
|
return ..()
|
|
|
|
/obj/item/weapon/gun/equipped(var/mob/user, var/slot)
|
|
if (slot != slot_l_hand && slot != slot_r_hand)
|
|
stop_aim()
|
|
if (user.client)
|
|
user.client.remove_gun_icons()
|
|
return ..()
|
|
|
|
//Removes lock fro mall targets
|
|
/obj/item/weapon/gun/proc/stop_aim()
|
|
if(aim_targets)
|
|
for(var/mob/living/M in aim_targets)
|
|
if(M)
|
|
M.NotTargeted(src) //Untargeting people.
|
|
del(aim_targets)
|
|
|
|
//Compute how to fire.....
|
|
//Return 1 if a target was found, 0 otherwise.
|
|
/obj/item/weapon/gun/proc/PreFire(atom/A as mob|obj|turf|area, mob/living/user as mob|obj, params)
|
|
//Lets not spam it.
|
|
if(lock_time > world.time - 2) return
|
|
|
|
user.set_dir(get_cardinal_dir(src, A))
|
|
if(isliving(A) && !(A in aim_targets))
|
|
Aim(A) //Clicked a mob, aim at them
|
|
return 1
|
|
|
|
//Didn't click someone, check if there is anyone along that guntrace
|
|
var/mob/living/M = GunTrace(usr.x,usr.y,A.x,A.y,usr.z,usr) //Find dat mob.
|
|
if(isliving(M) && (M in view(user)) && !(M in aim_targets))
|
|
Aim(M) //Aha! Aim at them!
|
|
return 1
|
|
|
|
return 0
|
|
|
|
//Aiming at the target mob.
|
|
/obj/item/weapon/gun/proc/Aim(var/mob/living/M)
|
|
if(!aim_targets || !(M in aim_targets))
|
|
lock_time = world.time
|
|
if(aim_targets && !multi_aim) //If they're targeting someone and they have a non multi_aim weapon.
|
|
for(var/mob/living/L in aim_targets)
|
|
if(L)
|
|
L.NotTargeted(src)
|
|
del(aim_targets)
|
|
usr.visible_message("\red <b>[usr] turns \the [src] on [M]!</b>")
|
|
else
|
|
usr.visible_message("\red <b>[usr] aims \a [src] at [M]!</b>")
|
|
M.Targeted(src)
|
|
|
|
//HE MOVED, SHOOT HIM!
|
|
/obj/item/weapon/gun/proc/TargetActed(var/mob/living/T)
|
|
var/mob/living/M = loc
|
|
if(M == T) return
|
|
if(!istype(M)) return
|
|
if(src != M.equipped())
|
|
stop_aim()
|
|
return
|
|
|
|
//reflex firing is disabled when help intent is set
|
|
if (M.a_intent == "help")
|
|
M << "\red You refrain from firing your [src] as your intent is set to help."
|
|
return
|
|
|
|
M.last_move_intent = world.time
|
|
var/firing_check = can_hit(T,usr) //0 if it cannot hit them, 1 if it is capable of hitting, and 2 if a special check is preventing it from firing.
|
|
if(firing_check > 0)
|
|
if(firing_check == 1)
|
|
Fire(T,usr, reflex = 1)
|
|
else if(!told_cant_shoot)
|
|
M << "\red They can't be hit from here!"
|
|
told_cant_shoot = 1
|
|
spawn(30)
|
|
told_cant_shoot = 0
|
|
|
|
usr.set_dir(get_cardinal_dir(src, T))
|
|
|
|
if (!keep_aim) // If keep_aim is set to lower aim after one shot, untarget the target
|
|
T.NotTargeted(src)
|
|
|
|
//Yay, math!
|
|
|
|
#define SIGN(X) ((X<0)?-1:1)
|
|
|
|
/proc/GunTrace(X1,Y1,X2,Y2,Z=1,exc_obj,PX1=16,PY1=16,PX2=16,PY2=16)
|
|
//bluh << "Tracin' [X1],[Y1] to [X2],[Y2] on floor [Z]."
|
|
var/turf/T
|
|
var/mob/living/M
|
|
if(X1==X2)
|
|
if(Y1==Y2) return 0 //Light cannot be blocked on same tile
|
|
else
|
|
var/s = SIGN(Y2-Y1)
|
|
Y1+=s
|
|
while(1)
|
|
T = locate(X1,Y1,Z)
|
|
if(!T) return 0
|
|
M = locate() in T
|
|
if(M) return M
|
|
M = locate() in orange(1,T)-exc_obj
|
|
if(M) return M
|
|
Y1+=s
|
|
else
|
|
var
|
|
m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1))
|
|
b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles
|
|
signX = SIGN(X2-X1)
|
|
signY = SIGN(Y2-Y1)
|
|
if(X1<X2) b+=m
|
|
while(1)
|
|
var/xvert = round(m*X1+b-Y1)
|
|
if(xvert) Y1+=signY //Line exits tile vertically
|
|
else X1+=signX //Line exits tile horizontally
|
|
T = locate(X1,Y1,Z)
|
|
if(!T) return 0
|
|
M = locate() in T
|
|
if(M) return M
|
|
M = locate() in orange(1,T)-exc_obj
|
|
if(M) return M
|
|
return 0
|
|
|
|
|
|
//Targeting management procs
|
|
/mob/var
|
|
list/targeted_by
|
|
target_time = -100
|
|
last_move_intent = -100
|
|
last_target_click = -5
|
|
target_locked = null
|
|
|
|
/mob/living/proc/Targeted(var/obj/item/weapon/gun/I) //Self explanitory.
|
|
if(!I.aim_targets)
|
|
I.aim_targets = list(src)
|
|
else if(I.multi_aim && I.aim_targets.len < 5) //multi_aim weapon, they can hold down a room.
|
|
I.aim_targets += src
|
|
else if(I.aim_targets.len >= 5)
|
|
if(ismob(I.loc))
|
|
I.loc << "You can only target 5 people at once!"
|
|
return
|
|
else
|
|
return
|
|
for(var/mob/living/K in viewers(usr))
|
|
K << 'sound/weapons/TargetOn.ogg'
|
|
|
|
if(!targeted_by) targeted_by = list()
|
|
targeted_by += I
|
|
I.lock_time = world.time + 20 //Target has 2 second to realize they're targeted and stop (or target the opponent).
|
|
src << "((\red <b>Your character is being targeted. They have 2 seconds to stop any click or move actions.</b> \black While targeted, they may \
|
|
drag and drop items in or into the map, speak, and click on interface buttons. Clicking on the map objects (floors and walls are fine), their items \
|
|
(other than a weapon to de-target), or moving will result in being fired upon. \red The aggressor may also fire manually, \
|
|
so try not to get on their bad side.\black ))"
|
|
|
|
if(targeted_by.len == 1)
|
|
spawn(0)
|
|
target_locked = image("icon" = 'icons/effects/Targeted.dmi', "icon_state" = "locking")
|
|
overlays += target_locked
|
|
spawn(0)
|
|
sleep(20)
|
|
if(target_locked)
|
|
target_locked = image("icon" = 'icons/effects/Targeted.dmi', "icon_state" = "locked")
|
|
update_targeted()
|
|
|
|
//Adding the buttons to the controller person
|
|
var/mob/living/T = I.loc
|
|
if(T)
|
|
if(T.client)
|
|
T.client.add_gun_icons()
|
|
else
|
|
I.lower_aim()
|
|
return
|
|
if(m_intent == "run" && T.client.target_can_move == 1 && T.client.target_can_run == 0)
|
|
src << "\red Your move intent is now set to walk, as your targeter permits it." //Self explanitory.
|
|
set_m_intent("walk")
|
|
|
|
//Processing the aiming. Should be probably in separate object with process() but lasy.
|
|
while(targeted_by && T.client)
|
|
if(last_move_intent > I.lock_time + 10 && !T.client.target_can_move) //If target moved when not allowed to
|
|
I.TargetActed(src)
|
|
if(I.last_moved_mob == src) //If they were the last ones to move, give them more of a grace period, so that an automatic weapon can hold down a room better.
|
|
I.lock_time = world.time + 5
|
|
I.lock_time = world.time + 5
|
|
I.last_moved_mob = src
|
|
else if(last_move_intent > I.lock_time + 10 && !T.client.target_can_run && m_intent == "run") //If the target ran while targeted
|
|
I.TargetActed(src)
|
|
if(I.last_moved_mob == src) //If they were the last ones to move, give them more of a grace period, so that an automatic weapon can hold down a room better.
|
|
I.lock_time = world.time + 5
|
|
I.lock_time = world.time + 5
|
|
I.last_moved_mob = src
|
|
if(last_target_click > I.lock_time + 10 && !T.client.target_can_click) //If the target clicked the map to pick something up/shoot/etc
|
|
I.TargetActed(src)
|
|
if(I.last_moved_mob == src) //If they were the last ones to move, give them more of a grace period, so that an automatic weapon can hold down a room better.
|
|
I.lock_time = world.time + 5
|
|
I.lock_time = world.time + 5
|
|
I.last_moved_mob = src
|
|
sleep(1)
|
|
|
|
/mob/living/proc/NotTargeted(var/obj/item/weapon/gun/I)
|
|
if(!I.silenced)
|
|
for(var/mob/living/M in viewers(src))
|
|
M << 'sound/weapons/TargetOff.ogg'
|
|
targeted_by -= I
|
|
I.aim_targets.Remove(src) //De-target them
|
|
if(!I.aim_targets.len)
|
|
del(I.aim_targets)
|
|
var/mob/living/T = I.loc //Remove the targeting icons
|
|
if(T && ismob(T) && !I.aim_targets)
|
|
T.client.remove_gun_icons()
|
|
if(!targeted_by.len)
|
|
del target_locked //Remove the overlay
|
|
del targeted_by
|
|
spawn(1) update_targeted()
|
|
|
|
/mob/living/Move()
|
|
. = ..()
|
|
for(var/obj/item/weapon/gun/G in targeted_by) //Handle moving out of the gunner's view.
|
|
var/mob/living/M = G.loc
|
|
if(!(M in view(src)))
|
|
NotTargeted(G)
|
|
for(var/obj/item/weapon/gun/G in src) //Handle the gunner loosing sight of their target/s
|
|
if(G.aim_targets)
|
|
for(var/mob/living/M in G.aim_targets)
|
|
if(M && !(M in view(src)))
|
|
M.NotTargeted(G)
|
|
|
|
//If you move out of range, it isn't going to still stay locked on you any more.
|
|
/client/var
|
|
target_can_move = 0
|
|
target_can_run = 0
|
|
target_can_click = 0
|
|
gun_mode = 0
|
|
|
|
//These are called by the on-screen buttons, adjusting what the victim can and cannot do.
|
|
/client/proc/add_gun_icons()
|
|
screen += usr.item_use_icon
|
|
screen += usr.gun_move_icon
|
|
if (target_can_move)
|
|
screen += usr.gun_run_icon
|
|
|
|
|
|
|
|
/client/proc/remove_gun_icons()
|
|
if(!usr) return 1 // Runtime prevention on N00k agents spawning with SMG
|
|
screen -= usr.item_use_icon
|
|
screen -= usr.gun_move_icon
|
|
if (target_can_move)
|
|
screen -= usr.gun_run_icon
|
|
|
|
/client/verb/ToggleGunMode()
|
|
set hidden = 1
|
|
gun_mode = !gun_mode
|
|
if(gun_mode)
|
|
usr << "You will now take people captive."
|
|
else
|
|
usr << "You will now shoot where you target."
|
|
for(var/obj/item/weapon/gun/G in usr)
|
|
G.stop_aim()
|
|
remove_gun_icons()
|
|
if(usr.gun_setting_icon)
|
|
usr.gun_setting_icon.icon_state = "gun[gun_mode]"
|
|
|
|
|
|
/client/verb/AllowTargetMove()
|
|
set hidden=1
|
|
|
|
//Changing client's permissions
|
|
target_can_move = !target_can_move
|
|
if(target_can_move)
|
|
usr << "Target may now walk."
|
|
//usr.gun_run_icon = new /obj/screen/gun/run(null) //adding icon for running permission
|
|
screen += usr.gun_run_icon
|
|
else
|
|
usr << "Target may no longer move."
|
|
target_can_run = 0
|
|
del(usr.gun_run_icon) //no need for icon for running permission
|
|
|
|
//Updating walking permission button
|
|
if(usr.gun_move_icon)
|
|
usr.gun_move_icon.icon_state = "no_walk[target_can_move]"
|
|
usr.gun_move_icon.name = "[target_can_move ? "Disallow" : "Allow"] Walking"
|
|
|
|
//Handling change for all the guns on client
|
|
for(var/obj/item/weapon/gun/G in usr)
|
|
G.lock_time = world.time + 5
|
|
if(G.aim_targets)
|
|
for(var/mob/living/M in G.aim_targets)
|
|
if(target_can_move)
|
|
M << "Your character may now <b>walk</b> at the discretion of their targeter."
|
|
if(!target_can_run)
|
|
M << "\red Your move intent is now set to walk, as your targeter permits it."
|
|
M.set_m_intent("walk")
|
|
else
|
|
M << "\red <b>Your character will now be shot if they move.</b>"
|
|
|
|
/mob/living/proc/set_m_intent(var/intent)
|
|
if (intent != "walk" && intent != "run")
|
|
return 0
|
|
m_intent = intent
|
|
if(hud_used)
|
|
if (hud_used.move_intent)
|
|
hud_used.move_intent.icon_state = intent == "walk" ? "walking" : "running"
|
|
|
|
client/verb/AllowTargetRun()
|
|
set hidden=1
|
|
|
|
//Changing client's permissions
|
|
target_can_run = !target_can_run
|
|
if(target_can_run)
|
|
usr << "Target may now run."
|
|
else
|
|
usr << "Target may no longer run."
|
|
|
|
//Updating running permission button
|
|
if(usr.gun_run_icon)
|
|
usr.gun_run_icon.icon_state = "no_run[target_can_run]"
|
|
usr.gun_run_icon.name = "[target_can_run ? "Disallow" : "Allow"] Running"
|
|
|
|
//Handling change for all the guns on client
|
|
for(var/obj/item/weapon/gun/G in src)
|
|
G.lock_time = world.time + 5
|
|
if(G.aim_targets)
|
|
for(var/mob/living/M in G.aim_targets)
|
|
if(target_can_run)
|
|
M << "Your character may now <b>run</b> at the discretion of their targeter."
|
|
else
|
|
M << "\red <b>Your character will now be shot if they run.</b>"
|
|
|
|
/client/verb/AllowTargetClick()
|
|
set hidden=1
|
|
|
|
//Changing client's permissions
|
|
target_can_click = !target_can_click
|
|
if(target_can_click)
|
|
usr << "Target may now use items."
|
|
else
|
|
usr << "Target may no longer use items."
|
|
|
|
if(usr.item_use_icon)
|
|
usr.item_use_icon.icon_state = "no_item[target_can_click]"
|
|
usr.item_use_icon.name = "[target_can_click ? "Disallow" : "Allow"] Item Use"
|
|
|
|
//Handling change for all the guns on client
|
|
for(var/obj/item/weapon/gun/G in src)
|
|
G.lock_time = world.time + 5
|
|
if(G.aim_targets)
|
|
for(var/mob/living/M in G.aim_targets)
|
|
if(target_can_click)
|
|
M << "Your character may now <b>use items</b> at the discretion of their targeter."
|
|
else
|
|
M << "\red <b>Your character will now be shot if they use items.</b>"
|