Files
Paradise/code/controllers/subsystem/SSthrowing.dm
HMBGERDO f9f82fd418 Thrown mobs cant move until the throw ends (#23775)
* if you being throwed, you're not moving

* throw block_movement variable

* forgot arg here

* tether might keep movement

* Update code/controllers/subsystem/SSthrowing.dm

Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>

---------

Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
2024-01-28 17:18:13 -05:00

161 lines
4.7 KiB
Plaintext

#define MAX_THROWING_DIST 512 // 2 z-levels on default width
#define MAX_TICKS_TO_MAKE_UP 3 //how many missed ticks will we attempt to make up for this run.
SUBSYSTEM_DEF(throwing)
name = "Throwing"
priority = FIRE_PRIORITY_THROWING
wait = 1
flags = SS_NO_INIT|SS_KEEP_TIMING|SS_TICKER
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
offline_implications = "Thrown objects may not react properly. Shuttle call recommended."
cpu_display = SS_CPUDISPLAY_LOW
var/list/currentrun
var/list/processing = list()
/datum/controller/subsystem/throwing/get_stat_details()
return "P:[length(processing)]"
/datum/controller/subsystem/throwing/get_metrics()
. = ..()
var/list/cust = list()
cust["processing"] = length(processing)
.["custom"] = cust
/datum/controller/subsystem/throwing/fire(resumed = 0)
if(!resumed)
src.currentrun = processing.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(length(currentrun))
var/atom/movable/AM = currentrun[currentrun.len]
var/datum/thrownthing/TT = currentrun[AM]
currentrun.len--
if(!AM || !TT)
processing -= AM
if(MC_TICK_CHECK)
return
continue
TT.tick()
if(MC_TICK_CHECK)
return
currentrun = null
/datum/thrownthing
var/atom/movable/thrownthing
var/atom/target
var/turf/target_turf
var/init_dir
var/maxrange
var/speed
var/mob/thrower
var/diagonals_first
var/dist_travelled = 0
var/start_time
var/dist_x
var/dist_y
var/dx
var/dy
var/force = MOVE_FORCE_DEFAULT
var/pure_diagonal
var/diagonal_error
var/datum/callback/callback
var/paused = FALSE
var/delayed_time = 0
var/last_move = 0
///When this variable is false, non dense mobs will be hit by a thrown item. useful for things that you dont want to be cheesed by crawling, EG. gravitational anomalies
var/dodgeable = TRUE
/// Can a thrown mob move themselves to stop the throw?
var/block_movement = TRUE
/datum/thrownthing/proc/tick()
var/atom/movable/AM = thrownthing
if(!isturf(AM.loc) || !AM.throwing)
finalize()
return
if(paused)
delayed_time += world.time - last_move
return
if(dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept
finalize()
return
var/atom/step
last_move = world.time
//calculate how many tiles to move, making up for any missed ticks.
var/tilestomove = CEILING(min(((((world.time + world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed * MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1)
while(tilestomove-- > 0)
if((dist_travelled >= maxrange || AM.loc == target_turf) && has_gravity(AM, AM.loc))
hitcheck() //Just to be sure
finalize()
return
if(dist_travelled <= max(dist_x, dist_y)) //if we haven't reached the target yet we home in on it, otherwise we use the initial direction
step = get_step(AM, get_dir(AM, target_turf))
else
step = get_step(AM, init_dir)
if(!pure_diagonal && !diagonals_first) // not a purely diagonal trajectory and we don't want all diagonal moves to be done first
if(diagonal_error >= 0 && max(dist_x, dist_y) - dist_travelled != 1) //we do a step forward unless we're right before the target
step = get_step(AM, dx)
diagonal_error += (diagonal_error < 0) ? dist_x / 2 : -dist_y
if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
finalize()
return
AM.Move(step, get_dir(AM, step))
dist_travelled++
if(dist_travelled > MAX_THROWING_DIST)
finalize()
return
/datum/thrownthing/proc/finalize(hit = FALSE, target = null)
set waitfor = 0
SSthrowing.processing -= thrownthing
//done throwing, either because it hit something or it finished moving
thrownthing.throwing = null
if(!hit)
for(var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on.
var/atom/A = thing
if(A == target)
hit = 1
thrownthing.throw_impact(A, src)
break
if(!hit)
thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground.
thrownthing.newtonian_move(init_dir)
else
thrownthing.newtonian_move(init_dir)
if(target)
thrownthing.throw_impact(target, src, speed)
if(callback)
callback.Invoke()
SEND_SIGNAL(thrownthing, COMSIG_MOVABLE_THROW_LANDED, src)
thrownthing.end_throw()
/datum/thrownthing/proc/hit_atom(atom/A)
finalize(hit = TRUE, target = A)
/datum/thrownthing/proc/hitcheck()
for(var/thing in get_turf(thrownthing))
var/atom/movable/AM = thing
if(AM == thrownthing || AM == thrower)
continue
if((AM.density || isliving(AM) && !dodgeable && !HAS_TRAIT(AM, TRAIT_DODGE_ALL_OBJECTS)) && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags & ON_BORDER))
finalize(hit = TRUE, target = AM)
return TRUE