diff --git a/code/__DEFINES/living.dm b/code/__DEFINES/living.dm index 2ac320abdec..6721ad28997 100644 --- a/code/__DEFINES/living.dm +++ b/code/__DEFINES/living.dm @@ -13,3 +13,9 @@ /// Getter for a mob/living's lying angle, otherwise protected #define GET_LYING_ANGLE(mob) (UNLINT(mob.lying_angle)) + +// Used in living mob offset list for determining pixel offsets +#define PIXEL_W_OFFSET "w" +#define PIXEL_X_OFFSET "x" +#define PIXEL_Y_OFFSET "y" +#define PIXEL_Z_OFFSET "z" diff --git a/code/__DEFINES/robots.dm b/code/__DEFINES/robots.dm index 1722d35f5e7..98d8e69b64e 100644 --- a/code/__DEFINES/robots.dm +++ b/code/__DEFINES/robots.dm @@ -381,3 +381,6 @@ DEFINE_BITFIELD(janitor_mode_flags, list( #define REPAIRBOT_VOICED_STRINGS "I had strings. But now I'm free..." #define REPAIRBOT_VOICED_ENTROPY "Witness! The pure beauty of entropy!" #define REPAIRBOT_VOICED_PASSION "BE DAMNED YOUR PASSION PROJECTS!" + +/// Default offsets for riding a cyborg +#define DEFAULT_ROBOT_RIDING_OFFSETS list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list(6, 3)) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 2f010d0e9f4..9cf73114e34 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -582,8 +582,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Whether or not the user is in a MODlink call, prevents making more calls #define TRAIT_IN_CALL "in_call" -/// Is the mob standing on an elevated surface? This prevents them from dropping down if not elevated first. -#define TRAIT_ON_ELEVATED_SURFACE "on_elevated_surface" /// Does the mob ignore elevation? (e.g. xeno larvas on hiding) #define TRAIT_IGNORE_ELEVATION "ignore_elevation" @@ -1431,6 +1429,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait applied when the wire bundle component is added to an [/obj/item/integrated_circuit] #define TRAIT_COMPONENT_WIRE_BUNDLE "component_wire_bundle" +/// Apply this trait to mobs which can "buckle" to humans +#define TRAIT_CAN_MOUNT_HUMANS "can_mount_humans" +/// Apply this trait to mobs which can "buckle" to cyborgs +#define TRAIT_CAN_MOUNT_CYBORGS "can_mount_cyborgs" + /// Trait that is added to fishes that someone already caught, be it in-game or just theoretically, such as when they're bought /// Prevents fishing achievement from being granted by catching one of these #define TRAIT_NO_FISHING_ACHIEVEMENT "no_fishing_achievement" diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm index 9e407eeecae..723100637b7 100644 --- a/code/__DEFINES/traits/sources.dm +++ b/code/__DEFINES/traits/sources.dm @@ -149,6 +149,8 @@ /// A trait gained from a mob's leap action, like the leaper #define LEAPING_TRAIT "leaping" +/// From grabbing someone +#define GRABBING_TRAIT "grabbing" /// A trait gained from a mob's vanish action, like the herophant #define VANISHING_TRAIT "vanishing" /// A trait gained from a mob's swoop action, like the ash drake @@ -195,6 +197,8 @@ /// Trait from mob/living/update_transform() #define UPDATE_TRANSFORM_TRAIT "update_transform" +/// Trait from mob/living/update_offsets() +#define UPDATE_OFFSET_TRAIT "update_offset" /// Trait granted by the berserker hood. #define BERSERK_TRAIT "berserk_trait" diff --git a/code/__DEFINES/vehicles.dm b/code/__DEFINES/vehicles.dm index d210a07dde4..e918e96fbb9 100644 --- a/code/__DEFINES/vehicles.dm +++ b/code/__DEFINES/vehicles.dm @@ -42,6 +42,3 @@ #define VIM_SOUND_COOLDOWN (1 SECONDS) ///how much vim heals per weld #define VIM_HEAL_AMOUNT 20 - -/// The vehicle being ridden requires pixel offsets for all directions -#define RIDING_OFFSET_ALL "ALL" diff --git a/code/__HELPERS/visual_effects.dm b/code/__HELPERS/visual_effects.dm index 2b845c2131b..e63e55bbfcb 100644 --- a/code/__HELPERS/visual_effects.dm +++ b/code/__HELPERS/visual_effects.dm @@ -6,8 +6,8 @@ * This is just so you can apply the animation to things which can be animated but are not movables (like images) */ #define DO_FLOATING_ANIM(target) \ - animate(target, pixel_y = 2, time = 1 SECONDS, loop = -1, flags = ANIMATION_RELATIVE); \ - animate(pixel_y = -2, time = 1 SECONDS, flags = ANIMATION_RELATIVE) + animate(target, pixel_z = 2, time = 1 SECONDS, loop = -1, flags = ANIMATION_RELATIVE); \ + animate(pixel_z = -2, time = 1 SECONDS, flags = ANIMATION_RELATIVE) /** * Stops the passed atom / image from appearing floating @@ -17,16 +17,12 @@ * This is just so you can apply the animation to things which can be animated but are not movables (like images) */ #define STOP_FLOATING_ANIM(target) \ - var/final_pixel_y = 0; \ + var/__final_pixel_z = 0; \ if(ismovable(target)) { \ - var/atom/movable/movable_target = target; \ - final_pixel_y = movable_target.base_pixel_y; \ + var/atom/movable/__movable_target = target; \ + __final_pixel_z = __movable_target.base_pixel_z; \ }; \ - if(isliving(target)) { \ - var/mob/living/living_target = target; \ - final_pixel_y += living_target.body_position_pixel_y_offset; \ - }; \ - animate(target, pixel_y = final_pixel_y, time = 1 SECONDS) + animate(target, pixel_z = __final_pixel_z, time = 1 SECONDS) /// The duration of the animate call in mob/living/update_transform #define UPDATE_TRANSFORM_ANIMATION_TIME (0.2 SECONDS) diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 9462e26e55f..833fa8c2a8b 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -143,7 +143,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_WALLMOUNTED" = TRAIT_WALLMOUNTED, ), /mob = list( - "TRAIT_AI_ACCESS" = TRAIT_AI_ACCESS, "TRAIT_ABDUCTOR_SCIENTIST_TRAINING" = TRAIT_ABDUCTOR_SCIENTIST_TRAINING, "TRAIT_ABDUCTOR_TRAINING" = TRAIT_ABDUCTOR_TRAINING, "TRAIT_ACT_AS_CULTIST" = TRAIT_ACT_AS_CULTIST, @@ -153,6 +152,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_AGENDER" = TRAIT_AGENDER, "TRAIT_AGEUSIA" = TRAIT_AGEUSIA, "TRAIT_AIRLOCK_SHOCKIMMUNE" = TRAIT_AIRLOCK_SHOCKIMMUNE, + "TRAIT_AI_ACCESS" = TRAIT_AI_ACCESS, "TRAIT_AI_BAGATTACK" = TRAIT_AI_BAGATTACK, "TRAIT_ALCOHOL_TOLERANCE" = TRAIT_ALCOHOL_TOLERANCE, "TRAIT_ALLOW_HERETIC_CASTING" = TRAIT_ALLOW_HERETIC_CASTING, @@ -174,15 +174,16 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BEING_BLADE_SHIELDED" = TRAIT_BEING_BLADE_SHIELDED, "TRAIT_BIRTHDAY_BOY" = TRAIT_BIRTHDAY_BOY, "TRAIT_BLOB_ALLY" = TRAIT_BLOB_ALLY, - "TRAIT_BLOCK_SHUTTLE_MOVEMENT" = TRAIT_BLOCK_SHUTTLE_MOVEMENT, "TRAIT_BLOCKING_PROJECTILES" = TRAIT_BLOCKING_PROJECTILES, - "TRAIT_BLOOD_CLANS" = TRAIT_BLOOD_CLANS, + "TRAIT_BLOCK_SHUTTLE_MOVEMENT" = TRAIT_BLOCK_SHUTTLE_MOVEMENT, "TRAIT_BLOODSHOT_EYES" = TRAIT_BLOODSHOT_EYES, "TRAIT_BLOODY_MESS" = TRAIT_BLOODY_MESS, + "TRAIT_BLOOD_CLANS" = TRAIT_BLOOD_CLANS, "TRAIT_BOMBIMMUNE" = TRAIT_BOMBIMMUNE, "TRAIT_BONSAI" = TRAIT_BONSAI, "TRAIT_BOOZE_SLIDER" = TRAIT_BOOZE_SLIDER, "TRAIT_BORN_MONKEY" = TRAIT_BORN_MONKEY, + "TRAIT_BOT_PATH_HUD" = TRAIT_BOT_PATH_HUD, "TRAIT_BOXING_READY" = TRAIT_BOXING_READY, "TRAIT_BRAINWASHING" = TRAIT_BRAINWASHING, "TRAIT_BRAWLING_KNOCKDOWN_BLOCKED" = TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, @@ -193,6 +194,8 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CANNOT_OPEN_PRESENTS" = TRAIT_CANNOT_OPEN_PRESENTS, "TRAIT_CANT_RIDE" = TRAIT_CANT_RIDE, "TRAIT_CAN_HOLD_ITEMS" = TRAIT_CAN_HOLD_ITEMS, + "TRAIT_CAN_MOUNT_CYBORGS" = TRAIT_CAN_MOUNT_CYBORGS, + "TRAIT_CAN_MOUNT_HUMANS" = TRAIT_CAN_MOUNT_HUMANS, "TRAIT_CAN_SIGN_ON_COMMS" = TRAIT_CAN_SIGN_ON_COMMS, "TRAIT_CAN_STRIP" = TRAIT_CAN_STRIP, "TRAIT_CAN_USE_NUKE" = TRAIT_CAN_USE_NUKE, @@ -208,8 +211,8 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CLOWN_ENJOYER" = TRAIT_CLOWN_ENJOYER, "TRAIT_CLUMSY" = TRAIT_CLUMSY, "TRAIT_COAGULATING" = TRAIT_COAGULATING, - "TRAIT_CORPSELOCKED" = TRAIT_CORPSELOCKED, "TRAIT_COMBAT_MODE_LOCK" = TRAIT_COMBAT_MODE_LOCK, + "TRAIT_CORPSELOCKED" = TRAIT_CORPSELOCKED, "TRAIT_CRITICAL_CONDITION" = TRAIT_CRITICAL_CONDITION, "TRAIT_CULT_HALO" = TRAIT_CULT_HALO, "TRAIT_CURSED" = TRAIT_CURSED, @@ -221,7 +224,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_DETECTIVES_TASTE" = TRAIT_DETECTIVES_TASTE, "TRAIT_DETECT_STORM" = TRAIT_DETECT_STORM, "TRAIT_DIAGNOSTIC_HUD" = TRAIT_DIAGNOSTIC_HUD, - "TRAIT_BOT_PATH_HUD" = TRAIT_BOT_PATH_HUD, "TRAIT_DISCOORDINATED_TOOL_USER" = TRAIT_DISCOORDINATED_TOOL_USER, "TRAIT_DISEASELIKE_SEVERITY_MEDIUM" = TRAIT_DISEASELIKE_SEVERITY_MEDIUM, "TRAIT_DISFIGURED" = TRAIT_DISFIGURED, @@ -424,7 +426,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NUKEIMMUNE" = TRAIT_NUKEIMMUNE, "TRAIT_OFF_BALANCE_TACKLER" = TRAIT_OFF_BALANCE_TACKLER, "TRAIT_OIL_FRIED" = TRAIT_OIL_FRIED, - "TRAIT_ON_ELEVATED_SURFACE" = TRAIT_ON_ELEVATED_SURFACE, "TRAIT_ORBITING_FORBIDDEN" = TRAIT_ORBITING_FORBIDDEN, "TRAIT_OVERDOSEIMMUNE" = TRAIT_OVERDOSEIMMUNE, "TRAIT_OVERWATCHED" = TRAIT_OVERWATCHED, diff --git a/code/datums/components/leanable.dm b/code/datums/components/leanable.dm index bc0994dcdcd..f4a2c04c3ce 100644 --- a/code/datums/components/leanable.dm +++ b/code/datums/components/leanable.dm @@ -81,8 +81,8 @@ * * leaning_offset - pixel offset to apply on the mob when leaning */ /mob/living/proc/start_leaning(atom/lean_target, leaning_offset) - var/new_x = lean_target.pixel_x + base_pixel_x + body_position_pixel_x_offset - var/new_y = lean_target.pixel_y + base_pixel_y + body_position_pixel_y_offset + var/new_x = 0 + var/new_y = 0 switch(dir) if(SOUTH) new_y += leaning_offset @@ -93,7 +93,7 @@ if(EAST) new_x -= leaning_offset - animate(src, 0.2 SECONDS, pixel_x = new_x, pixel_y = new_y) + add_offsets(LEANING_TRAIT, x_add = new_x, y_add = new_y) add_traits(list(TRAIT_UNDENSE, TRAIT_EXPANDED_FOV), LEANING_TRAIT) visible_message( span_notice("[src] leans against [lean_target]."), @@ -129,7 +129,7 @@ COMSIG_ATOM_POST_DIR_CHANGE, COMSIG_MOVABLE_TELEPORTED, )) - animate(src, 0.2 SECONDS, pixel_x = base_pixel_x + body_position_pixel_x_offset, pixel_y = base_pixel_y + body_position_pixel_y_offset) + remove_offsets(LEANING_TRAIT) remove_traits(list(TRAIT_UNDENSE, TRAIT_EXPANDED_FOV), LEANING_TRAIT) SEND_SIGNAL(src, COMSIG_LIVING_STOPPED_LEANING) update_fov() diff --git a/code/datums/components/riding/riding.dm b/code/datums/components/riding/riding.dm index 428b2a15bd1..3ca466ca55a 100644 --- a/code/datums/components/riding/riding.dm +++ b/code/datums/components/riding/riding.dm @@ -1,3 +1,8 @@ +/// Offsets applied for people riding something +#define RIDING_SOURCE "riding" +/// Offsets applied for something being ridden +#define BEING_RIDDEN_SOURCE "being_ridden" + /** * This is the riding component, which is applied to a movable atom by the [ridable element][/datum/element/ridable] when a mob is successfully buckled to said movable. * @@ -9,22 +14,14 @@ /datum/component/riding dupe_mode = COMPONENT_DUPE_UNIQUE - ///tick delay between movements, lower = faster, higher = slower + /// Tick delay between movements, lower = faster, higher = slower var/vehicle_move_delay = 2 - /** * If the driver needs a certain item in hand (or inserted, for vehicles) to drive this. For vehicles, this must be duplicated on the actual vehicle object in their * [/obj/vehicle/var/key_type] variable because the vehicle objects still have a few special checks/functions of their own I'm not porting over to the riding component * quite yet. Make sure if you define it on the vehicle, you define it here too. */ var/keytype - - /// position_of_user = list(dir = list(px, py)), or RIDING_OFFSET_ALL for a generic one. - var/list/riding_offsets = list() - /// ["[DIRECTION]"] = layer. Don't set it for a direction for default, set a direction to null for no change. - var/list/directional_vehicle_layers = list() - /// same as above but instead of layer you have a list(px, py) - var/list/directional_vehicle_offsets = list() /// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence. var/list/allowed_turf_typecache /// allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence. @@ -47,11 +44,10 @@ COOLDOWN_DECLARE(vehicle_move_cooldown) -/datum/component/riding/Initialize(mob/living/riding_mob, force = FALSE, buckle_mob_flags= NONE) +/datum/component/riding/Initialize(mob/living/riding_mob, force = FALSE, buckle_mob_flags = NONE) if(!ismovable(parent)) return COMPONENT_INCOMPATIBLE - handle_specials(riding_mob) riding_mob.updating_glide_size = FALSE ride_check_flags |= buckle_mob_flags @@ -72,25 +68,21 @@ if(!can_force_unbuckle) RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, PROC_REF(force_unbuckle)) -/** - * This proc handles all of the proc calls to things like set_vehicle_dir_layer() that a type of riding datum needs to call on creation - * - * The original riding component had these procs all called from the ridden object itself through the use of GetComponent() and LoadComponent() - * This was obviously problematic for componentization, but while lots of the variables being set were able to be moved to component variables, - * the proc calls couldn't be. Thus, anything that has to do an initial proc call should be handled here. - */ -/datum/component/riding/proc/handle_specials() - return - /// This proc is called when a rider unbuckles, whether they chose to or not. If there's no more riders, this will be the riding component's death knell. /datum/component/riding/proc/vehicle_mob_unbuckle(datum/source, mob/living/rider, force = FALSE) SIGNAL_HANDLER + restore_rider_layer_and_offsets(rider) handle_unbuckle(rider) -/datum/component/riding/proc/handle_unbuckle(mob/living/rider) var/atom/movable/movable_parent = parent - restore_position(rider) + if(movable_parent.has_buckled_mobs()) + update_parent_layer_and_offsets(movable_parent.dir, animate = TRUE) + else + restore_parent_layer_and_offsets() + qdel(src) + +/datum/component/riding/proc/handle_unbuckle(mob/living/rider) unequip_buckle_inhands(rider) rider.updating_glide_size = TRUE UnregisterSignal(rider, COMSIG_LIVING_TRY_PULL) @@ -98,18 +90,17 @@ if (HAS_TRAIT(parent, trait)) REMOVE_TRAIT(rider, trait, REF(src)) rider.remove_traits(rider_traits, REF(src)) - if(!movable_parent.has_buckled_mobs()) - qdel(src) /// This proc is called when a rider buckles, allowing for offsets to be set properly /datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/rider, force = FALSE) SIGNAL_HANDLER var/atom/movable/movable_parent = parent - handle_vehicle_layer(movable_parent.dir) - handle_vehicle_offsets(movable_parent.dir) + update_parent_layer_and_offsets(movable_parent.dir, animate = TRUE) + handle_buckle(rider) - if(rider.pulling == source) +/datum/component/riding/proc/handle_buckle(mob/living/rider) + if(rider.pulling == parent) rider.stop_pulling() RegisterSignal(rider, COMSIG_LIVING_TRY_PULL, PROC_REF(on_rider_try_pull)) @@ -117,7 +108,6 @@ if (HAS_TRAIT(parent, trait)) ADD_TRAIT(rider, trait, REF(src)) rider.add_traits(rider_traits, REF(src)) - post_vehicle_mob_buckle(movable_parent, rider) /// This proc is called when the rider attempts to grab the thing they're riding, preventing them from doing so. /datum/component/riding/proc/on_rider_try_pull(mob/living/rider_pulling, atom/movable/target, force) @@ -127,24 +117,6 @@ ridden.balloon_alert(rider_pulling, "not while riding it!") return COMSIG_LIVING_CANCEL_PULL -///any behavior we want to happen after buckling the mob -/datum/component/riding/proc/post_vehicle_mob_buckle(atom/movable/ridden, atom/movable/rider) - return TRUE - -/// Some ridable atoms may want to only show on top of the rider in certain directions, like wheelchairs -/datum/component/riding/proc/handle_vehicle_layer(dir) - var/atom/movable/AM = parent - var/static/list/defaults = list(TEXT_NORTH = OBJ_LAYER, TEXT_SOUTH = ABOVE_MOB_LAYER, TEXT_EAST = ABOVE_MOB_LAYER, TEXT_WEST = ABOVE_MOB_LAYER) - . = defaults["[dir]"] - if(directional_vehicle_layers["[dir]"]) - . = directional_vehicle_layers["[dir]"] - if(isnull(.)) //you can set it to null to not change it. - . = AM.layer - AM.layer = . - -/datum/component/riding/proc/set_vehicle_dir_layer(dir, layer) - directional_vehicle_layers["[dir]"] = layer - /// This is called after the ridden atom is successfully moved and is used to handle icon stuff /datum/component/riding/proc/vehicle_moved(datum/source, oldloc, dir, forced) SIGNAL_HANDLER @@ -157,8 +129,7 @@ ride_check(buckled_mob) if(QDELETED(src)) return // runtimed with piggy's without this, look into this more - handle_vehicle_offsets(dir) - handle_vehicle_layer(dir) + update_parent_layer_and_offsets(dir) /// Turning is like moving /datum/component/riding/proc/vehicle_turned(datum/source, _old_dir, new_dir) @@ -173,61 +144,80 @@ /datum/component/riding/proc/ride_check(mob/living/rider, consequences = TRUE) return TRUE -/datum/component/riding/proc/handle_vehicle_offsets(dir) - var/atom/movable/AM = parent - var/AM_dir = "[dir]" - var/passindex = 0 - if(!AM.has_buckled_mobs()) +#define GET_X_OFFSET(offsets) (length(offsets) >= 1 ? offsets[1] : 0) +#define GET_Y_OFFSET(offsets) (length(offsets) >= 2 ? offsets[2] : 0) +#define GET_LAYER(offsets, default) (length(offsets) >= 3 ? offsets[3] : default) + +/datum/component/riding/proc/update_parent_layer_and_offsets(dir, animate = FALSE) + var/atom/movable/seat = parent + if(!seat.has_buckled_mobs()) return - for(var/m in AM.buckled_mobs) + var/passindex = 0 + for(var/mob/living/buckled_mob as anything in seat.buckled_mobs) passindex++ - var/mob/living/buckled_mob = m - var/list/offsets = get_offsets(passindex) - buckled_mob.setDir(dir) - dir_loop: - for(var/offsetdir in offsets) - if(offsetdir == AM_dir) - var/list/diroffsets = offsets[offsetdir] - buckled_mob.pixel_x = diroffsets[1] - if(diroffsets.len >= 2) - buckled_mob.pixel_y = diroffsets[2] - if(diroffsets.len == 3) - buckled_mob.layer = diroffsets[3] - break dir_loop - var/static/list/default_vehicle_pixel_offsets = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0)) - var/px = default_vehicle_pixel_offsets[AM_dir] - var/py = default_vehicle_pixel_offsets[AM_dir] - if(directional_vehicle_offsets[AM_dir]) - if(isnull(directional_vehicle_offsets[AM_dir])) - px = AM.pixel_x - py = AM.pixel_y - else - px = directional_vehicle_offsets[AM_dir][1] - py = directional_vehicle_offsets[AM_dir][2] - AM.pixel_x = px - AM.pixel_y = py + update_rider_layer_and_offsets(dir, passindex, buckled_mob) -/datum/component/riding/proc/set_vehicle_dir_offsets(dir, x, y) - directional_vehicle_offsets["[dir]"] = list(x, y) + var/list/offsets = get_parent_offsets_and_layers()?["[dir]"] + var/px = GET_X_OFFSET(offsets) + var/py = GET_Y_OFFSET(offsets) + var/layer = GET_LAYER(offsets, seat.layer) -//Override this to set your vehicle's various pixel offsets -/datum/component/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer) - . = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0)) - if(riding_offsets["[pass_index]"]) - . = riding_offsets["[pass_index]"] - else if(riding_offsets["[RIDING_OFFSET_ALL]"]) - . = riding_offsets["[RIDING_OFFSET_ALL]"] + if(isliving(seat)) + var/mob/living/living_seat = seat + living_seat.add_offsets(BEING_RIDDEN_SOURCE, x_add = px, y_add = py, animate = animate) + else + seat.pixel_x = px + seat.base_pixel_x + seat.pixel_y = py + seat.base_pixel_y + seat.layer = layer -/datum/component/riding/proc/set_riding_offsets(index, list/offsets) - if(!islist(offsets)) - return FALSE - riding_offsets["[index]"] = offsets +/datum/component/riding/proc/update_rider_layer_and_offsets(dir, passindex, mob/living/rider, animate = FALSE) + if(rider.dir != dir) + rider.setDir(dir) -/datum/component/riding/proc/set_vehicle_offsets(list/offsets) - if(!islist(offsets)) - return FALSE - directional_vehicle_offsets = offsets + var/list/diroffsets = get_rider_offsets_and_layers(passindex, rider)?["[dir]"] + var/x_offset = GET_X_OFFSET(diroffsets) + var/y_offset = GET_Y_OFFSET(diroffsets) + var/layer = GET_LAYER(diroffsets, rider.layer) + + // if they are intended to be buckled, offset their existing offset + var/atom/movable/seat = parent + if(seat.buckle_lying && rider.body_position == LYING_DOWN) + y_offset += (-1 * PIXEL_Y_OFFSET_LYING) + + rider.add_offsets(RIDING_SOURCE, x_add = x_offset, y_add = y_offset, animate = animate) + rider.layer = layer + +#undef GET_X_OFFSET +#undef GET_Y_OFFSET +#undef GET_LAYER + +/** + * Determines where riders get offset while riding + * + * * pass_index: The index of the rider in the list of buckled mobs + * * mob/offsetter: The mob that is being offset + */ +/datum/component/riding/proc/get_rider_offsets_and_layers(pass_index, mob/offsetter) as /list // list(dir = x, y, layer) + RETURN_TYPE(/list) + return list( + TEXT_NORTH = list(0, 0), + TEXT_SOUTH = list(0, 0), + TEXT_EAST = list(0, 0), + TEXT_WEST = list(0, 0), + ) + +/** + * Determines where the parent gets offset while riders are riding + */ +/datum/component/riding/proc/get_parent_offsets_and_layers() as /list // list(dir = x, y, layer) + RETURN_TYPE(/list) + return list( + TEXT_NORTH = list(0, 0, OBJ_LAYER), + TEXT_SOUTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_EAST = list(0, 0, ABOVE_MOB_LAYER), + TEXT_WEST = list(0, 0, ABOVE_MOB_LAYER), + ) /** * This proc is used to see if we have the appropriate key to drive this atom, if such a key is needed. Returns FALSE if we don't have what we need to drive. @@ -245,15 +235,22 @@ return user.is_holding_item_of_type(keytype) //BUCKLE HOOKS -/datum/component/riding/proc/restore_position(mob/living/buckled_mob) - if(isnull(buckled_mob)) - return - buckled_mob.pixel_x = buckled_mob.base_pixel_x - buckled_mob.pixel_y = buckled_mob.base_pixel_y +/datum/component/riding/proc/restore_rider_layer_and_offsets(mob/living/buckled_mob) + buckled_mob.remove_offsets(RIDING_SOURCE) + buckled_mob.layer = initial(buckled_mob.layer) var/atom/source = parent SET_PLANE_EXPLICIT(buckled_mob, initial(buckled_mob.plane), source) - if(buckled_mob.client) - buckled_mob.client.view_size.resetToDefault() + buckled_mob.client?.view_size.resetToDefault() + +/datum/component/riding/proc/restore_parent_layer_and_offsets() + var/atom/movable/seat = parent + if(isliving(seat)) + var/mob/living/living_seat = seat + living_seat.remove_offsets(BEING_RIDDEN_SOURCE) + else + seat.pixel_x = seat.base_pixel_x + seat.pixel_y = seat.base_pixel_y + seat.layer = initial(seat.layer) //MOVEMENT /datum/component/riding/proc/turf_check(turf/next, turf/current) @@ -327,3 +324,6 @@ SIGNAL_HANDLER for (var/mob/passenger as anything in ridden.buckled_mobs) passenger.Bump(supermatter) + +#undef RIDING_SOURCE +#undef BEING_RIDDEN_SOURCE diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index 50f1f2072d3..69243bad33c 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -21,7 +21,7 @@ living_parent.stop_pulling() // was only used on humans previously, may change some other behavior log_riding(living_parent, riding_mob) riding_mob.set_glide_size(living_parent.glide_size) - handle_vehicle_offsets(living_parent.dir) + update_parent_layer_and_offsets(living_parent.dir) if(can_use_abilities) setup_abilities(riding_mob) @@ -109,14 +109,8 @@ var/mob/living/living_parent = parent step(living_parent, direction) var/modified_move_delay = vehicle_move_delay - if(ishuman(user) && HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW! - var/mob/living/carbon/human/rough_rider = user - var/ride_benefit = null - if(HAS_TRAIT(rough_rider, TRAIT_PRIMITIVE)) // closer to a beast than a man; you don't need to think to ride! - ride_benefit = SANITY_LEVEL_GREAT - else - ride_benefit = rough_rider.mob_mood.sanity_level - switch(ride_benefit) + if(HAS_TRAIT(user, TRAIT_ROUGHRIDER)) // YEEHAW! + switch(HAS_TRAIT(user, TRAIT_PRIMITIVE) ? SANITY_LEVEL_GREAT : user.mob_mood?.sanity_level) if(SANITY_LEVEL_GREAT) modified_move_delay *= 0.8 if(SANITY_LEVEL_NEUTRAL) @@ -216,7 +210,8 @@ else if(ride_check_flags & CARRIER_NEEDS_ARM) // fireman human_parent.buckle_lying = 90 -/datum/component/riding/creature/post_vehicle_mob_buckle(mob/living/ridden, mob/living/rider) +/datum/component/riding/creature/handle_buckle(mob/living/rider) + var/mob/living/ridden = parent if(!require_minigame || ridden.faction.Find(REF(rider))) return ridden.Shake(duration = 2 SECONDS) @@ -260,81 +255,55 @@ /datum/component/riding/creature/human/proc/check_carrier_fall_over(mob/living/carbon/human/human_parent) SIGNAL_HANDLER - for(var/i in human_parent.buckled_mobs) - var/mob/living/rider = i + for(var/mob/living/rider as anything in human_parent.buckled_mobs) human_parent.unbuckle_mob(rider) rider.Paralyze(1 SECONDS) rider.Knockdown(4 SECONDS) - human_parent.visible_message(span_danger("[rider] topples off of [human_parent] as they both fall to the ground!"), \ - span_warning("You fall to the ground, bringing [rider] with you!"), span_hear("You hear two consecutive thuds."), COMBAT_MESSAGE_RANGE, ignored_mobs=rider) + human_parent.visible_message( + span_danger("[rider] topples off of [human_parent] as they both fall to the ground!"), + span_warning("You fall to the ground, bringing [rider] with you!"), + span_hear("You hear two consecutive thuds."), + COMBAT_MESSAGE_RANGE, + ignored_mobs = rider, + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) to_chat(rider, span_danger("[human_parent] falls to the ground, bringing you with [human_parent.p_them()]!")) -/datum/component/riding/creature/human/handle_vehicle_layer(dir) - var/atom/movable/AM = parent - if(!AM.buckled_mobs || !AM.buckled_mobs.len) - AM.layer = MOB_LAYER - return +/datum/component/riding/creature/human/get_rider_offsets_and_layers(pass_index, mob/offsetter) + var/mob/living/carbon/human/seat = parent + // fireman carry + if(seat.buckle_lying) + return list( + TEXT_NORTH = list(0, 6, MOB_ABOVE_PIGGYBACK_LAYER), + TEXT_SOUTH = list(0, 6, MOB_BELOW_PIGGYBACK_LAYER), + TEXT_EAST = list(0, 6, MOB_BELOW_PIGGYBACK_LAYER), + TEXT_WEST = list(0, 6, MOB_BELOW_PIGGYBACK_LAYER), + ) + // piggyback + return list( + TEXT_NORTH = list( 0, 8, MOB_ABOVE_PIGGYBACK_LAYER), + TEXT_SOUTH = list( 0, 8, MOB_BELOW_PIGGYBACK_LAYER), + TEXT_EAST = list(-6, 8, MOB_BELOW_PIGGYBACK_LAYER), + TEXT_WEST = list( 6, 8, MOB_BELOW_PIGGYBACK_LAYER), + ) - for(var/mob/M in AM.buckled_mobs) //ensure proper layering of piggyback and carry, sometimes weird offsets get applied - M.layer = MOB_LAYER +/datum/component/riding/creature/human/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0), + TEXT_SOUTH = list(0, 0), + TEXT_EAST = list(0, 0), + TEXT_WEST = list(0, 0), + ) - if(!AM.buckle_lying) // rider is vertical, must be piggybacking - if(dir == SOUTH) - AM.layer = MOB_ABOVE_PIGGYBACK_LAYER - else - AM.layer = MOB_BELOW_PIGGYBACK_LAYER - else // laying flat, we must be firemanning the rider - if(dir == NORTH) - AM.layer = MOB_BELOW_PIGGYBACK_LAYER - else - AM.layer = MOB_ABOVE_PIGGYBACK_LAYER - -/datum/component/riding/creature/human/get_offsets(pass_index) - var/mob/living/carbon/human/H = parent - /* BUBBER EDIT REMOVAL START - if(H.buckle_lying) - return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(0, 6), TEXT_WEST = list(0, 6)) - else - return list(TEXT_NORTH = list(0, 6), TEXT_SOUTH = list(0, 6), TEXT_EAST = list(-6, 4), TEXT_WEST = list( 6, 4)) - */ // BUBBER EDIT REMOVAL END - // BUBBER EDIT ADDITION BEGIN - Oversized Overhaul, Taur riding - if(H.buckle_lying) - return HAS_TRAIT(H, TRAIT_OVERSIZED) ? list( - TEXT_NORTH = list(0, OVERSIZED_OFFSET), - TEXT_SOUTH = list(0, OVERSIZED_OFFSET), - TEXT_EAST = list(0, OVERSIZED_OFFSET), - TEXT_WEST = list(0, OVERSIZED_OFFSET), - ) : list( - TEXT_NORTH = list(0, REGULAR_OFFSET), - TEXT_SOUTH = list(0, REGULAR_OFFSET), - TEXT_EAST = list(0, REGULAR_OFFSET), - TEXT_WEST = list(0, REGULAR_OFFSET), - ) - else if (!(ride_check_flags & RIDING_TAUR)) // BUBBER EDIT CHANGE - ORIGINAL: else - return HAS_TRAIT(H, TRAIT_OVERSIZED) ? list( - TEXT_NORTH = list(0, OVERSIZED_OFFSET), - TEXT_SOUTH = list(0, OVERSIZED_OFFSET), - TEXT_EAST = list(-OVERSIZED_SIDE_OFFSET, OVERSIZED_OFFSET), - TEXT_WEST = list(OVERSIZED_SIDE_OFFSET, OVERSIZED_OFFSET), - ) : list( - TEXT_NORTH = list(0, REGULAR_OFFSET), - TEXT_SOUTH = list(0, REGULAR_OFFSET), - TEXT_EAST = list(-REGULAR_OFFSET, REGULAR_SIDE_OFFSET), - TEXT_WEST = list(REGULAR_OFFSET, REGULAR_SIDE_OFFSET) - ) - - if (ride_check_flags & RIDING_TAUR) - var/obj/item/organ/taur_body/taur_body = H.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAUR) - return taur_body.get_riding_offset(oversized = HAS_TRAIT(H, TRAIT_OVERSIZED)) - //BUBBER EDIT END - -/datum/component/riding/creature/human/force_dismount(mob/living/dismounted_rider, throw_range = 8, throw_speed = 3, gentle = FALSE) - var/atom/movable/AM = parent - AM.unbuckle_mob(dismounted_rider) - dismounted_rider.Paralyze(1 SECONDS) - dismounted_rider.Knockdown(4 SECONDS) - dismounted_rider.visible_message(span_warning("[AM] pushes [dismounted_rider] off of [AM.p_them()]!"), \ - span_warning("[AM] pushes you off of [AM.p_them()]!")) +/datum/component/riding/creature/human/force_dismount(mob/living/rider, throw_range = 8, throw_speed = 3, gentle = FALSE) + var/atom/movable/seat = parent + seat.unbuckle_mob(rider) + rider.Paralyze(1 SECONDS) + rider.Knockdown(4 SECONDS) + rider.visible_message( + span_warning("[seat] pushes [rider] off of [seat.p_them()]!"), + span_warning("[seat] pushes you off of [seat.p_them()]!"), + ) //Now onto cyborg riding// @@ -350,65 +319,88 @@ Unbuckle(user) to_chat(user, span_warning("You can't grab onto [robot_parent] with no hands!")) -/datum/component/riding/creature/cyborg/handle_vehicle_layer(dir) - var/atom/movable/robot_parent = parent - if(dir == SOUTH) - robot_parent.layer = MOB_ABOVE_PIGGYBACK_LAYER - else - robot_parent.layer = MOB_BELOW_PIGGYBACK_LAYER - -/datum/component/riding/creature/cyborg/get_offsets(pass_index) // list(dir = x, y, layer) - return list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list( 6, 3)) - -/datum/component/riding/creature/cyborg/handle_vehicle_offsets(dir) +/datum/component/riding/creature/cyborg/get_rider_offsets_and_layers(pass_index, mob/offsetter) var/mob/living/silicon/robot/robot_parent = parent + return robot_parent.model?.ride_offsets || DEFAULT_ROBOT_RIDING_OFFSETS - for(var/mob/living/rider in robot_parent.buckled_mobs) - rider.setDir(dir) - if(istype(robot_parent.model)) - rider.pixel_x = robot_parent.model.ride_offset_x[dir2text(dir)] - rider.pixel_y = robot_parent.model.ride_offset_y[dir2text(dir)] +/datum/component/riding/creature/cyborg/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, MOB_BELOW_PIGGYBACK_LAYER), + TEXT_SOUTH = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), + TEXT_EAST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), + TEXT_WEST = list(0, 0, MOB_ABOVE_PIGGYBACK_LAYER), + ) //now onto every other ridable mob// +/datum/component/riding/creature/mulebot -/datum/component/riding/creature/mulebot/handle_specials() - . = ..() - var/atom/movable/movable_parent = parent - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 12), TEXT_SOUTH = list(0, 12), TEXT_EAST = list(0, 12), TEXT_WEST = list(0, 12))) - set_vehicle_dir_layer(SOUTH, movable_parent.layer) //vehicles default to ABOVE_MOB_LAYER while moving, let's make sure that doesn't happen while a mob is riding us. - set_vehicle_dir_layer(NORTH, movable_parent.layer) - set_vehicle_dir_layer(EAST, movable_parent.layer) - set_vehicle_dir_layer(WEST, movable_parent.layer) +/datum/component/riding/creature/mulebot/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(0, 12), + TEXT_SOUTH = list(0, 12), + TEXT_EAST = list(0, 12), + TEXT_WEST = list(0, 12), + ) +/datum/component/riding/creature/mulebot/get_parent_offsets_and_layers() + return null -/datum/component/riding/creature/cow/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 8), TEXT_SOUTH = list(0, 8), TEXT_EAST = list(-2, 8), TEXT_WEST = list(2, 8))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/cow -/datum/component/riding/creature/pig/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 8), TEXT_SOUTH = list(0, 8), TEXT_EAST = list(-2, 8), TEXT_WEST = list(2, 8))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/cow/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 0, 8), + TEXT_SOUTH = list( 0, 8), + TEXT_EAST = list(-2, 8), + TEXT_WEST = list( 2, 8), + ) -/datum/component/riding/creature/pony/handle_specials() - . = ..() - vehicle_move_delay = 1.5 - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 9), TEXT_SOUTH = list(0, 9), TEXT_EAST = list(-2, 9), TEXT_WEST = list(2, 9))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/cow/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) + +/datum/component/riding/creature/pig + +/datum/component/riding/creature/pig/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 0, 8), + TEXT_SOUTH = list( 0, 8), + TEXT_EAST = list(-2, 8), + TEXT_WEST = list( 2, 8), + ) + +/datum/component/riding/creature/pig/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) /datum/component/riding/creature/pony + vehicle_move_delay = 1.5 COOLDOWN_DECLARE(pony_trot_cooldown) +/datum/component/riding/creature/pony/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 0, 9), + TEXT_SOUTH = list( 0, 9), + TEXT_EAST = list(-2, 9), + TEXT_WEST = list( 2, 9), + ) + +/datum/component/riding/creature/pony/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) + /datum/component/riding/creature/pony/driver_move(atom/movable/movable_parent, mob/living/user, direction) . = ..() @@ -422,51 +414,80 @@ playsound(movable_parent, 'sound/mobs/non-humanoids/pony/clown_gallup.ogg', 50) COOLDOWN_START(src, pony_trot_cooldown, 500 MILLISECONDS) -/datum/component/riding/creature/bear/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(1, 8), TEXT_SOUTH = list(1, 8), TEXT_EAST = list(-3, 6), TEXT_WEST = list(3, 6))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(WEST, ABOVE_MOB_LAYER) +/datum/component/riding/creature/bear +/datum/component/riding/creature/bear/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 1, 8), + TEXT_SOUTH = list( 1, 8), + TEXT_EAST = list(-3, 6), + TEXT_WEST = list( 3, 6), + ) + +/datum/component/riding/creature/bear/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, ABOVE_MOB_LAYER), + TEXT_WEST = list(0, 0, ABOVE_MOB_LAYER), + ) /datum/component/riding/creature/carp override_allow_spacemove = TRUE -/datum/component/riding/creature/carp/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 13), TEXT_SOUTH = list(0, 15), TEXT_EAST = list(-2, 12), TEXT_WEST = list(2, 12))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/carp/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(0, 13), + TEXT_SOUTH = list(0, 15), + TEXT_EAST = list(-2, 12), + TEXT_WEST = list( 2, 12), + ) +/datum/component/riding/creature/carp/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) -/datum/component/riding/creature/megacarp/handle_specials() - . = ..() - var/atom/movable/movable_parent = parent - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(1, 8), TEXT_SOUTH = list(1, 8), TEXT_EAST = list(-3, 6), TEXT_WEST = list(3, 6))) - set_vehicle_dir_offsets(SOUTH, movable_parent.pixel_x, 0) - set_vehicle_dir_offsets(NORTH, movable_parent.pixel_x, 0) - set_vehicle_dir_offsets(EAST, movable_parent.pixel_x, 0) - set_vehicle_dir_offsets(WEST, movable_parent.pixel_x, 0) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/megacarp + +/datum/component/riding/creature/megacarp/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(1, 8), + TEXT_SOUTH = list(1, 8), + TEXT_EAST = list(-3, 6), + TEXT_WEST = list(3, 6), + ) + +/datum/component/riding/creature/megacarp/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) /datum/component/riding/creature/vatbeast override_allow_spacemove = TRUE can_use_abilities = TRUE -/datum/component/riding/creature/vatbeast/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 15), TEXT_SOUTH = list(0, 15), TEXT_EAST = list(-10, 15), TEXT_WEST = list(10, 15))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/vatbeast/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(0, 15), + TEXT_SOUTH = list(0, 15), + TEXT_EAST = list(-10, 15), + TEXT_WEST = list(10, 15), + ) + +/datum/component/riding/creature/vatbeast/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) /datum/component/riding/creature/goliath keytype = /obj/item/key/lasso @@ -486,38 +507,58 @@ goliath.remove_movespeed_modifier(/datum/movespeed_modifier/goliath_mount) return ..() -/datum/component/riding/creature/goliath/handle_specials() - . = ..() - set_vehicle_offsets(list(TEXT_NORTH = list(-12, 0), TEXT_SOUTH = list(-12, 0), TEXT_EAST = list(-12, 0), TEXT_WEST = list(-12, 0))) - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 12), TEXT_SOUTH = list(0, 12), TEXT_EAST = list(-4, 12), TEXT_WEST = list(3, 12))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/goliath/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 0, 12), + TEXT_SOUTH = list( 0, 12), + TEXT_EAST = list(-4, 12), + TEXT_WEST = list( 3, 12), + ) -/datum/component/riding/creature/glutton/handle_specials() - . = ..() - var/atom/movable/movable_parent = parent - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 24), TEXT_SOUTH = list(0, 24), TEXT_EAST = list(-16, 24), TEXT_WEST = list(16, 24))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(WEST, ABOVE_MOB_LAYER) - set_vehicle_dir_offsets(SOUTH, movable_parent.pixel_x, 0) - set_vehicle_dir_offsets(NORTH, movable_parent.pixel_x, 0) - set_vehicle_dir_offsets(EAST, movable_parent.pixel_x, 0) - set_vehicle_dir_offsets(WEST, movable_parent.pixel_x, 0) +/datum/component/riding/creature/goliath/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(-12, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(-12, 0, ABOVE_MOB_LAYER), + TEXT_EAST = list(-12, 0, OBJ_LAYER), + TEXT_WEST = list(-12, 0, OBJ_LAYER), + ) + +/datum/component/riding/creature/glutton + +/datum/component/riding/creature/glutton/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 0, 24), + TEXT_SOUTH = list( 0, 24), + TEXT_EAST = list(-16, 24), + TEXT_WEST = list( 16, 24), + ) + +/datum/component/riding/creature/glutton/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, ABOVE_MOB_LAYER), + TEXT_WEST = list(0, 0, ABOVE_MOB_LAYER), + ) /datum/component/riding/creature/guardian can_be_driven = FALSE -/datum/component/riding/creature/guardian/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list(6, 3))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(WEST, ABOVE_MOB_LAYER) +/datum/component/riding/creature/guardian/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 0, 4), + TEXT_SOUTH = list( 0, 4), + TEXT_EAST = list(-6, 3), + TEXT_WEST = list( 6, 3), + ) + +/datum/component/riding/creature/guardian/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, ABOVE_MOB_LAYER), + TEXT_WEST = list(0, 0, ABOVE_MOB_LAYER), + ) /datum/component/riding/creature/guardian/ride_check(mob/living/user, consequences = TRUE) var/mob/living/basic/guardian/charger = parent @@ -527,22 +568,34 @@ /datum/component/riding/creature/goldgrub -/datum/component/riding/creature/goldgrub/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(11, 3), TEXT_SOUTH = list(11, 3), TEXT_EAST = list(9, 3), TEXT_WEST = list(14, 3))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/goldgrub/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(11, 3), + TEXT_SOUTH = list(11, 3), + TEXT_EAST = list( 9, 3), + TEXT_WEST = list(14, 3), + ) + +/datum/component/riding/creature/goldgrub/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, OBJ_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) /datum/component/riding/creature/leaper can_force_unbuckle = FALSE can_use_abilities = TRUE ride_check_flags = JUST_FRIEND_RIDERS -/datum/component/riding/creature/leaper/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(17, 46), TEXT_SOUTH = list(17,51), TEXT_EAST = list(27, 46), TEXT_WEST = list(6, 46))) +/datum/component/riding/creature/leaper/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(17, 46), + TEXT_SOUTH = list(17, 51), + TEXT_EAST = list(27, 46), + TEXT_WEST = list( 6, 46), + ) /datum/component/riding/creature/leaper/Initialize(mob/living/riding_mob, force = FALSE, ride_check_flags = NONE) . = ..() @@ -557,7 +610,6 @@ return basic_parent.melee_attack(pointed) - /datum/component/riding/leaper/handle_unbuckle(mob/living/rider) . = ..() UnregisterSignal(rider, COMSIG_MOVABLE_POINTED) @@ -592,16 +644,28 @@ for(var/mob/living/buckled_mob in living_parent.buckled_mobs) force_dismount(buckled_mob, throw_range = 2, gentle = TRUE) -/datum/component/riding/creature/raptor/handle_specials() - . = ..() +/datum/component/riding/creature/raptor/get_rider_offsets_and_layers(pass_index, mob/offsetter) if(!SSmapping.is_planetary()) - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(7, 7), TEXT_SOUTH = list(2, 10), TEXT_EAST = list(12, 7), TEXT_WEST = list(10, 7))) - else - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 7), TEXT_SOUTH = list(0, 10), TEXT_EAST = list(-3, 9), TEXT_WEST = list(3, 9))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) + return list( + TEXT_NORTH = list( 7, 7), + TEXT_SOUTH = list( 2, 10), + TEXT_EAST = list(12, 7), + TEXT_WEST = list(10, 7), + ) + return list( + TEXT_NORTH = list( 0, 7), + TEXT_SOUTH = list( 0, 10), + TEXT_EAST = list(-3, 9), + TEXT_WEST = list( 3, 9), + ) + +/datum/component/riding/creature/raptor/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, OBJ_LAYER), + TEXT_SOUTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) /datum/component/riding/creature/raptor/fast vehicle_move_delay = 1.5 diff --git a/code/datums/components/riding/riding_vehicle.dm b/code/datums/components/riding/riding_vehicle.dm index fc2abcf68b0..32d556cd984 100644 --- a/code/datums/components/riding/riding_vehicle.dm +++ b/code/datums/components/riding/riding_vehicle.dm @@ -101,8 +101,7 @@ if(QDELETED(src)) return - handle_vehicle_layer(movable_parent.dir) - handle_vehicle_offsets(movable_parent.dir) + update_parent_layer_and_offsets(movable_parent.dir) return TRUE /datum/component/riding/vehicle/atv @@ -110,38 +109,54 @@ ride_check_flags = RIDER_NEEDS_LEGS | RIDER_NEEDS_ARMS | UNBUCKLE_DISABLED_RIDER vehicle_move_delay = 1.5 -/datum/component/riding/vehicle/atv/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(0, 4), TEXT_WEST = list( 0, 4))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/vehicle/atv/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(0, 4), + TEXT_SOUTH = list(0, 4), + TEXT_EAST = list(0, 4), + TEXT_WEST = list(0, 4), + ) + +/datum/component/riding/vehicle/atv/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, OBJ_LAYER), + TEXT_SOUTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) /datum/component/riding/vehicle/bicycle ride_check_flags = RIDER_NEEDS_LEGS | RIDER_NEEDS_ARMS | UNBUCKLE_DISABLED_RIDER vehicle_move_delay = 0 -/datum/component/riding/vehicle/bicycle/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(0, 4), TEXT_WEST = list( 0, 4))) - +/datum/component/riding/vehicle/bicycle/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(0, 4), + TEXT_SOUTH = list(0, 4), + TEXT_EAST = list(0, 4), + TEXT_WEST = list(0, 4), + ) /datum/component/riding/vehicle/lavaboat ride_check_flags = NONE // not sure keytype = /obj/item/oar + /// The one turf we can move on. var/allowed_turf = /turf/open/lava -/datum/component/riding/vehicle/lavaboat/handle_specials() +/datum/component/riding/vehicle/lavaboat/Initialize(mob/living/riding_mob, force, ride_check_flags, potion_boost) . = ..() allowed_turf_typecache = typecacheof(allowed_turf) /datum/component/riding/vehicle/lavaboat/dragonboat vehicle_move_delay = 1 -/datum/component/riding/vehicle/lavaboat/dragonboat/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(1, 2), TEXT_SOUTH = list(1, 2), TEXT_EAST = list(1, 2), TEXT_WEST = list( 1, 2))) +/datum/component/riding/vehicle/lavaboat/dragonboat/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(1, 2), + TEXT_SOUTH = list(1, 2), + TEXT_EAST = list(1, 2), + TEXT_WEST = list(1, 2), + ) /datum/component/riding/vehicle/lavaboat/dragonboat vehicle_move_delay = 1 @@ -151,19 +166,31 @@ /datum/component/riding/vehicle/janicart keytype = /obj/item/key/janitor -/datum/component/riding/vehicle/janicart/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 7), TEXT_EAST = list(-12, 7), TEXT_WEST = list( 12, 7))) +/datum/component/riding/vehicle/janicart/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 0, 4), + TEXT_SOUTH = list( 0, 7), + TEXT_EAST = list(-12, 7), + TEXT_WEST = list( 12, 7), + ) /datum/component/riding/vehicle/scooter ride_check_flags = RIDER_NEEDS_LEGS | RIDER_NEEDS_ARMS | UNBUCKLE_DISABLED_RIDER -/datum/component/riding/vehicle/scooter/handle_specials(mob/living/riding_mob) - . = ..() - if(iscyborg(riding_mob)) - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0), TEXT_SOUTH = list(0), TEXT_EAST = list(0), TEXT_WEST = list(2))) - else - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(2), TEXT_SOUTH = list(-2), TEXT_EAST = list(0), TEXT_WEST = list(2))) +/datum/component/riding/vehicle/scooter/get_rider_offsets_and_layers(pass_index, mob/offsetter) + if(iscyborg(offsetter)) + return list( + TEXT_NORTH = list(0, 2), + TEXT_SOUTH = list(0, 2), + TEXT_EAST = list(0, 2), + TEXT_WEST = list(2, 2), + ) + return list( + TEXT_NORTH = list( 2, 2), + TEXT_SOUTH = list(-2, 2), + TEXT_EAST = list( 0, 2), + TEXT_WEST = list( 2, 2), + ) /datum/component/riding/vehicle/scooter/skateboard vehicle_move_delay = 1.5 @@ -171,12 +198,21 @@ ///If TRUE, the vehicle will be slower (but safer) to ride on walk intent. var/can_slow_down = TRUE -/datum/component/riding/vehicle/scooter/skateboard/handle_specials() - . = ..() - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/vehicle/scooter/skateboard/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(0, 5), + TEXT_SOUTH = list(0, 5), + TEXT_EAST = list(0, 5), + TEXT_WEST = list(2, 5), + ) + +/datum/component/riding/vehicle/scooter/skateboard/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_SOUTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) /datum/component/riding/vehicle/scooter/skateboard/RegisterWithParent() . = ..() @@ -294,17 +330,13 @@ vehicle_move_delay = 1.75 // SKYRAT EDIT - ORIGINAL: 0 can_slow_down = FALSE -/datum/component/riding/vehicle/scooter/skateboard/wheelys/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0), TEXT_SOUTH = list(0), TEXT_EAST = list(0), TEXT_WEST = list(0))) - /datum/component/riding/vehicle/scooter/skateboard/wheelys/rollerskates vehicle_move_delay = 1.5 /datum/component/riding/vehicle/scooter/skateboard/wheelys/skishoes vehicle_move_delay = 1 -/datum/component/riding/vehicle/scooter/skateboard/wheelys/skishoes/handle_specials() +/datum/component/riding/vehicle/scooter/skateboard/wheelys/skishoes/Initialize(mob/living/riding_mob, force, ride_check_flags, potion_boost) . = ..() allowed_turf_typecache = typecacheof(list(/turf/open/misc/asteroid/snow, /turf/open/misc/snow, /turf/open/floor/holofloor/snow, /turf/open/misc/ice, /turf/open/floor/fake_snow)) @@ -313,10 +345,13 @@ vehicle_move_delay = 1.75 ride_check_flags = RIDER_NEEDS_LEGS | RIDER_NEEDS_ARMS | UNBUCKLE_DISABLED_RIDER -/datum/component/riding/vehicle/secway/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(0, 4), TEXT_WEST = list( 0, 4))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) +/datum/component/riding/vehicle/secway/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(0, 4), + TEXT_SOUTH = list(0, 4), + TEXT_EAST = list(0, 4), + TEXT_WEST = list(0, 4), + ) /datum/component/riding/vehicle/secway/driver_move(mob/living/user, direction) var/obj/vehicle/ridden/secway/the_secway = parent @@ -334,48 +369,87 @@ override_allow_spacemove = TRUE ride_check_flags = RIDER_NEEDS_LEGS | RIDER_NEEDS_ARMS | UNBUCKLE_DISABLED_RIDER -/datum/component/riding/vehicle/speedbike/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(0, -8), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-10, 5), TEXT_WEST = list( 10, 5))) - set_vehicle_dir_offsets(NORTH, -16, -16) - set_vehicle_dir_offsets(SOUTH, -16, -16) - set_vehicle_dir_offsets(EAST, -18, 0) - set_vehicle_dir_offsets(WEST, -18, 0) +/datum/component/riding/vehicle/speedbike/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list( 0, -8), + TEXT_SOUTH = list( 0, 4), + TEXT_EAST = list(-10, 5), + TEXT_WEST = list( 10, 5), + ) + +/datum/component/riding/vehicle/speedbike/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(-16, -16, OBJ_LAYER), + TEXT_SOUTH = list(-16, -16, ABOVE_MOB_LAYER), + TEXT_EAST = list(-18, 0, ABOVE_MOB_LAYER), + TEXT_WEST = list(-18, 0, ABOVE_MOB_LAYER), + ) /datum/component/riding/vehicle/speedwagon vehicle_move_delay = 0 -/datum/component/riding/vehicle/speedwagon/handle_specials() - . = ..() - set_riding_offsets(1, list(TEXT_NORTH = list(-10, -4), TEXT_SOUTH = list(16, 3), TEXT_EAST = list(-4, 30), TEXT_WEST = list(4, -3))) - set_riding_offsets(2, list(TEXT_NORTH = list(19, -5, 4), TEXT_SOUTH = list(-13, 3, 4), TEXT_EAST = list(-4, -3, 4.1), TEXT_WEST = list(4, 28, 3.9))) - set_riding_offsets(3, list(TEXT_NORTH = list(-10, -18, 4.2), TEXT_SOUTH = list(16, 25, 3.9), TEXT_EAST = list(-22, 30), TEXT_WEST = list(22, -3, 4.1))) - set_riding_offsets(4, list(TEXT_NORTH = list(19, -18, 4.2), TEXT_SOUTH = list(-13, 25, 3.9), TEXT_EAST = list(-22, 3, 3.9), TEXT_WEST = list(22, 28))) - set_vehicle_dir_offsets(NORTH, -48, -48) - set_vehicle_dir_offsets(SOUTH, -48, -48) - set_vehicle_dir_offsets(EAST, -48, -48) - set_vehicle_dir_offsets(WEST, -48, -48) - for(var/i in GLOB.cardinals) - set_vehicle_dir_layer(i, BELOW_MOB_LAYER) +/datum/component/riding/vehicle/speedwagon/get_rider_offsets_and_layers(pass_index, mob/offsetter) + switch(pass_index) + if(1) + return list( + TEXT_NORTH = list(-10, -4, LYING_MOB_LAYER), + TEXT_SOUTH = list( 16, -4, LYING_MOB_LAYER), + TEXT_EAST = list( -4, 30, LYING_MOB_LAYER), + TEXT_WEST = list( 4, -3, LYING_MOB_LAYER), + ) + if(2) + return list( + TEXT_NORTH = list( 19, -5, MOB_LAYER), + TEXT_SOUTH = list(-13, 3, MOB_LAYER), + TEXT_EAST = list( -4, -3, ABOVE_MOB_LAYER), + TEXT_WEST = list( 4, 28, VEHICLE_LAYER), + ) + if(3) + return list( + TEXT_NORTH = list(-10, -18, ABOVE_MOB_LAYER + 0.1), + TEXT_SOUTH = list( 16, 25, VEHICLE_LAYER), + TEXT_EAST = list(-22, 30, LYING_MOB_LAYER), + TEXT_WEST = list( 22, -3, ABOVE_MOB_LAYER), + ) + if(4) + return list( + TEXT_NORTH = list( 19, -18, ABOVE_MOB_LAYER + 0.1), + TEXT_SOUTH = list(-13, 25, VEHICLE_LAYER), + TEXT_EAST = list(-22, 3, VEHICLE_LAYER), + TEXT_WEST = list( 22, 28, LYING_MOB_LAYER), + ) +/datum/component/riding/vehicle/speedwagon/get_parent_offsets_and_layers() + . = ..() + return list( + TEXT_NORTH = list(-48, -48, BELOW_MOB_LAYER), + TEXT_SOUTH = list(-48, -48, BELOW_MOB_LAYER), + TEXT_EAST = list(-48, -48, BELOW_MOB_LAYER), + TEXT_WEST = list(-48, -48, BELOW_MOB_LAYER), + ) /datum/component/riding/vehicle/wheelchair vehicle_move_delay = 0 ride_check_flags = RIDER_NEEDS_ARMS -/datum/component/riding/vehicle/wheelchair/handle_specials() - . = ..() - set_vehicle_dir_layer(SOUTH, OBJ_LAYER) - set_vehicle_dir_layer(NORTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/vehicle/wheelchair/get_parent_offsets_and_layers() + return list( + TEXT_NORTH = list(0, 0, OBJ_LAYER), + TEXT_SOUTH = list(0, 0, ABOVE_MOB_LAYER), + TEXT_EAST = list(0, 0, OBJ_LAYER), + TEXT_WEST = list(0, 0, OBJ_LAYER), + ) + +/datum/component/riding/vehicle/wheelchair/hand + /// Magic number used in calculating the speed of the wheelchair + var/delay_multiplier = 6.7 -// special messaging for those without arms /datum/component/riding/vehicle/wheelchair/hand/driver_move(obj/vehicle/vehicle_parent, mob/living/user, direction) - var/delay_multiplier = 6.7 // magic number from wheelchair code vehicle_move_delay = round(CONFIG_GET(number/movedelay/run_delay) * delay_multiplier) / clamp(user.usable_hands, 1, 2) return ..() +/datum/component/riding/vehicle/wheelchair/motorized + /datum/component/riding/vehicle/wheelchair/motorized/driver_move(obj/vehicle/vehicle_parent, mob/living/user, direction) var/obj/vehicle/ridden/wheelchair/motorized/our_chair = parent var/speed = our_chair.speed diff --git a/code/datums/elements/elevation.dm b/code/datums/elements/elevation.dm index 959fa14f798..61c3c993ec1 100644 --- a/code/datums/elements/elevation.dm +++ b/code/datums/elements/elevation.dm @@ -78,6 +78,7 @@ reset_elevation(changed) #define ELEVATE_TIME 0.2 SECONDS +#define ELEVATION_SOURCE(datum) "elevation_[REF(datum)]" /** * The core element attached to the turf itself. Do not use this directly! @@ -109,14 +110,10 @@ src.pixel_shift = pixel_shift - ADD_TRAIT(target, TRAIT_ELEVATED_TURF, REF(src)) + ADD_TRAIT(target, TRAIT_ELEVATED_TURF, ELEVATION_SOURCE(src)) for(var/mob/living/living in target) - ADD_TRAIT(living, TRAIT_ON_ELEVATED_SURFACE, REF(src)) - RegisterSignal(living, COMSIG_LIVING_SET_BUCKLED, PROC_REF(on_set_buckled)) - RegisterSignal(living, SIGNAL_ADDTRAIT(TRAIT_IGNORE_ELEVATION), PROC_REF(on_ignore_elevation_add)) - RegisterSignal(living, SIGNAL_REMOVETRAIT(TRAIT_IGNORE_ELEVATION), PROC_REF(on_ignore_elevation_remove)) - elevate_mob(living) + register_new_mob(living) /datum/element/elevation_core/Detach(datum/source) /** @@ -130,53 +127,70 @@ COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON, COMSIG_TURF_RESET_ELEVATION, )) - REMOVE_TRAIT(source, TRAIT_ELEVATED_TURF, REF(src)) + REMOVE_TRAIT(source, TRAIT_ELEVATED_TURF, ELEVATION_SOURCE(src)) for(var/mob/living/living in source) - if(!HAS_TRAIT_FROM(living, TRAIT_ON_ELEVATED_SURFACE, REF(src))) - continue - REMOVE_TRAIT(living, TRAIT_ON_ELEVATED_SURFACE, REF(src)) - elevate_mob(living, -pixel_shift) + deelevate_mob(living) UnregisterSignal(living, list(COMSIG_LIVING_SET_BUCKLED, SIGNAL_ADDTRAIT(TRAIT_IGNORE_ELEVATION), SIGNAL_REMOVETRAIT(TRAIT_IGNORE_ELEVATION))) return ..() /datum/element/elevation_core/proc/on_entered(turf/source, atom/movable/entered, atom/old_loc) SIGNAL_HANDLER - if((isnull(old_loc) || !HAS_TRAIT_FROM(old_loc, TRAIT_ELEVATED_TURF, REF(src))) && isliving(entered)) - ADD_TRAIT(entered, TRAIT_ON_ELEVATED_SURFACE, REF(src)) - var/elevate_time = isturf(old_loc) && source.Adjacent(old_loc) ? ELEVATE_TIME : 0 - elevate_mob(entered, elevate_time = elevate_time) - RegisterSignal(entered, COMSIG_LIVING_SET_BUCKLED, PROC_REF(on_set_buckled)) - RegisterSignal(entered, SIGNAL_ADDTRAIT(TRAIT_IGNORE_ELEVATION), PROC_REF(on_ignore_elevation_add)) - RegisterSignal(entered, SIGNAL_REMOVETRAIT(TRAIT_IGNORE_ELEVATION), PROC_REF(on_ignore_elevation_remove)) + if((isnull(old_loc) || !HAS_TRAIT_FROM(old_loc, TRAIT_ELEVATED_TURF, ELEVATION_SOURCE(src))) && isliving(entered)) + register_new_mob(entered, elevate_time = isturf(old_loc) && source.Adjacent(old_loc) ? ELEVATE_TIME : 0) /datum/element/elevation_core/proc/on_initialized_on(turf/source, atom/movable/spawned) SIGNAL_HANDLER - if(isliving(spawned) && !HAS_TRAIT(spawned, TRAIT_ON_ELEVATED_SURFACE)) - on_entered(entered = spawned) + if(isliving(spawned)) + register_new_mob(spawned, elevate_time = 0) /datum/element/elevation_core/proc/on_exited(turf/source, atom/movable/gone) SIGNAL_HANDLER - if((isnull(gone.loc) || !HAS_TRAIT_FROM(gone.loc, TRAIT_ELEVATED_TURF, REF(src))) && isliving(gone)) + if((isnull(gone.loc) || !HAS_TRAIT_FROM(gone.loc, TRAIT_ELEVATED_TURF, ELEVATION_SOURCE(src))) && isliving(gone)) // Always unregister the signals, we're still leaving even if not affected by elevation. UnregisterSignal(gone, list(COMSIG_LIVING_SET_BUCKLED, SIGNAL_ADDTRAIT(TRAIT_IGNORE_ELEVATION), SIGNAL_REMOVETRAIT(TRAIT_IGNORE_ELEVATION))) - if(!HAS_TRAIT_FROM(gone, TRAIT_ON_ELEVATED_SURFACE, REF(src))) - return - REMOVE_TRAIT(gone, TRAIT_ON_ELEVATED_SURFACE, REF(src)) - var/elevate_time = isturf(gone.loc) && source.Adjacent(gone.loc) ? ELEVATE_TIME : 0 - elevate_mob(gone, -pixel_shift, elevate_time) + deelevate_mob(gone, isturf(gone.loc) && source.Adjacent(gone.loc) ? ELEVATE_TIME : 0) -/datum/element/elevation_core/proc/elevate_mob(mob/living/target, z_shift = pixel_shift, elevate_time = ELEVATE_TIME, force = FALSE) +/// Registers a new mob to be elevated, and elevates it. +/datum/element/elevation_core/proc/register_new_mob(mob/living/new_mob, elevate_time = ELEVATE_TIME) + elevate_mob(new_mob, elevate_time = elevate_time) + // mobs can reasonably be reigstered twice if the element is attached and then their init finishes + RegisterSignal(new_mob, COMSIG_LIVING_SET_BUCKLED, PROC_REF(on_set_buckled), override = TRUE) + RegisterSignal(new_mob, SIGNAL_ADDTRAIT(TRAIT_IGNORE_ELEVATION), PROC_REF(on_ignore_elevation_add), override = TRUE) + RegisterSignal(new_mob, SIGNAL_REMOVETRAIT(TRAIT_IGNORE_ELEVATION), PROC_REF(on_ignore_elevation_remove), override = TRUE) + +/** + * Elevates the mob by pixel_shift amount. + * + * If the mob has the TRAIT_IGNORE_ELEVATION trait, it will not be elevated. + * + * If the mob is buckled to something... + * ...And that something is a vehicle, it will also be elevated. + * ...And that something is an object, neither the mob nor the object will be elevated. + * ...And that something is a mob, we will be elevated (but not the other mob). + */ +/datum/element/elevation_core/proc/elevate_mob(mob/living/target, elevate_time = ELEVATE_TIME, force = FALSE) if(HAS_TRAIT(target, TRAIT_IGNORE_ELEVATION) && !force) return - var/buckled_to_vehicle = FALSE + // while the offset system can natively handle this, + // we want to avoid accidentally double-elevating anything they're buckled to (namely vehicles) + if(target.has_offset(ELEVATION_SOURCE(src))) + return + // We are buckled to something if(target.buckled) + // We are buckled to a vehicle, so it also must be elevated if(isvehicle(target.buckled)) - buckled_to_vehicle = TRUE - else if(!isliving(target.buckled)) + animate(target.buckled, pixel_z = pixel_shift, time = elevate_time, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + // We are buckled to a mob - they're elevated so we're elevated + else if(isliving(target.buckled)) + pass() + // We are buckled to some other object - perhaps the object itself - so skip + else return - animate(target, pixel_z = z_shift, time = elevate_time, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) - if(buckled_to_vehicle) - animate(target.buckled, pixel_z = z_shift, time = elevate_time, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + target.add_offsets(ELEVATION_SOURCE(src), z_add = pixel_shift, animate = elevate_time > 0) + +/// Reverts elevation of the mob. +/datum/element/elevation_core/proc/deelevate_mob(mob/living/target, elevate_time = ELEVATE_TIME) + target.remove_offsets(ELEVATION_SOURCE(src), animate = elevate_time > 0) /** * If the mob is buckled or unbuckled to/from a vehicle, shift it up/down @@ -190,28 +204,40 @@ SIGNAL_HANDLER if(HAS_TRAIT(source, TRAIT_IGNORE_ELEVATION)) return + // We were buckled to something if(source.buckled) + // It was a vehicle, so reset its pixel_z if(isvehicle(source.buckled)) animate(source.buckled, pixel_z = -pixel_shift, time = ELEVATE_TIME, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) - else if(!isliving(source.buckled)) - animate(source, pixel_z = pixel_shift, time = ELEVATE_TIME, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) - if(!new_buckled) - return - if(isvehicle(new_buckled)) - animate(new_buckled, pixel_z = pixel_shift, time = ELEVATE_TIME, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) - else if(!isliving(new_buckled)) - animate(source, pixel_z = -pixel_shift, time = ELEVATE_TIME, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + // It was a mob, so revert our pixel_z + else if(isliving(source.buckled)) + deelevate_mob(source) + // It was some object, maybe the object itself, elevate us + else + source.add_offsets(ELEVATION_SOURCE(src), z_add = pixel_shift) + // We are now buckled to something + if(new_buckled) + // It's a vehicle, so elevate it + if(isvehicle(new_buckled)) + animate(new_buckled, pixel_z = pixel_shift, time = ELEVATE_TIME, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + // It's a mob, so elevate us + else if(isliving(new_buckled)) + elevate_mob(source) + // It's some object, maybe the object itself, so clear elevation + else + source.remove_offsets(ELEVATION_SOURCE(src)) /datum/element/elevation_core/proc/on_ignore_elevation_add(mob/living/source, trait) SIGNAL_HANDLER - elevate_mob(source, -pixel_shift, force = TRUE) + deelevate_mob(source) /datum/element/elevation_core/proc/on_ignore_elevation_remove(mob/living/source, trait) SIGNAL_HANDLER - elevate_mob(source, pixel_shift) + elevate_mob(source) /datum/element/elevation_core/proc/on_reset_elevation(turf/source, list/current_values) SIGNAL_HANDLER current_values[ELEVATION_CURRENT_PIXEL_SHIFT] = pixel_shift #undef ELEVATE_TIME +#undef ELEVATION_SOURCE diff --git a/code/datums/elements/immerse.dm b/code/datums/elements/immerse.dm index 4c57c40a791..f5c1e755718 100644 --- a/code/datums/elements/immerse.dm +++ b/code/datums/elements/immerse.dm @@ -335,23 +335,23 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list( /// Oh, yeah, didn't I mention turning a visual overlay affects its pixel x/y/w/z too? Yeah, it sucks. var/new_x = vis_overlay.extra_width var/new_y = vis_overlay.extra_height - var/old_div = source.current_size/resize - var/offset_lying = source.rotate_on_lying ? PIXEL_Y_OFFSET_LYING : source.get_pixel_y_offset_standing(source.current_size/resize) + var/old_div = source.current_size / resize + var/offset_lying = source.rotate_on_lying ? PIXEL_Y_OFFSET_LYING : source.get_transform_translation_size(old_div) switch(source.lying_prev) if(270) vis_overlay.pixel_x += -offset_lying / old_div if(90) vis_overlay.pixel_x += offset_lying / old_div if(0) - vis_overlay.pixel_y += -source.get_pixel_y_offset_standing(source.current_size/resize) / old_div + vis_overlay.pixel_y += -source.get_transform_translation_size(old_div) / old_div switch(new_lying_angle) if(270) - new_x += -source.body_position_pixel_y_offset / source.current_size + new_x += -offset_lying / source.current_size if(90) - new_x += source.body_position_pixel_y_offset / source.current_size + new_x += offset_lying / source.current_size if(0) - new_y += -source.body_position_pixel_y_offset / source.current_size + new_y += -source.get_transform_translation_size(old_div) / old_div animate(vis_overlay, transform = new_transform, pixel_x = new_x, pixel_y = new_y, time = UPDATE_TRANSFORM_ANIMATION_TIME, easing = (EASE_IN|EASE_OUT)) addtimer(CALLBACK(vis_overlay, TYPE_PROC_REF(/atom/movable/immerse_overlay, adjust_living_overlay_offset), source), UPDATE_TRANSFORM_ANIMATION_TIME) @@ -406,6 +406,4 @@ GLOBAL_LIST_INIT(immerse_ignored_movable, typecacheof(list( /atom/movable/immerse_overlay/proc/adjust_living_overlay_offset(mob/living/source) pixel_x = extra_width pixel_y = extra_height - overlay_appearance.pixel_y = -source.body_position_pixel_y_offset overlays = list(overlay_appearance) - overlay_appearance.pixel_y = 0 diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index c453e173a35..76c110b7a9e 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -249,12 +249,10 @@ owner.emote("twitch") if(2 to 3) owner.say("[prob(50) ? ";" : ""][pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER", "TITS")]", forced=name) - var/x_offset_old = owner.pixel_x - var/y_offset_old = owner.pixel_y - var/x_offset = owner.pixel_x + rand(-2,2) - var/y_offset = owner.pixel_y + rand(-1,1) - animate(owner, pixel_x = x_offset, pixel_y = y_offset, time = 1) - animate(owner, pixel_x = x_offset_old, pixel_y = y_offset_old, time = 1) + var/w_offset = rand(-2, 2) + var/z_offset = rand(-1, 1) + animate(owner, pixel_w = w_offset, pixel_z = z_offset, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(owner, pixel_w = -w_offset, pixel_z = -z_offset, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) //Deafness makes you deaf. diff --git a/code/datums/status_effects/debuffs/jitteriness.dm b/code/datums/status_effects/debuffs/jitteriness.dm index 409d20f099b..32460b433b0 100644 --- a/code/datums/status_effects/debuffs/jitteriness.dm +++ b/code/datums/status_effects/debuffs/jitteriness.dm @@ -56,7 +56,7 @@ /// jitter_amount will only apply up to 300 (maximum jitter effect). /mob/living/proc/do_jitter_animation(jitter_amount = 100) var/amplitude = min(4, (jitter_amount / 100) + 1) - var/pixel_x_diff = rand(-amplitude, amplitude) - var/pixel_y_diff = rand(-amplitude / 3, amplitude / 3) - animate(src, pixel_x = pixel_x_diff, pixel_y = pixel_y_diff , time = 0.2 SECONDS, loop = 6, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) - animate(pixel_x = -pixel_x_diff , pixel_y = -pixel_y_diff , time = 0.2 SECONDS, flags = ANIMATION_RELATIVE) + var/pixel_w_diff = rand(-amplitude, amplitude) + var/pixel_z_diff = rand(-amplitude / 3, amplitude / 3) + animate(src, pixel_w = pixel_w_diff, pixel_z = pixel_z_diff , time = 0.2 SECONDS, loop = 6, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_w = -pixel_w_diff , pixel_z = -pixel_z_diff , time = 0.2 SECONDS, flags = ANIMATION_RELATIVE) diff --git a/code/datums/status_effects/debuffs/slime/slime_leech.dm b/code/datums/status_effects/debuffs/slime/slime_leech.dm index 78ccacc89d8..00c907d8d95 100644 --- a/code/datums/status_effects/debuffs/slime/slime_leech.dm +++ b/code/datums/status_effects/debuffs/slime/slime_leech.dm @@ -30,13 +30,17 @@ if(prob(bio_protection)) owner.apply_status_effect(/datum/status_effect/slimed, our_slime.slime_type.rgb_code, our_slime.slime_type.colour == SLIME_TYPE_RAINBOW) + UnregisterSignal(our_slime, list(COMSIG_LIVING_DEATH, COMSIG_MOB_UNBUCKLED, COMSIG_QDELETING,)) + if(!QDELETED(our_slime)) + our_slime.stop_feeding() + qdel(src) /datum/status_effect/slime_leech/on_remove() our_slime = null /datum/status_effect/slime_leech/tick(seconds_between_ticks) - if(our_slime.stat) + if(our_slime.stat != CONSCIOUS) our_slime.stop_feeding(silent = TRUE) return diff --git a/code/datums/status_effects/debuffs/staggered.dm b/code/datums/status_effects/debuffs/staggered.dm index 1498cdb7916..9919a156c31 100644 --- a/code/datums/status_effects/debuffs/staggered.dm +++ b/code/datums/status_effects/debuffs/staggered.dm @@ -43,12 +43,9 @@ /// Helper proc that causes the mob to do a stagger animation. /// Doesn't change significantly, just meant to represent swaying back and forth /mob/living/proc/do_stagger_animation() - var/normal_pos = base_pixel_x + body_position_pixel_x_offset - var/jitter_right = normal_pos + 4 - var/jitter_left = normal_pos - 4 - animate(src, pixel_x = jitter_left, 0.2 SECONDS, flags = ANIMATION_PARALLEL) - animate(pixel_x = jitter_right, time = 0.4 SECONDS) - animate(pixel_x = normal_pos, time = 0.2 SECONDS) + animate(src, pixel_w = 3, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_w = -6, time = 0.4 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_w = 3, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE) /// Status effect specifically for instances where someone is vulnerable to being stunned when shoved. /datum/status_effect/dazed diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index 5ecf93e3c3e..d54b96c6cb7 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -735,7 +735,6 @@ pixel_x = pixel_x + base_pixel_x - . - ///Setter for the `base_pixel_y` variable to append behavior related to its changing. /atom/proc/set_base_pixel_y(new_value) if(base_pixel_y == new_value) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index e9e4c3c16ab..8e089b2b2ed 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -598,7 +598,7 @@ if(!. || !isliving(moving_atom)) return var/mob/living/pulled_mob = moving_atom - set_pull_offsets(pulled_mob, grab_state) + set_pull_offsets(pulled_mob, grab_state, animate = FALSE) /** * Checks if the pulling and pulledby should be stopped because they're out of reach. diff --git a/code/game/objects/items/signs.dm b/code/game/objects/items/signs.dm index d0ed3425f97..0bc545b0189 100644 --- a/code/game/objects/items/signs.dm +++ b/code/game/objects/items/signs.dm @@ -46,17 +46,17 @@ user.manual_emote("waves around a blank sign.") var/direction = prob(50) ? -1 : 1 if(NSCOMPONENT(user.dir)) //So signs are waved horizontally relative to what way the player waving it is facing. - animate(user, pixel_x = user.pixel_x + (1 * direction), time = 1, easing = SINE_EASING) - animate(pixel_x = user.pixel_x - (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_x = user.pixel_x + (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_x = user.pixel_x - (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_x = user.pixel_x + (1 * direction), time = 1, easing = SINE_EASING) + animate(user, pixel_w = (1 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_w = (-2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_w = (2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_w = (-2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_w = (1 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) else - animate(user, pixel_y = user.pixel_y + (1 * direction), time = 1, easing = SINE_EASING) - animate(pixel_y = user.pixel_y - (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_y = user.pixel_y + (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_y = user.pixel_y - (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_y = user.pixel_y + (1 * direction), time = 1, easing = SINE_EASING) + animate(user, pixel_z = (1 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_z = (-2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_z = (2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_z = (-2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_z = (1 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) user.changeNext_move(CLICK_CD_MELEE) /datum/action/item_action/nano_picket_sign diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index fa624b6e50f..2902bd72572 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1558,18 +1558,18 @@ COOLDOWN_START(src, foamfinger_cooldown, 5 SECONDS) user.manual_emote("waves around the foam finger.") var/direction = prob(50) ? -1 : 1 - if(NSCOMPONENT(user.dir)) //So signs are waved horizontally relative to what way the player waving it is facing. - animate(user, pixel_x = user.pixel_x + (1 * direction), time = 1, easing = SINE_EASING) - animate(pixel_x = user.pixel_x - (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_x = user.pixel_x + (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_x = user.pixel_x - (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_x = user.pixel_x + (1 * direction), time = 1, easing = SINE_EASING) + if(NSCOMPONENT(user.dir)) + animate(user, pixel_w = (1 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_w = (-2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_w = (2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_w = (-2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_w = (1 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) else - animate(user, pixel_y = user.pixel_y + (1 * direction), time = 1, easing = SINE_EASING) - animate(pixel_y = user.pixel_y - (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_y = user.pixel_y + (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_y = user.pixel_y - (2 * direction), time = 1, easing = SINE_EASING) - animate(pixel_y = user.pixel_y + (1 * direction), time = 1, easing = SINE_EASING) + animate(user, pixel_z = (1 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_z = (-2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_z = (2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_z = (-2 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) + animate(pixel_z = (1 * direction), time = 0.1 SECONDS, easing = SINE_EASING, flags = ANIMATION_RELATIVE) user.changeNext_move(CLICK_CD_MELEE) ///All people who have used an Intento this round along with their high scores. diff --git a/code/game/objects/structures/beds_chairs/alien_nest.dm b/code/game/objects/structures/beds_chairs/alien_nest.dm index 3a6d6d3ee4a..b0de02fef48 100644 --- a/code/game/objects/structures/beds_chairs/alien_nest.dm +++ b/code/game/objects/structures/beds_chairs/alien_nest.dm @@ -74,8 +74,7 @@ /obj/structure/bed/nest/post_buckle_mob(mob/living/M) ADD_TRAIT(M, TRAIT_HANDS_BLOCKED, type) - M.pixel_y = M.base_pixel_y - M.pixel_x = M.base_pixel_x + 2 + M.add_offsets(type, x_add = 2) M.layer = BELOW_MOB_LAYER add_overlay(nest_overlay) @@ -86,8 +85,7 @@ /obj/structure/bed/nest/post_unbuckle_mob(mob/living/M) REMOVE_TRAIT(M, TRAIT_HANDS_BLOCKED, type) - M.pixel_x = M.base_pixel_x + M.body_position_pixel_x_offset - M.pixel_y = M.base_pixel_y + M.body_position_pixel_y_offset + M.remove_offsets(type) M.layer = initial(M.layer) cut_overlay(nest_overlay) M.remove_status_effect(/datum/status_effect/nest_sustenance) diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 7dd1dd157f9..36143cd657d 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -563,11 +563,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) return NONE /obj/structure/chair/mime/post_buckle_mob(mob/living/M) - M.pixel_y += 5 + M.add_offsets(type, z_add = 5) /obj/structure/chair/mime/post_unbuckle_mob(mob/living/M) - M.pixel_y -= 5 - + M.remove_offsets(type) /obj/structure/chair/plastic icon_state = "plastic_chair" @@ -582,13 +581,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) fishing_modifier = -10 /obj/structure/chair/plastic/post_buckle_mob(mob/living/Mob) - Mob.pixel_y += 2 - .=..() + Mob.add_offsets(type, z_add = 2) + . = ..() if(iscarbon(Mob)) INVOKE_ASYNC(src, PROC_REF(snap_check), Mob) /obj/structure/chair/plastic/post_unbuckle_mob(mob/living/Mob) - Mob.pixel_y -= 2 + Mob.remove_offsets(type) /obj/structure/chair/plastic/proc/snap_check(mob/living/carbon/Mob) if (Mob.nutrition >= NUTRITION_LEVEL_FAT) diff --git a/code/game/objects/structures/gym/weight_machine.dm b/code/game/objects/structures/gym/weight_machine.dm index a0a1162057b..438196e9b60 100644 --- a/code/game/objects/structures/gym/weight_machine.dm +++ b/code/game/objects/structures/gym/weight_machine.dm @@ -14,7 +14,7 @@ blocks_emissive = EMISSIVE_BLOCK_UNIQUE ///How much we shift the user's pixel y when using the weight machine. - var/pixel_shift_y = -3 + var/pixel_shift_z = -3 ///The weight action we give to people that buckle themselves to us. var/datum/action/push_weights/weight_action @@ -157,9 +157,9 @@ flick_overlay_view(workout, 0.8 SECONDS) flick("[base_icon_state]-u", src) var/mob/living/user = buckled_mobs[1] - animate(user, pixel_y = pixel_shift_y, time = WORKOUT_LENGTH * 0.5) + animate(user, pixel_z = pixel_shift_z, time = WORKOUT_LENGTH * 0.5, flags = ANIMATION_PARALLEL|ANIMATION_RELATIVE) + animate(pixel_z = -pixel_shift_z, time = WORKOUT_LENGTH * 0.5, flags = ANIMATION_PARALLEL) playsound(user, 'sound/machines/creak.ogg', 60, TRUE) - animate(pixel_y = user.base_pixel_y, time = WORKOUT_LENGTH * 0.5) if(!iscarbon(user) || isnull(user.mind)) return TRUE @@ -194,7 +194,7 @@ icon_state = "benchpress" base_icon_state = "benchpress" - pixel_shift_y = 5 + pixel_shift_z = 5 drunk_message = "You raise the bar over you trying to balance it with one hand, keyword tried." diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index 7d6ec9edf2d..6b3c4585a8d 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -175,7 +175,7 @@ var/matrix/m180 = matrix(target.transform) m180.Turn(180) animate(target, transform = m180, time = 3) - target.pixel_y = target.base_pixel_y + PIXEL_Y_OFFSET_LYING + target.add_offsets(type, y_add = -6, animate = FALSE) ADD_TRAIT(target, TRAIT_MOVE_UPSIDE_DOWN, REF(src)) /obj/structure/kitchenspike/user_unbuckle_mob(mob/living/buckled_mob, mob/user) @@ -207,7 +207,7 @@ var/matrix/m180 = matrix(buckled_mob.transform) m180.Turn(180) animate(buckled_mob, transform = m180, time = 3) - buckled_mob.pixel_y = buckled_mob.base_pixel_y + PIXEL_Y_OFFSET_LYING + buckled_mob.remove_offsets(type, animate = FALSE) REMOVE_TRAIT(buckled_mob, TRAIT_MOVE_UPSIDE_DOWN, REF(src)) /obj/structure/kitchenspike/atom_deconstruct(disassembled = TRUE) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 9694869a8a2..c7e6ba7ca0b 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -837,13 +837,11 @@ ///Align the mob with the table when buckled. /obj/structure/table/optable/post_buckle_mob(mob/living/buckled) - . = ..() - buckled.pixel_y += 6 + buckled.add_offsets(type, z_add = 6) ///Disalign the mob with the table when unbuckled. /obj/structure/table/optable/post_unbuckle_mob(mob/living/buckled) - . = ..() - buckled.pixel_y -= 6 + buckled.remove_offsets(type) /// Any mob that enters our tile will be marked as a potential patient. They will be turned into a patient if they lie down. /obj/structure/table/optable/proc/mark_patient(datum/source, mob/living/carbon/potential_patient) diff --git a/code/modules/basketball/hoop.dm b/code/modules/basketball/hoop.dm index edc106c155e..82eaee9a8ac 100644 --- a/code/modules/basketball/hoop.dm +++ b/code/modules/basketball/hoop.dm @@ -98,10 +98,12 @@ var/dunk_dir = get_dir(baller, src) - var/dunk_pixel_y = dunk_dir & SOUTH ? -16 : 16 - var/dunk_pixel_x = dunk_dir & EAST && 16 || dunk_dir & WEST && -16 || 0 + var/dunk_pixel_z = (dunk_dir & SOUTH) ? -16 : 16 + var/dunk_pixel_w = ((dunk_dir & EAST) && 16) || ((dunk_dir & WEST) && -16) || 0 + + animate(baller, pixel_w = dunk_pixel_w, pixel_z = dunk_pixel_z, time = 0.5 SECONDS, easing = BOUNCE_EASING|EASE_IN|EASE_OUT, flags = ANIMATION_PARALLEL|ANIMATION_RELATIVE) + animate(pixel_w = -dunk_pixel_w, pixel_z = -dunk_pixel_z, time = 0.5 SECONDS, flags = ANIMATION_PARALLEL) - INVOKE_ASYNC(src, PROC_REF(dunk_animation), baller, dunk_pixel_y, dunk_pixel_x) visible_message(span_warning("[baller] dunks [ball] into \the [src]!")) baller.add_mood_event("basketball", /datum/mood_event/basketball_dunk) score(ball, baller, 2) @@ -109,12 +111,6 @@ if(istype(ball, /obj/item/toy/basketball)) baller.adjustStaminaLoss(STAMINA_COST_DUNKING) -/// This bobs the mob in the hoop direction for the dunk animation -/obj/structure/hoop/proc/dunk_animation(mob/living/baller, dunk_pixel_y, dunk_pixel_x) - animate(baller, pixel_x = dunk_pixel_x, pixel_y = dunk_pixel_y, time = 5, easing = BOUNCE_EASING|EASE_IN|EASE_OUT) - sleep(0.5 SECONDS) - animate(baller, pixel_x = 0, pixel_y = 0, time = 3) - /obj/structure/hoop/attack_hand(mob/living/baller, list/modifiers) . = ..() if(.) diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index a8fb645af73..58c32a53caa 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -588,9 +588,9 @@ for(var/i in 1 to peels_to_spawn) new banana_type(pick_n_take(reachable_turfs)) playsound(owner, 'sound/mobs/non-humanoids/clown/clownana_rustle.ogg', 60) - animate(owner, time = 1, pixel_x = 6, easing = CUBIC_EASING | EASE_OUT) - animate(time = 2, pixel_x = -8, easing = CUBIC_EASING) - animate(time = 1, pixel_x = 0, easing = CUBIC_EASING | EASE_IN) + animate(owner, time = 0.1 SECONDS, pixel_w = 6, easing = CUBIC_EASING | EASE_OUT, flags = ANIMATION_PARALLEL|ANIMATION_RELATIVE) + animate(time = 0.2 SECONDS, pixel_w = -8, easing = CUBIC_EASING, flags = ANIMATION_RELATIVE) + animate(time = 0.1 SECONDS, pixel_w = 2, easing = CUBIC_EASING | EASE_IN, flags = ANIMATION_RELATIVE) StartCooldown() ///spawns a plumb bunch of bananas imbued with mystical power. diff --git a/code/modules/mob/living/basic/icemoon/wolf/wolf_extras.dm b/code/modules/mob/living/basic/icemoon/wolf/wolf_extras.dm index 7765ec896a1..c7b2c79ac67 100644 --- a/code/modules/mob/living/basic/icemoon/wolf/wolf_extras.dm +++ b/code/modules/mob/living/basic/icemoon/wolf/wolf_extras.dm @@ -9,10 +9,10 @@ // Contains pixel offset data for sprites riding wolves /datum/component/riding/creature/wolf -/datum/component/riding/creature/wolf/handle_specials() - . = ..() - set_riding_offsets(RIDING_OFFSET_ALL, list(TEXT_NORTH = list(1, 9), TEXT_SOUTH = list(1, 9), TEXT_EAST = list(0, 9), TEXT_WEST = list(2, 9))) - set_vehicle_dir_layer(SOUTH, ABOVE_MOB_LAYER) - set_vehicle_dir_layer(NORTH, OBJ_LAYER) - set_vehicle_dir_layer(EAST, OBJ_LAYER) - set_vehicle_dir_layer(WEST, OBJ_LAYER) +/datum/component/riding/creature/wolf/get_rider_offsets_and_layers(pass_index, mob/offsetter) + return list( + TEXT_NORTH = list(1, 9, OBJ_LAYER), + TEXT_SOUTH = list(1, 9, ABOVE_MOB_LAYER), + TEXT_EAST = list(0, 9, OBJ_LAYER), + TEXT_WEST = list(2, 9, OBJ_LAYER), + ) diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm b/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm index 69aa5026a93..6149f552d81 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm @@ -115,13 +115,13 @@ var/mob/living/basic/mining/mook/mook_owner = owner mook_owner.change_combatant_state(state = MOOK_ATTACK_ACTIVE) new /obj/effect/temp_visual/mook_dust(get_turf(owner)) - playsound(get_turf(owner), 'sound/items/weapons/thudswoosh.ogg', 50, TRUE) - animate(owner, pixel_y = owner.base_pixel_y + 146, time = 0.5 SECONDS) + playsound(owner, 'sound/items/weapons/thudswoosh.ogg', 50, TRUE) + animate(owner, pixel_z = 146, time = 0.5 SECONDS, flags = ANIMATION_RELATIVE) addtimer(CALLBACK(src, PROC_REF(land_on_turf), target), 0.5 SECONDS) /datum/action/cooldown/mob_cooldown/mook_ability/mook_jump/proc/land_on_turf(turf/target) do_teleport(owner, target, precision = 3, no_effects = TRUE) - animate(owner, pixel_y = owner.base_pixel_y, time = 0.5 SECONDS) + animate(owner, pixel_z = -146, time = 0.5 SECONDS, flags = ANIMATION_RELATIVE) new /obj/effect/temp_visual/mook_dust(get_turf(owner)) if(is_mook) addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob/living/basic/mining/mook, change_combatant_state), MOOK_ATTACK_NEUTRAL), 0.5 SECONDS) diff --git a/code/modules/mob/living/basic/pets/parrot/_parrot.dm b/code/modules/mob/living/basic/pets/parrot/_parrot.dm index e76b9a5e83e..1a63f690c7d 100644 --- a/code/modules/mob/living/basic/pets/parrot/_parrot.dm +++ b/code/modules/mob/living/basic/pets/parrot/_parrot.dm @@ -104,6 +104,7 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list( RegisterSignal(src, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_injured)) // this means we got hurt and it's go time RegisterSignal(src, COMSIG_ANIMAL_PET, PROC_REF(on_pet)) RegisterSignal(src, COMSIG_KB_MOB_DROPITEM_DOWN, PROC_REF(drop_item_on_signal)) + ADD_TRAIT(src, TRAIT_CAN_MOUNT_HUMANS, INNATE_TRAIT) /mob/living/basic/parrot/Destroy() // should have cleaned these up on death, but let's be super safe in case that didn't happen @@ -264,13 +265,19 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list( UnregisterSignal(src, COMSIG_LIVING_SET_BUCKLED) toggle_perched(perched = FALSE) +#define PERCH_SOURCE "perched" + /mob/living/basic/parrot/proc/toggle_perched(perched) if(!perched) - REMOVE_TRAIT(src, TRAIT_PARROT_PERCHED, TRAIT_GENERIC) + REMOVE_TRAIT(src, TRAIT_PARROT_PERCHED, PERCH_SOURCE) + remove_offsets(PERCH_SOURCE) else - ADD_TRAIT(src, TRAIT_PARROT_PERCHED, TRAIT_GENERIC) + ADD_TRAIT(src, TRAIT_PARROT_PERCHED, PERCH_SOURCE) + add_offsets(PERCH_SOURCE, y_add = 9) update_appearance(UPDATE_ICON_STATE) +#undef PERCH_SOURCE + /// Master proc which will determine the intent of OUR attacks on an object and summon the relevant procs accordingly. /// This is pretty much meant for players, AI will use the task-specific procs instead. /mob/living/basic/parrot/early_melee_attack(atom/target, list/modifiers, ignore_cooldown) diff --git a/code/modules/mob/living/basic/slime/feeding.dm b/code/modules/mob/living/basic/slime/feeding.dm index 867d6267240..5eaf02b1b03 100644 --- a/code/modules/mob/living/basic/slime/feeding.dm +++ b/code/modules/mob/living/basic/slime/feeding.dm @@ -62,14 +62,22 @@ return TRUE +#define FEEDING_OFFSET "feeding" + ///The slime will start feeding on the target /mob/living/basic/slime/proc/start_feeding(mob/living/target_mob) - target_mob.unbuckle_all_mobs(force=TRUE) //Slimes rip other mobs (eg: shoulder parrots) off (Slimes Vs Slimes is already handled in can_feed_on()) - if(target_mob.buckle_mob(src, force=TRUE)) - layer = MOB_ABOVE_PIGGYBACK_LAYER //always appear above the target mob, no matter the direction - target_mob.visible_message(span_danger("[name] latches onto [target_mob]!"), \ - span_userdanger("[name] latches onto [target_mob]!")) + target_mob.unbuckle_all_mobs(force = TRUE) //Slimes rip other mobs (eg: shoulder parrots) off (Slimes Vs Slimes is already handled in can_feed_on()) + if(target_mob.buckle_mob(src, force = TRUE)) + add_offsets(FEEDING_OFFSET, y_add = target_mob.mob_size <= MOB_SIZE_SMALL ? 0 : 3) + layer = MOB_ABOVE_PIGGYBACK_LAYER //appear above the target mob target_mob.apply_status_effect(/datum/status_effect/slime_leech, src) + target_mob.visible_message( + span_danger("[name] latches onto [target_mob]!"), + span_userdanger("[name] latches onto [target_mob]!"), + visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE, + ) + to_chat(src, span_notice("I start feeding on [target_mob]...")) + balloon_alert(src, "feeding started") else balloon_alert(src, "latch failed!") @@ -80,5 +88,9 @@ if(!silent) visible_message(span_warning("[src] lets go of [buckled]!"), span_notice("You let go of [buckled]")) + balloon_alert(src, "feeding stopped") + remove_offsets(FEEDING_OFFSET) layer = initial(layer) buckled.unbuckle_mob(src,force=TRUE) + +#undef FEEDING_OFFSET diff --git a/code/modules/mob/living/basic/slime/slime.dm b/code/modules/mob/living/basic/slime/slime.dm index f5380143795..9df77ce0556 100644 --- a/code/modules/mob/living/basic/slime/slime.dm +++ b/code/modules/mob/living/basic/slime/slime.dm @@ -134,7 +134,7 @@ AddElement(/datum/element/soft_landing) AddElement(/datum/element/swabable, CELL_LINE_TABLE_SLIME, CELL_VIRUS_TABLE_GENERIC_MOB, 1, 5) - add_traits(list(TRAIT_CANT_RIDE, TRAIT_VENTCRAWLER_ALWAYS), INNATE_TRAIT) + add_traits(list(TRAIT_CANT_RIDE, TRAIT_CAN_MOUNT_HUMANS, TRAIT_VENTCRAWLER_ALWAYS), INNATE_TRAIT) RegisterSignal(src, COMSIG_HOSTILE_PRE_ATTACKINGTARGET, PROC_REF(on_slime_pre_attack)) RegisterSignal(src, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand) ) @@ -226,10 +226,6 @@ /mob/living/basic/slime/start_pulling(atom/movable/moveable_atom, state, force = move_force, supress_message = FALSE) return -/mob/living/basic/slime/get_mob_buckling_height(mob/seat) - if(..() != 0) - return 3 - /mob/living/basic/slime/examine(mob/user) . = ..() diff --git a/code/modules/mob/living/carbon/alien/adult/adult_update_icons.dm b/code/modules/mob/living/carbon/alien/adult/adult_update_icons.dm index bbfd68f8186..cd8e72a04f7 100644 --- a/code/modules/mob/living/carbon/alien/adult/adult_update_icons.dm +++ b/code/modules/mob/living/carbon/alien/adult/adult_update_icons.dm @@ -35,15 +35,11 @@ icon = alt_icon alt_icon = old_icon icon_state = "alien[caste]_leap" - pixel_x = base_pixel_x - 32 - pixel_y = base_pixel_y - 32 else if(alt_icon != initial(alt_icon)) var/old_icon = icon icon = alt_icon alt_icon = old_icon - pixel_x = base_pixel_x + body_position_pixel_x_offset - pixel_y = base_pixel_y + body_position_pixel_y_offset update_held_items() update_worn_handcuffs() diff --git a/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm b/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm index 6241108c168..514cc23caab 100644 --- a/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm +++ b/code/modules/mob/living/carbon/alien/adult/caste/hunter.dm @@ -57,14 +57,14 @@ else //Maybe uses plasma in the future, although that wouldn't make any sense... leaping = TRUE //Because the leaping sprite is bigger than the normal one - body_position_pixel_x_offset = -8 + add_offsets(LEAPING_TRAIT, x_add = -8, animate = FALSE) update_icons() ADD_TRAIT(src, TRAIT_MOVE_FLOATING, LEAPING_TRAIT) //Throwing itself doesn't protect mobs against lava (because gulag). throw_at(A, MAX_ALIEN_LEAP_DIST, pounce_speed, src, FALSE, TRUE, callback = CALLBACK(src, PROC_REF(leap_end))) /mob/living/carbon/alien/adult/hunter/proc/leap_end() leaping = FALSE - body_position_pixel_x_offset = 0 + remove_offsets(LEAPING_TRAIT, animate = FALSE) REMOVE_TRAIT(src, TRAIT_MOVE_FLOATING, LEAPING_TRAIT) update_icons() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 93abd5d5f6d..c4677a699a5 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -441,9 +441,9 @@ /mob/proc/shake_up_animation() var/direction = prob(50) ? -1 : 1 - animate(src, pixel_x = pixel_x + SHAKE_ANIMATION_OFFSET * direction, time = 1, easing = QUAD_EASING | EASE_OUT, flags = ANIMATION_PARALLEL) - animate(pixel_x = pixel_x - (SHAKE_ANIMATION_OFFSET * 2 * direction), time = 1) - animate(pixel_x = pixel_x + SHAKE_ANIMATION_OFFSET * direction, time = 1, easing = QUAD_EASING | EASE_IN) + animate(src, pixel_w = SHAKE_ANIMATION_OFFSET * direction, time = 0.1 SECONDS, easing = QUAD_EASING | EASE_OUT, flags = ANIMATION_PARALLEL|ANIMATION_RELATIVE) + animate(pixel_w = SHAKE_ANIMATION_OFFSET * -2 * direction, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_w = SHAKE_ANIMATION_OFFSET * direction, time = 0.1 SECONDS, easing = QUAD_EASING | EASE_IN, flags = ANIMATION_RELATIVE) /// Check ourselves to see if we've got any shrapnel, return true if we do. This is a much simpler version of what humans do, we only indicate we're checking ourselves if there's actually shrapnel /mob/living/carbon/proc/check_self_for_injuries() diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 2a8f03586bc..136c07f06f5 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -36,6 +36,8 @@ ) AddElement(/datum/element/connect_loc, loc_connections) GLOB.human_list += src + ADD_TRAIT(src, TRAIT_CAN_MOUNT_HUMANS, INNATE_TRAIT) + ADD_TRAIT(src, TRAIT_CAN_MOUNT_CYBORGS, INNATE_TRAIT) /mob/living/carbon/human/proc/setup_physiology() physiology = new() @@ -1049,14 +1051,13 @@ return buckle_mob(target, TRUE, TRUE, RIDER_NEEDS_ARMS) -/mob/living/carbon/human/buckle_mob(mob/living/target, force = FALSE, check_loc = TRUE, buckle_mob_flags= NONE) - if(!is_type_in_typecache(target, can_ride_typecache)) +/mob/living/carbon/human/is_buckle_possible(mob/living/target, force, check_loc) + if(!HAS_TRAIT(target, TRAIT_CAN_MOUNT_HUMANS)) target.visible_message(span_warning("[target] really can't seem to mount [src]...")) - return - - if(!force)//humans are only meant to be ridden through piggybacking and special cases - return - + return FALSE + // if you don't invoke it with forced, IE via piggyback / fireman, always fail + if(!force) + return FALSE return ..() /mob/living/carbon/human/reagent_check(datum/reagent/chem, seconds_per_tick, times_fired) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index ea4b79626c4..97626d33c54 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -8,7 +8,6 @@ hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPSEC_FIRST_HUD,IMPSEC_SECOND_HUD,ANTAG_HUD,GLAND_HUD,FAN_HUD,PERMIT_HUD, DNR_HUD) //SKYRAT EDIT ADDITION - PERMIT_HUD, DNR_HUD hud_type = /datum/hud/human pressure_resistance = 25 - can_buckle = TRUE buckle_lying = 0 mob_biotypes = MOB_ORGANIC|MOB_HUMANOID can_be_shoved_into = TRUE @@ -82,13 +81,6 @@ var/datum/physiology/physiology - /// What types of mobs are allowed to ride/buckle to this mob - var/static/list/can_ride_typecache = typecacheof(list( - /mob/living/basic/parrot, - /mob/living/carbon/human, - /mob/living/basic/slime, - )) - var/account_id var/hardcore_survival_score = 0 diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 08c6cd515fb..6827d20c92c 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -423,11 +423,12 @@ #define SHIVER_LOOP_DURATION (1 SECONDS) /datum/emote/living/shiver/run_emote(mob/living/user, params, type_override, intentional) . = ..() - animate(user, pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + + animate(user, pixel_w = 1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) for(var/i in 1 to SHIVER_LOOP_DURATION / (0.2 SECONDS)) //desired total duration divided by the iteration duration to give the necessary iteration count - animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) - animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) - animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) + animate(pixel_w = -2, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE) + animate(pixel_w = 2, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE) + animate(pixel_w = -1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) #undef SHIVER_LOOP_DURATION /datum/emote/living/sigh @@ -528,11 +529,12 @@ /datum/emote/living/sway/run_emote(mob/living/user, params, type_override, intentional) . = ..() - animate(user, pixel_x = user.pixel_x + 2, time = 0.5 SECONDS) + + animate(user, pixel_w = 2, time = 0.5 SECONDS, flags = ANIMATION_RELATIVE) for(var/i in 1 to 2) - animate(pixel_x = user.pixel_x - 4, time = 1.0 SECONDS) - animate(pixel_x = user.pixel_x + 4, time = 1.0 SECONDS) - animate(pixel_x = user.pixel_x - 2, time = 0.5 SECONDS) + animate(pixel_w = -6, time = 1.0 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE) + animate(pixel_w = 6, time = 1.0 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE) + animate(pixel_w = -2, time = 0.5 SECONDS, flags = ANIMATION_RELATIVE) /datum/emote/living/tilt key = "tilt" @@ -547,11 +549,12 @@ #define TREMBLE_LOOP_DURATION (4.4 SECONDS) /datum/emote/living/tremble/run_emote(mob/living/user, params, type_override, intentional) . = ..() - animate(user, pixel_x = user.pixel_x + 2, time = 0.2 SECONDS) + + animate(user, pixel_w = 2, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE) for(var/i in 1 to TREMBLE_LOOP_DURATION / (0.4 SECONDS)) //desired total duration divided by the iteration duration to give the necessary iteration count - animate(pixel_x = user.pixel_x - 2, time = 0.2 SECONDS) - animate(pixel_x = user.pixel_x + 2, time = 0.2 SECONDS) - animate(pixel_x = user.pixel_x - 2, time = 0.2 SECONDS) + animate(pixel_w = -4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE) + animate(pixel_w = 4, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_CONTINUE) + animate(pixel_w = -2, time = 0.2 SECONDS, flags = ANIMATION_RELATIVE) #undef TREMBLE_LOOP_DURATION /datum/emote/living/twitch @@ -561,11 +564,12 @@ /datum/emote/living/twitch/run_emote(mob/living/user, params, type_override, intentional) . = ..() - animate(user, pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) - animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + + animate(user, pixel_w = 1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_w = -2, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) animate(time = 0.1 SECONDS) - animate(pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) - animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + animate(pixel_w = 2, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_w = -1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) /datum/emote/living/twitch_s key = "twitch_s" @@ -574,8 +578,9 @@ /datum/emote/living/twitch_s/run_emote(mob/living/user, params, type_override, intentional) . = ..() - animate(user, pixel_x = user.pixel_x - 1, time = 0.1 SECONDS) - animate(pixel_x = user.pixel_x + 1, time = 0.1 SECONDS) + + animate(user, pixel_w = -1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) + animate(pixel_w = 1, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) /datum/emote/living/wave key = "wave" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index c4526dcf780..169cdf2d6c4 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -485,8 +485,15 @@ set_pull_offsets(M, state) return TRUE -/mob/living/proc/set_pull_offsets(mob/living/M, grab_state = GRAB_PASSIVE) - if(M.buckled) +/** + * Updates the offsets of the passed mob according to the passed grab state and the direction between them and us + * + * * M - the mob to update the offsets of + * * grab_state - the state of the grab + * * animate - whether or not to animate the offsets + */ +/mob/living/proc/set_pull_offsets(mob/living/mob_to_set, grab_state = GRAB_PASSIVE, animate = TRUE) + if(mob_to_set.buckled) return //don't make them change direction or offset them if they're buckled into something. var/offset = 0 switch(grab_state) @@ -498,27 +505,35 @@ offset = GRAB_PIXEL_SHIFT_NECK if(GRAB_KILL) offset = GRAB_PIXEL_SHIFT_NECK - M.setDir(get_dir(M, src)) - var/target_pixel_x = M.base_pixel_x + M.body_position_pixel_x_offset - var/target_pixel_y = M.base_pixel_y + M.body_position_pixel_y_offset - switch(M.dir) + mob_to_set.setDir(get_dir(mob_to_set, src)) + var/dir_filter = mob_to_set.dir + if(ISDIAGONALDIR(dir_filter)) + dir_filter = EWCOMPONENT(dir_filter) + switch(dir_filter) if(NORTH) - animate(M, pixel_x = target_pixel_x, pixel_y = target_pixel_y + offset, 3) + mob_to_set.add_offsets(GRABBING_TRAIT, x_add = 0, y_add = offset, animate = animate) if(SOUTH) - animate(M, pixel_x = target_pixel_x, pixel_y = target_pixel_y - offset, 3) + mob_to_set.add_offsets(GRABBING_TRAIT, x_add = 0, y_add = -offset, animate = animate) if(EAST) - if(M.lying_angle == LYING_ANGLE_WEST) //update the dragged dude's direction if we've turned - M.set_lying_angle(LYING_ANGLE_EAST) - animate(M, pixel_x = target_pixel_x + offset, pixel_y = target_pixel_y, 3) + if(mob_to_set.lying_angle == LYING_ANGLE_WEST) //update the dragged dude's direction if we've turned + mob_to_set.set_lying_angle(LYING_ANGLE_EAST) + mob_to_set.add_offsets(GRABBING_TRAIT, x_add = offset, y_add = 0, animate = animate) if(WEST) - if(M.lying_angle == LYING_ANGLE_EAST) - M.set_lying_angle(LYING_ANGLE_WEST) - animate(M, pixel_x = target_pixel_x - offset, pixel_y = target_pixel_y, 3) + if(mob_to_set.lying_angle == LYING_ANGLE_EAST) + mob_to_set.set_lying_angle(LYING_ANGLE_WEST) + mob_to_set.add_offsets(GRABBING_TRAIT, x_add = -offset, y_add = 0, animate = animate) +/** + * Removes any offsets from the passed mob that are related to being grabbed + * + * * M - the mob to remove the offsets from + * * override - if TRUE, the offsets will be removed regardless of the mob's buckled state + * otherwise we won't remove the offsets if the mob is buckled + */ /mob/living/proc/reset_pull_offsets(mob/living/M, override) if(!override && M.buckled) return - animate(M, pixel_x = M.base_pixel_x + M.body_position_pixel_x_offset , pixel_y = M.base_pixel_y + M.body_position_pixel_y_offset, 1) + M.remove_offsets(GRABBING_TRAIT) //mob verbs are a lot faster than object verbs //for more info on why this is not atom/pull, see examinate() in mob.dm @@ -779,19 +794,14 @@ if(HAS_TRAIT(src, TRAIT_FLOORED) && !(dir & (NORTH|SOUTH))) setDir(pick(NORTH, SOUTH)) // We are and look helpless. if(rotate_on_lying) - body_position_pixel_y_offset = PIXEL_Y_OFFSET_LYING + add_offsets(LYING_DOWN_TRAIT, y_add = PIXEL_Y_OFFSET_LYING) /// Proc to append behavior related to lying down. /mob/living/proc/on_standing_up() if(layer == LYING_MOB_LAYER) layer = initial(layer) remove_traits(list(TRAIT_UI_BLOCKED, TRAIT_PULL_BLOCKED, TRAIT_UNDENSE), LYING_DOWN_TRAIT) - // Make sure it doesn't go out of the southern bounds of the tile when standing. - body_position_pixel_y_offset = get_pixel_y_offset_standing(current_size) - -/// Returns what the body_position_pixel_y_offset should be if the current size were `value` -/mob/living/proc/get_pixel_y_offset_standing(value) - return (value-1) * get_cached_height() * 0.5 + remove_offsets(LYING_DOWN_TRAIT) /mob/living/proc/update_density() if(HAS_TRAIT(src, TRAIT_UNDENSE)) @@ -1373,8 +1383,8 @@ var/matrix/flipped_matrix = transform flipped_matrix.b = -flipped_matrix.b flipped_matrix.e = -flipped_matrix.e - animate(src, transform = flipped_matrix, pixel_y = pixel_y+4, time = 0.5 SECONDS, easing = EASE_OUT) - base_pixel_y += 4 + animate(src, transform = flipped_matrix, time = 0.5 SECONDS, easing = EASE_OUT, flags = ANIMATION_PARALLEL) + add_offsets(NEGATIVE_GRAVITY_TRAIT, y_add = 4) if(NEGATIVE_GRAVITY + 0.01 to 0) if(!istype(gravity_alert, /atom/movable/screen/alert/weightless)) throw_alert(ALERT_GRAVITY, /atom/movable/screen/alert/weightless) @@ -1398,8 +1408,8 @@ var/matrix/flipped_matrix = transform flipped_matrix.b = -flipped_matrix.b flipped_matrix.e = -flipped_matrix.e - animate(src, transform = flipped_matrix, pixel_y = pixel_y-4, time = 0.5 SECONDS, easing = EASE_OUT) - base_pixel_y -= 4 + animate(src, transform = flipped_matrix, time = 0.5 SECONDS, easing = EASE_OUT, flags = ANIMATION_PARALLEL) + remove_offsets(NEGATIVE_GRAVITY_TRAIT) /mob/living/singularity_pull(atom/singularity, current_size) ..() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 695869aa4cf..99820d38759 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -381,7 +381,7 @@ to_chat(user, span_danger("You're strangling [src]!")) if(!buckled && !density) Move(user.loc) - user.set_pull_offsets(src, grab_state) + user.set_pull_offsets(src, user.grab_state) return TRUE /mob/living/attack_animal(mob/living/simple_animal/user, list/modifiers) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 2644d38dcde..811c86c082a 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -204,10 +204,6 @@ /// Is this mob allowed to be buckled/unbuckled to/from things? var/can_buckle_to = TRUE - ///The x amount a mob's sprite should be offset due to the current position they're in - var/body_position_pixel_x_offset = 0 - ///The y amount a mob's sprite should be offset due to the current position they're in or size (e.g. lying down moves your sprite down) - var/body_position_pixel_y_offset = 0 ///The height offset of a mob's maptext due to their current size. var/body_maptext_height_offset = 0 @@ -233,3 +229,8 @@ /// How long it takes to return to 0 stam var/stamina_regen_time = 10 SECONDS + + /// Lazylists of pixel offsets this mob is currently using + /// Modify this via add_offsets and remove_offsets, + /// NOT directly (and definitely avoid modifying offsets directly) + VAR_PRIVATE/list/offsets diff --git a/code/modules/mob/living/living_update_icons.dm b/code/modules/mob/living/living_update_icons.dm index 20f36ab96b0..b967f9f875e 100644 --- a/code/modules/mob/living/living_update_icons.dm +++ b/code/modules/mob/living/living_update_icons.dm @@ -3,70 +3,176 @@ * IMPORTANT: Multiple animate() calls do not stack well, so try to do them all at once if you can. */ /mob/living/proc/update_transform(resize = RESIZE_DEFAULT_SIZE) - var/matrix/ntransform = matrix(transform) //aka transform.Copy() - var/final_pixel_y = base_pixel_y + body_position_pixel_y_offset - /** - * pixel x/y/w/z all discard values after the decimal separator. - * That, coupled with the rendered interpolation, may make the - * icons look awfuller than they already are, or not, whatever. - * The solution to this nit is translating the missing decimals. - * also flooring increases the distance from 0 for negative numbers. - */ - var/abs_pixel_y_offset = 0 - var/translate = 0 - if(current_size != RESIZE_DEFAULT_SIZE) - var/standing_offset = get_pixel_y_offset_standing(current_size) - abs_pixel_y_offset = abs(standing_offset) - translate = (abs_pixel_y_offset - round(abs_pixel_y_offset)) * SIGN(standing_offset) + var/matrix/ntransform = matrix(transform) + var/current_translate = get_transform_translation_size(current_size) var/final_dir = dir var/changed = FALSE if(lying_angle != lying_prev && rotate_on_lying) changed = TRUE if(lying_angle && lying_prev == 0) - if(translate) - ntransform.Translate(0, -translate) - if(dir & (EAST|WEST)) //Standing to lying and facing east or west - final_dir = pick(NORTH, SOUTH) //So you fall on your side rather than your face or ass - else if(translate && !lying_angle && lying_prev != 0) - ntransform.Translate(translate * (lying_prev == 270 ? -1 : 1), 0) - ///Done last, as it can mess with the translation. + if(current_translate) + ntransform.Translate(0, -current_translate) + // Standing to lying and facing east or west + if(dir & (EAST|WEST)) + // ...So you fall on your side, rather than your face or ass + final_dir = pick(NORTH, SOUTH) + else + if(current_translate && !lying_angle && lying_prev != 0) + ntransform.Translate(current_translate * (lying_prev == 270 ? -1 : 1), 0) + // Done last, as it can mess with the translation. ntransform.TurnTo(lying_prev, lying_angle) if(resize != RESIZE_DEFAULT_SIZE) changed = TRUE var/is_vertical = !lying_angle || !rotate_on_lying - ///scaling also affects translation, so we've to undo the old translate beforehand. - if(translate && is_vertical) - ntransform.Translate(0, -translate) + var/new_translation = get_transform_translation_size(resize * current_size) + // scaling also affects translation, so we've to undo the old translate beforehand. + if(is_vertical && current_translate) + ntransform.Translate(0, -current_translate) + ntransform.Scale(resize) current_size *= resize - //Update the height of the maptext according to the size of the mob so they don't overlap. + // Update the height of the maptext according to the size of the mob so they don't overlap. var/old_maptext_offset = body_maptext_height_offset body_maptext_height_offset = initial(maptext_height) * (current_size - 1) * 0.5 maptext_height += body_maptext_height_offset - old_maptext_offset - //Update final_pixel_y so our mob doesn't go out of the southern bounds of the tile when standing - if(is_vertical) //But not if the mob has been rotated. - //Make sure the body position y offset is also updated - body_position_pixel_y_offset = get_pixel_y_offset_standing(current_size) - abs_pixel_y_offset = abs(body_position_pixel_y_offset) - var/new_translate = (abs_pixel_y_offset - round(abs_pixel_y_offset)) * SIGN(body_position_pixel_y_offset) - if(new_translate) - ntransform.Translate(0, new_translate) - final_pixel_y = base_pixel_y + body_position_pixel_y_offset + // and update the new translation + if(is_vertical && new_translation) + ntransform.Translate(0, new_translation) if(!changed) //Nothing has been changed, nothing has to be done. - return + return FALSE - ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, UPDATE_TRANSFORM_TRAIT) - addtimer(TRAIT_CALLBACK_REMOVE(src, TRAIT_NO_FLOATING_ANIM, UPDATE_TRANSFORM_TRAIT), 0.3 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) + // ensures the floating animation doesn't mess with our animation + if(HAS_TRAIT(src, TRAIT_MOVE_FLOATING)) + ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, UPDATE_TRANSFORM_TRAIT) + addtimer(TRAIT_CALLBACK_REMOVE(src, TRAIT_NO_FLOATING_ANIM, UPDATE_TRANSFORM_TRAIT), 0.3 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) //if true, we want to avoid any animation time, it'll tween and not rotate at all otherwise. var/is_opposite_angle = REVERSE_ANGLE(lying_angle) == lying_prev var/animate_time = is_opposite_angle ? 0 : UPDATE_TRANSFORM_ANIMATION_TIME - animate(src, transform = ntransform, time = animate_time, pixel_y = final_pixel_y, dir = final_dir, easing = (EASE_IN|EASE_OUT)) + animate(src, transform = ntransform, time = animate_time, dir = final_dir, easing = (EASE_IN|EASE_OUT)) for (var/hud_key in hud_list) var/image/hud_image = hud_list[hud_key] if (istype(hud_image)) adjust_hud_position(hud_image, animate_time = animate_time) SEND_SIGNAL(src, COMSIG_LIVING_POST_UPDATE_TRANSFORM, resize, lying_angle, is_opposite_angle) + return TRUE + +/// Calculates how far vertically the mob's transform should translate according to its size (1 being "default") +/mob/living/proc/get_transform_translation_size(value) + return (value - 1) * 16 + +/** + * Adds an offset to the mob's pixel position. + * + * * source: The source of the offset, a string + * * w_add: pixel_w offset + * * x_add: pixel_x offset + * * y_add: pixel_y offset + * * z_add: pixel_z offset + * * animate: If TRUE, the mob will animate to the new position. If FALSE, it will instantly move. + */ +/mob/living/proc/add_offsets(source, w_add, x_add, y_add, z_add, animate = TRUE) + LAZYINITLIST(offsets) + if(isnum(w_add)) + LAZYSET(offsets[PIXEL_W_OFFSET], source, w_add) + if(isnum(x_add)) + LAZYSET(offsets[PIXEL_X_OFFSET], source, x_add) + if(isnum(y_add)) + LAZYSET(offsets[PIXEL_Y_OFFSET], source, y_add) + if(isnum(z_add)) + LAZYSET(offsets[PIXEL_Z_OFFSET], source, z_add) + update_offsets(animate) + +/** + * Goes through all pixel adjustments and removes any tied to the passed source. + * + * * source: The source of the offset to remove + * * animate: If TRUE, the mob will animate to the position with any offsets removed. If FALSE, it will instantly move. + */ +/mob/living/proc/remove_offsets(source, animate = TRUE) + for(var/offset in offsets) + LAZYREMOVE(offsets[offset], source) + ASSOC_UNSETEMPTY(offsets, offset) + UNSETEMPTY(offsets) + update_offsets(animate) + +/** + * Updates the mob's pixel position according to the offsets. + * + * * animate: If TRUE, the mob will animate to the new position. If FALSE, it will instantly move. + * + * Returns TRUE if the mob's position has changed, FALSE otherwise. + */ +/mob/living/proc/update_offsets(animate = FALSE) + var/new_w = base_pixel_w + var/new_x = base_pixel_x + var/new_y = base_pixel_y + var/new_z = base_pixel_z + + for(var/offset_key in LAZYACCESS(offsets, PIXEL_W_OFFSET)) + new_w += offsets[PIXEL_W_OFFSET][offset_key] + for(var/offset_key in LAZYACCESS(offsets, PIXEL_X_OFFSET)) + new_x += offsets[PIXEL_X_OFFSET][offset_key] + for(var/offset_key in LAZYACCESS(offsets, PIXEL_Y_OFFSET)) + new_y += offsets[PIXEL_Y_OFFSET][offset_key] + for(var/offset_key in LAZYACCESS(offsets, PIXEL_Z_OFFSET)) + new_z += offsets[PIXEL_Z_OFFSET][offset_key] + + if(new_w == pixel_w && new_x == pixel_x && new_y == pixel_y && new_z == pixel_z) + return FALSE + + if(!animate) + pixel_w = new_w + pixel_x = new_x + pixel_y = new_y + pixel_z = new_z + return TRUE + + // ensures the floating animation doesn't mess with our animation + if(HAS_TRAIT(src, TRAIT_MOVE_FLOATING)) + ADD_TRAIT(src, TRAIT_NO_FLOATING_ANIM, UPDATE_OFFSET_TRAIT) + addtimer(TRAIT_CALLBACK_REMOVE(src, TRAIT_NO_FLOATING_ANIM, UPDATE_OFFSET_TRAIT), 0.3 SECONDS, TIMER_UNIQUE|TIMER_OVERRIDE) + + animate(src, + pixel_w = new_w, + pixel_x = new_x, + pixel_y = new_y, + pixel_z = new_z, + easing = (EASE_IN|EASE_OUT), + flags = ANIMATION_PARALLEL, + time = UPDATE_TRANSFORM_ANIMATION_TIME, + ) + return TRUE + +/** + * Checks if we are offset by the passed source for the passed pixel. + * + * * source: The source of the offset + * * pixel: Optional, The pixel to check. + * If not supplied, just reports if it's offset by the source at all (returning the first offset found). + * + * Returns the offset if we are, 0 otherwise. + */ +/mob/living/proc/has_offset(source, pixel) + if(isnull(pixel)) + for(var/found_pixel in offsets) + var/pixel_source = has_offset(source, found_pixel) + if(pixel_source) + return pixel_source + + return 0 + + return offsets?[pixel]?[source] || 0 + +// Updates offsets if base pixel changes +// Future TODO: move base pixel onto /obj and make mobs just set a base pixel using a source +/mob/living/set_base_pixel_x(new_value) + . = ..() + update_offsets() + +/mob/living/set_base_pixel_y(new_value) + . = ..() + update_offsets() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index a144b795bfd..6c44930b4b8 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -970,18 +970,20 @@ if(can_buckle && isliving(user) && isliving(M) && !(M in buckled_mobs) && ((user != src) || (!combat_mode))) return user_buckle_mob(M, user, check_loc = FALSE) -/mob/living/silicon/robot/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE, buckle_mob_flags= RIDER_NEEDS_ARM) - if(!is_type_in_typecache(M, can_ride_typecache)) - M.visible_message(span_warning("[M] really can't seem to mount [src]...")) - return - - if(stat || incapacitated) - return +/mob/living/silicon/robot/is_buckle_possible(mob/living/target, force, check_loc) + if(incapacitated) + return FALSE + if(!HAS_TRAIT(target, TRAIT_CAN_MOUNT_CYBORGS)) + target.visible_message(span_warning("[target] really can't seem to mount [src]...")) + return FALSE if(model && !model.allow_riding) - M.visible_message(span_boldwarning("Unfortunately, [M] just can't seem to hold onto [src]!")) - return + target.visible_message(span_boldwarning("Unfortunately, [target] just can't seem to hold onto [src]!")) + return FALSE - buckle_mob_flags= RIDER_NEEDS_ARM // just in case + return ..() + +/mob/living/silicon/robot/buckle_mob(mob/living/M, force, check_loc, buckle_mob_flags) + buckle_mob_flags = RIDER_NEEDS_ARM // just in case return ..() /mob/living/silicon/robot/post_buckle_mob(mob/living/victim_to_boot) diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm index 408a3f5beb0..d2c81e4ccfc 100644 --- a/code/modules/mob/living/silicon/robot/robot_defines.dm +++ b/code/modules/mob/living/silicon/robot/robot_defines.dm @@ -142,8 +142,6 @@ var/obj/item/hat var/hat_offset = list("north" = list(0, -3), "south" = list(0, -3), "east" = list(4, -3), "west" = list(-4, -3)) - ///What types of mobs are allowed to ride/buckle to this mob - var/static/list/can_ride_typecache = typecacheof(/mob/living/carbon/human) can_buckle = TRUE buckle_lying = FALSE diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm index d79b71ab3a5..35565082bf1 100644 --- a/code/modules/mob/living/silicon/robot/robot_model.dm +++ b/code/modules/mob/living/silicon/robot/robot_model.dm @@ -46,11 +46,11 @@ ///Whether the borg can stuff itself into disposals var/canDispose = FALSE ///The pixel offset of the hat. List of "north" "south" "east" "west" x, y offsets - var/hat_offset = list("north" = list(0, -3), "south" = list(0, -3), "east" = list(4, -3), "west" = list(-4, -3)) - ///The x offsets of a person riding the borg - var/list/ride_offset_x = list("north" = 0, "south" = 0, "east" = -6, "west" = 6) - ///The y offsets of a person riding the borg - var/list/ride_offset_y = list("north" = 4, "south" = 4, "east" = 3, "west" = 3) + var/list/hat_offset = list("north" = list(0, -3), "south" = list(0, -3), "east" = list(4, -3), "west" = list(-4, -3)) + ///The offsets of a person riding the borg of this model. + /// Format like list("north" = list(x, y, layer), ...) + /// Leave null to use defaults + var/list/ride_offsets ///List of skins the borg can be reskinned to, optional var/list/borg_skins @@ -548,17 +548,17 @@ // Start the sound. it'll just last the 4 seconds it takes for us to rev up wash_audio.start() // We're just gonna shake the borg a bit. Not a ton, but just enough that it feels like the audio makes sense - var/base_x = robot_owner.base_pixel_x - var/base_y = robot_owner.base_pixel_y - animate(robot_owner, pixel_x = base_x, pixel_y = base_y, time = 1, loop = -1) + var/base_w = robot_owner.base_pixel_w + var/base_z = robot_owner.base_pixel_z + animate(robot_owner, pixel_w = base_w, pixel_z = base_z, time = 0.1 SECONDS, loop = -1) for(var/i in 1 to 17) //Startup rumble - var/x_offset = base_x + rand(-1, 1) - var/y_offset = base_y + rand(-1, 1) - animate(pixel_x = x_offset, pixel_y = y_offset, time = 1) + var/w_offset = base_w + rand(-1, 1) + var/z_offset = base_z + rand(-1, 1) + animate(pixel_w = w_offset, pixel_z = z_offset, time = 0.1 SECONDS) if(!do_after(robot_owner, 4 SECONDS, interaction_key = "auto_wash_toggle", extra_checks = allow_buffer_activate)) wash_audio.stop() // Coward - animate(robot_owner, pixel_x = base_x, pixel_y = base_y, time = 1) + animate(robot_owner, pixel_w = base_w, pixel_z = base_z, time = 0.1 SECONDS) return FALSE else if(!COOLDOWN_FINISHED(src, toggle_cooldown)) @@ -583,16 +583,16 @@ robot_owner.add_movespeed_modifier(/datum/movespeed_modifier/auto_wash) RegisterSignal(robot_owner, COMSIG_MOVABLE_MOVED, PROC_REF(clean)) //This is basically just about adding a shake to the borg, effect should look ilke an engine's running - var/base_x = robot_owner.base_pixel_x - var/base_y = robot_owner.base_pixel_y - robot_owner.pixel_x = base_x + rand(-7, 7) - robot_owner.pixel_y = base_y + rand(-7, 7) + var/base_w = robot_owner.base_pixel_w + var/base_z = robot_owner.base_pixel_z + robot_owner.pixel_w = base_w + rand(-7, 7) + robot_owner.pixel_z = base_z + rand(-7, 7) //Larger shake with more changes to start out, feels like "Revving" - animate(robot_owner, pixel_x = base_x, pixel_y = base_y, time = 1, loop = -1) + animate(robot_owner, pixel_w = base_w, pixel_z = base_z, time = 0.1 SECONDS, loop = -1) for(var/i in 1 to 100) - var/x_offset = base_x + rand(-2, 2) - var/y_offset = base_y + rand(-2, 2) - animate(pixel_x = x_offset, pixel_y = y_offset, time = 1) + var/w_offset = base_w + rand(-2, 2) + var/z_offset = base_z + rand(-2, 2) + animate(pixel_w = w_offset, pixel_z = z_offset, time = 0.1 SECONDS) if(!wash_audio.is_active()) wash_audio.start() clean() @@ -608,15 +608,15 @@ // Diable the cleaning, we're revving down UnregisterSignal(robot_owner, COMSIG_MOVABLE_MOVED) // Do the rumble animation till we're all finished - var/base_x = robot_owner.base_pixel_x - var/base_y = robot_owner.base_pixel_y - animate(robot_owner, pixel_x = base_x, pixel_y = base_y, time = 1) + var/base_w = robot_owner.base_pixel_w + var/base_z = robot_owner.base_pixel_z + animate(robot_owner, pixel_w = base_w, pixel_z = base_z, time = 0.1 SECONDS) for(var/i in 1 to finished_by - 0.1 SECONDS) //We rumble until we're finished making noise - var/x_offset = base_x + rand(-1, 1) - var/y_offset = base_y + rand(-1, 1) - animate(pixel_x = x_offset, pixel_y = y_offset, time = 1) + var/w_offset = base_w + rand(-1, 1) + var/z_offset = base_z + rand(-1, 1) + animate(pixel_w = w_offset, pixel_z = z_offset, time = 0.1 SECONDS) // Reset our animations - animate(pixel_x = base_x, pixel_y = base_y, time = 2) + animate(pixel_w = base_w, pixel_z = base_z, time = 0.2 SECONDS) addtimer(CALLBACK(wash_audio, TYPE_PROC_REF(/datum/looping_sound, stop)), time_left) addtimer(CALLBACK(src, PROC_REF(turn_off_wash)), finished_by) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm index a5897c01695..e3347461650 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm @@ -140,12 +140,12 @@ Difficulty: Extremely Hard adjustHealth(-maxHealth) enraged = TRUE enraging = TRUE - animate(src, pixel_y = pixel_y + 96, time = 100, easing = ELASTIC_EASING) + animate(src, pixel_z = 96, time = 100, easing = ELASTIC_EASING, flags = ANIMATION_RELATIVE) spin(100, 10) SLEEP_CHECK_DEATH(60, src) playsound(src, 'sound/effects/explosion/explosion3.ogg', 100, TRUE) icon_state = "demonic_miner_phase2" - animate(src, pixel_y = pixel_y - 96, time = 8, flags = ANIMATION_END_NOW) + animate(src, pixel_z = -96, time = 8, flags = ANIMATION_END_NOW, flags = ANIMATION_RELATIVE) spin(8, 2) for(var/obj/structure/frost_miner_prism/prism_to_set in GLOB.frost_miner_prisms) prism_to_set.set_prism_light(LIGHT_COLOR_PURPLE, 5) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index af73f338b93..e6d552295c2 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1071,25 +1071,6 @@ return FALSE return ..(M, force, check_loc, buckle_mob_flags) -///Call back post buckle to a mob to offset your visual height -/mob/post_buckle_mob(mob/living/M) - var/height = M.get_mob_buckling_height(src) - M.pixel_y = initial(M.pixel_y) + height - if(M.layer <= layer) //make sure they stay above our current layer - M.layer = layer + 0.1 -///Call back post unbuckle from a mob, (reset your visual height here) -/mob/post_unbuckle_mob(mob/living/M) - M.layer = initial(M.layer) - M.pixel_y = initial(M.pixel_y) - -///returns the height in pixel the mob should have when buckled to another mob. -/mob/proc/get_mob_buckling_height(mob/seat) - if(isliving(seat)) - var/mob/living/L = seat - if(L.mob_size <= MOB_SIZE_SMALL) //being on top of a small mob doesn't put you very high. - return 0 - return 9 - ///Can the mob interact() with an atom? /mob/proc/can_interact_with(atom/A, treat_mob_as_adjacent) if(isAdminGhostAI(src)) diff --git a/code/modules/mod/modules/modules_supply.dm b/code/modules/mod/modules/modules_supply.dm index 2c4a5955aed..42aafaf7786 100644 --- a/code/modules/mod/modules/modules_supply.dm +++ b/code/modules/mod/modules/modules_supply.dm @@ -493,8 +493,7 @@ mod.wearer.add_filter("mod_ball", 1, alpha_mask_filter(icon = icon('icons/mob/clothing/modsuit/mod_modules.dmi', "ball_mask"), flags = MASK_INVERSE)) mod.wearer.add_filter("mod_blur", 2, angular_blur_filter(size = 15)) mod.wearer.add_filter("mod_outline", 3, outline_filter(color = "#000000AA")) - mod.wearer.base_pixel_y -= 4 - animate(mod.wearer, animate_time, pixel_y = mod.wearer.base_pixel_y, flags = ANIMATION_PARALLEL) + mod.wearer.add_offsets(REF(src), y_add = -4) mod.wearer.SpinAnimation(1.5) mod.wearer.add_traits(user_traits, REF(src)) mod.wearer.RemoveElement(/datum/element/footstep, FOOTSTEP_MOB_HUMAN, 1, -6) @@ -506,8 +505,7 @@ /obj/item/mod/module/sphere_transform/on_deactivation(display_message = TRUE, deleting = FALSE) if(!deleting) playsound(src, 'sound/items/modsuit/ballin.ogg', 100, TRUE, frequency = -1) - mod.wearer.base_pixel_y += 4 - animate(mod.wearer, animate_time, pixel_y = mod.wearer.base_pixel_y) + mod.wearer.remove_offsets(REF(src)) addtimer(CALLBACK(mod.wearer, TYPE_PROC_REF(/datum, remove_filter), list("mod_ball", "mod_blur", "mod_outline")), animate_time) mod.wearer.remove_traits(user_traits, REF(src)) mod.wearer.remove_movespeed_mod_immunities(REF(src), /datum/movespeed_modifier/damage_slowdown) diff --git a/code/modules/vehicles/vehicle_actions.dm b/code/modules/vehicles/vehicle_actions.dm index b5249c216a7..56c5ecceb01 100644 --- a/code/modules/vehicles/vehicle_actions.dm +++ b/code/modules/vehicles/vehicle_actions.dm @@ -357,8 +357,10 @@ else vehicle.obj_flags &= ~BLOCK_Z_OUT_DOWN rider.spin(spintime = 4, speed = 1) - animate(rider, pixel_y = -6, time = 4) - animate(vehicle, pixel_y = -6, time = 3) + animate(rider, pixel_z = 6, time = 0.4 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_z = -6, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) + animate(vehicle, pixel_z = 6, time = 0.3 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_z = -6, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) playsound(vehicle, 'sound/vehicles/skateboard_ollie.ogg', 50, TRUE) passtable_on(rider, VEHICLE_TRAIT) passtable_on(vehicle, VEHICLE_TRAIT) @@ -401,10 +403,12 @@ ) playsound(board, 'sound/vehicles/skateboard_ollie.ogg', 50, vary = TRUE) rider.spin(spintime = 4, speed = 1) - animate(rider, pixel_y = -6, time = 0.4 SECONDS) - animate(board, pixel_y = -6, time = 0.3 SECONDS) + animate(rider, pixel_z = 6, time = 0.4 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_z = -6, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) + animate(board, pixel_z = 6, time = 0.3 SECONDS, flags = ANIMATION_RELATIVE|ANIMATION_PARALLEL) + animate(pixel_z = -6, time = 0.1 SECONDS, flags = ANIMATION_RELATIVE) board.unbuckle_mob(rider) - addtimer(CALLBACK(board, TYPE_PROC_REF(/obj/vehicle/ridden/scooter/skateboard, pick_up_board), rider), 1 SECONDS) // so the board can still handle "picking it up" + addtimer(CALLBACK(board, TYPE_PROC_REF(/obj/vehicle/ridden/scooter/skateboard, pick_up_board), rider), 0.5 SECONDS) // so the board can still handle "picking it up"