Skip to content

Commit

Permalink
make projectiles work at a distance
Browse files Browse the repository at this point in the history
  • Loading branch information
Erikafox committed Dec 30, 2024
1 parent edf0f70 commit 7398a64
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 58 deletions.
6 changes: 3 additions & 3 deletions code/__DEFINES/guns.dm
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@
#define GUN_NO_SAFETY_MALFUNCTION_CHANCE_HIGH 15

//aiming down sights values
#define PISTOL_ZOOM 1
#define PISTOL_ZOOM 2
#define SHOTGUN_ZOOM 2
#define SMG_ZOOM 2
#define RIFLE_ZOOM 3
#define DMR_ZOOM 5
#define RIFLE_ZOOM 2
#define DMR_ZOOM 4

//ads slowdown
#define PISTOL_AIM_SLOWDOWN 0.1
Expand Down
5 changes: 4 additions & 1 deletion code/game/mecha/equipment/weapons/weapons.dm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@

var/turf/curloc = get_turf(chassis)
var/turf/targloc = get_turf(target)

var/modifiers = params2list(params)

if (!targloc || !istype(targloc) || !curloc)
return 0
if (targloc == curloc)
Expand All @@ -48,7 +51,7 @@
spread = round((rand() - 0.5) * variance)
else
spread = round((i / projectiles_per_shot - 0.5) * variance)
A.preparePixelProjectile(target, chassis.occupant, params, spread)
A.preparePixelProjectile(target, chassis.occupant, modifiers, spread)

A.fire()
playsound(chassis, fire_sound, 50, TRUE)
Expand Down
3 changes: 2 additions & 1 deletion code/modules/mining/equipment/kinetic_crusher.dm
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,15 @@

/obj/item/kinetic_crusher/afterattack(atom/target, mob/living/user, proximity_flag, clickparams)
. = ..()
var/modifiers = params2list(clickparams)
if(!HAS_TRAIT(src, TRAIT_WIELDED))
return
if(!proximity_flag && charged)//Mark a target, or mine a tile.
var/turf/proj_turf = user.loc
if(!isturf(proj_turf))
return
var/obj/projectile/destabilizer/D = new /obj/projectile/destabilizer(proj_turf)
D.preparePixelProjectile(target, user, clickparams)
D.preparePixelProjectile(target, user, modifiers)
D.firer = user
D.hammer_synced = src
playsound(user, 'sound/weapons/plasma_cutter.ogg', 100, TRUE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,11 @@ Doesn't work on other aliens/AI.*/
if(!isturf(U) || !isturf(T))
return FALSE

var/modifiers = params2list(params)
user.visible_message("<span class='danger'>[user] spits neurotoxin!</span>", "<span class='alertalien'>You spit neurotoxin.</span>")
var/obj/projectile/bullet/neurotoxin/A = new /obj/projectile/bullet/neurotoxin(user.loc)
A.preparePixelProjectile(target, user, params)

A.preparePixelProjectile(target, user, modifiers)
A.fire()
user.newtonian_move(get_dir(U, T))
user.adjustPlasma(-p_cost)
Expand Down
5 changes: 3 additions & 2 deletions code/modules/projectiles/ammunition/_firing.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
qdel(reagents)

/obj/item/ammo_casing/proc/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread, atom/fired_from)
var/modifiers = params2list(params)
var/turf/curloc
if(user)
curloc = get_turf(user)
Expand All @@ -66,9 +67,9 @@
direct_target = target
if(!direct_target)
if(user)
BB.preparePixelProjectile(target, user, params, spread)
BB.preparePixelProjectile(target, user, modifiers, spread)
else
BB.preparePixelProjectile(target, curloc, params, spread)
BB.preparePixelProjectile(target, curloc, modifiers, spread)
BB.fire(null, direct_target)
BB = null
return TRUE
Expand Down
6 changes: 4 additions & 2 deletions code/modules/projectiles/guns/misc/beam_rifle.dm
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@
if(!istype(curloc))
return
targloc = get_turf_in_angle(lastangle, curloc, 10)
P.preparePixelProjectile(targloc, current_user, current_user.client.mouseParams, 0)
var/mouse_modifiers = params2list(current_user.client.mouseParams)
P.preparePixelProjectile(targloc, current_user, mouse_modifiers, 0)
P.fire(lastangle)

/obj/item/gun/energy/beam_rifle/process()
Expand Down Expand Up @@ -399,7 +400,8 @@
firing_dir = BB.firer.dir
if(!BB.suppressed && firing_effect_type)
new firing_effect_type(get_turf(src), firing_dir)
BB.preparePixelProjectile(target, user, params, spread)
var/modifiers = params2list(params)
BB.preparePixelProjectile(target, user, modifiers, spread)
BB.fire(gun? gun.lastangle : null, null)
BB = null
return TRUE
Expand Down
3 changes: 2 additions & 1 deletion code/modules/projectiles/guns/misc/blastcannon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
/obj/item/gun/blastcannon/afterattack(atom/target, mob/user, flag, params)
if((!bomb && bombcheck) || (!target) || (get_dist(get_turf(target), get_turf(user)) <= 2))
return ..()
var/modifiers = params2list(params)
var/power = bomb? calculate_bomb() : debug_power
power = min(power, max_power)
QDEL_NULL(bomb)
Expand All @@ -98,7 +99,7 @@
log_game("Blast wave fired from [AREACOORD(starting)] at [AREACOORD(targturf)] ([target.name]) by [key_name(user)] with power [heavy]/[medium]/[light].")
var/obj/projectile/blastwave/BW = new(loc, heavy, medium, light)
BW.hugbox = hugbox
BW.preparePixelProjectile(target, get_turf(src), params, 0)
BW.preparePixelProjectile(target, get_turf(src), modifiers, 0)
BW.fire()
name = initial(name)
desc = initial(desc)
Expand Down
115 changes: 68 additions & 47 deletions code/modules/projectiles/projectile.dm
Original file line number Diff line number Diff line change
Expand Up @@ -838,62 +838,83 @@
homing_offset_y = -homing_offset_y

//Spread is FORCED!
/obj/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
var/turf/curloc = get_turf(source)
var/turf/targloc = get_turf(target)
/obj/projectile/proc/preparePixelProjectile(atom/target, atom/source, list/modifiers = null, spread = 0)
if(!(isnull(modifiers) || islist(modifiers)))
stack_trace("WARNING: Projectile [type] fired with non-list modifiers, likely was passed click params.")
modifiers = null

var/turf/source_loc = get_turf(source)
var/turf/target_loc = get_turf(target)
if(isnull(source_loc))
stack_trace("WARNING: Projectile [type] fired from nullspace.")
qdel(src)
return FALSE

trajectory_ignore_forcemove = TRUE
forceMove(get_turf(source))
forceMove(source_loc)
trajectory_ignore_forcemove = FALSE
starting = get_turf(source)

starting = source_loc
pixel_x = source.pixel_x
pixel_y = source.pixel_y
original = target
if(targloc || !params)
yo = targloc.y - curloc.y
xo = targloc.x - curloc.x
setAngle(Get_Angle(src, targloc) + spread)
if(length(modifiers))
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, target_loc && target, modifiers)

if(isliving(source) && params)
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params)
p_x = calculated[2]
p_y = calculated[3]

setAngle(calculated[1] + spread)
else if(targloc)
yo = targloc.y - curloc.y
xo = targloc.x - curloc.x
setAngle(Get_Angle(src, targloc) + spread)
else
stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
qdel(src)
return TRUE

if(target_loc)
yo = target_loc.y - source_loc.y
xo = target_loc.x - source_loc.x
setAngle(get_angle(src, target_loc) + spread)
return TRUE

stack_trace("WARNING: Projectile [type] fired without a target or mouse parameters to aim with.")
qdel(src)
return FALSE

/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params)
var/list/modifiers = params2list(params)
var/p_x = 0
var/p_y = 0
/proc/calculate_projectile_angle_and_pixel_offsets(atom/source, atom/target, modifiers)
var/angle = 0
if(LAZYACCESS(modifiers, ICON_X))
p_x = text2num(LAZYACCESS(modifiers, ICON_X))
if(LAZYACCESS(modifiers, ICON_Y))
p_y = text2num(LAZYACCESS(modifiers, ICON_Y))
if(LAZYACCESS(modifiers, SCREEN_LOC))
//Split screen-loc up into X+Pixel_X and Y+Pixel_Y
var/list/screen_loc_params = splittext(LAZYACCESS(modifiers, SCREEN_LOC), ",")

//Split X+Pixel_X up into list(X, Pixel_X)
var/list/screen_loc_X = splittext(screen_loc_params[1],":")

//Split Y+Pixel_Y up into list(Y, Pixel_Y)
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32
var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32

//Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
var/list/screenview = getviewsize(user.client.view)
var/screenviewX = screenview[1] * world.icon_size
var/screenviewY = screenview[2] * world.icon_size

var/ox = round(screenviewX/2) - user.client.pixel_x //"origin" x
var/oy = round(screenviewY/2) - user.client.pixel_y //"origin" y
angle = ATAN2(y - oy, x - ox)
var/p_x = LAZYACCESS(modifiers, ICON_X) ? text2num(LAZYACCESS(modifiers, ICON_X)) : world.icon_size / 2 // ICON_(X|Y) are measured from the bottom left corner of the icon.
var/p_y = LAZYACCESS(modifiers, ICON_Y) ? text2num(LAZYACCESS(modifiers, ICON_Y)) : world.icon_size / 2 // This centers the target if modifiers aren't passed.

if(target)
var/turf/source_loc = get_turf(source)
var/turf/target_loc = get_turf(target)
var/dx = ((target_loc.x - source_loc.x) * world.icon_size) + (target.pixel_x - source.pixel_x) + (p_x - (world.icon_size / 2))
var/dy = ((target_loc.y - source_loc.y) * world.icon_size) + (target.pixel_y - source.pixel_y) + (p_y - (world.icon_size / 2))

angle = ATAN2(dy, dx)
return list(angle, p_x, p_y)

if(!ismob(source) || !LAZYACCESS(modifiers, SCREEN_LOC))
CRASH("Can't make trajectory calculations without a target or click modifiers and a client.")

var/mob/user = source
if(!user.client)
CRASH("Can't make trajectory calculations without a target or click modifiers and a client.")

//Split screen-loc up into X+Pixel_X and Y+Pixel_Y
var/list/screen_loc_params = splittext(LAZYACCESS(modifiers, SCREEN_LOC), ",")
//Split X+Pixel_X up into list(X, Pixel_X)
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
//Split Y+Pixel_Y up into list(Y, Pixel_Y)
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")

var/tx = (text2num(screen_loc_X[1]) - 1) * world.icon_size + text2num(screen_loc_X[2])
var/ty = (text2num(screen_loc_Y[1]) - 1) * world.icon_size + text2num(screen_loc_Y[2])

//Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
var/list/screenview = getviewsize(user.client.view)
var/screenviewX = screenview[1] * world.icon_size
var/screenviewY = screenview[2] * world.icon_size

var/ox = round(screenviewX/2) - user.client.pixel_x //"origin" x
var/oy = round(screenviewY/2) - user.client.pixel_y //"origin" y
angle = ATAN2(tx - oy, ty - ox)
return list(angle, p_x, p_y)

/obj/projectile/Destroy()
Expand Down

0 comments on commit 7398a64

Please sign in to comment.