mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-01-08 08:31:53 +00:00
* refactor: Movement cross/uncross implementation.
* wrong var name
* fix unit tests dropping PDAs into nowhere
* Add documentation.
* remove unused constants
* say which procs are off limits
* fix simpleanimal z change runtime
* helps not to leave merge conflicts
* kill me
* fix typecast
* fix projectile/table collision
* treadmills don't cause MC to crash anymore
* connect_loc is appropriate here
* fix windoors and teleporters
* fix bonfires and clarify docs
* fix proximity sensors
Tested with sensors in crates, sensors in modsuits
Tested new proximity component with firing projectiles at singularity
Tested new proximity component with portable flashes
Tested new proximity component with facehuggers
* lint
* fix: polarized access helper false positives
* Revert "fix: polarized access helper false positives"
This reverts commit 9814f98cf6.
* hopefully the right change for mindflayer steam
* Changes following cameras
* fix glass table collision
* appears to fix doorspam
* fix ore bags not picking up ore
* fix signatures of /Exited
* remove debug log
* remove duplicate signal registrar
* fix emptying bags into locations
* I don't trust these nested Move calls
* use connect_loc for upgraded resonator fields
* use moveToNullspace
* fix spiderweb crossing
* fix pass checking for windows from a tile off
* fix bluespace closet/transparency issues
* fix mechs not interacting with doors and probably other things
* fix debug
* fix telepete
* add some docs
* stop trying to shoehorn prox monitor into cards
* I should make sure things build
* kill override signal warning
* undef signal
* not many prox monitors survive going off like this
* small fixes to storage
* make moving wormholes respect signals
* use correct signals for pulse demon
* fix pulse heart too
* fix smoke signals
* may have fucked singulo projectile swerve
* fix singulo projectile arcing
* remove duplicate define
* just look at it
* hopefully last cleanups of incorrect signal usage
* fix squeaking
* may god have mercy on my soul
* Apply suggestions from code review
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Signed-off-by: warriorstar-orion <orion@snowfrost.garden>
* lewc review
* Apply suggestions from code review
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Signed-off-by: warriorstar-orion <orion@snowfrost.garden>
* burza review
* fix bad args for grenade assemblies
* Update code/__DEFINES/is_helpers.dm
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Signed-off-by: warriorstar-orion <orion@snowfrost.garden>
---------
Signed-off-by: warriorstar-orion <orion@snowfrost.garden>
Co-authored-by: DGamerL <daan.lyklema@gmail.com>
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
515 lines
14 KiB
Plaintext
515 lines
14 KiB
Plaintext
/mob/CanPass(atom/movable/mover, border_dir)
|
|
var/horizontal = FALSE
|
|
if(isliving(src))
|
|
var/mob/living/L = src
|
|
horizontal = IS_HORIZONTAL(L)
|
|
|
|
if(isprojectile(mover))
|
|
return projectile_hit_check(mover)
|
|
if(mover.throwing)
|
|
return (!density || horizontal || (mover.throwing?.get_thrower() == src))
|
|
if(mover.checkpass(PASSMOB))
|
|
return 1
|
|
if(buckled == mover)
|
|
return TRUE
|
|
if(ismob(mover))
|
|
var/mob/moving_mob = mover
|
|
if(src in moving_mob.grab_do_not_move)
|
|
return TRUE
|
|
if(mover in buckled_mobs)
|
|
return TRUE
|
|
return (!mover.density || !density || horizontal)
|
|
|
|
/mob/proc/projectile_hit_check(obj/item/projectile/P)
|
|
return !(P.always_hit_living_nondense && (stat != DEAD)) && !density
|
|
|
|
/client/verb/toggle_throw_mode()
|
|
set hidden = 1
|
|
if(iscarbon(mob))
|
|
var/mob/living/carbon/C = mob
|
|
C.toggle_throw_mode()
|
|
else
|
|
to_chat(usr, "<span class='danger'>This mob type cannot throw items.</span>")
|
|
|
|
/client/proc/Move_object(direct)
|
|
if(mob && mob.control_object)
|
|
if(mob.control_object.density)
|
|
step(mob.control_object, direct)
|
|
if(!mob.control_object)
|
|
return
|
|
mob.control_object.setDir(direct)
|
|
else
|
|
mob.control_object.forceMove(get_step(mob.control_object, direct))
|
|
return
|
|
|
|
#define CONFUSION_LIGHT_COEFFICIENT 0.15
|
|
#define CONFUSION_HEAVY_COEFFICIENT 0.075
|
|
#define CONFUSION_MAX 80 SECONDS
|
|
|
|
|
|
/client/Move(n, direct)
|
|
if(world.time < move_delay)
|
|
return
|
|
|
|
input_data.desired_move_dir_add = NONE
|
|
input_data.desired_move_dir_sub = NONE
|
|
|
|
var/old_move_delay = move_delay
|
|
move_delay = world.time + world.tick_lag //this is here because Move() can now be called multiple times per tick
|
|
if(!mob || !mob.loc)
|
|
return 0
|
|
|
|
if(!n || !direct) // why did we never check this before?
|
|
return FALSE
|
|
|
|
if(mob.notransform)
|
|
return 0 //This is sota the goto stop mobs from moving var
|
|
|
|
if(mob.throwing && mob.throwing.block_movement)
|
|
return
|
|
|
|
if(mob.control_object)
|
|
return Move_object(direct)
|
|
|
|
if(!isliving(mob))
|
|
return mob.Move(n, direct)
|
|
|
|
if(mob.stat == DEAD)
|
|
mob.ghostize()
|
|
return 0
|
|
|
|
if(moving)
|
|
return 0
|
|
|
|
var/mob/living/living_mob = null
|
|
if(isliving(mob))
|
|
living_mob = mob
|
|
if(living_mob.incorporeal_move)//Move though walls
|
|
Process_Incorpmove(direct)
|
|
return
|
|
|
|
if(mob.remote_control) //we're controlling something, our movement is relayed to it
|
|
return mob.remote_control.relaymove(mob, direct)
|
|
|
|
if(isAI(mob))
|
|
if(istype(mob.loc, /obj/item/aicard))
|
|
var/obj/O = mob.loc
|
|
return O.relaymove(mob, direct) // aicards have special relaymove stuff
|
|
return AIMove(n, direct, mob)
|
|
|
|
|
|
if(Process_Grab())
|
|
return
|
|
|
|
if(mob.buckled) //if we're buckled to something, tell it we moved.
|
|
return mob.buckled.relaymove(mob, direct)
|
|
|
|
if(living_mob && !(living_mob.mobility_flags & MOBILITY_MOVE))
|
|
return
|
|
|
|
if(!mob.lastarea)
|
|
mob.lastarea = get_area(mob.loc)
|
|
|
|
if(isobj(mob.loc) || ismob(mob.loc)) //Inside an object, tell it we moved
|
|
var/atom/O = mob.loc
|
|
return O.relaymove(mob, direct)
|
|
|
|
if(!mob.Process_Spacemove(direct))
|
|
return 0
|
|
|
|
if(mob.restrained()) // Why being pulled while cuffed prevents you from moving
|
|
for(var/mob/M in orange(1, mob))
|
|
if(M.pulling == mob)
|
|
if(!M.incapacitated() && mob.Adjacent(M))
|
|
to_chat(src, "<span class='warning'>You're restrained! You can't move!</span>")
|
|
move_delay = world.time + 10
|
|
return 0
|
|
else
|
|
M.stop_pulling()
|
|
|
|
|
|
var/delay = mob.movement_delay()
|
|
if(old_move_delay + world.tick_lag > world.time)
|
|
move_delay = old_move_delay
|
|
else
|
|
move_delay = world.time
|
|
mob.last_movement = world.time
|
|
|
|
delay = TICKS2DS(-round(-(DS2TICKS(delay)))) //Rounded to the next tick in equivalent ds
|
|
|
|
|
|
if(locate(/obj/item/grab, mob))
|
|
if(!isalienhunter(mob)) // i hate grab code
|
|
delay += 7
|
|
|
|
if(istype(living_mob))
|
|
var/newdir = NONE
|
|
var/confusion = living_mob.get_confusion()
|
|
if(confusion > CONFUSION_MAX)
|
|
newdir = pick(GLOB.alldirs)
|
|
else if(prob(confusion * CONFUSION_HEAVY_COEFFICIENT))
|
|
newdir = angle2dir(dir2angle(direct) + pick(90, -90))
|
|
else if(prob(confusion * CONFUSION_LIGHT_COEFFICIENT))
|
|
newdir = angle2dir(dir2angle(direct) + pick(45, -45))
|
|
if(newdir)
|
|
direct = newdir
|
|
n = get_step(mob, direct)
|
|
|
|
mob.last_movement_dir = direct
|
|
|
|
var/prev_pulling_loc = null
|
|
if(mob.pulling)
|
|
prev_pulling_loc = mob.pulling.loc
|
|
|
|
if(!(direct & (direct - 1))) // cardinal direction
|
|
. = mob.SelfMove(n, direct, delay)
|
|
else // diagonal movements take longer
|
|
var/diag_delay = delay * SQRT_2
|
|
. = mob.SelfMove(n, direct, diag_delay)
|
|
if(mob.loc == n)
|
|
// only incur the extra delay if the move was *actually* diagonal
|
|
// There would be a bit of visual jank if we try to walk diagonally next to a wall
|
|
// and the move ends up being cardinal, rather than diagonal,
|
|
// but that's better than it being jank on every *successful* diagonal move.
|
|
delay = diag_delay
|
|
move_delay += delay
|
|
|
|
if(mob.pulledby)
|
|
mob.pulledby.stop_pulling()
|
|
|
|
if(prev_pulling_loc && mob.pulling?.face_while_pulling && (mob.pulling.loc != prev_pulling_loc))
|
|
mob.setDir(get_dir(mob, mob.pulling)) // Face welding tanks and stuff when pulling
|
|
|
|
if(mob && . && mob.throwing)
|
|
mob.throwing.finalize(FALSE)
|
|
|
|
#undef CONFUSION_LIGHT_COEFFICIENT
|
|
#undef CONFUSION_HEAVY_COEFFICIENT
|
|
#undef CONFUSION_MAX
|
|
|
|
|
|
/mob/proc/SelfMove(turf/n, direct, movetime)
|
|
return Move(n, direct, movetime)
|
|
|
|
///Process_Grab()
|
|
///Called by client/Move()
|
|
///Checks to see if you are being grabbed and if so attemps to break it
|
|
/client/proc/Process_Grab()
|
|
if(length(mob.grabbed_by))
|
|
if(mob.incapacitated(FALSE, TRUE)) // Can't break out of grabs if you're incapacitated
|
|
return TRUE
|
|
if(HAS_TRAIT(mob, TRAIT_IMMOBILIZED))
|
|
return TRUE //You can't move, so you can't break it by trying to move.
|
|
var/list/grabbing = list()
|
|
|
|
if(istype(mob.l_hand, /obj/item/grab))
|
|
var/obj/item/grab/G = mob.l_hand
|
|
grabbing += G.affecting
|
|
|
|
if(istype(mob.r_hand, /obj/item/grab))
|
|
var/obj/item/grab/G = mob.r_hand
|
|
grabbing += G.affecting
|
|
|
|
for(var/X in mob.grabbed_by)
|
|
var/obj/item/grab/G = X
|
|
switch(G.state)
|
|
|
|
if(GRAB_PASSIVE)
|
|
if(!grabbing.Find(G.assailant)) //moving always breaks a passive grab unless we are also grabbing our grabber.
|
|
qdel(G)
|
|
|
|
if(GRAB_AGGRESSIVE)
|
|
move_delay = world.time + 10
|
|
if(!prob(25))
|
|
return TRUE
|
|
mob.visible_message("<span class='danger'>[mob] has broken free of [G.assailant]'s grip!</span>")
|
|
qdel(G)
|
|
|
|
if(GRAB_NECK)
|
|
move_delay = world.time + 10
|
|
if(!prob(5))
|
|
return TRUE
|
|
mob.visible_message("<span class='danger'>[mob] has broken free of [G.assailant]'s headlock!</span>")
|
|
qdel(G)
|
|
return FALSE
|
|
|
|
|
|
///Process_Incorpmove
|
|
///Called by client/Move()
|
|
///Allows mobs to run though walls
|
|
/client/proc/Process_Incorpmove(direct)
|
|
var/turf/mobloc = get_turf(mob)
|
|
if(!isliving(mob))
|
|
return
|
|
var/mob/living/L = mob
|
|
switch(L.incorporeal_move)
|
|
if(INCORPOREAL_MOVE_NORMAL)
|
|
L.forceMove(get_step(L, direct))
|
|
L.dir = direct
|
|
if(INCORPOREAL_MOVE_NINJA)
|
|
if(prob(50))
|
|
var/locx
|
|
var/locy
|
|
switch(direct)
|
|
if(NORTH)
|
|
locx = mobloc.x
|
|
locy = (mobloc.y+2)
|
|
if(locy>world.maxy)
|
|
return
|
|
if(SOUTH)
|
|
locx = mobloc.x
|
|
locy = (mobloc.y-2)
|
|
if(locy<1)
|
|
return
|
|
if(EAST)
|
|
locy = mobloc.y
|
|
locx = (mobloc.x+2)
|
|
if(locx>world.maxx)
|
|
return
|
|
if(WEST)
|
|
locy = mobloc.y
|
|
locx = (mobloc.x-2)
|
|
if(locx<1)
|
|
return
|
|
else
|
|
return
|
|
L.forceMove(locate(locx,locy,mobloc.z))
|
|
spawn(0)
|
|
var/limit = 2//For only two trailing shadows.
|
|
for(var/turf/T in get_line(mobloc, L.loc))
|
|
new /obj/effect/temp_visual/dir_setting/ninja/shadow(T, L.dir)
|
|
limit--
|
|
if(limit<=0)
|
|
break
|
|
else
|
|
new /obj/effect/temp_visual/dir_setting/ninja/shadow(mobloc, L.dir)
|
|
L.forceMove(get_step(L, direct))
|
|
L.dir = direct
|
|
if(INCORPOREAL_MOVE_HOLY_BLOCK)
|
|
var/turf/simulated/floor/stepTurf = get_step(L, direct)
|
|
if(stepTurf.flags & BLESSED_TILE)
|
|
to_chat(L, "<span class='warning'>Holy energies block your path.</span>")
|
|
L.notransform = TRUE
|
|
spawn(2)
|
|
L.notransform = FALSE
|
|
else
|
|
L.forceMove(get_step(L, direct))
|
|
L.dir = direct
|
|
return TRUE
|
|
|
|
|
|
///Process_Spacemove
|
|
///Called by /client/Move()
|
|
///For moving in space
|
|
///Return 1 for movement 0 for none
|
|
/mob/Process_Spacemove(movement_dir = 0)
|
|
if(..())
|
|
return 1
|
|
var/atom/movable/backup = get_spacemove_backup(movement_dir)
|
|
if(backup)
|
|
if(istype(backup) && movement_dir && !backup.anchored)
|
|
var/opposite_dir = turn(movement_dir, 180)
|
|
if(backup.newtonian_move(opposite_dir)) //You're pushing off something movable, so it moves
|
|
to_chat(src, "<span class='notice'>You push off of [backup] to propel yourself.</span>")
|
|
return 1
|
|
return 0
|
|
|
|
/mob/get_spacemove_backup(movement_dir)
|
|
for(var/A in orange(1, get_turf(src)))
|
|
if(isarea(A))
|
|
continue
|
|
else if(isturf(A))
|
|
var/turf/turf = A
|
|
if(isspaceturf(turf))
|
|
continue
|
|
if(!turf.density && !mob_negates_gravity())
|
|
continue
|
|
return A
|
|
else
|
|
var/atom/movable/AM = A
|
|
if(AM == buckled) //Kind of unnecessary but let's just be sure
|
|
continue
|
|
if(!AM.CanPass(src) || AM.density)
|
|
if(AM.anchored)
|
|
return AM
|
|
if(pulling == AM)
|
|
continue
|
|
if(get_turf(AM) == get_step(get_turf(src), movement_dir)) // No pushing off objects in front of you, while simultaneously pushing them fowards to go faster in space.
|
|
continue
|
|
. = AM
|
|
|
|
|
|
/mob/proc/mob_has_gravity(turf/T)
|
|
return has_gravity(src, T)
|
|
|
|
/mob/proc/mob_negates_gravity()
|
|
return 0
|
|
|
|
/mob/proc/Move_Pulled(atom/A)
|
|
if(HAS_TRAIT(src, TRAIT_CANNOT_PULL) || restrained() || !pulling)
|
|
return
|
|
if(pulling.anchored || pulling.move_resist > move_force || !pulling.Adjacent(src))
|
|
stop_pulling()
|
|
return
|
|
if(isliving(pulling))
|
|
var/mob/living/L = pulling
|
|
if(L.buckled && L.buckled.buckle_prevents_pull) //if they're buckled to something that disallows pulling, prevent it
|
|
stop_pulling()
|
|
return
|
|
if(A == loc && pulling.density)
|
|
return
|
|
if(!Process_Spacemove(get_dir(pulling.loc, A)))
|
|
return
|
|
if(src in pulling.contents)
|
|
return
|
|
var/target_turf = get_step(pulling, get_dir(pulling.loc, A))
|
|
if(get_dist(target_turf, loc) > 1) // Make sure the turf we are trying to pull to is adjacent to the user.
|
|
return // We do not use Adjacent() here because it checks if there are dense objects in the way, making it impossible to move an object to the side if we're blocked on both sides.
|
|
if(ismob(pulling))
|
|
var/mob/M = pulling
|
|
var/atom/movable/t = M.pulling
|
|
M.stop_pulling()
|
|
. = step(pulling, get_dir(pulling.loc, A)) // we set the return value to step here, if we don't having someone buckled in to a chair and being pulled won't let them be unbuckeled
|
|
if(M)
|
|
M.start_pulling(t)
|
|
else
|
|
. = step(pulling, get_dir(pulling.loc, A))
|
|
|
|
/mob/proc/update_gravity(has_gravity)
|
|
return
|
|
|
|
/client/proc/check_has_body_select()
|
|
return mob && mob.hud_used && mob.hud_used.zone_select && istype(mob.hud_used.zone_select, /atom/movable/screen/zone_sel)
|
|
|
|
/client/verb/body_toggle_head()
|
|
set name = "body-toggle-head"
|
|
set hidden = 1
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/next_in_line
|
|
switch(mob.zone_selected)
|
|
if(BODY_ZONE_HEAD)
|
|
next_in_line = BODY_ZONE_PRECISE_EYES
|
|
if(BODY_ZONE_PRECISE_EYES)
|
|
next_in_line = BODY_ZONE_PRECISE_MOUTH
|
|
else
|
|
next_in_line = BODY_ZONE_HEAD
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(next_in_line, mob)
|
|
|
|
/client/verb/body_r_arm()
|
|
set name = "body-r-arm"
|
|
set hidden = 1
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/next_in_line
|
|
if(mob.zone_selected == BODY_ZONE_R_ARM)
|
|
next_in_line = BODY_ZONE_PRECISE_R_HAND
|
|
else
|
|
next_in_line = BODY_ZONE_R_ARM
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(next_in_line, mob)
|
|
|
|
/client/verb/body_chest()
|
|
set name = "body-chest"
|
|
set hidden = 1
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(BODY_ZONE_CHEST, mob)
|
|
|
|
/client/verb/body_l_arm()
|
|
set name = "body-l-arm"
|
|
set hidden = 1
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/next_in_line
|
|
if(mob.zone_selected == BODY_ZONE_L_ARM)
|
|
next_in_line = BODY_ZONE_PRECISE_L_HAND
|
|
else
|
|
next_in_line = BODY_ZONE_L_ARM
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(next_in_line, mob)
|
|
|
|
/client/verb/body_r_leg()
|
|
set name = "body-r-leg"
|
|
set hidden = 1
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/next_in_line
|
|
if(mob.zone_selected == BODY_ZONE_R_LEG)
|
|
next_in_line = BODY_ZONE_PRECISE_R_FOOT
|
|
else
|
|
next_in_line = BODY_ZONE_R_LEG
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(next_in_line, mob)
|
|
|
|
/client/verb/body_groin()
|
|
set name = "body-groin"
|
|
set hidden = 1
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(BODY_ZONE_PRECISE_GROIN, mob)
|
|
|
|
/client/verb/body_l_leg()
|
|
set name = "body-l-leg"
|
|
set hidden = 1
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/next_in_line
|
|
if(mob.zone_selected == BODY_ZONE_L_LEG)
|
|
next_in_line = BODY_ZONE_PRECISE_L_FOOT
|
|
else
|
|
next_in_line = BODY_ZONE_L_LEG
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(next_in_line, mob)
|
|
|
|
/client/verb/toggle_walk_run()
|
|
set name = "toggle-walk-run"
|
|
set hidden = TRUE
|
|
set instant = TRUE
|
|
if(mob)
|
|
mob.toggle_move_intent()
|
|
|
|
/mob/proc/toggle_move_intent()
|
|
if(iscarbon(src))
|
|
var/mob/living/carbon/C = src
|
|
if(C.legcuffed)
|
|
to_chat(C, "<span class='notice'>You are legcuffed! You cannot run until you get [C.legcuffed] removed!</span>")
|
|
C.m_intent = MOVE_INTENT_WALK //Just incase
|
|
C.hud_used.move_intent.icon_state = "walking"
|
|
return
|
|
|
|
var/icon_toggle
|
|
if(m_intent == MOVE_INTENT_RUN)
|
|
m_intent = MOVE_INTENT_WALK
|
|
icon_toggle = "walking"
|
|
else
|
|
m_intent = MOVE_INTENT_RUN
|
|
icon_toggle = "running"
|
|
|
|
if(hud_used && hud_used.move_intent && hud_used.static_inventory)
|
|
hud_used.move_intent.icon_state = icon_toggle
|
|
for(var/atom/movable/screen/mov_intent/selector in hud_used.static_inventory)
|
|
selector.update_icon()
|
|
SEND_SIGNAL(src, COMSIG_MOVE_INTENT_TOGGLED)
|