mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-29 19:11:51 +00:00
* removes double spaces AFTER symbols * Fixing conflicts Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: GoldenAlpharex <jerego1234@hotmail.com>
570 lines
16 KiB
Plaintext
570 lines
16 KiB
Plaintext
/**
|
|
* If your mob is concious, drop the item in the active hand
|
|
*
|
|
* This is a hidden verb, likely for binding with winset for hotkeys
|
|
*/
|
|
/client/verb/drop_item()
|
|
set hidden = TRUE
|
|
if(!iscyborg(mob) && mob.stat == CONSCIOUS)
|
|
mob.dropItemToGround(mob.get_active_held_item())
|
|
return
|
|
|
|
/**
|
|
* force move the control_object of your client mob
|
|
*
|
|
* Used in admin possession and called from the client Move proc
|
|
* ensures the possessed object moves and not the admin mob
|
|
*
|
|
* Has no sanity other than checking density
|
|
*/
|
|
/client/proc/Move_object(direct)
|
|
if(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))
|
|
|
|
#define MOVEMENT_DELAY_BUFFER 0.75
|
|
#define MOVEMENT_DELAY_BUFFER_DELTA 1.25
|
|
|
|
/**
|
|
* Move a client in a direction
|
|
*
|
|
* Huge proc, has a lot of functionality
|
|
*
|
|
* Mostly it will despatch to the mob that you are the owner of to actually move
|
|
* in the physical realm
|
|
*
|
|
* Things that stop you moving as a mob:
|
|
* * world time being less than your next move_delay
|
|
* * not being in a mob, or that mob not having a loc
|
|
* * missing the n and direction parameters
|
|
* * being in remote control of an object (calls Moveobject instead)
|
|
* * being dead (it ghosts you instead)
|
|
*
|
|
* Things that stop you moving as a mob living (why even have OO if you're just shoving it all
|
|
* in the parent proc with istype checks right?):
|
|
* * having incorporeal_move set (calls Process_Incorpmove() instead)
|
|
* * being grabbed
|
|
* * being buckled (relaymove() is called to the buckled atom instead)
|
|
* * having your loc be some other mob (relaymove() is called on that mob instead)
|
|
* * Not having MOBILITY_MOVE
|
|
* * Failing Process_Spacemove() call
|
|
*
|
|
* At this point, if the mob is is confused, then a random direction and target turf will be calculated for you to travel to instead
|
|
*
|
|
* Now the parent call is made (to the byond builtin move), which moves you
|
|
*
|
|
* Some final move delay calculations (doubling if you moved diagonally successfully)
|
|
*
|
|
* if mob throwing is set I believe it's unset at this point via a call to finalize
|
|
*
|
|
* Finally if you're pulling an object and it's dense, you are turned 180 after the move
|
|
* (if you ask me, this should be at the top of the move so you don't dance around)
|
|
*
|
|
*/
|
|
/client/Move(new_loc, direct)
|
|
if(world.time < move_delay) //do not move anything ahead of this check please
|
|
return FALSE
|
|
else
|
|
next_move_dir_add = 0
|
|
next_move_dir_sub = 0
|
|
var/old_move_delay = move_delay
|
|
move_delay = world.time + world.tick_lag //this is here because Move() can now be called mutiple times per tick
|
|
if(!mob || !mob.loc)
|
|
return FALSE
|
|
if(!new_loc || !direct)
|
|
return FALSE
|
|
if(mob.notransform)
|
|
return FALSE //This is sota the goto stop mobs from moving var
|
|
if(mob.control_object)
|
|
return Move_object(direct)
|
|
if(!isliving(mob))
|
|
return mob.Move(new_loc, direct)
|
|
if(mob.stat == DEAD)
|
|
mob.ghostize()
|
|
return FALSE
|
|
if(mob.force_moving)
|
|
return FALSE
|
|
//SKYRAT EDIT ADDITION BEGIN - PIXEL_SHIFT
|
|
if(mob.shifting)
|
|
mob.pixel_shift(direct)
|
|
return FALSE
|
|
else if(mob.is_shifted)
|
|
mob.unpixel_shift()
|
|
//SKYRAT EDIT ADDITION END
|
|
|
|
var/mob/living/L = mob //Already checked for isliving earlier
|
|
if(L.incorporeal_move && !is_secret_level(mob.z)) //Move though walls
|
|
Process_Incorpmove(direct)
|
|
return FALSE
|
|
|
|
if(mob.remote_control) //we're controlling something, our movement is relayed to it
|
|
return mob.remote_control.relaymove(mob, direct)
|
|
|
|
if(isAI(mob))
|
|
return AIMove(new_loc,direct,mob)
|
|
|
|
if(Process_Grab()) //are we restrained by someone's grip?
|
|
return
|
|
|
|
if(mob.buckled) //if we're buckled to something, tell it we moved.
|
|
return mob.buckled.relaymove(mob, direct)
|
|
|
|
if(!(L.mobility_flags & MOBILITY_MOVE))
|
|
return FALSE
|
|
|
|
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 FALSE
|
|
|
|
if(SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_PRE_MOVE, new_loc) & COMSIG_MOB_CLIENT_BLOCK_PRE_MOVE)
|
|
return FALSE
|
|
|
|
//We are now going to move
|
|
var/add_delay = mob.cached_multiplicative_slowdown
|
|
mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay * ( (NSCOMPONENT(direct) && EWCOMPONENT(direct)) ? 2 : 1 ) )) // set it now in case of pulled objects
|
|
if(old_move_delay + (add_delay*MOVEMENT_DELAY_BUFFER_DELTA) + MOVEMENT_DELAY_BUFFER > world.time)
|
|
move_delay = old_move_delay
|
|
else
|
|
move_delay = world.time
|
|
|
|
var/confusion = L.get_confusion()
|
|
if(confusion)
|
|
var/newdir = 0
|
|
if(confusion > 40)
|
|
newdir = pick(GLOB.alldirs)
|
|
else if(prob(confusion * 1.5))
|
|
newdir = angle2dir(dir2angle(direct) + pick(90, -90))
|
|
else if(prob(confusion * 3))
|
|
newdir = angle2dir(dir2angle(direct) + pick(45, -45))
|
|
if(newdir)
|
|
direct = newdir
|
|
new_loc = get_step(L, direct)
|
|
|
|
. = ..()
|
|
|
|
if((direct & (direct - 1)) && mob.loc == new_loc) //moved diagonally successfully
|
|
add_delay *= 2
|
|
mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay))
|
|
move_delay += add_delay
|
|
if(.) // If mob is null here, we deserve the runtime
|
|
if(mob.throwing)
|
|
mob.throwing.finalize(FALSE)
|
|
|
|
// At this point we've moved the client's attached mob. This is one of the only ways to guess that a move was done
|
|
// as a result of player input and not because they were pulled or any other magic.
|
|
SEND_SIGNAL(mob, COMSIG_MOB_CLIENT_MOVED)
|
|
|
|
var/atom/movable/P = mob.pulling
|
|
if(P && !ismob(P) && P.density)
|
|
mob.setDir(turn(mob.dir, 180))
|
|
|
|
/**
|
|
* Checks to see if you're being grabbed and if so attempts to break it
|
|
*
|
|
* Called by client/Move()
|
|
*/
|
|
/client/proc/Process_Grab()
|
|
if(!mob.pulledby)
|
|
return FALSE
|
|
if(mob.pulledby == mob.pulling && mob.pulledby.grab_state == GRAB_PASSIVE) //Don't autoresist passive grabs if we're grabbing them too.
|
|
return FALSE
|
|
if(mob.incapacitated(ignore_restraints = TRUE))
|
|
COOLDOWN_START(src, move_delay, 1 SECONDS)
|
|
return TRUE
|
|
else if(HAS_TRAIT(mob, TRAIT_RESTRAINED))
|
|
COOLDOWN_START(src, move_delay, 1 SECONDS)
|
|
to_chat(src, span_warning("You're restrained! You can't move!"))
|
|
return TRUE
|
|
return mob.resist_grab(TRUE)
|
|
|
|
|
|
/**
|
|
* Allows mobs to ignore density and phase through objects
|
|
*
|
|
* Called by client/Move()
|
|
*
|
|
* The behaviour depends on the incorporeal_move value of the mob
|
|
*
|
|
* * INCORPOREAL_MOVE_BASIC - forceMoved to the next tile with no stop
|
|
* * INCORPOREAL_MOVE_SHADOW - the same but leaves a cool effect path
|
|
* * INCORPOREAL_MOVE_JAUNT - the same but blocked by holy tiles
|
|
*
|
|
* You'll note this is another mob living level proc living at the client level
|
|
*/
|
|
/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_BASIC)
|
|
var/T = get_step(L,direct)
|
|
if(T)
|
|
L.forceMove(T)
|
|
L.setDir(direct)
|
|
if(INCORPOREAL_MOVE_SHADOW)
|
|
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
|
|
var/target = locate(locx,locy,mobloc.z)
|
|
if(target)
|
|
L.forceMove(target)
|
|
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)
|
|
var/T = get_step(L,direct)
|
|
if(T)
|
|
L.forceMove(T)
|
|
L.setDir(direct)
|
|
if(INCORPOREAL_MOVE_JAUNT) //Incorporeal move, but blocked by holy-watered tiles and salt piles.
|
|
var/turf/open/floor/stepTurf = get_step(L, direct)
|
|
if(stepTurf)
|
|
var/obj/effect/decal/cleanable/food/salt/salt = locate() in stepTurf
|
|
if(salt)
|
|
to_chat(L, span_warning("[salt] bars your passage!"))
|
|
if(isrevenant(L))
|
|
var/mob/living/simple_animal/revenant/R = L
|
|
R.reveal(20)
|
|
R.stun(20)
|
|
return
|
|
if(stepTurf.turf_flags & NOJAUNT)
|
|
to_chat(L, span_warning("Some strange aura is blocking the way."))
|
|
return
|
|
if(locate(/obj/effect/blessing) in stepTurf)
|
|
to_chat(L, span_warning("Holy energies block your path!"))
|
|
return
|
|
|
|
L.forceMove(stepTurf)
|
|
L.setDir(direct)
|
|
return TRUE
|
|
|
|
|
|
/**
|
|
* Handles mob/living movement in space (or no gravity)
|
|
*
|
|
* Called by /client/Move()
|
|
*
|
|
* return TRUE for movement or FALSE for none
|
|
*
|
|
* You can move in space if you have a spacewalk ability
|
|
*/
|
|
/mob/Process_Spacemove(movement_dir = 0)
|
|
. = ..()
|
|
if(. || HAS_TRAIT(src, TRAIT_SPACEWALK))
|
|
return TRUE
|
|
var/atom/movable/backup = get_spacemove_backup()
|
|
if(backup)
|
|
if(istype(backup) && movement_dir && !backup.anchored)
|
|
if(backup.newtonian_move(turn(movement_dir, 180))) //You're pushing off something movable, so it moves
|
|
to_chat(src, span_info("You push off of [backup] to propel yourself."))
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/**
|
|
* Find movable atoms? near a mob that are viable for pushing off when moving
|
|
*/
|
|
/mob/get_spacemove_backup()
|
|
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)
|
|
continue
|
|
if(ismob(AM))
|
|
var/mob/M = AM
|
|
if(M.buckled)
|
|
continue
|
|
if(AM.density || !AM.CanPass(src, get_dir(AM, src)))
|
|
if(AM.anchored)
|
|
return AM
|
|
if(pulling == AM)
|
|
continue
|
|
. = AM
|
|
|
|
/**
|
|
* Returns true if a mob has gravity
|
|
*
|
|
* I hate that this exists
|
|
*/
|
|
/mob/proc/mob_has_gravity()
|
|
return has_gravity()
|
|
|
|
/**
|
|
* Does this mob ignore gravity
|
|
*/
|
|
/mob/proc/mob_negates_gravity()
|
|
return FALSE
|
|
|
|
/// Called when this mob slips over, override as needed
|
|
/mob/proc/slip(knockdown_amount, obj/O, lube, paralyze, force_drop)
|
|
mind?.add_memory(MEMORY_SLIPPED, list(DETAIL_WHAT_BY = O, DETAIL_PROTAGONIST = src), story_value = STORY_VALUE_OKAY)
|
|
return
|
|
|
|
/// Update the gravity status of this mob
|
|
/mob/proc/update_gravity(has_gravity, override=FALSE)
|
|
var/speed_change = max(0, has_gravity - STANDARD_GRAVITY)
|
|
if(!speed_change)
|
|
remove_movespeed_modifier(/datum/movespeed_modifier/gravity)
|
|
else
|
|
add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/gravity, multiplicative_slowdown=speed_change)
|
|
|
|
//bodypart selection verbs - Cyberboss
|
|
//8: repeated presses toggles through head - eyes - mouth
|
|
//9: eyes 8: head 7: mouth
|
|
//4: r-arm 5: chest 6: l-arm
|
|
//1: r-leg 2: groin 3: l-leg
|
|
|
|
///Validate the client's mob has a valid zone selected
|
|
/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)
|
|
|
|
/**
|
|
* Hidden verb to set the target zone of a mob to the head
|
|
*
|
|
* (bound to 8) - repeated presses toggles through head - eyes - mouth
|
|
*/
|
|
|
|
///Hidden verb to target the head, bound to 8
|
|
/client/verb/body_toggle_head()
|
|
set name = "body-toggle-head"
|
|
set hidden = TRUE
|
|
|
|
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)
|
|
|
|
///Hidden verb to target the eyes, bound to 7
|
|
/client/verb/body_eyes()
|
|
set name = "body-eyes"
|
|
set hidden = TRUE
|
|
|
|
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_EYES, mob)
|
|
|
|
///Hidden verb to target the mouth, bound to 9
|
|
/client/verb/body_mouth()
|
|
set name = "body-mouth"
|
|
set hidden = TRUE
|
|
|
|
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_MOUTH, mob)
|
|
|
|
///Hidden verb to target the right arm, bound to 4
|
|
/client/verb/body_r_arm()
|
|
set name = "body-r-arm"
|
|
set hidden = TRUE
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(BODY_ZONE_R_ARM, mob)
|
|
|
|
///Hidden verb to target the chest, bound to 5
|
|
/client/verb/body_chest()
|
|
set name = "body-chest"
|
|
set hidden = TRUE
|
|
|
|
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)
|
|
|
|
///Hidden verb to target the left arm, bound to 6
|
|
/client/verb/body_l_arm()
|
|
set name = "body-l-arm"
|
|
set hidden = TRUE
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(BODY_ZONE_L_ARM, mob)
|
|
|
|
///Hidden verb to target the right leg, bound to 1
|
|
/client/verb/body_r_leg()
|
|
set name = "body-r-leg"
|
|
set hidden = TRUE
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(BODY_ZONE_R_LEG, mob)
|
|
|
|
///Hidden verb to target the groin, bound to 2
|
|
/client/verb/body_groin()
|
|
set name = "body-groin"
|
|
set hidden = TRUE
|
|
|
|
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)
|
|
|
|
///Hidden verb to target the left leg, bound to 3
|
|
/client/verb/body_l_leg()
|
|
set name = "body-l-leg"
|
|
set hidden = TRUE
|
|
|
|
if(!check_has_body_select())
|
|
return
|
|
|
|
var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select
|
|
selector.set_selected_zone(BODY_ZONE_L_LEG, mob)
|
|
|
|
///Verb to toggle the walk or run status
|
|
/client/verb/toggle_walk_run()
|
|
set name = "toggle-walk-run"
|
|
set hidden = TRUE
|
|
set instant = TRUE
|
|
if(mob)
|
|
mob.toggle_move_intent(usr)
|
|
|
|
/**
|
|
* Toggle the move intent of the mob
|
|
*
|
|
* triggers an update the move intent hud as well
|
|
*/
|
|
/mob/proc/toggle_move_intent(mob/user)
|
|
if(m_intent == MOVE_INTENT_RUN)
|
|
m_intent = MOVE_INTENT_WALK
|
|
else
|
|
//SKYRAT EDIT ADDITION BEGIN - GUNPOINT
|
|
if (HAS_TRAIT(src,TRAIT_NORUNNING))
|
|
to_chat(src, "You find yourself unable to run.")
|
|
return FALSE
|
|
//SKYRAT EDIT ADDITION END
|
|
m_intent = MOVE_INTENT_RUN
|
|
if(hud_used?.static_inventory)
|
|
for(var/atom/movable/screen/mov_intent/selector in hud_used.static_inventory)
|
|
selector.update_appearance()
|
|
|
|
///Moves a mob upwards in z level
|
|
/mob/verb/up()
|
|
set name = "Move Upwards"
|
|
set category = "IC"
|
|
|
|
var/turf/current_turf = get_turf(src)
|
|
var/turf/above_turf = SSmapping.get_turf_above(current_turf)
|
|
var/ventcrawling_mob = HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING)
|
|
|
|
if(can_zFall(above_turf, 1, current_turf, DOWN) && !ventcrawling_mob) //Will be fall down if we go up?
|
|
to_chat(src, "<span class='notice'>You are not Superman.<span>")
|
|
return
|
|
|
|
if(zMove(UP, TRUE, ventcrawling_mob))
|
|
to_chat(src, span_notice("You move upwards."))
|
|
|
|
///Moves a mob down a z level
|
|
/mob/verb/down()
|
|
set name = "Move Down"
|
|
set category = "IC"
|
|
|
|
var/ventcrawling_mob = HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING)
|
|
|
|
if(zMove(DOWN, TRUE, ventcrawling_mob))
|
|
to_chat(src, span_notice("You move down."))
|
|
|
|
/mob/can_zFall(turf/source, levels, turf/target, direction)
|
|
if(buckled)
|
|
return buckled.can_zFall(source, levels, target, direction)
|
|
return ..()
|
|
|
|
///Move a mob between z levels, if it's valid to move z's on this turf
|
|
/mob/proc/zMove(dir, feedback = FALSE, ventcrawling = FALSE)
|
|
if(dir != UP && dir != DOWN)
|
|
return FALSE
|
|
if(incapacitated())
|
|
if(feedback)
|
|
to_chat(src, span_warning("You can't do that right now!"))
|
|
return FALSE
|
|
var/turf/target = get_step_multiz(src, dir)
|
|
if(!target)
|
|
if(feedback)
|
|
to_chat(src, span_warning("There's nowhere to go in that direction!"))
|
|
return FALSE
|
|
if(!canZMove(dir, target) && !ventcrawling)
|
|
if(feedback)
|
|
to_chat(src, span_warning("You couldn't move there!"))
|
|
return FALSE
|
|
if(!ventcrawling) //let this be handled in atmosmachinery.dm
|
|
return Move(target)
|
|
else
|
|
var/obj/machinery/atmospherics/pipe = loc
|
|
pipe.relaymove(src, dir)
|
|
return TRUE
|
|
|
|
/// Can this mob move between z levels
|
|
/mob/proc/canZMove(direction, turf/target)
|
|
return FALSE
|
|
|
|
/mob/abstract_move(atom/destination)
|
|
var/turf/new_turf = get_turf(destination)
|
|
if(is_secret_level(new_turf.z) && !client?.holder)
|
|
return
|
|
return ..()
|