/mob/CanPass(atom/movable/mover, turf/target) 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 !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, "This mob type cannot throw items.") /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, "You're restrained! You can't move!") 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("[mob] has broken free of [G.assailant]'s grip!") qdel(G) if(GRAB_NECK) move_delay = world.time + 10 if(!prob(5)) return TRUE mob.visible_message("[mob] has broken free of [G.assailant]'s headlock!") 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, "Holy energies block your path.") 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, "You push off of [backup] to propel yourself.") 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, "You are legcuffed! You cannot run until you get [C.legcuffed] removed!") 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)