Merge pull request #4494 from Citadel-Station-13/upstream-merge-32433
[MIRROR] [READY]Refactors projectile trajectories, fixes piercing projectile inaccuracy and beam rifle visual deflections
This commit is contained in:
@@ -400,7 +400,8 @@
|
||||
|
||||
/obj/item/gun/dropped(mob/user)
|
||||
..()
|
||||
zoom(user,FALSE)
|
||||
if(zoomed)
|
||||
zoom(user,FALSE)
|
||||
if(azoom)
|
||||
azoom.Remove(user)
|
||||
if(alight)
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
#define ZOOM_LOCK_CENTER_VIEW 2
|
||||
#define ZOOM_LOCK_OFF 3
|
||||
|
||||
#define ZOOM_SPEED_STEP 0
|
||||
#define ZOOM_SPEED_INSTANT 1
|
||||
|
||||
#define AUTOZOOM_PIXEL_STEP_FACTOR 48
|
||||
|
||||
#define AIMING_BEAM_ANGLE_CHANGE_THRESHOLD 0.1
|
||||
@@ -45,7 +42,7 @@
|
||||
var/lastangle = 0
|
||||
var/aiming_lastangle = 0
|
||||
var/mob/current_user = null
|
||||
var/obj/effect/projectile_beam/current_tracer
|
||||
var/list/obj/effect/projectile_beam/current_tracers
|
||||
|
||||
var/structure_piercing = 2 //Amount * 2. For some reason structures aren't respecting this unless you have it doubled. Probably with the objects in question's Bump() code instead of this but I'll deal with this later.
|
||||
var/structure_bleed_coeff = 0.7
|
||||
@@ -69,9 +66,8 @@
|
||||
//ZOOMING
|
||||
var/zoom_current_view_increase = 0
|
||||
var/zoom_target_view_increase = 10
|
||||
var/zoom_speed = ZOOM_SPEED_STEP
|
||||
var/zooming = FALSE
|
||||
var/zoom_lock = ZOOM_LOCK_AUTOZOOM_FREEMOVE
|
||||
var/zoom_lock = ZOOM_LOCK_OFF
|
||||
var/zooming_angle
|
||||
var/current_zoom_x = 0
|
||||
var/current_zoom_y = 0
|
||||
@@ -80,7 +76,6 @@
|
||||
var/static/image/charged_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_charged")
|
||||
var/static/image/drained_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_empty")
|
||||
|
||||
var/datum/action/item_action/zoom_speed_action/zoom_speed_action
|
||||
var/datum/action/item_action/zoom_lock_action/zoom_lock_action
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/debug
|
||||
@@ -103,15 +98,6 @@
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/ui_action_click(owner, action)
|
||||
if(istype(action, /datum/action/item_action/zoom_speed_action))
|
||||
zoom_speed++
|
||||
if(zoom_speed > 1)
|
||||
zoom_speed = ZOOM_SPEED_STEP
|
||||
switch(zoom_speed)
|
||||
if(ZOOM_SPEED_STEP)
|
||||
to_chat(owner, "<span class='boldnotice'>You switch [src]'s digital zoom to stepper mode.</span>")
|
||||
if(ZOOM_SPEED_INSTANT)
|
||||
to_chat(owner, "<span class='boldnotice'>You switch [src]'s digital zoom to instant mode.</span>")
|
||||
if(istype(action, /datum/action/item_action/zoom_lock_action))
|
||||
zoom_lock++
|
||||
if(zoom_lock > 3)
|
||||
@@ -135,8 +121,6 @@
|
||||
var/total_time = SSfastprocess.wait
|
||||
if(delay_override)
|
||||
total_time = delay_override
|
||||
if(zoom_speed == ZOOM_SPEED_INSTANT)
|
||||
total_time = 0
|
||||
zoom_animating = total_time
|
||||
animate(current_user.client, pixel_x = current_zoom_x, pixel_y = current_zoom_y , total_time, SINE_EASING, ANIMATION_PARALLEL)
|
||||
zoom_animating = 0
|
||||
@@ -150,18 +134,10 @@
|
||||
/obj/item/gun/energy/beam_rifle/proc/handle_zooming()
|
||||
if(!zooming || !check_user())
|
||||
return
|
||||
if(zoom_speed == ZOOM_SPEED_INSTANT)
|
||||
current_user.client.change_view(world.view + zoom_target_view_increase)
|
||||
zoom_current_view_increase = zoom_target_view_increase
|
||||
set_autozoom_pixel_offsets_immediate(zooming_angle)
|
||||
smooth_zooming()
|
||||
return
|
||||
if(zoom_current_view_increase > zoom_target_view_increase)
|
||||
return
|
||||
zoom_current_view_increase++
|
||||
current_user.client.change_view(zoom_current_view_increase + world.view)
|
||||
current_user.client.change_view(world.view + zoom_target_view_increase)
|
||||
zoom_current_view_increase = zoom_target_view_increase
|
||||
set_autozoom_pixel_offsets_immediate(zooming_angle)
|
||||
smooth_zooming(SSfastprocess.wait * zoom_target_view_increase * zoom_speed)
|
||||
smooth_zooming()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/start_zooming()
|
||||
if(zoom_lock == ZOOM_LOCK_OFF)
|
||||
@@ -169,8 +145,9 @@
|
||||
zooming = TRUE
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/stop_zooming()
|
||||
zooming = FALSE
|
||||
reset_zooming()
|
||||
if(zooming)
|
||||
zooming = FALSE
|
||||
reset_zooming()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/reset_zooming()
|
||||
if(!check_user(FALSE))
|
||||
@@ -204,14 +181,14 @@
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/Initialize()
|
||||
. = ..()
|
||||
current_tracers = list()
|
||||
START_PROCESSING(SSprojectiles, src)
|
||||
zoom_speed_action = new(src)
|
||||
zoom_lock_action = new(src)
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
set_user(null)
|
||||
QDEL_NULL(current_tracer)
|
||||
QDEL_LIST(current_tracers)
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/emp_act(severity)
|
||||
@@ -245,6 +222,7 @@
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/process()
|
||||
if(!aiming)
|
||||
last_process = world.time
|
||||
return
|
||||
check_user()
|
||||
handle_zooming()
|
||||
@@ -299,7 +277,7 @@
|
||||
set waitfor = FALSE
|
||||
aiming_time_left = aiming_time
|
||||
aiming = FALSE
|
||||
QDEL_NULL(current_tracer)
|
||||
QDEL_LIST(current_tracers)
|
||||
stop_zooming()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/proc/set_user(mob/user)
|
||||
@@ -341,7 +319,7 @@
|
||||
sync_ammo()
|
||||
afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE)
|
||||
stop_aiming()
|
||||
QDEL_NULL(current_tracer)
|
||||
QDEL_LIST(current_tracers)
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE)
|
||||
@@ -555,136 +533,103 @@
|
||||
handle_impact(target)
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/Collide(atom/target)
|
||||
paused = TRUE
|
||||
if(check_pierce(target))
|
||||
permutated += target
|
||||
return FALSE
|
||||
if(!QDELETED(target))
|
||||
cached = get_turf(target)
|
||||
paused = FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE)
|
||||
paused = TRUE
|
||||
if(!QDELETED(target))
|
||||
cached = get_turf(target)
|
||||
handle_hit(target)
|
||||
paused = FALSE
|
||||
. = ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan
|
||||
icon_state = ""
|
||||
var/tracer_type = /obj/effect/projectile_beam/tracer
|
||||
var/starting_z
|
||||
var/starting_p_x
|
||||
var/starting_p_y
|
||||
var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end.
|
||||
var/constant_tracer = FALSE
|
||||
var/travelled_p_x = 0
|
||||
var/travelled_p_y = 0
|
||||
var/tracer_spawned = FALSE
|
||||
var/beam_index
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/Destroy()
|
||||
paused = TRUE //STOP HITTING WHEN YOU'RE ALREADY BEING DELETED!
|
||||
spawn_tracer(constant_tracer)
|
||||
if(loc)
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
beam_segments[beam_index] = pcache
|
||||
generate_tracers(constant_tracer)
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/proc/spawn_tracer(put_in_rifle = FALSE)
|
||||
if(tracer_spawned)
|
||||
return
|
||||
tracer_spawned = TRUE
|
||||
//Remind me to port baystation trajectories so this shit isn't needed...
|
||||
var/pixels_travelled = round(sqrt(travelled_p_x**2 + travelled_p_y**2),1)
|
||||
var/scaling = pixels_travelled/world.icon_size
|
||||
var/midpoint_p_x = round(starting_p_x + (travelled_p_x / 2))
|
||||
var/midpoint_p_y = round(starting_p_y + (travelled_p_y / 2))
|
||||
var/tracer_px = midpoint_p_x % world.icon_size
|
||||
var/tracer_py = midpoint_p_y % world.icon_size
|
||||
var/tracer_lx = (midpoint_p_x - tracer_px) / world.icon_size
|
||||
var/tracer_ly = (midpoint_p_y - tracer_py) / world.icon_size
|
||||
var/obj/effect/projectile_beam/PB = new tracer_type(src)
|
||||
PB.apply_vars(Angle, tracer_px, tracer_py, color, scaling, locate(tracer_lx,tracer_ly,starting_z))
|
||||
if(put_in_rifle && istype(gun))
|
||||
if(gun.current_tracer)
|
||||
QDEL_NULL(gun.current_tracer)
|
||||
gun.current_tracer = PB
|
||||
else
|
||||
QDEL_IN(PB, 5)
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/Collide(atom/target)
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
. = ..()
|
||||
if(. && !QDELETED(src)) //successful touch and not destroyed.
|
||||
beam_segments[beam_index] = pcache
|
||||
beam_index = pcache
|
||||
beam_segments[beam_index] = null
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/proc/check_for_turf_edge(turf/T)
|
||||
if(!istype(T))
|
||||
return TRUE
|
||||
var/tx = T.x
|
||||
var/ty = T.y
|
||||
if(tx < 10 || tx > (world.maxx - 10) || ty < 10 || ty > (world.maxy-10))
|
||||
return TRUE
|
||||
return FALSE
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/before_z_change(turf/oldloc, turf/newloc)
|
||||
var/datum/point/pcache = trajectory.copy_to()
|
||||
beam_segments[beam_index] = pcache
|
||||
beam_index = RETURN_PRECISE_POINT(newloc)
|
||||
beam_segments[beam_index] = null
|
||||
return ..()
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/proc/generate_tracers(highlander = FALSE, cleanup = TRUE)
|
||||
set waitfor = FALSE
|
||||
if(highlander && istype(gun))
|
||||
QDEL_LIST(gun.current_tracers)
|
||||
for(var/datum/point/p in beam_segments)
|
||||
gun.current_tracers += generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 0)
|
||||
else
|
||||
for(var/datum/point/p in beam_segments)
|
||||
generate_projectile_beam_between_points(p, beam_segments[p], tracer_type, color, 5)
|
||||
if(cleanup)
|
||||
QDEL_LIST(beam_segments)
|
||||
beam_segments = null
|
||||
QDEL_NULL(beam_index)
|
||||
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/fire(setAngle, atom/direct_target) //oranges didn't let me make this a var the first time around so copypasta time
|
||||
set waitfor = 0
|
||||
set waitfor = FALSE
|
||||
var/turf/starting = get_turf(src)
|
||||
trajectory = new(starting.x, starting.y, starting.z, 0, 0, setAngle? setAngle : Angle, 33)
|
||||
if(!log_override && firer && original)
|
||||
add_logs(firer, original, "fired at", src, " [get_area(src)]")
|
||||
fired = TRUE
|
||||
if(setAngle)
|
||||
Angle = setAngle
|
||||
var/next_run = world.time
|
||||
var/old_pixel_x = pixel_x
|
||||
var/old_pixel_y = pixel_y
|
||||
var/safety = 0 //The code works fine, but... just in case...
|
||||
var/turf/c2
|
||||
var/starting_x = loc.x
|
||||
var/starting_y = loc.y
|
||||
starting_z = loc.z
|
||||
starting_p_x = starting_x * world.icon_size + pixel_x
|
||||
starting_p_y = starting_y * world.icon_size + pixel_y
|
||||
beam_segments = list() //initialize segment list with the list for the first segment
|
||||
beam_index = RETURN_PRECISE_POINT(src)
|
||||
beam_segments[beam_index] = null //record start.
|
||||
if(spread)
|
||||
Angle += (rand() - 0.5) * spread
|
||||
while(loc)
|
||||
if(paused || QDELETED(src))
|
||||
return
|
||||
if(++safety > (range * 3)) //If it's looping for way, way too long...
|
||||
qdel(src)
|
||||
stack_trace("WARNING: [type] projectile encountered infinite recursion in [__FILE__]/[__LINE__]!")
|
||||
return //Kill!
|
||||
if(spread)
|
||||
Angle += (rand() - 0.5) * spread
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
var/Pixel_x=sin(Angle)+16*sin(Angle)*2
|
||||
var/Pixel_y=cos(Angle)+16*cos(Angle)*2
|
||||
travelled_p_x += Pixel_x
|
||||
travelled_p_y += Pixel_y
|
||||
var/pixel_x_offset = old_pixel_x + Pixel_x
|
||||
var/pixel_y_offset = old_pixel_y + Pixel_y
|
||||
var/new_x = x
|
||||
var/new_y = y
|
||||
while(pixel_x_offset > 16)
|
||||
pixel_x_offset -= 32
|
||||
old_pixel_x -= 32
|
||||
new_x++// x++
|
||||
while(pixel_x_offset < -16)
|
||||
pixel_x_offset += 32
|
||||
old_pixel_x += 32
|
||||
new_x--
|
||||
while(pixel_y_offset > 16)
|
||||
pixel_y_offset -= 32
|
||||
old_pixel_y -= 32
|
||||
new_y++
|
||||
while(pixel_y_offset < -16)
|
||||
pixel_y_offset += 32
|
||||
old_pixel_y += 32
|
||||
new_y--
|
||||
pixel_x = old_pixel_x
|
||||
pixel_y = old_pixel_y
|
||||
step_towards(src, locate(new_x, new_y, z))
|
||||
next_run += max(world.tick_lag, speed)
|
||||
var/delay = next_run - world.time
|
||||
if(delay <= world.tick_lag*2)
|
||||
pixel_x = pixel_x_offset
|
||||
pixel_y = pixel_y_offset
|
||||
trajectory.increment()
|
||||
var/turf/T = trajectory.return_turf()
|
||||
if(T.z != loc.z)
|
||||
before_z_change(loc, T)
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(T)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
else
|
||||
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (delay <= 3 ? delay - 1 : delay)), flags = ANIMATION_END_NOW)
|
||||
old_pixel_x = pixel_x_offset
|
||||
old_pixel_y = pixel_y_offset
|
||||
step_towards(src, T)
|
||||
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
|
||||
|
||||
if(can_hit_target(original, permutated))
|
||||
Collide(original)
|
||||
c2 = loc
|
||||
Range()
|
||||
if(check_for_turf_edge(loc))
|
||||
spawn_tracer(constant_tracer)
|
||||
c2 = get_turf(src)
|
||||
if(istype(c2))
|
||||
cached = c2
|
||||
|
||||
@@ -704,76 +649,3 @@
|
||||
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
|
||||
qdel(src)
|
||||
return FALSE
|
||||
|
||||
/obj/effect/projectile_beam
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
layer = ABOVE_MOB_LAYER
|
||||
anchored = TRUE
|
||||
light_power = 1
|
||||
light_range = 2
|
||||
light_color = "#00ffff"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
flags_1 = ABSTRACT_1
|
||||
appearance_flags = 0
|
||||
|
||||
/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE)
|
||||
var/matrix/M
|
||||
if(!override)
|
||||
M = transform
|
||||
else
|
||||
M = new
|
||||
M.Scale(nx,ny)
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE)
|
||||
var/matrix/M
|
||||
if(!override)
|
||||
M = transform
|
||||
else
|
||||
M = new
|
||||
M.Turn(angle)
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1)
|
||||
if(angle_override && p_x && p_y && color_override && scaling)
|
||||
apply_vars(angle_override, p_x, p_y, color_override, scaling)
|
||||
return ..()
|
||||
|
||||
/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x, p_y, color_override, scaling = 1, new_loc, increment = 0)
|
||||
var/mutable_appearance/look = new(src)
|
||||
look.pixel_x = p_x
|
||||
look.pixel_y = p_y
|
||||
if(color_override)
|
||||
look.color = color_override
|
||||
appearance = look
|
||||
scale_to(1,scaling, FALSE)
|
||||
turn_to(angle_override, FALSE)
|
||||
if(!isnull(new_loc)) //If you want to null it just delete it...
|
||||
forceMove(new_loc)
|
||||
for(var/i in 1 to increment)
|
||||
pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
|
||||
pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
|
||||
|
||||
/obj/effect/projectile_beam/tracer
|
||||
icon_state = "tracer_beam"
|
||||
|
||||
/obj/effect/projectile_beam/tracer/aiming
|
||||
icon_state = "gbeam"
|
||||
|
||||
/datum/action/item_action/zoom_speed_action
|
||||
name = "Toggle Zooming Speed"
|
||||
icon_icon = 'icons/mob/actions/actions_spells.dmi'
|
||||
button_icon_state = "projectile"
|
||||
background_icon_state = "bg_tech"
|
||||
|
||||
/datum/action/item_action/zoom_lock_action
|
||||
name = "Switch Zoom Mode"
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "zoom_mode"
|
||||
background_icon_state = "bg_tech"
|
||||
|
||||
/obj/effect/projectile_beam/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/projectile_beam/singularity_act()
|
||||
return
|
||||
|
||||
@@ -31,16 +31,11 @@
|
||||
var/last_projectile_move = 0
|
||||
var/last_process = 0
|
||||
var/time_offset = 0
|
||||
var/old_pixel_x = 0
|
||||
var/old_pixel_y = 0
|
||||
var/pixel_x_increment = 0
|
||||
var/pixel_y_increment = 0
|
||||
var/pixel_x_offset = 0
|
||||
var/pixel_y_offset = 0
|
||||
var/new_x = 0
|
||||
var/new_y = 0
|
||||
var/datum/point/vector/trajectory
|
||||
var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location!
|
||||
|
||||
var/speed = 0.8 //Amount of deciseconds it takes for projectile to travel
|
||||
var/pixel_speed = 33 //pixels per move - DO NOT FUCK WITH THIS UNLESS YOU ABSOLUTELY KNOW WHAT YOU ARE DOING OR UNEXPECTED THINGS /WILL/ HAPPEN!
|
||||
var/Angle = 0
|
||||
var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle
|
||||
var/spread = 0 //amount (in degrees) of projectile spread
|
||||
@@ -48,6 +43,9 @@
|
||||
var/ricochets = 0
|
||||
var/ricochets_max = 2
|
||||
var/ricochet_chance = 30
|
||||
|
||||
var/colliding = FALSE //pause processing..
|
||||
|
||||
var/ignore_source_check = FALSE
|
||||
|
||||
var/damage = 10
|
||||
@@ -168,20 +166,28 @@
|
||||
|
||||
/obj/item/projectile/proc/vol_by_damage()
|
||||
if(src.damage)
|
||||
return CLAMP((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100
|
||||
return CLAMP((src.damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then CLAMP the value between 30 and 100
|
||||
else
|
||||
return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume
|
||||
|
||||
/obj/item/projectile/proc/on_ricochet(atom/A)
|
||||
return
|
||||
|
||||
/obj/item/projectile/Collide(atom/A)
|
||||
colliding = TRUE
|
||||
if(check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
|
||||
ricochets++
|
||||
if(A.handle_ricochet(src))
|
||||
on_ricochet(A)
|
||||
ignore_source_check = TRUE
|
||||
range = initial(range)
|
||||
return FALSE
|
||||
return TRUE
|
||||
if(firer && !ignore_source_check)
|
||||
if(A == firer || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech
|
||||
loc = A.loc
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(get_turf(A))
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
|
||||
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
|
||||
@@ -197,25 +203,32 @@
|
||||
|
||||
if(!prehit(A))
|
||||
if(forcedodge)
|
||||
loc = target_turf
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(target_turf)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
|
||||
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
|
||||
if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
|
||||
loc = target_turf
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(target_turf)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
if(A)
|
||||
permutated.Add(A)
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
else
|
||||
var/atom/alt = select_target(A)
|
||||
if(alt)
|
||||
if(!prehit(alt))
|
||||
colliding = FALSE
|
||||
return FALSE
|
||||
alt.bullet_act(src, def_zone)
|
||||
qdel(src)
|
||||
colliding = FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
|
||||
if(!A || !A.density || (A.flags_1 & ON_BORDER_1) || ismob(A) || A == original) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs or machines/structures on that tile.
|
||||
return
|
||||
@@ -246,12 +259,30 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/projectile/proc/return_predicted_turf_after_moves(moves, forced_angle) //I say predicted because there's no telling that the projectile won't change direction/location in flight.
|
||||
if(!trajectory && isnull(forced_angle) && isnull(Angle))
|
||||
return FALSE
|
||||
var/datum/point/vector/current = trajectory
|
||||
if(!current)
|
||||
var/turf/T = get_turf(src)
|
||||
current = new(T.x, T.y, T.z, pixel_x, pixel_y, isnull(forced_angle)? Angle : forced_angle, pixel_speed)
|
||||
var/datum/point/vector/v = current.return_vector_after_increments(moves)
|
||||
return v.return_turf()
|
||||
|
||||
/obj/item/projectile/proc/return_pathing_turfs_in_moves(moves, forced_angle)
|
||||
var/turf/current = get_turf(src)
|
||||
var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle)
|
||||
return getline(current, ending)
|
||||
|
||||
/obj/item/projectile/proc/before_z_change(turf/oldloc, turf/newloc)
|
||||
return
|
||||
|
||||
/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
|
||||
return TRUE //Bullets don't drift in space
|
||||
|
||||
/obj/item/projectile/process()
|
||||
last_process = world.time
|
||||
if(!loc || !fired)
|
||||
if(!loc || !fired || !trajectory)
|
||||
fired = FALSE
|
||||
return PROCESS_KILL
|
||||
if(paused || !isturf(loc))
|
||||
@@ -285,73 +316,70 @@
|
||||
setAngle(angle)
|
||||
if(spread)
|
||||
setAngle(Angle + ((rand() - 0.5) * spread))
|
||||
var/turf/starting = get_turf(src)
|
||||
if(isnull(Angle)) //Try to resolve through offsets if there's no angle set.
|
||||
var/turf/starting = get_turf(src)
|
||||
if(isnull(xo) || isnull(yo))
|
||||
stack_trace("WARNING: Projectile [type] deleted due to being unable to resolve a target after angle was null!")
|
||||
qdel(src)
|
||||
return
|
||||
var/turf/target = locate(CLAMP(starting + xo, 1, world.maxx), CLAMP(starting + yo, 1, world.maxy), starting.z)
|
||||
setAngle(Get_Angle(src, target))
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
old_pixel_x = pixel_x
|
||||
old_pixel_y = pixel_y
|
||||
trajectory = new(starting.x, starting.y, starting.z, 0, 0, Angle, pixel_speed)
|
||||
last_projectile_move = world.time
|
||||
fired = TRUE
|
||||
if(!isprocessing)
|
||||
START_PROCESSING(SSprojectiles, src)
|
||||
pixel_move(1) //move it now!
|
||||
|
||||
/obj/item/projectile/proc/setAngle(new_angle) //wrapper for overrides.
|
||||
Angle = new_angle
|
||||
return TRUE
|
||||
|
||||
/obj/item/projectile/proc/pixel_move(moves)
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
if(trajectory)
|
||||
trajectory.set_angle(new_angle)
|
||||
return TRUE
|
||||
|
||||
pixel_x_increment=round((sin(Angle)+16*sin(Angle)*2), 1) //round() is a floor operation when only one argument is supplied, we don't want that here
|
||||
pixel_y_increment=round((cos(Angle)+16*cos(Angle)*2), 1)
|
||||
pixel_x_offset = old_pixel_x + pixel_x_increment
|
||||
pixel_y_offset = old_pixel_y + pixel_y_increment
|
||||
new_x = x
|
||||
new_y = y
|
||||
/obj/item/projectile/forceMove(atom/target)
|
||||
. = ..()
|
||||
if(trajectory && !trajectory_ignore_forcemove && isturf(target))
|
||||
trajectory.initialize_location(target.x, target.y, target.z, 0, 0)
|
||||
|
||||
while(pixel_x_offset > 16)
|
||||
pixel_x_offset -= 32
|
||||
old_pixel_x -= 32
|
||||
new_x++// x++
|
||||
while(pixel_x_offset < -16)
|
||||
pixel_x_offset += 32
|
||||
old_pixel_x += 32
|
||||
new_x--
|
||||
while(pixel_y_offset > 16)
|
||||
pixel_y_offset -= 32
|
||||
old_pixel_y -= 32
|
||||
new_y++
|
||||
while(pixel_y_offset < -16)
|
||||
pixel_y_offset += 32
|
||||
old_pixel_y += 32
|
||||
new_y--
|
||||
/obj/item/projectile/proc/pixel_move(moves, trajectory_multiplier = 1)
|
||||
if(!loc || !trajectory)
|
||||
return
|
||||
last_projectile_move = world.time
|
||||
if(!nondirectional_sprite)
|
||||
var/matrix/M = new
|
||||
M.Turn(Angle)
|
||||
transform = M
|
||||
trajectory.increment(trajectory_multiplier)
|
||||
var/turf/T = trajectory.return_turf()
|
||||
if(T.z != loc.z)
|
||||
before_z_change(loc, T)
|
||||
trajectory_ignore_forcemove = TRUE
|
||||
forceMove(T)
|
||||
trajectory_ignore_forcemove = FALSE
|
||||
pixel_x = trajectory.return_px()
|
||||
pixel_y = trajectory.return_py()
|
||||
else
|
||||
step_towards(src, T)
|
||||
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier
|
||||
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier
|
||||
animate(src, pixel_x = trajectory.return_px(), pixel_y = trajectory.return_py(), time = 1, flags = ANIMATION_END_NOW)
|
||||
|
||||
step_towards(src, locate(new_x, new_y, z))
|
||||
pixel_x = old_pixel_x
|
||||
pixel_y = old_pixel_y
|
||||
animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = 1, flags = ANIMATION_END_NOW)
|
||||
old_pixel_x = pixel_x_offset
|
||||
old_pixel_y = pixel_y_offset
|
||||
if(can_hit_target(original, permutated))
|
||||
Collide(original)
|
||||
Range()
|
||||
last_projectile_move = world.time
|
||||
|
||||
//Returns true if the target atom is on our current turf and above the right layer
|
||||
/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
|
||||
if(target && (target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target))
|
||||
if(loc == get_turf(target))
|
||||
if(!(target in passthrough))
|
||||
return TRUE
|
||||
return FALSE
|
||||
return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
|
||||
|
||||
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
|
||||
var/turf/curloc = get_turf(source)
|
||||
@@ -362,7 +390,8 @@
|
||||
if(targloc || !params)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
|
||||
setAngle(Get_Angle(src, targloc))
|
||||
|
||||
if(isliving(source) && params)
|
||||
var/list/calculated = calculate_projectile_angle_and_pixel_offsets(source, params)
|
||||
p_x = calculated[2]
|
||||
@@ -372,8 +401,13 @@
|
||||
setAngle(calculated[1] + spread)
|
||||
else
|
||||
setAngle(calculated[1])
|
||||
else
|
||||
else if(targloc)
|
||||
yo = targloc.y - curloc.y
|
||||
xo = targloc.x - curloc.x
|
||||
setAngle(Get_Angle(src, targloc))
|
||||
else
|
||||
stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
|
||||
qdel(src)
|
||||
|
||||
/proc/calculate_projectile_angle_and_pixel_offsets(mob/user, params)
|
||||
var/list/mouse_control = params2list(params)
|
||||
|
||||
@@ -19,7 +19,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
|
||||
neigbours[A] = src
|
||||
|
||||
/datum/space_level/proc/set_neigbours(list/L)
|
||||
for(var/datum/point/P in L)
|
||||
for(var/datum/space_transition_point/P in L)
|
||||
if(P.x == xi)
|
||||
if(P.y == yi+1)
|
||||
neigbours[TEXT_NORTH] = P.spl
|
||||
@@ -35,13 +35,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
|
||||
neigbours[TEXT_WEST] = P.spl
|
||||
P.spl.neigbours[TEXT_EAST] = src
|
||||
|
||||
/datum/point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
|
||||
/datum/space_transition_point //this is explicitly utilitarian datum type made specially for the space map generation and are absolutely unusable for anything else
|
||||
var/list/neigbours = list()
|
||||
var/x
|
||||
var/y
|
||||
var/datum/space_level/spl
|
||||
|
||||
/datum/point/New(nx, ny, list/point_grid)
|
||||
/datum/space_transition_point/New(nx, ny, list/point_grid)
|
||||
if(!point_grid)
|
||||
qdel(src)
|
||||
return
|
||||
@@ -55,7 +55,7 @@ GLOBAL_LIST_EMPTY(z_levels_list)
|
||||
return
|
||||
point_grid[x][y] = src
|
||||
|
||||
/datum/point/proc/set_neigbours(list/grid)
|
||||
/datum/space_transition_point/proc/set_neigbours(list/grid)
|
||||
var/max_X = grid.len
|
||||
var/list/max_Y = grid[1]
|
||||
max_Y = max_Y.len
|
||||
@@ -86,13 +86,13 @@ GLOBAL_LIST_EMPTY(z_levels_list)
|
||||
k++
|
||||
var/list/point_grid[conf_set_len*2+1][conf_set_len*2+1]
|
||||
var/list/grid = list()
|
||||
var/datum/point/P
|
||||
var/datum/space_transition_point/P
|
||||
for(var/i = 1, i<=conf_set_len*2+1, i++)
|
||||
for(var/j = 1, j<=conf_set_len*2+1, j++)
|
||||
P = new/datum/point(i,j, point_grid)
|
||||
P = new/datum/space_transition_point(i,j, point_grid)
|
||||
point_grid[i][j] = P
|
||||
grid.Add(P)
|
||||
for(var/datum/point/pnt in grid)
|
||||
for(var/datum/space_transition_point/pnt in grid)
|
||||
pnt.set_neigbours(point_grid)
|
||||
P = point_grid[conf_set_len+1][conf_set_len+1]
|
||||
var/list/possible_points = list()
|
||||
|
||||
Reference in New Issue
Block a user