diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm
new file mode 100644
index 0000000000..cc6e5bd49a
--- /dev/null
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movement.dm
@@ -0,0 +1,3 @@
+/// Called from /mob/living/PushAM -- Called when this mob is about to push a movable, but before it moves
+/// (aotm/movable/being_pushed)
+#define COMSIG_LIVING_PUSHING_MOVABLE "living_pushing_movable"
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
new file mode 100644
index 0000000000..5d2a471c0a
--- /dev/null
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
@@ -0,0 +1,2 @@
+///From base of mob/living/MobBump() (mob/living)
+#define COMSIG_LIVING_MOB_BUMP "living_mob_bump"
diff --git a/code/__DEFINES/movement.dm b/code/__DEFINES/movement.dm
index 5bf7de8647..bccbd425dd 100644
--- a/code/__DEFINES/movement.dm
+++ b/code/__DEFINES/movement.dm
@@ -13,7 +13,7 @@ GLOBAL_VAR_INIT(glide_size_multiplier, 1.0)
/// Then that's multiplied by the global glide size multiplier. 1.25 by default feels pretty close to spot on. This is just to try to get byond to behave.
/// The whole result is then clamped to within the range above.
/// Not very readable but it works
-#define DELAY_TO_GLIDE_SIZE(delay) (clamp(((32 / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE))
+#define DELAY_TO_GLIDE_SIZE(delay) (clamp(((world.icon_size / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE))
/// Enables smooth movement
// #define SMOOTH_MOVEMENT
diff --git a/code/__HELPERS/matrices/transform_matrix.dm b/code/__HELPERS/matrices/transform_matrix.dm
index 251ef8151f..8f8a67535e 100644
--- a/code/__HELPERS/matrices/transform_matrix.dm
+++ b/code/__HELPERS/matrices/transform_matrix.dm
@@ -19,7 +19,7 @@
speed /= segments
if(parallel)
- animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
+ animate(src, transform = matrices[1], time = speed, loops, flags = ANIMATION_PARALLEL)
else
animate(src, transform = matrices[1], time = speed, loops)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index b415b4720f..428784e953 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1176,25 +1176,22 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
var/initialpixely = pixel_y
var/shiftx = rand(-pixelshiftx,pixelshiftx)
var/shifty = rand(-pixelshifty,pixelshifty)
- animate(src, pixel_x = pixel_x + shiftx, pixel_y = pixel_y + shifty, time = 0.2, loop = duration)
- pixel_x = initialpixelx
- pixel_y = initialpixely
+ animate(src, pixel_x = shiftx, pixel_y = shifty, time = 0.2, loop = duration, flags = ANIMATION_RELATIVE)
+ animate(pixel_x = initialpixelx, pixel_y = initialpixely, time = 0.2)
-/atom/proc/do_jiggle(targetangle = 45, timer = 20)
+/atom/proc/do_jiggle(targetangle = 25, timer = 20)
var/matrix/OM = matrix(transform)
var/matrix/M = matrix(transform)
- var/halftime = timer * 0.5
M.Turn(pick(-targetangle, targetangle))
- animate(src, transform = M, time = halftime, easing = ELASTIC_EASING)
- animate(src, transform = OM, time = halftime, easing = ELASTIC_EASING)
+ animate(src, transform = M, time = timer * 0.1, easing = BACK_EASING | EASE_IN)
+ animate(transform = OM, time = timer * 0.4, easing = ELASTIC_EASING)
/atom/proc/do_squish(squishx = 1.2, squishy = 0.6, timer = 20)
var/matrix/OM = matrix(transform)
var/matrix/M = matrix(transform)
- var/halftime = timer * 0.5
M.Scale(squishx, squishy)
- animate(src, transform = M, time = halftime, easing = BOUNCE_EASING)
- animate(src, transform = OM, time = halftime, easing = BOUNCE_EASING)
+ animate(src, transform = M, time = timer * 0.5, easing = ELASTIC_EASING)
+ animate(transform = OM, time = timer * 0.5, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL)
/proc/weightclass2text(var/w_class)
switch(w_class)
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 692f2317ef..d3d0fb32b6 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -60,7 +60,7 @@
if(client && hud_used)
hud_used.reorganize_alerts()
thealert.transform = matrix(32, 6, MATRIX_TRANSLATE)
- animate(thealert, transform = matrix(), time = 2.5, easing = CUBIC_EASING)
+ animate(thealert, transform = matrix(), time = 2.5, easing = BACK_EASING)
if(thealert.timeout)
addtimer(CALLBACK(src, .proc/alert_timeout, thealert, category), thealert.timeout)
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index 0070362f8b..935379b721 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -178,7 +178,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
starting.Scale(0.1,0.1)
E.transform = starting
var/matrix/TM = matrix()
- animate(E,pixel_x = px,pixel_y = py, transform = TM, time = timing)
+ animate(E,pixel_x = px,pixel_y = py, transform = TM, time = timing, easing = SINE_EASING | EASE_OUT)
else
E.pixel_y = py
E.pixel_x = px
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 8f3a7ef02c..23486cac29 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -126,6 +126,8 @@
return DISCARD_LAST_ACTION
user.do_attack_animation(O)
O.attacked_by(src, user)
+ if(force >= 20)
+ shake_camera(user, ((force - 15) * 0.01 + 1), ((force - 15) * 0.01))
/atom/movable/proc/attacked_by()
return
diff --git a/code/datums/chatmessage.dm b/code/datums/chatmessage.dm
index a8d8e1e2fb..ca35552dfa 100644
--- a/code/datums/chatmessage.dm
+++ b/code/datums/chatmessage.dm
@@ -200,6 +200,7 @@
message.maptext_height = mheight
message.maptext_x = (CHAT_MESSAGE_WIDTH - owner.bound_width) * -0.5
message.maptext = MAPTEXT(complete_text)
+ message.pixel_x = -owner.pixel_x //Dogborgs and other wide boys have a pixel offset. This accounts for that
// View the message
LAZYADDASSOC(owned_by.seen_messages, message_loc, src)
@@ -210,10 +211,6 @@
scheduled_destruction = world.time + (lifespan - CHAT_MESSAGE_EOL_FADE)
enter_subsystem()
- var/mob/living/silicon/robot/R = target
- if(iscyborg(R))
- if((R.module.dogborg == TRUE || R.dogborg == TRUE) && isturf(R.loc)) //I hate whoever that thought that putting two types of dogborg that don't even sync up properly was good
- message.pixel_x = 16
/**
* Applies final animations to overlay CHAT_MESSAGE_EOL_FADE deciseconds prior to message deletion
diff --git a/code/datums/components/bouncy.dm b/code/datums/components/bouncy.dm
index fed603410e..3c4e228b59 100644
--- a/code/datums/components/bouncy.dm
+++ b/code/datums/components/bouncy.dm
@@ -32,7 +32,7 @@
var/atom/movable/A = parent
switch(rand(1, 3))
if(1)
- A.do_jiggle(45 + rand(-10, 10) * bouncy_mod, 14)
+ A.do_jiggle(25 + rand(-5, 5) * bouncy_mod, 14)
if(2)
var/min_b = 0.6/bouncy_mod
var/max_b = 1.2 * bouncy_mod
diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm
index 98bbdbed05..40daac88cf 100644
--- a/code/datums/components/storage/storage.dm
+++ b/code/datums/components/storage/storage.dm
@@ -432,25 +432,26 @@
if(M.incapacitated() || !M.canUseStorage())
return
var/atom/A = parent
- A.add_fingerprint(M)
// this must come before the screen objects only block, dunno why it wasn't before
if(over_object == M)
user_show_to_mob(M, trigger_on_found = TRUE)
if(isrevenant(M))
INVOKE_ASYNC(GLOBAL_PROC, .proc/RevenantThrow, over_object, M, source)
return
+ if(check_locked(null, M) || !M.CanReach(A) || (!M.CanReach(over_object) && !istype(over_object, /atom/movable/screen)))
+ return
+ playsound(A, "rustle", 50, TRUE, -5)
+ A.do_jiggle()
+ A.add_fingerprint(M)
if(!istype(over_object, /atom/movable/screen))
INVOKE_ASYNC(src, .proc/dump_content_at, over_object, M)
return
if(A.loc != M)
return
- playsound(A, "rustle", 50, TRUE, -5)
- A.do_jiggle()
if(istype(over_object, /atom/movable/screen/inventory/hand))
var/atom/movable/screen/inventory/hand/H = over_object
M.putItemFromInventoryInHandIfPossible(A, H.held_index)
return
- A.add_fingerprint(M)
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE, trigger_on_found = FALSE)
var/atom/A = parent
diff --git a/code/datums/components/virtual_reality.dm b/code/datums/components/virtual_reality.dm
index 56e06e3582..c0e6e9dba6 100644
--- a/code/datums/components/virtual_reality.dm
+++ b/code/datums/components/virtual_reality.dm
@@ -84,9 +84,9 @@
if(VR)
VR.level_below = src
level_above = VR
- M.transfer_ckey(vr_M, FALSE)
mastermind = M.mind
mastermind.current.audiovisual_redirect = parent
+ M.transfer_ckey(vr_M, FALSE)
RegisterSignal(mastermind, COMSIG_PRE_MIND_TRANSFER, .proc/switch_player)
RegisterSignal(M, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING), .proc/game_over)
RegisterSignal(M, COMSIG_MOB_PRE_PLAYER_CHANGE, .proc/player_hijacked)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 1de7a1576e..4077f86e52 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1322,7 +1322,7 @@
filters += filter(arglist(arguments))
UNSETEMPTY(filter_data)
-/atom/proc/transition_filter(name, time, list/new_params, easing, loop)
+/atom/proc/transition_filter(name, time, list/new_params, easing, loop, parallel = TRUE)
var/filter = get_filter(name)
if(!filter)
return
@@ -1333,7 +1333,7 @@
for(var/thing in new_params)
params[thing] = new_params[thing]
- animate(filter, new_params, time = time, easing = easing, loop = loop)
+ animate(filter, new_params, time = time, easing = easing, loop = loop, flags = (parallel ? ANIMATION_PARALLEL : 0))
for(var/param in params)
filter_data[name][param] = params[param]
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 4b137d8b60..0323217341 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -605,11 +605,11 @@
if(throwing && !throw_override)
return
if(on && !(movement_type & FLOATING))
- animate(src, pixel_y = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
- animate(pixel_y = -2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
+ animate(src, pixel_z = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
+ animate(pixel_z = -4, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
setMovetype(movement_type | FLOATING)
else if (!on && (movement_type & FLOATING))
- animate(src, pixel_y = initial(pixel_y), time = 10)
+ animate(src, pixel_z = initial(pixel_y), time = 10)
setMovetype(movement_type & ~FLOATING)
floating_need_update = FALSE // assume it's done
@@ -775,4 +775,4 @@
M.Turn(pick(-30, 30))
animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = M, easing = CUBIC_EASING)
sleep(1)
- animate(I, alpha = 0, transform = matrix(), time = 1)
+ animate(I, alpha = 0, transform = matrix(), time = 1, flags = ANIMATION_PARALLEL)
diff --git a/code/game/objects/items/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm
index 595b24d214..2b0b8da670 100644
--- a/code/game/objects/items/pneumaticCannon.dm
+++ b/code/game/objects/items/pneumaticCannon.dm
@@ -205,6 +205,10 @@
if(!throw_item(target, I, user))
break
+ if(user)
+ shake_camera(user, (pressureSetting * 0.75 + 1), (pressureSetting * 0.75))
+
+
/obj/item/pneumatic_cannon/proc/throw_item(turf/target, obj/item/I, mob/user)
if(!istype(I))
return FALSE
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 38886e4908..02c2936f8d 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -110,7 +110,11 @@ distance_multiplier - Can be used to multiply the distance at which the sound is
*/
/mob/proc/playsound_local(turf/turf_source, soundin, vol as num, vary, frequency, falloff_exponent = SOUND_FALLOFF_EXPONENT, channel = 0, pressure_affected = TRUE, sound/S, max_distance,
- falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = SOUND_DEFAULT_DISTANCE_MULTIPLIER, envwet = -10000, envdry = 0)
+ falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE, distance_multiplier = SOUND_DEFAULT_DISTANCE_MULTIPLIER, envwet = -10000, envdry = 0, virtual_hearer)
+ if(audiovisual_redirect)
+ virtual_hearer = get_turf(src)
+ audiovisual_redirect.playsound_local(turf_source, soundin, vol, vary, frequency, falloff_exponent, channel, pressure_affected, S, max_distance, falloff_distance, distance_multiplier, max(0, envwet), -10000, virtual_hearer)
+ //No return here, as we want to deliberately support the possibility of shenanigans in which mobs with clients can have active AV redirects to completely different players
if(!client)
return
@@ -134,7 +138,7 @@ distance_multiplier - Can be used to multiply the distance at which the sound is
S.frequency = get_rand_frequency()
if(isturf(turf_source))
- var/turf/T = get_turf(src)
+ var/turf/T = virtual_hearer || get_turf(src)
//sound volume falloff with distance
var/distance = get_dist(T, turf_source)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index dfa562ca70..6483f726a9 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -121,7 +121,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
remove_verb(src, /mob/dead/observer/verb/boo)
remove_verb(src, /mob/dead/observer/verb/possess)
- animate(src, pixel_y = 2, time = 10, loop = -1)
+ animate(src, pixel_z = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
+ animate(pixel_z = -4, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
add_to_dead_mob_list()
@@ -539,8 +540,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/stop_orbit(datum/component/orbiter/orbits)
. = ..()
//restart our floating animation after orbit is done.
- pixel_y = 0
- animate(src, pixel_y = 2, time = 10, loop = -1)
+ pixel_z = 0
+ animate(src, pixel_z = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
+ animate(pixel_z = -4, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
/mob/dead/observer/verb/jumptomob() //Moves the ghost instead of just changing the ghosts's eye -Nodrak
set category = "Ghost"
diff --git a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
index 9563959ebc..ff4a7d2bba 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
@@ -51,7 +51,7 @@
// update_icons() //Handled in update_transform(), leaving this here as a reminder
update_transform()
-/mob/living/carbon/alien/humanoid/update_transform() //The old method of updating lying/standing was update_icons(). Aliens still expect that.
+/mob/living/carbon/alien/humanoid/update_transform(do_animate) //The old method of updating lying/standing was update_icons(). Aliens still expect that.
if(lying > 0)
lying = 90 //Anything else looks silly
..()
diff --git a/code/modules/mob/living/carbon/alien/larva/update_icons.dm b/code/modules/mob/living/carbon/alien/larva/update_icons.dm
index e6e7e657e8..85416261c7 100644
--- a/code/modules/mob/living/carbon/alien/larva/update_icons.dm
+++ b/code/modules/mob/living/carbon/alien/larva/update_icons.dm
@@ -21,7 +21,7 @@
else
icon_state = "larva[state]"
-/mob/living/carbon/alien/larva/update_transform() //All this is handled in update_icons()
+/mob/living/carbon/alien/larva/update_transform(do_animate) //All this is handled in update_icons()
..()
return update_icons()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 6efa32b48b..e9150f202d 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -81,6 +81,7 @@
//Called when we bump onto a mob
/mob/living/proc/MobBump(mob/M)
+ SEND_SIGNAL(src, COMSIG_LIVING_MOB_BUMP, M)
//Even if we don't push/swap places, we "touched" them, so spread fire
spreadFire(M)
@@ -88,6 +89,7 @@
return TRUE
var/they_can_move = TRUE
+
if(isliving(M))
var/mob/living/L = M
they_can_move = CHECK_MOBILITY(L, MOBILITY_MOVE)
@@ -105,16 +107,16 @@
//Should stop you pushing a restrained person out of the way
if(L.pulledby && L.pulledby != src && L.restrained())
if(!(world.time % 5))
- to_chat(src, "[L] is restrained, you cannot push past.")
- return 1
+ to_chat(src, span_warning("[L] is restrained, you cannot push past."))
+ return TRUE
if(L.pulling)
if(ismob(L.pulling))
var/mob/P = L.pulling
if(P.restrained())
if(!(world.time % 5))
- to_chat(src, "[L] is restraining [P], you cannot push past.")
- return 1
+ to_chat(src, span_warning("[L] is restraining [P], you cannot push past."))
+ return TRUE
//CIT CHANGES START HERE - makes it so resting stops you from moving through standing folks or over prone bodies without a short delay
if(!CHECK_MOBILITY(src, MOBILITY_STAND))
@@ -142,7 +144,7 @@
//END OF CIT CHANGES
if(moving_diagonally)//no mob swap during diagonal moves.
- return 1
+ return TRUE
//handle micro bumping on help intent
if(a_intent == INTENT_HELP)
@@ -156,7 +158,8 @@
if(!too_strong)
mob_swap = TRUE
else
- if(M.pulledby == src && a_intent == INTENT_GRAB)
+ //You can swap with the person you are dragging on grab intent, and restrained people in most cases
+ if(M.pulledby == src && !too_strong)
mob_swap = TRUE
//restrained people act if they were on 'help' intent to prevent a person being pulled from being separated from their puller
else if((M.restrained() || M.a_intent == INTENT_HELP) && (restrained() || a_intent == INTENT_HELP))
@@ -164,8 +167,8 @@
if(mob_swap)
//switch our position with M
if(loc && !loc.Adjacent(M.loc))
- return 1
- now_pushing = 1
+ return TRUE
+ now_pushing = TRUE
var/oldloc = loc
var/oldMloc = M.loc
@@ -185,29 +188,33 @@
if(!M_passmob)
M.pass_flags &= ~PASSMOB
- now_pushing = 0
+ now_pushing = FALSE
if(!move_failed)
- return 1
+ return TRUE
//okay, so we didn't switch. but should we push?
//not if he's not CANPUSH of course
if(!(M.status_flags & CANPUSH))
- return 1
+ return TRUE
if(handle_micro_bump_other(M))
return TRUE
if(isliving(M))
var/mob/living/L = M
if(HAS_TRAIT(L, TRAIT_PUSHIMMUNE))
- return 1
- //If they're a human, and they're not in help intent, block pushing
- if(ishuman(M) && (M.a_intent != INTENT_HELP))
- return TRUE
+ return TRUE
+ if(M.a_intent != INTENT_HELP)
+ //If they're a human, and they're not in help intent, block pushing
+ if(ishuman(M))
+ return TRUE
+ //if they are a cyborg, and they're alive and not in help intent, block pushing
+ if(iscyborg(M) && M.stat != DEAD)
+ return TRUE
//anti-riot equipment is also anti-push
for(var/obj/item/I in M.held_items)
if(!istype(M, /obj/item/clothing))
if(prob(I.block_chance*2))
- return 1
+ return TRUE
/mob/living/get_photo_description(obj/item/camera/camera)
var/list/mob_details = list()
@@ -238,21 +245,40 @@
if(!client && (mob_size < MOB_SIZE_SMALL))
return
now_pushing = TRUE
- var/t = get_dir(src, AM)
+ SEND_SIGNAL(src, COMSIG_LIVING_PUSHING_MOVABLE, AM)
+ var/dir_to_target = get_dir(src, AM)
+
+ // If there's no dir_to_target then the player is on the same turf as the atom they're trying to push.
+ // This can happen when a player is stood on the same turf as a directional window. All attempts to push
+ // the window will fail as get_dir will return 0 and the player will be unable to move the window when
+ // it should be pushable.
+ // In this scenario, we will use the facing direction of the /mob/living attempting to push the atom as
+ // a fallback.
+ if(!dir_to_target)
+ dir_to_target = dir
+
var/push_anchored = FALSE
if((AM.move_resist * MOVE_FORCE_CRUSH_RATIO) <= force)
- if(move_crush(AM, move_force, t))
+ if(move_crush(AM, move_force, dir_to_target))
push_anchored = TRUE
- if((AM.move_resist * MOVE_FORCE_FORCEPUSH_RATIO) <= force) //trigger move_crush and/or force_push regardless of if we can push it normally
- if(force_push(AM, move_force, t, push_anchored))
+ if((AM.move_resist * MOVE_FORCE_FORCEPUSH_RATIO) <= force) //trigger move_crush and/or force_push regardless of if we can push it normally
+ if(force_push(AM, move_force, dir_to_target, push_anchored))
push_anchored = TRUE
+ if(ismob(AM))
+ var/mob/mob_to_push = AM
+ var/atom/movable/mob_buckle = mob_to_push.buckled
+ // If we can't pull them because of what they're buckled to, make sure we can push the thing they're buckled to instead.
+ // If neither are true, we're not pushing anymore.
+ if(mob_buckle && (mob_buckle.buckle_prevents_pull || (force < (mob_buckle.move_resist * MOVE_FORCE_PUSH_RATIO))))
+ now_pushing = FALSE
+ return
if((AM.anchored && !push_anchored) || (force < (AM.move_resist * MOVE_FORCE_PUSH_RATIO)))
now_pushing = FALSE
return
- if (istype(AM, /obj/structure/window))
+ if(istype(AM, /obj/structure/window))
var/obj/structure/window/W = AM
if(W.fulltile)
- for(var/obj/structure/window/win in get_step(W,t))
+ for(var/obj/structure/window/win in get_step(W, dir_to_target))
now_pushing = FALSE
return
if(pulling == AM)
@@ -260,8 +286,9 @@
var/current_dir
if(isliving(AM))
current_dir = AM.dir
- if(step(AM, t) && Process_Spacemove(t))
- step(src, t)
+ if(AM.Move(get_step(AM.loc, dir_to_target), dir_to_target, glide_size))
+ AM.add_fingerprint(src)
+ Move(get_step(loc, dir_to_target), dir_to_target)
if(current_dir)
AM.setDir(current_dir)
now_pushing = FALSE
@@ -361,29 +388,33 @@
offset = GRAB_PIXEL_SHIFT_NECK
if(GRAB_KILL)
offset = GRAB_PIXEL_SHIFT_NECK
- M.setDir(get_dir(M, src))
- switch(M.dir)
- if(NORTH)
- animate(M, pixel_x = 0, pixel_y = offset, 3)
- if(SOUTH)
- animate(M, pixel_x = 0, pixel_y = -offset, 3)
- if(EAST)
- if(M.lying == 270) //update the dragged dude's direction if we've turned
- M.lying = 90
- M.update_transform() //force a transformation update, otherwise it'll take a few ticks for update_mobility() to do so
- M.lying_prev = M.lying
- animate(M, pixel_x = offset, pixel_y = 0, 3)
- if(WEST)
- if(M.lying == 90)
- M.lying = 270
- M.update_transform()
- M.lying_prev = M.lying
- animate(M, pixel_x = -offset, pixel_y = 0, 3)
+ var/target_dir = get_dir(M, src)
+ M.setDir(target_dir)
+ var/target_x
+ var/target_y
+ if(target_dir & NORTH)
+ target_y += offset
+ if(target_dir & SOUTH)
+ target_y -= offset
+ if(target_dir & EAST)
+ target_x += offset
+ if(target_dir & WEST)
+ target_x -= offset
+ if(target_x || target_y)
+ if(0 < target_x && M.lying == 270)
+ M.lying = 90
+ M.update_transform(FALSE) //force a transformation update, otherwise it'll take a few ticks for update_mobility() to do so
+ M.lying_prev = M.lying
+ if(0 > target_x && M.lying == 90)
+ M.lying = 270
+ M.update_transform(FALSE)
+ M.lying_prev = M.lying
+ animate(M, pixel_x = target_x, pixel_y = target_y, time = 3, flags = ANIMATION_PARALLEL)
/mob/living/proc/reset_pull_offsets(mob/living/M, override)
if(!override && M.buckled)
return
- animate(M, pixel_x = 0, pixel_y = 0, 1)
+ animate(M, pixel_x = 0, pixel_y = 0, time = 3, flags = ANIMATION_PARALLEL)
//mob verbs are a lot faster than object verbs
//for more info on why this is not atom/pull, see examinate() in mob.dm
@@ -901,12 +932,11 @@
if(anchored || (buckled && buckled.anchored))
fixed = 1
if(on && !(movement_type & FLOATING) && !fixed)
- animate(src, pixel_y = pixel_y + 2, time = 10, loop = -1)
- sleep(10)
- animate(src, pixel_y = pixel_y - 2, time = 10, loop = -1)
+ animate(src, pixel_z = 2, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
+ animate(pixel_z = -4, time = 10, loop = -1, flags = ANIMATION_RELATIVE)
setMovetype(movement_type | FLOATING)
else if(((!on || fixed) && (movement_type & FLOATING)))
- animate(src, pixel_y = get_standard_pixel_y_offset(lying), time = 10)
+ animate(src, pixel_z = get_standard_pixel_y_offset(lying), time = 10)
setMovetype(movement_type & ~FLOATING)
// The src mob is trying to strip an item from someone
@@ -1005,7 +1035,7 @@
var/pixel_y_diff = rand(-amplitude/3, amplitude/3)
var/final_pixel_x = get_standard_pixel_x_offset(lying)
var/final_pixel_y = get_standard_pixel_y_offset(lying)
- animate(src, pixel_x = pixel_x + pixel_x_diff, pixel_y = pixel_y + pixel_y_diff , time = 2, loop = 6)
+ animate(src, pixel_x = pixel_x_diff, pixel_y = pixel_y_diff , time = 2, loop = 6, flags = ANIMATION_PARALLEL | ANIMATION_RELATIVE)
animate(pixel_x = final_pixel_x , pixel_y = final_pixel_y , time = 2)
floating_need_update = TRUE
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 08314338dc..65b77a751a 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -249,7 +249,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
/mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, message_mode, atom/movable/source)
SEND_SIGNAL(src, COMSIG_MOVABLE_HEAR, args) //parent calls can't overwrite the current proc args.
- if(!client)
+ if(!client && !audiovisual_redirect)
return
var/deaf_message
var/deaf_type
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 5b487f503e..1671c4bca9 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -482,7 +482,7 @@
update_action_buttons_icon()
return mobility_flags
-/mob/living/simple_animal/update_transform()
+/mob/living/simple_animal/update_transform(do_animate)
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
var/changed = 0
diff --git a/code/modules/mob/living/update_icons.dm b/code/modules/mob/living/update_icons.dm
index d3264c93a2..4ad861bf2b 100644
--- a/code/modules/mob/living/update_icons.dm
+++ b/code/modules/mob/living/update_icons.dm
@@ -1,5 +1,5 @@
//IMPORTANT: Multiple animate() calls do not stack well, so try to do them all at once if you can.
-/mob/living/update_transform()
+/mob/living/update_transform(do_animate = TRUE)
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
var/final_pixel_y = pixel_y
var/changed = 0
@@ -25,5 +25,9 @@
resize = RESIZE_DEFAULT_SIZE
if(changed)
- animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, easing = EASE_IN|EASE_OUT)
+ if(do_animate)
+ animate(src, transform = ntransform, time = 2, pixel_y = final_pixel_y, easing = EASE_IN|EASE_OUT, flags = ANIMATION_PARALLEL)
+ else
+ transform = ntransform
+ pixel_y = final_pixel_y
floating_need_update = TRUE
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 5b13208c0c..be10567790 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -141,7 +141,7 @@
return
hearers -= ignored_mobs
- if(target_message && target && istype(target) && target.client)
+ if(target_message && target && istype(target) && (target.client || target.audiovisual_redirect))
hearers -= target
if(omni)
target.show_message(target_message)
@@ -158,7 +158,7 @@
if(self_message)
hearers -= src
for(var/mob/M in hearers)
- if(!M.client)
+ if(!M.client && !M.audiovisual_redirect)
continue
if(omni)
M.show_message(message)
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 561425c710..8595839831 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -229,17 +229,23 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
return copytext_char(sanitize(.),1,MAX_MESSAGE_LEN)
/proc/shake_camera(mob/M, duration, strength=1)
- if(!M || !M.client || duration < 1)
+ set waitfor = FALSE
+ if(!M || !M.client || duration <= 0)
return
var/client/C = M.client
+ if (C.prefs.screenshake==0)
+ return
var/oldx = C.pixel_x
var/oldy = C.pixel_y
- var/max = strength*world.icon_size
- var/min = -(strength*world.icon_size)
+ var/clientscreenshake = (C.prefs.screenshake * 0.01)
+ var/max = (strength*clientscreenshake) * world.icon_size
+ var/min = -((strength*clientscreenshake) * world.icon_size)
+ var/roundedduration = -round(-duration) // round() with only one arg will always round down. so uh. this is Something all right
- for(var/i in 0 to duration-1)
+ for(var/i in 0 to roundedduration-1)
+ duration--
if (i == 0)
- animate(C, pixel_x=rand(min,max), pixel_y=rand(min,max), time=1)
+ animate(C, pixel_x=(rand(min,max)*duration), pixel_y=(rand(min,max)*duration), time=1)
else
animate(pixel_x=rand(min,max), pixel_y=rand(min,max), time=1)
animate(pixel_x=oldx, pixel_y=oldy, time=1)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index 836ed3b804..3f2f4d3e65 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -3,6 +3,7 @@
name = "projectile gun"
icon_state = "pistol"
w_class = WEIGHT_CLASS_NORMAL
+ recoil = 0.25
var/spawnwithmagazine = TRUE
var/mag_type = /obj/item/ammo_box/magazine/m10mm //Removes the need for max_ammo and caliber info
var/obj/item/ammo_box/magazine/magazine
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index afb30631e0..fe42fc2d99 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -5,6 +5,7 @@
mag_type = /obj/item/ammo_box/magazine/internal/cylinder
fire_sound = "sound/weapons/revolvershot.ogg"
casing_ejector = FALSE
+ recoil = 0.5
/obj/item/gun/ballistic/revolver/Initialize(mapload)
. = ..()
@@ -285,6 +286,7 @@
item_state = "shotgun"
w_class = WEIGHT_CLASS_BULKY
weapon_weight = WEAPON_MEDIUM
+ recoil = 1
force = 10
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BACK
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index f7d57b43a0..b52620e7e0 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -5,6 +5,7 @@
item_state = "shotgun"
fire_sound = "sound/weapons/gunshotshotgunshot.ogg"
w_class = WEIGHT_CLASS_BULKY
+ recoil = 1
force = 10
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BACK
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index dd759f9e3c..03dfc46713 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -16,6 +16,7 @@
name = "energy gun"
desc = "A basic energy-based gun."
icon = 'icons/obj/guns/energy.dmi'
+ recoil = 0.1
var/obj/item/stock_parts/cell/cell //What type of power cell this uses
var/cell_type = /obj/item/stock_parts/cell
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index 3f41ac859f..9b10a843e8 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -8,6 +8,7 @@
item_flags = NONE
obj_flags = UNIQUE_RENAME
weapon_weight = WEAPON_LIGHT
+ recoil = 0.5
can_flashlight = 1
flight_x_offset = 15
flight_y_offset = 9
diff --git a/code/modules/projectiles/guns/misc/syringe_gun.dm b/code/modules/projectiles/guns/misc/syringe_gun.dm
index 07066023b3..8de7633a79 100644
--- a/code/modules/projectiles/guns/misc/syringe_gun.dm
+++ b/code/modules/projectiles/guns/misc/syringe_gun.dm
@@ -4,6 +4,7 @@
icon_state = "syringegun"
item_state = "syringegun"
w_class = WEIGHT_CLASS_NORMAL
+ recoil = 0.1
throw_speed = 3
throw_range = 7
force = 4
diff --git a/html/changelogs/AutoChangeLog-pr-15640.yml b/html/changelogs/AutoChangeLog-pr-15640.yml
new file mode 100644
index 0000000000..1b94ea8a36
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-15640.yml
@@ -0,0 +1,4 @@
+author: "SandPoot"
+delete-after: True
+changes:
+ - refactor: "Does some extremely minor touches on pulling/pushing code."
diff --git a/html/changelogs/AutoChangeLog-pr-15656.yml b/html/changelogs/AutoChangeLog-pr-15656.yml
new file mode 100644
index 0000000000..f0b3f92dd6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-15656.yml
@@ -0,0 +1,16 @@
+author: "Bhijn & Myr"
+delete-after: True
+changes:
+ - bugfix: "The shake animation, jiggle animation, squish animation, jitter animation, and float animation, have all been fixed."
+ - bugfix: "This also means that storage animations are fully working again. It's been a few years!"
+ - bugfix: "The pull animation no longer interrupts ongoing animations."
+ - tweak: "The pull animation now supports diagonal directions (currently only applies to the initial grab! pull code is spaghetti)"
+ - bugfix: "All screenshake sources now fully support the screenshake pref"
+ - code_imp: "cit_screenshake.dm has been fully merged into the base files."
+ - bugfix: "You can no longer remotely apply fingerprints to storage objects by clicking and dragging it around. Additionally, storage objects now rustle again when clicking and dragging (only took like,, a year to fix)"
+ - bugfix: "The pickup animation now properly slides into your spaceman again, instead of just kinda disappearing."
+ - tweak: When pulling a resting mob, they'll now skip the laying animation entirely, fixing a visual oddity where they shrink and grow to flip.
+ - tweak: Alerts are now a little snappier and bouncier, as they've been swapped from sine easing, to back easing.
+ - tweak: Radial menus now use sine easing, rather than linear easing. This just looks a little prettier.
+ - tweak: Runechat now properly respects an object's X offset. Previously, it relied on a hardcoded check for dogborgs.
+ - tweak: The float animation now uses pixel_z instead of pixel_y, fixing issues where the Y offset gets wiped due to the float animation. This also makes floating fully compatible with ctrl+WASD."
diff --git a/html/changelogs/AutoChangeLog-pr-15662.yml b/html/changelogs/AutoChangeLog-pr-15662.yml
new file mode 100644
index 0000000000..9a8281f206
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-15662.yml
@@ -0,0 +1,4 @@
+author: "Bhijn & Myr"
+delete-after: True
+changes:
+ - bugfix: "Audiovisual redirection now works exactly as it used to. In laymen's terms, this means folks in VR sleepers are aware of the world around them again!"
diff --git a/modular_citadel/code/game/objects/cit_screenshake.dm b/modular_citadel/code/game/objects/cit_screenshake.dm
deleted file mode 100644
index 222de37f82..0000000000
--- a/modular_citadel/code/game/objects/cit_screenshake.dm
+++ /dev/null
@@ -1,51 +0,0 @@
-//we vlambeer now
-
-/obj/proc/shake_camera(mob/M, duration, strength=1)//byond's wonky with this shit
- set waitfor = FALSE
- if(!M || !M.client || duration <= 0)
- return
- var/client/C = M.client
- if (C.prefs.screenshake==0)
- return
- var/oldx = C.pixel_x
- var/oldy = C.pixel_y
- var/clientscreenshake = (C.prefs.screenshake * 0.01)
- var/max = (strength*clientscreenshake) * world.icon_size
- var/min = -((strength*clientscreenshake) * world.icon_size)
-
- for(var/i in 0 to duration-1)
- if (i == 0)
- animate(C, pixel_x=rand(min,max), pixel_y=rand(min,max), time=1)
- else
- animate(pixel_x=rand(min,max), pixel_y=rand(min,max), time=1)
- animate(pixel_x=oldx, pixel_y=oldy, time=1)
-
-/obj/item/gun/energy
- recoil = 0.1
-
-/obj/item/gun/energy/kinetic_accelerator
- recoil = 0.5
-
-/obj/item/gun/ballistic
- recoil = 0.25
-
-/obj/item/gun/ballistic/shotgun
- recoil = 1
-
-/obj/item/gun/ballistic/revolver
- recoil = 0.5
-
-/obj/item/gun/ballistic/revolver/doublebarrel
- recoil = 1
-
-/obj/item/gun/syringe
- recoil = 0.1
-
-/obj/item/pneumatic_cannon/fire_items(turf/target, mob/user)
- . = ..()
- shake_camera(user, (pressureSetting * 0.75 + 1), (pressureSetting * 0.75))
-
-/obj/item/attack_obj(obj/O, mob/living/user)
- . = ..()
- if(force >= 20)
- shake_camera(user, ((force - 15) * 0.01 + 1), ((force - 15) * 0.01))
diff --git a/tgstation.dme b/tgstation.dme
index 27189b92c8..832c93203b 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -154,6 +154,8 @@
#include "code\__DEFINES\dcs\helpers.dm"
#include "code\__DEFINES\dcs\signals.dm"
#include "code\__DEFINES\dcs\signals\signals_subsystem.dm"
+#include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_movement.dm"
+#include "code\__DEFINES\dcs\signals\signals_mob\signals_mob_living.dm"
#include "code\__DEFINES\mapping\maploader.dm"
#include "code\__DEFINES\material\worth.dm"
#include "code\__DEFINES\mobs\innate_abilities.dm"
@@ -3783,7 +3785,6 @@
#include "interface\skin.dmf"
#include "modular_citadel\code\datums\components\souldeath.dm"
#include "modular_citadel\code\datums\status_effects\chems.dm"
-#include "modular_citadel\code\game\objects\cit_screenshake.dm"
#include "modular_citadel\code\game\objects\effects\temporary_visuals\souldeath.dm"
#include "modular_citadel\code\modules\admin\holder2.dm"
#include "modular_citadel\code\modules\admin\secrets.dm"