diff --git a/code/game/objects/structures/deployable_turret.dm b/code/game/objects/structures/deployable_turret.dm index 01ea1a1b120..90303e727c7 100644 --- a/code/game/objects/structures/deployable_turret.dm +++ b/code/game/objects/structures/deployable_turret.dm @@ -116,7 +116,7 @@ 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) + calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(controller, target_turf, modifiers) /obj/machinery/deployable_turret/proc/direction_track(mob/user, atom/targeted) if(user.incapacitated()) @@ -251,6 +251,6 @@ . = ..() 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.calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(user, targeted_atom, modifiers) E.direction_track(user, targeted_atom) E.checkfire(targeted_atom, user) diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 0ac6ef17530..fd376ee9cee 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -550,7 +550,7 @@ user.pixel_x = 8 user.pixel_y = -12 - emitter.last_projectile_params = calculate_projectile_angle_and_pixel_offsets(user, clickparams) + emitter.last_projectile_params = calculate_projectile_angle_and_pixel_offsets(user, null, clickparams) if(emitter.charge >= 10 && world.time > delay) emitter.charge -= 10 diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 5d2b59f47a0..7e8321e1e29 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -860,65 +860,107 @@ if(prob(50)) homing_offset_y = -homing_offset_y -//Spread is FORCED! -/obj/projectile/proc/preparePixelProjectile(atom/target, atom/source, modifiers, spread = 0) - if(!isnull(modifiers) && !islist(modifiers)) +/** + * Aims the projectile at a target. + * + * Must be passed at least one of a target or a list of click parameters. + * If only passed the click modifiers the source atom must be a mob with a client. + * + * Arguments: + * - [target][/atom]: (Optional) The thing that the projectile will be aimed at. + * - [source][/atom]: The initial location of the projectile or the thing firing it. + * - [modifiers][/list]: (Optional) A list of click parameters to apply to this operation. + * - deviation: (Optional) How the trajectory should deviate from the target in degrees. + * - //Spread is FORCED! + */ +/obj/projectile/proc/preparePixelProjectile(atom/target, atom/source, list/modifiers = null, deviation = 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 - var/turf/curloc = get_turf(source) - var/turf/targloc = get_turf(target) trajectory_ignore_forcemove = TRUE - forceMove(get_turf(source)) + forceMove(source_loc) trajectory_ignore_forcemove = FALSE - starting = get_turf(source) - original = target - if(targloc || !length(modifiers)) - yo = targloc.y - curloc.y - xo = targloc.x - curloc.x - set_angle(get_angle(src, targloc) + spread) - if(isliving(source) && length(modifiers)) - var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, modifiers) + starting = source_loc + original = target + if(length(modifiers)) + var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, target_loc && target, modifiers) + p_x = calculated[2] p_y = calculated[3] + set_angle(calculated[1] + deviation) + return TRUE - set_angle(calculated[1] + spread) - else if(targloc) - yo = targloc.y - curloc.y - xo = targloc.x - curloc.x - set_angle(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) + if(target_loc) + yo = target_loc.y - source_loc.y + xo = target_loc.x - source_loc.x + set_angle(get_angle(src, target_loc) + deviation) + return TRUE -/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, modifiers) + stack_trace("WARNING: Projectile [type] fired without a target or mouse parameters to aim with.") + qdel(src) + return FALSE + +/** + * Calculates the pixel offsets and angle that a projectile should be launched at. + * + * Arguments: + * - [source][/atom]: The thing that the projectile is being shot from. + * - [target][/atom]: (Optional) The thing that the projectile is being shot at. + * - If this is not provided the source atom must be a mob with a client. + * - [modifiers][/list]: A list of click parameters used to modify the shot angle. + */ +/proc/calculate_projectile_angle_and_pixel_offsets(atom/source, atom/target, modifiers) var/p_x = 0 var/p_y = 0 var/angle = 0 if(LAZYACCESS(modifiers, ICON_X)) - p_x = text2num(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), ",") + p_y += text2num(LAZYACCESS(modifiers, ICON_Y)) - //Split X+Pixel_X up into list(X, Pixel_X) - var/list/screen_loc_X = splittext(screen_loc_params[1],":") + 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 + var/dy = ((target_loc.y - source_loc.y) * world.icon_size) + target.pixel_y - //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 + angle = ATAN2(dy, dx) + return list(angle, p_x, p_y) - //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 + 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.") - 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) + //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()