diff --git a/code/__DEFINES/dcs/signals/signals_movable.dm b/code/__DEFINES/dcs/signals/signals_movable.dm index 5b3ae553ddadc..6bcfbde38a980 100644 --- a/code/__DEFINES/dcs/signals/signals_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_movable.dm @@ -69,8 +69,8 @@ // /datum/element/movetype_handler signals /// Called when the floating anim has to be temporarily stopped and restarted later: (timer) #define COMSIG_PAUSE_FLOATING_ANIM "pause_floating_anim" -/// From base of datum/element/movetype_handler/on_movement_type_trait_gain: (flag) +/// From base of datum/element/movetype_handler/on_movement_type_trait_gain: (flag, old_movement_type) #define COMSIG_MOVETYPE_FLAG_ENABLED "movetype_flag_enabled" -/// From base of datum/element/movetype_handler/on_movement_type_trait_loss: (flag) +/// From base of datum/element/movetype_handler/on_movement_type_trait_loss: (flag, old_movement_type) #define COMSIG_MOVETYPE_FLAG_DISABLED "movetype_flag_disabled" diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 342b99743fd63..04e7d943ddb6e 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -141,6 +141,10 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define FLOATING (1<<3) #define PHASING (1<<4) //! When moving, will Bump()/Cross() everything, but won't be stopped. #define THROWN (1<<5) //! while an atom is being thrown +#define UPSIDE_DOWN (1<<6) /// The mob is walking on the ceiling. Or is generally just, upside down. + +/// Combination flag for movetypes which, for all intents and purposes, mean the mob is not touching the ground +#define MOVETYPES_NOT_TOUCHING_GROUND (FLYING|FLOATING|UPSIDE_DOWN) //! ## Fire and Acid stuff, for resistance_flags #define LAVA_PROOF (1<<0) diff --git a/code/__DEFINES/gravity.dm b/code/__DEFINES/gravity.dm index eba2af77e122a..a638b22be3dd6 100644 --- a/code/__DEFINES/gravity.dm +++ b/code/__DEFINES/gravity.dm @@ -12,7 +12,18 @@ /// Singularity is stage 6 (11x11) #define STAGE_SIX 11 //! From supermatter shard -/// Anything above this is high gravity, anything below no grav until negative gravity -#define STANDARD_GRAVITY 1 +/** + * The point where gravity is negative enough to pull you upwards. + * That means walking checks for a ceiling instead of a floor, and you can fall "upwards" + * + * This should only be possible on multi-z maps because it works like shit on maps that aren't. + */ +#define NEGATIVE_GRAVITY -1 + +#define STANDARD_GRAVITY 1 //Anything above this is high gravity, anything below no grav until negative gravity /// The gravity strength threshold for high gravity damage. -#define GRAVITY_DAMAGE_TRESHOLD 3 +#define GRAVITY_DAMAGE_THRESHOLD 3 +/// The scaling factor for high gravity damage. +#define GRAVITY_DAMAGE_SCALING 0.5 +/// The maximum [BRUTE] damage a mob can take from high gravity per second. +#define GRAVITY_DAMAGE_MAXIMUM 1.5 diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 7385f71578e02..dd6121db10c3d 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -317,4 +317,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// The person with this trait always appears as 'unknown'. #define TRAIT_UNKNOWN "unknown" +/// We are ignoring gravity +#define TRAIT_IGNORING_GRAVITY "ignores_gravity" +/// We have some form of forced gravity acting on us +#define TRAIT_FORCED_GRAVITY "forced_gravity" +#define TRAIT_MOVE_UPSIDE_DOWN "move_upside_down" +#define TRAIT_NEGATES_GRAVITY "negates_gravity" + // END TRAIT DEFINES diff --git a/code/__DEFINES/traits/sources.dm b/code/__DEFINES/traits/sources.dm index fea059205dc72..d52b459750be9 100644 --- a/code/__DEFINES/traits/sources.dm +++ b/code/__DEFINES/traits/sources.dm @@ -133,3 +133,6 @@ #define NO_GRAVITY_TRAIT "no-gravity" #define LIFECANDLE_TRAIT "lifecandle" #define LEAPER_BUBBLE_TRAIT "leaper-bubble" +#define NEGATIVE_GRAVITY_TRAIT "negative-gravity" +/// Sources for TRAIT_IGNORING_GRAVITY +#define IGNORING_GRAVITY_NEGATION "ignoring_gravity_negation" diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 2d121bb1829d5..8d75b40d3dd9d 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -153,7 +153,8 @@ DEFINE_BITFIELD(movement_type, list( "FLYING" = FLYING, "VENTCRAWLING" = VENTCRAWLING, "FLOATING" = FLOATING, - "PHASING" = PHASING + "PHASING" = PHASING, + "UPSIDE_DOWN" = UPSIDE_DOWN, )) DEFINE_BITFIELD(mat_container_flags, list( diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index bb40b3836fbf8..aab4c39b3d4b4 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -178,7 +178,11 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NORADDAMAGE" = TRAIT_NORADDAMAGE, "TRAIT_MOBILE" = TRAIT_MOBILE, "INSTANT_DO_AFTER" = INSTANT_DO_AFTER, - "TRAIT_UNKNOWN" = TRAIT_UNKNOWN + "TRAIT_UNKNOWN" = TRAIT_UNKNOWN, + "TRAIT_IGNORING_GRAVITY" = TRAIT_IGNORING_GRAVITY, + "TRAIT_FORCED_GRAVITY" = TRAIT_FORCED_GRAVITY, + "TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN, + "TRAIT_NEGATES_GRAVITY" = TRAIT_NEGATES_GRAVITY ), /obj/item/integrated_circuit = list( "TRAIT_COMPONENT_MMI" = TRAIT_COMPONENT_MMI, diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index dd5f5e8722411..51325b3bab772 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -248,6 +248,11 @@ If you're feeling frisky, examine yourself and click the underlined item to pull var/mob/living/carbon/M = usr return M.help_shake_act(M) +/atom/movable/screen/alert/negative + name = "Negative Gravity" + desc = "You're getting pulled upwards. While you won't have to worry about falling down anymore, you may accidentally fall upwards!" + icon_state = "negative" + /atom/movable/screen/alert/weightless name = "Weightless" desc = "Gravity has ceased affecting you, and you're floating around aimlessly. You'll need something large and heavy, like a \ diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index add3bf18afaa8..d2d8fba411651 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -55,6 +55,10 @@ SUBSYSTEM_DEF(mapping) var/datum/space_level/empty_space var/num_of_res_levels = 1 + ///shows the default gravity value for each z level. recalculated when gravity generators change. + ///List in the form: list(z level num = max generator gravity in that z level OR the gravity level trait) + var/list/gravity_by_z_level = list() + /datum/controller/subsystem/mapping/PreInit() ..() #ifdef FORCE_MAP @@ -126,6 +130,7 @@ SUBSYSTEM_DEF(mapping) generate_station_area_list() transit = add_new_zlevel("Transit/Reserved", list(ZTRAIT_RESERVED = TRUE)) initialize_reserved_level(transit.z_value) + calculate_default_z_level_gravities() return SS_INIT_SUCCESS /datum/controller/subsystem/mapping/fire(resumed) @@ -617,6 +622,9 @@ GLOBAL_LIST_EMPTY(the_station_areas) /// - Adds to z_list, and builds its area turfs /datum/controller/subsystem/mapping/proc/manage_z_level(datum/space_level/new_z, filled_with_space, contain_turfs = TRUE) z_list += new_z + + gravity_by_z_level.len += 1 + if(contain_turfs) build_area_turfs(new_z.z_value, filled_with_space) @@ -632,6 +640,10 @@ GLOBAL_LIST_EMPTY(the_station_areas) var/area/our_area = to_contain.loc our_area.contained_turfs += to_contain +/datum/controller/subsystem/mapping/proc/calculate_default_z_level_gravities() + for(var/z_level in 1 to length(z_list)) + calculate_z_level_gravity(z_level) + /datum/controller/subsystem/mapping/proc/generate_z_level_linkages() for(var/z_level in 1 to length(z_list)) generate_linkages_for_z_level(z_level) @@ -650,3 +662,16 @@ GLOBAL_LIST_EMPTY(the_station_areas) multiz_levels[z_level] = new /list(LARGEST_Z_LEVEL_INDEX) multiz_levels[z_level][Z_LEVEL_UP] = !!z_above multiz_levels[z_level][Z_LEVEL_DOWN] = !!z_below + +/datum/controller/subsystem/mapping/proc/calculate_z_level_gravity(z_level_number) + if(!isnum(z_level_number) || z_level_number < 1) + return FALSE + + var/max_gravity = 0 + + for(var/obj/machinery/gravity_generator/main/grav_gen as anything in GLOB.gravity_generators["[z_level_number]"]) + max_gravity = max(grav_gen.setting, max_gravity) + + max_gravity = max_gravity || level_trait(z_level_number, ZTRAIT_GRAVITY) || 0 //just to make sure no nulls + gravity_by_z_level[z_level_number] = max_gravity + return max_gravity diff --git a/code/datums/components/caltrop.dm b/code/datums/components/caltrop.dm index 67e76e0592e17..ff2c7611bc549 100644 --- a/code/datums/components/caltrop.dm +++ b/code/datums/components/caltrop.dm @@ -55,7 +55,7 @@ if(!(flags & CALTROP_BYPASS_SHOES) && (H.shoes || feetCover)) return - if((H.movement_type & (FLYING|FLOATING)) || (H.body_position == LYING_DOWN)|| H.buckled) + if((H.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || (H.body_position == LYING_DOWN)|| H.buckled) return var/damage = rand(min_damage, max_damage) diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm index c439bcee66ce0..3db67bab6209a 100644 --- a/code/datums/components/chasm.dm +++ b/code/datums/components/chasm.dm @@ -69,7 +69,7 @@ return FALSE if(!isliving(AM) && !isobj(AM)) return FALSE - if(is_type_in_typecache(AM, forbidden_types) || AM.throwing || (AM.movement_type & (FLOATING|FLYING))) + if(is_type_in_typecache(AM, forbidden_types) || AM.throwing || (AM.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) return FALSE //Flies right over the chasm if(ismob(AM)) diff --git a/code/datums/components/conveyor_movement.dm b/code/datums/components/conveyor_movement.dm index 43fb9979a2cc9..6ec3f30830731 100644 --- a/code/datums/components/conveyor_movement.dm +++ b/code/datums/components/conveyor_movement.dm @@ -24,7 +24,7 @@ source.delay = speed //We use the default delay if(living_parent) var/mob/living/moving_mob = parent - if((moving_mob.movement_type & (FLOATING|FLYING)) && !moving_mob.stat) + if((moving_mob.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) && !moving_mob.stat) return MOVELOOP_SKIP_STEP var/atom/movable/moving_parent = parent if(moving_parent.anchored || !moving_parent.has_gravity()) diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm index 3b244d5e16f8a..39907f144d6d0 100644 --- a/code/datums/components/slippery.dm +++ b/code/datums/components/slippery.dm @@ -34,7 +34,7 @@ if(!isliving(arrived)) return var/mob/living/victim = arrived - if(!(victim.movement_type & (FLOATING|FLYING)) && victim.slip(knockdown_time, parent, lube_flags, paralyze_time, force_drop_items) && callback) + if(!(victim.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) && victim.slip(knockdown_time, parent, lube_flags, paralyze_time, force_drop_items) && callback) callback.Invoke(victim) /datum/component/slippery/UnregisterFromParent() diff --git a/code/datums/components/spikes.dm b/code/datums/components/spikes.dm index be078a73721c7..a2a2daac40a68 100644 --- a/code/datums/components/spikes.dm +++ b/code/datums/components/spikes.dm @@ -58,7 +58,7 @@ if(ishuman(C)) var/mob/living/carbon/human/H = C var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET)) - if((H.movement_type & (FLOATING|FLYING)) || H.body_position == LYING_DOWN || H.buckled || H.shoes || feetCover) + if((H.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || H.body_position == LYING_DOWN || H.buckled || H.shoes || feetCover) prick(H, 0.5) else prick(H, 2) diff --git a/code/datums/components/squashable.dm b/code/datums/components/squashable.dm index f9159614909fd..9091ef34e981d 100644 --- a/code/datums/components/squashable.dm +++ b/code/datums/components/squashable.dm @@ -53,7 +53,7 @@ if(isliving(crossing_movable)) var/mob/living/crossing_mob = crossing_movable - if(crossing_mob.mob_size > MOB_SIZE_SMALL && !(crossing_mob.movement_type & (FLOATING|FLYING))) + if(crossing_mob.mob_size > MOB_SIZE_SMALL && !(crossing_mob.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) if(HAS_TRAIT(crossing_mob, TRAIT_PACIFISM)) crossing_mob.visible_message("[crossing_mob] carefully steps over [parent_as_living].", "You carefully step over [parent_as_living] to avoid hurting it.") return diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index 8757402c7b2e9..9c1d694be9bc9 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -94,7 +94,7 @@ return if(istype(arrived, /obj/effect/dummy/phased_mob)) //don't squeek if they're in a phased/jaunting container. return - if(arrived.movement_type & (FLYING|FLOATING) || !arrived.has_gravity()) + if(arrived.movement_type & MOVETYPES_NOT_TOUCHING_GROUND || !arrived.has_gravity()) return var/atom/current_parent = parent if(isturf(current_parent?.loc)) diff --git a/code/datums/elements/forced_gravity.dm b/code/datums/elements/forced_gravity.dm index 17f2651dc485c..51a0c270e77fa 100644 --- a/code/datums/elements/forced_gravity.dm +++ b/code/datums/elements/forced_gravity.dm @@ -4,7 +4,7 @@ var/gravity var/ignore_space -/datum/element/forced_gravity/Attach(datum/target, gravity=1, ignore_space=FALSE) +/datum/element/forced_gravity/Attach(datum/target, gravity=1, ignore_space=FALSE, can_override = FALSE) . = ..() if(!isatom(target)) return ELEMENT_INCOMPATIBLE @@ -12,21 +12,26 @@ src.gravity = gravity src.ignore_space = ignore_space - RegisterSignal(target, COMSIG_ATOM_HAS_GRAVITY, PROC_REF(gravity_check)) + RegisterSignal(target, COMSIG_ATOM_HAS_GRAVITY, PROC_REF(gravity_check), override = can_override) if(isturf(target)) - RegisterSignal(target, COMSIG_TURF_HAS_GRAVITY, PROC_REF(turf_gravity_check)) + RegisterSignal(target, COMSIG_TURF_HAS_GRAVITY, PROC_REF(turf_gravity_check), override = can_override) + + ADD_TRAIT(target, TRAIT_FORCED_GRAVITY, REF(src)) /datum/element/forced_gravity/Detach(datum/source, force) . = ..() var/static/list/signals_b_gone = list(COMSIG_ATOM_HAS_GRAVITY, COMSIG_TURF_HAS_GRAVITY) UnregisterSignal(source, signals_b_gone) + REMOVE_TRAIT(source, TRAIT_FORCED_GRAVITY, REF(src)) /datum/element/forced_gravity/proc/gravity_check(datum/source, turf/location, list/gravs) SIGNAL_HANDLER - if(!ignore_space && isspaceturf(location)) - return + if(!ignore_space && location.force_no_gravity) + return FALSE gravs += gravity + return TRUE + /datum/element/forced_gravity/proc/turf_gravity_check(datum/source, atom/checker, list/gravs) SIGNAL_HANDLER - return gravity_check(null, source, gravs) + gravity_check(null, source, gravs) diff --git a/code/datums/elements/movetype_handler.dm b/code/datums/elements/movetype_handler.dm index 3e648d01c4f5a..b33800738307e 100644 --- a/code/datums/elements/movetype_handler.dm +++ b/code/datums/elements/movetype_handler.dm @@ -52,7 +52,9 @@ if(!(source.movement_type & (FLOATING|FLYING)) && (trait == TRAIT_MOVE_FLYING || trait == TRAIT_MOVE_FLOATING) && !paused_floating_anim_atoms[source] && !HAS_TRAIT(source, TRAIT_NO_FLOATING_ANIM)) DO_FLOATING_ANIM(source) source.movement_type |= flag - SEND_SIGNAL(source, COMSIG_MOVETYPE_FLAG_ENABLED, flag) + if((trait == TRAIT_MOVE_FLYING || trait == TRAIT_MOVE_FLOATING) && !(source.movement_type & (FLOATING|FLYING))) + stop_floating(source) + SEND_SIGNAL(source, COMSIG_MOVETYPE_FLAG_DISABLED, flag) /// Called when a movement type trait is removed from the movable. Disables the relative bitflag if it wasn't there in the compile-time bitfield. /datum/element/movetype_handler/proc/on_movement_type_trait_loss(atom/movable/source, trait) @@ -60,10 +62,14 @@ var/flag = GLOB.movement_type_trait_to_flag[trait] if(initial(source.movement_type) & flag) return + var/old_state = source.movement_type source.movement_type &= ~flag - if((trait == TRAIT_MOVE_FLYING || trait == TRAIT_MOVE_FLOATING) && !(source.movement_type & (FLOATING|FLYING))) + if((old_state & (FLOATING|FLYING)) && !(source.movement_type & (FLOATING|FLYING))) stop_floating(source) - SEND_SIGNAL(source, COMSIG_MOVETYPE_FLAG_DISABLED, flag) + var/turf/pitfall = source.loc //Things that don't fly fall in open space. + if(istype(pitfall)) + pitfall.zFall(source) + SEND_SIGNAL(source, COMSIG_MOVETYPE_FLAG_DISABLED, flag, old_state) /// Called when the TRAIT_NO_FLOATING_ANIM trait is added to the movable. Stops it from bobbing up and down. /datum/element/movetype_handler/proc/on_no_floating_anim_trait_gain(atom/movable/source, trait) diff --git a/code/datums/proximity_monitor/fields/gravity.dm b/code/datums/proximity_monitor/fields/gravity.dm index ccac71a6d8508..b55a6521c32ed 100644 --- a/code/datums/proximity_monitor/fields/gravity.dm +++ b/code/datums/proximity_monitor/fields/gravity.dm @@ -9,7 +9,7 @@ /datum/proximity_monitor/advanced/gravity/setup_field_turf(turf/T) . = ..() - T.AddElement(/datum/element/forced_gravity, gravity_value) + T.AddElement(/datum/element/forced_gravity, gravity_value, can_override = TRUE) modified_turfs[T] = gravity_value /datum/proximity_monitor/advanced/gravity/cleanup_field_turf(turf/T) diff --git a/code/datums/weather/weather_types/floor_is_lava.dm b/code/datums/weather/weather_types/floor_is_lava.dm index 9762499693560..61bf86a2c3c12 100644 --- a/code/datums/weather/weather_types/floor_is_lava.dm +++ b/code/datums/weather/weather_types/floor_is_lava.dm @@ -35,6 +35,6 @@ return if(!L.client) //Only sentient people are going along with it! return - if(L.movement_type & (FLOATING|FLYING)) + if(L.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return L.adjustFireLoss(3) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 9aa198d1ae78c..674d8de01175e 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1897,6 +1897,12 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom) * Sends signals [COMSIG_ATOM_HAS_GRAVITY] and [COMSIG_TURF_HAS_GRAVITY], both can force gravity with * the forced gravity var. * + * HEY JACKASS, LISTEN + * IF YOU ADD SOMETHING TO THIS PROC, MAKE SURE /mob/living ACCOUNTS FOR IT + * + * Living mobs treat gravity in an event based manner. We've decomposed this proc into different checks + * for them to use. If you add more to it, make sure you do that, or things will behave strangely + * * Gravity situations: * * No gravity if you're not in a turf * * No gravity if this atom is in is a space turf @@ -1909,32 +1915,25 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom) if(!isturf(gravity_turf)) gravity_turf = get_turf(src) - if(!gravity_turf) + if(!gravity_turf)//no gravity in nullspace return FALSE var/list/forced_gravity = list() SEND_SIGNAL(src, COMSIG_ATOM_HAS_GRAVITY, gravity_turf, forced_gravity) - if(!length(forced_gravity)) - SEND_SIGNAL(gravity_turf, COMSIG_TURF_HAS_GRAVITY, src, forced_gravity) + SEND_SIGNAL(gravity_turf, COMSIG_TURF_HAS_GRAVITY, src, forced_gravity) if(length(forced_gravity)) - var/max_grav - for(var/i in forced_gravity) - max_grav = max(max_grav, i) - return max_grav + var/positive_grav = max(forced_gravity) + var/negative_grav = min(min(forced_gravity), 0) //negative grav needs to be below or equal to 0 - if(!gravity_turf.check_gravity()) // Turf never has gravity - return FALSE - var/area/A = get_area(gravity_turf) - if(A.has_gravity) // Areas which always has gravity - return TRUE - else if(SSmapping.level_trait(gravity_turf.z, ZTRAIT_GRAVITY)) // If the z-level always has gravity - return TRUE - else if(GLOB.gravity_generators["[gravity_turf.get_virtual_z_level()]"]) // If there's a gravity generator on our z level - var/max_grav = 0 - for(var/obj/machinery/gravity_generator/main/G in GLOB.gravity_generators["[gravity_turf.get_virtual_z_level()]"]) - max_grav = max(G.setting,max_grav) - return max_grav - return FALSE + //our gravity is sum of the most massive positive and negative numbers returned by the signal + //so that adding two forced_gravity elements with an effect size of 1 each doesnt add to 2 gravity + //but negative force gravity effects can cancel out positive ones + + return (positive_grav + negative_grav) + + var/area/turf_area = gravity_turf.loc + + return !gravity_turf.force_no_gravity && (SSmapping.gravity_by_z_level[gravity_turf.z] || turf_area.has_gravity) /* * Called when something made out of plasma is exposed to high temperatures. diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index b860bda0a83f1..7940d16e74694 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -125,7 +125,7 @@ /obj/effect/mine/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER - if(!isturf(loc) || AM.throwing || (AM.movement_type & (FLYING | FLOATING)) || !AM.has_gravity() || triggered) + if(!isturf(loc) || AM.throwing || (AM.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || !AM.has_gravity() || triggered) return if(ismob(AM)) checksmartmine(AM) diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm index 1c16677c2f466..bb2e99f70d127 100644 --- a/code/game/objects/items/handcuffs.dm +++ b/code/game/objects/items/handcuffs.dm @@ -215,7 +215,7 @@ . = ..() update_icon() var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = PROC_REF(spring_trap), + COMSIG_ATOM_ENTERED = PROC_REF(trap_stepped_on), ) AddElement(/datum/element/connect_loc, loc_connections) @@ -241,41 +241,53 @@ update_appearance() playsound(src, 'sound/effects/snap.ogg', 50, TRUE) -/obj/item/restraints/legcuffs/beartrap/proc/spring_trap(datum/source, AM as mob|obj) +/obj/item/restraints/legcuffs/beartrap/proc/trap_stepped_on(datum/source, atom/movable/entering, ...) SIGNAL_HANDLER - if(armed && isturf(loc)) - if(isliving(AM)) - var/mob/living/L = AM - var/snap = TRUE - if(istype(L.buckled, /obj/vehicle)) - var/obj/vehicle/ridden_vehicle = L.buckled - if(!ridden_vehicle.are_legs_exposed) //close the trap without injuring/trapping the rider if their legs are inside the vehicle at all times. - close_trap() - ridden_vehicle.visible_message("[ridden_vehicle] triggers \the [src].") - - if(L.movement_type & (FLYING|FLOATING)) //don't close the trap if they're flying/floating over it. - snap = FALSE - - var/def_zone = BODY_ZONE_CHEST - if(snap && iscarbon(L)) - var/mob/living/carbon/C = L - if(C.body_position == STANDING_UP) - def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - if(!C.legcuffed && C.num_legs >= 2) //beartrap can't cuff your leg if there's already a beartrap or legcuffs, or you don't have two legs. - C.legcuffed = src - forceMove(C) - C.update_equipment_speed_mods() - C.update_inv_legcuffed() - SSblackbox.record_feedback("tally", "handcuffs", 1, type) - else if(snap && isanimal(L)) - var/mob/living/simple_animal/SA = L - if(SA.mob_size <= MOB_SIZE_TINY) //don't close the trap if they're as small as a mouse. - snap = FALSE - if(snap) - close_trap() - L.visible_message("[L] triggers \the [src].", \ - "You trigger \the [src]!") - L.apply_damage(trap_damage, BRUTE, def_zone) + + spring_trap(entering) + +/** + * Tries to spring the trap on the target movable. + * + * This proc is safe to call without knowing if the target is valid or if the trap is armed. + * + * Does not trigger on tiny mobs. + * If ignore_movetypes is FALSE, does not trigger on floating / flying / etc. mobs. + */ +/obj/item/restraints/legcuffs/beartrap/proc/spring_trap(atom/movable/target, ignore_movetypes = FALSE, hit_prone = FALSE) + if(!armed || !isturf(loc) || !isliving(target)) + return + + var/mob/living/victim = target + if(istype(victim.buckled, /obj/vehicle)) + var/obj/vehicle/ridden_vehicle = victim.buckled + if(!ridden_vehicle.are_legs_exposed) //close the trap without injuring/trapping the rider if their legs are inside the vehicle at all times. + close_trap() + ridden_vehicle.visible_message("[ridden_vehicle] triggers \the [src].") + return + + //don't close the trap if they're as small as a mouse + if(victim.mob_size <= MOB_SIZE_TINY) + return + if(!ignore_movetypes && (victim.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) + return + + close_trap() + if(ignore_movetypes) + victim.visible_message("\The [src] ensnares [victim]!", \ + "\The [src] ensnares you!") + else + victim.visible_message("[victim] triggers \the [src].", \ + "You trigger \the [src]!") + var/def_zone = BODY_ZONE_CHEST + if(iscarbon(victim) && (victim.body_position == STANDING_UP || hit_prone)) + var/mob/living/carbon/carbon_victim = victim + def_zone = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + if(!carbon_victim.legcuffed && carbon_victim.num_legs >= 2) //beartrap can't cuff your leg if there's already a beartrap or legcuffs, or you don't have two legs. + INVOKE_ASYNC(carbon_victim, TYPE_PROC_REF(/mob/living/carbon, equip_to_slot), src, ITEM_SLOT_LEGCUFFED) + SSblackbox.record_feedback("tally", "handcuffs", 1, type) + + victim.apply_damage(trap_damage, BRUTE, def_zone) /obj/item/restraints/legcuffs/beartrap/energy name = "energy snare" @@ -296,7 +308,7 @@ qdel(src) /obj/item/restraints/legcuffs/beartrap/energy/attack_hand(mob/user, list/modifiers) - spring_trap(null, user) + spring_trap(user) return ..() /obj/item/restraints/legcuffs/beartrap/energy/cyborg @@ -371,7 +383,7 @@ /obj/item/restraints/legcuffs/bola/energy/ensnare(mob/living/carbon/C) var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy/cyborg(get_turf(C)) - B.spring_trap(null, C) + B.spring_trap(C, ignore_movetypes = TRUE) qdel(src) /obj/item/restraints/legcuffs/bola/energy/emp_act(severity) diff --git a/code/game/objects/items/stacks/sheets/mineral/glass.dm b/code/game/objects/items/stacks/sheets/mineral/glass.dm index 80f392130647d..3602fc2b74d28 100644 --- a/code/game/objects/items/stacks/sheets/mineral/glass.dm +++ b/code/game/objects/items/stacks/sheets/mineral/glass.dm @@ -295,7 +295,7 @@ SIGNAL_HANDLER if(isliving(AM)) var/mob/living/L = AM - if(!(L.movement_type & (FLYING|FLOATING)) || L.buckled) + if(!(L.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) || L.buckled) playsound(src, 'sound/effects/glass_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 30 : 50, TRUE) /obj/item/shard/plasma diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm index f48bcdf352da5..37987a431deb6 100644 --- a/code/game/objects/structures/kitchen_spike.dm +++ b/code/game/objects/structures/kitchen_spike.dm @@ -84,6 +84,7 @@ m180.Turn(180) animate(L, transform = m180, time = 3) L.pixel_y = L.base_pixel_y + PIXEL_Y_OFFSET_LYING + ADD_TRAIT(user, TRAIT_MOVE_UPSIDE_DOWN, REF(src)) else if (has_buckled_mobs()) for(var/mob/living/L in buckled_mobs) user_unbuckle_mob(L, user) @@ -129,6 +130,7 @@ m180.Turn(180) animate(M, transform = m180, time = 3) M.pixel_y = M.base_pixel_y + PIXEL_Y_OFFSET_LYING + REMOVE_TRAIT(M, TRAIT_MOVE_UPSIDE_DOWN, REF(src)) M.adjustBruteLoss(30) src.visible_message("[M] falls free of [src]!") unbuckle_mob(M,force=1) diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index cd6f467120bcc..ca961d47a5197 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -84,7 +84,7 @@ /obj/structure/railing/CanPass(atom/movable/mover, border_dir) . = ..() if(border_dir & dir) - return . || mover.throwing || mover.movement_type & (FLYING | FLOATING) + return . || mover.throwing || mover.movement_type & MOVETYPES_NOT_TOUCHING_GROUND return TRUE /obj/structure/railing/proc/on_exit(datum/source, atom/movable/leaving, direction) @@ -102,7 +102,7 @@ if (leaving.throwing) return - if (leaving.movement_type & (PHASING | FLYING | FLOATING)) + if (leaving.movement_type & (PHASING | MOVETYPES_NOT_TOUCHING_GROUND)) return if (leaving.move_force >= MOVE_FORCE_EXTREMELY_STRONG) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 544cb9177e98b..1a657d3bc2c98 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -317,7 +317,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/table) check_break(M) /obj/structure/table/glass/proc/check_break(mob/living/M) - if(M.has_gravity() && M.mob_size > MOB_SIZE_SMALL && !(M.movement_type & (FLOATING|FLYING))) + if(M.has_gravity() && M.mob_size > MOB_SIZE_SMALL && !(M.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) table_shatter(M) /obj/structure/table/glass/proc/table_shatter(mob/living/victim) diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 6b0f5a24a69ef..d6a6ae2dd1d22 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -99,7 +99,7 @@ CREATION_TEST_IGNORE_SELF(/turf/open) /turf/open/indestructible/sound/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) . = ..() - if(istype(arrived) && !(arrived.movement_type & (FLYING|FLOATING))) + if(istype(arrived) && !(arrived.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) playsound(src,sound,50,1) /turf/open/indestructible/necropolis diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm index a31ddf285f808..104b7d6dadd28 100644 --- a/code/game/turfs/open/lava.dm +++ b/code/game/turfs/open/lava.dm @@ -125,7 +125,7 @@ else if (isliving(thing)) . = 1 var/mob/living/L = thing - if(L.movement_type & (FLOATING|FLYING)) + if(L.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) continue //YOU'RE FLYING OVER IT var/buckle_check = L.buckled if(isobj(buckle_check)) diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm index 4cef4cfdf32af..005628458fbd8 100644 --- a/code/game/turfs/open/openspace.dm +++ b/code/game/turfs/open/openspace.dm @@ -31,6 +31,13 @@ CREATION_TEST_IGNORE_SUBTYPES(/turf/open/openspace) /turf/open/openspace/airless initial_gas_mix = AIRLESS_ATMOS +/turf/open/openspace/Initialize(mapload) + . = ..() + var/area/our_area = loc + if(istype(our_area, /area/space)) + force_no_gravity = TRUE + return INITIALIZE_HINT_LATELOAD + /turf/open/openspace/can_have_cabling() if(locate(/obj/structure/lattice/catwalk, src)) return TRUE diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index d4e29778c1bab..54672809445a6 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -38,6 +38,8 @@ z_eventually_space = TRUE vis_flags = VIS_INHERIT_ID //when this be added to vis_contents of something it be associated with something on clicking, important for visualisation of turf in openspace and interraction with openspace that show you turf. + force_no_gravity = TRUE + /turf/open/space/basic/New() //Do not convert to Initialize //This is used to optimize the map loader return diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 94342afcd56a3..a1992909487a4 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -72,6 +72,9 @@ CREATION_TEST_IGNORE_SELF(/turf) /// See __DEFINES/construction.dm for RCD_MEMORY_*. var/rcd_memory + ///whether or not this turf forces movables on it to have no gravity (unless they themselves have forced gravity) + var/force_no_gravity = FALSE + ///Icon-smoothing variable to map a diagonal wall corner with a fixed underlay. var/list/fixed_underlay = null diff --git a/code/modules/antagonists/clock_cult/traps/receivers/skewer.dm b/code/modules/antagonists/clock_cult/traps/receivers/skewer.dm index d9d66ea55c9f4..b66d84885dc28 100644 --- a/code/modules/antagonists/clock_cult/traps/receivers/skewer.dm +++ b/code/modules/antagonists/clock_cult/traps/receivers/skewer.dm @@ -27,7 +27,7 @@ var/target_stabbed = FALSE density = TRUE for(var/mob/living/M in get_turf(src)) - if(M.incorporeal_move || M.movement_type & (FLOATING|FLYING)) + if(M.incorporeal_move || M.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) continue if(buckle_mob(M, TRUE)) target_stabbed = TRUE diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm index 39399d9e8064a..94f2af29bb758 100644 --- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm +++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm @@ -4,6 +4,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( /obj/machinery/field/containment, /obj/machinery/power/supermatter_crystal, + /obj/machinery/gravity_generator, /obj/machinery/doomsday_device, /obj/machinery/nuclearbomb, /obj/machinery/nuclearbomb/selfdestruct, diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 4769f01272687..db98df285b98e 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -175,7 +175,7 @@ if(armed) if(ismob(AM)) var/mob/MM = AM - if(!(MM.movement_type & (FLOATING|FLYING))) + if(!(MM.movement_type & MOVETYPES_NOT_TOUCHING_GROUND)) if(ishuman(AM)) var/mob/living/carbon/H = AM if(H.m_intent == MOVE_INTENT_RUN) diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm index 6e3a364ab8ff3..a1cecec5fe1f1 100644 --- a/code/modules/clothing/shoes/magboots.dm +++ b/code/modules/clothing/shoes/magboots.dm @@ -12,6 +12,16 @@ equip_delay_other = 70 resistance_flags = FIRE_PROOF +/obj/item/clothing/shoes/magboots/equipped(mob/user, slot) + . = ..() + if(slot & ITEM_SLOT_FEET) + update_gravity_trait(user) + else + REMOVE_TRAIT(user, TRAIT_NEGATES_GRAVITY, type) + +/obj/item/clothing/shoes/magboots/dropped(mob/user) + . = ..() + REMOVE_TRAIT(user, TRAIT_NEGATES_GRAVITY, type) /obj/item/clothing/shoes/magboots/verb/toggle() set name = "Toggle Magboots" @@ -22,7 +32,7 @@ attack_self(usr) -/obj/item/clothing/shoes/magboots/attack_self(mob/user) +/obj/item/clothing/shoes/magboots/attack_self(mob/living/user) if(magpulse) clothing_flags &= ~NOSLIP slowdown = SHOES_SLOWDOWN @@ -31,9 +41,8 @@ slowdown = slowdown_active magpulse = !magpulse icon_state = "[magboot_state][magpulse]" - to_chat(user, "You [magpulse ? "enable" : "disable"] the mag-pulse traction system.") - user.update_inv_shoes() //so our mob-overlays update - user.update_gravity(user.has_gravity()) + update_gravity_trait(user) + user.refresh_gravity() update_action_buttons() /obj/item/clothing/shoes/magboots/negates_gravity() @@ -43,6 +52,13 @@ . = ..() . += "Its mag-pulse traction system appears to be [magpulse ? "enabled" : "disabled"]." +///Adds/removes the gravity negation trait from the wearer depending on if the magpulse system is turned on. +/obj/item/clothing/shoes/magboots/proc/update_gravity_trait(mob/user) + if(magpulse) + ADD_TRAIT(user, TRAIT_NEGATES_GRAVITY, type) + else + REMOVE_TRAIT(user, TRAIT_NEGATES_GRAVITY, type) + /obj/item/clothing/shoes/magboots/advance desc = "Advanced magnetic boots that have a lighter magnetic pull, placing less burden on the wearer." @@ -69,6 +85,7 @@ clothing_flags = NOSLIP /obj/item/clothing/shoes/magboots/commando/attack_self(mob/user) //Code for the passive no-slip of the commando magboots to always apply, kind of a shit code solution though. + . = ..() if(magpulse) slowdown = SHOES_SLOWDOWN else @@ -77,7 +94,6 @@ icon_state = "[magboot_state][magpulse]" to_chat(user, "You [magpulse ? "enable" : "disable"] the mag-pulse traction system.") user.update_inv_shoes() - user.update_gravity(user.has_gravity()) update_action_buttons() /obj/item/clothing/shoes/magboots/crushing diff --git a/code/modules/mapping/space_management/zlevel_manager.dm b/code/modules/mapping/space_management/zlevel_manager.dm index d43aedc2a225d..7e7c8e188e887 100644 --- a/code/modules/mapping/space_management/zlevel_manager.dm +++ b/code/modules/mapping/space_management/zlevel_manager.dm @@ -27,6 +27,7 @@ var/datum/space_level/S = new z_type(new_z, name, traits, orbital_body_type) manage_z_level(S, filled_with_space = TRUE, contain_turfs = contain_turfs) generate_linkages_for_z_level(new_z) + calculate_z_level_gravity(new_z) SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_Z, S) return S diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 5ce3b199f2e90..04313e3f0c07c 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -32,6 +32,9 @@ GLOB.new_player_list -= src return ..() +/mob/dead/new_player/mob_negates_gravity() + return TRUE //no need to calculate if they have gravity. + /mob/dead/new_player/prepare_huds() return diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index b776e3bf4bc43..a4e01f2cd0d6f 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -1,6 +1,6 @@ /mob/living/carbon/slip(knockdown_amount, obj/O, lube, paralyze, force_drop) - if(movement_type & (FLYING|FLOATING)) + if(movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return FALSE if((lube & NO_SLIP_ON_CATWALK) && (locate(/obj/structure/lattice/catwalk) in get_turf(src))) return FALSE @@ -63,9 +63,9 @@ REMOVE_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) -/mob/living/carbon/on_movement_type_flag_disabled(datum/source, flag) +/mob/living/carbon/on_movement_type_flag_disabled(datum/source, flag, old_movement_type) . = ..() - if(flag & (FLYING | FLOATING) && !(movement_type & (FLYING | FLOATING))) + if(old_movement_type & (FLYING | FLOATING) && !(movement_type & (FLYING | FLOATING))) var/limbless_slowdown = 0 if(usable_legs < default_num_legs) limbless_slowdown += (default_num_legs - usable_legs) * 3 diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 12961b8d82daa..d3050b5df6689 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -12,6 +12,11 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) . = ..() remove_from_all_data_huds() + +// We don't want your dummy floating up and down in the preference menu. +/mob/living/carbon/human/dummy/mob_negates_gravity() + return TRUE + /mob/living/carbon/human/dummy/prepare_data_huds() return diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index a4f6a35ff6439..06d5bf93df7b0 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -2391,6 +2391,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(isturf(H.loc)) var/turf/T = H.loc T.Entered(H) + H.refresh_gravity() ///Calls the DMI data for a custom icon for a given bodypart from the Species Datum. /datum/species/proc/get_custom_icons(var/part) diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm index b3608f641cd33..1c1b9752b350b 100644 --- a/code/modules/mob/living/init_signals.dm +++ b/code/modules/mob/living/init_signals.dm @@ -41,6 +41,16 @@ RegisterSignal(src, COMSIG_MOVETYPE_FLAG_ENABLED, PROC_REF(on_movement_type_flag_enabled)) RegisterSignal(src, COMSIG_MOVETYPE_FLAG_DISABLED, PROC_REF(on_movement_type_flag_disabled)) + RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_NEGATES_GRAVITY), SIGNAL_REMOVETRAIT(TRAIT_NEGATES_GRAVITY)), PROC_REF(on_negate_gravity)) + RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_IGNORING_GRAVITY), SIGNAL_REMOVETRAIT(TRAIT_IGNORING_GRAVITY)), PROC_REF(on_ignore_gravity)) + RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_FORCED_GRAVITY), SIGNAL_REMOVETRAIT(TRAIT_FORCED_GRAVITY)), PROC_REF(on_force_gravity)) + // We hook for forced grav changes from our turf and ourselves + var/static/list/loc_connections = list( + SIGNAL_ADDTRAIT(TRAIT_FORCED_GRAVITY) = PROC_REF(on_loc_force_gravity), + SIGNAL_REMOVETRAIT(TRAIT_FORCED_GRAVITY) = PROC_REF(on_loc_force_gravity), + ) + AddElement(/datum/element/connect_loc, loc_connections) + ///Called when TRAIT_KNOCKEDOUT is added to the mob. /mob/living/proc/on_knockedout_trait_gain(datum/source) SIGNAL_HANDLER @@ -63,6 +73,29 @@ SIGNAL_HANDLER REMOVE_TRAIT(src, TRAIT_KNOCKEDOUT, TRAIT_DEATHCOMA) +/// Called when [TRAIT_NEGATES_GRAVITY] is gained or lost +/mob/living/proc/on_negate_gravity(datum/source) + SIGNAL_HANDLER + if(!isgroundlessturf(loc)) + if(HAS_TRAIT(src, TRAIT_NEGATES_GRAVITY)) + ADD_TRAIT(src, TRAIT_IGNORING_GRAVITY, IGNORING_GRAVITY_NEGATION) + else + REMOVE_TRAIT(src, TRAIT_IGNORING_GRAVITY, IGNORING_GRAVITY_NEGATION) + +/// Called when [TRAIT_IGNORING_GRAVITY] is gained or lost +/mob/living/proc/on_ignore_gravity(datum/source) + SIGNAL_HANDLER + refresh_gravity() + +/// Called when [TRAIT_FORCED_GRAVITY] is gained or lost +/mob/living/proc/on_force_gravity(datum/source) + SIGNAL_HANDLER + refresh_gravity() + +/// Called when our loc's [TRAIT_FORCED_GRAVITY] is gained or lost +/mob/living/proc/on_loc_force_gravity(datum/source) + SIGNAL_HANDLER + refresh_gravity() ///Called when TRAIT_IMMOBILIZED is added to the mob. /mob/living/proc/on_immobilized_trait_gain(datum/source) @@ -178,11 +211,11 @@ clear_alert("succumb") ///From [element/movetype_handler/on_movement_type_trait_gain()] -/mob/living/proc/on_movement_type_flag_enabled(datum/source, trait) +/mob/living/proc/on_movement_type_flag_enabled(datum/source, trait, flag, old_movement_type) SIGNAL_HANDLER update_movespeed(FALSE) ///From [element/movetype_handler/on_movement_type_trait_loss()] -/mob/living/proc/on_movement_type_flag_disabled(datum/source, trait) +/mob/living/proc/on_movement_type_flag_disabled(datum/source, trait, flag, old_movement_type) SIGNAL_HANDLER update_movespeed(FALSE) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index b98d460e29a1f..0be85eaa01ca3 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -36,14 +36,7 @@ if(environment) handle_environment(environment) - //Handle gravity - var/gravity = has_gravity() - update_gravity(gravity) - - if(gravity > STANDARD_GRAVITY) - if(!get_filter("gravity")) - add_filter("gravity",1,list("type"="motion_blur", "x"=0, "y"=0)) - handle_high_gravity(gravity) + handle_gravity(delta_time, times_fired) if(stat != DEAD) handle_traits(delta_time) // eye, ear, brain damages @@ -117,9 +110,20 @@ /mob/living/proc/update_damage_hud() return -/mob/living/proc/handle_high_gravity(gravity) - if(gravity >= GRAVITY_DAMAGE_TRESHOLD) //Aka gravity values of 3 or more - var/grav_stregth = gravity - GRAVITY_DAMAGE_TRESHOLD - adjustBruteLoss(min(grav_stregth,3)) +/mob/living/proc/handle_gravity(seconds_per_tick, times_fired) + if(gravity_state > STANDARD_GRAVITY) + handle_high_gravity(gravity_state, seconds_per_tick, times_fired) + +/mob/living/proc/gravity_animate() + if(!get_filter("gravity")) + add_filter("gravity",1,list("type"="motion_blur", "x"=0, "y"=0)) + animate(get_filter("gravity"), y = 1, time = 10, loop = -1) + animate(y = 0, time = 10) + +/mob/living/proc/handle_high_gravity(gravity, seconds_per_tick, times_fired) + if(gravity < GRAVITY_DAMAGE_THRESHOLD) //Aka gravity values of 3 or more + return + var/grav_strength = gravity - GRAVITY_DAMAGE_THRESHOLD + adjustBruteLoss(min(GRAVITY_DAMAGE_SCALING * grav_strength, GRAVITY_DAMAGE_MAXIMUM) * seconds_per_tick) #undef BODYTEMP_DIVISOR diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 58f66906a0bb1..00771145a2264 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -24,6 +24,7 @@ // it prevents 'GLOB.poi_list' being glitched. without this, it will show xeno(or some mobs) twice in orbit panel. //color correction RegisterSignal(src, COMSIG_MOVABLE_ENTERED_AREA, PROC_REF(apply_color_correction)) + gravity_setup() /mob/living/ComponentInitialize() . = ..() @@ -955,25 +956,51 @@ /mob/living/proc/get_visible_name() return name -/mob/living/update_gravity(has_gravity) - . = ..() - if(!SSticker.HasRoundStarted()) - return - var/was_weightless = alerts["gravity"] && istype(alerts["gravity"], /atom/movable/screen/alert/weightless) - if(has_gravity) - if(has_gravity == 1) - clear_alert("gravity") - else - if(has_gravity >= GRAVITY_DAMAGE_TRESHOLD) - throw_alert("gravity", /atom/movable/screen/alert/veryhighgravity) - else - throw_alert("gravity", /atom/movable/screen/alert/highgravity) - if(was_weightless) - REMOVE_TRAIT(src, TRAIT_MOVE_FLOATING, NO_GRAVITY_TRAIT) +/mob/living/proc/update_gravity(gravity) + // Handle movespeed stuff + var/speed_change = max(0, gravity - STANDARD_GRAVITY) + if(speed_change) + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/gravity, multiplicative_slowdown=speed_change) else - throw_alert("gravity", /atom/movable/screen/alert/weightless) - if(!was_weightless) - ADD_TRAIT(src, TRAIT_MOVE_FLOATING, NO_GRAVITY_TRAIT) + remove_movespeed_modifier(/datum/movespeed_modifier/gravity) + + // Time to add/remove gravity alerts. sorry for the mess it's gotta be fast + var/atom/movable/screen/alert/gravity_alert = alerts["gravity"] + switch(gravity) + if(-INFINITY to NEGATIVE_GRAVITY) + if(!istype(gravity_alert, /atom/movable/screen/alert/negative)) + throw_alert("gravity", /atom/movable/screen/alert/negative) + ADD_TRAIT(src, TRAIT_MOVE_UPSIDE_DOWN, NEGATIVE_GRAVITY_TRAIT) + 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, flags = ANIMATION_PARALLEL) + base_pixel_y += 4 + if(NEGATIVE_GRAVITY + 0.01 to 0) + if(!istype(gravity_alert, /atom/movable/screen/alert/weightless)) + throw_alert("gravity", /atom/movable/screen/alert/weightless) + ADD_TRAIT(src, TRAIT_MOVE_FLOATING, NO_GRAVITY_TRAIT) + if(0.01 to STANDARD_GRAVITY) + if(gravity_alert) + clear_alert("gravity") + if(STANDARD_GRAVITY + 0.01 to GRAVITY_DAMAGE_THRESHOLD - 0.01) + throw_alert("gravity", /atom/movable/screen/alert/highgravity) + if(GRAVITY_DAMAGE_THRESHOLD to INFINITY) + throw_alert("gravity", /atom/movable/screen/alert/veryhighgravity) + + // If we had no gravity alert, or the same alert as before, go home + if(!gravity_alert || alerts["gravity"] == gravity_alert) + return + // By this point we know that we do not have the same alert as we used to + if(istype(gravity_alert, /atom/movable/screen/alert/weightless)) + REMOVE_TRAIT(src, TRAIT_MOVE_FLOATING, NO_GRAVITY_TRAIT) + if(istype(gravity_alert, /atom/movable/screen/alert/negative)) + REMOVE_TRAIT(src, TRAIT_MOVE_UPSIDE_DOWN, NEGATIVE_GRAVITY_TRAIT) + 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, flags = ANIMATION_PARALLEL) + base_pixel_y -= 4 // The src mob is trying to strip an item from someone // Override if a certain type of mob should be behave differently when stripping items (can't, for example) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 7e5917bde22ba..c7b849c0c4b69 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -169,3 +169,6 @@ ///The x amount a mob's sprite should be offset due to the current position they're in var/body_position_pixel_y_offset = 0 + /// What our current gravity state is. Used to avoid duplicate animates and such + var/gravity_state = null + diff --git a/code/modules/mob/living/living_movement.dm b/code/modules/mob/living/living_movement.dm index eaf9b84962334..25b8815ef6b45 100644 --- a/code/modules/mob/living/living_movement.dm +++ b/code/modules/mob/living/living_movement.dm @@ -1,8 +1,60 @@ -/mob/living/Moved() +/mob/living/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE) . = ..() update_turf_movespeed(loc) update_looking_move() + if(HAS_TRAIT(src, TRAIT_NEGATES_GRAVITY)) + if(!isgroundlessturf(loc)) + ADD_TRAIT(src, TRAIT_IGNORING_GRAVITY, IGNORING_GRAVITY_NEGATION) + else + REMOVE_TRAIT(src, TRAIT_IGNORING_GRAVITY, IGNORING_GRAVITY_NEGATION) + var/turf/old_turf = get_turf(old_loc) + var/turf/new_turf = get_turf(src) + // If we're moving to/from nullspace, refresh + // Easier then adding nullchecks to all this shit, and technically right since a null turf means nograv + if(isnull(old_turf) || isnull(new_turf)) + if(!QDELING(src)) + refresh_gravity() + return + // If the turf gravity has changed, then it's possible that our state has changed, so update + if(HAS_TRAIT(old_turf, TRAIT_FORCED_GRAVITY) != HAS_TRAIT(new_turf, TRAIT_FORCED_GRAVITY) || new_turf.force_no_gravity != old_turf.force_no_gravity) + refresh_gravity() + + // Going to do area gravity checking here + var/area/old_area = get_area(old_turf) + var/area/new_area = get_area(new_turf) + // If the area gravity has changed, then it's possible that our state has changed, so update + if(old_area.has_gravity != new_area.has_gravity) + refresh_gravity() + +/mob/living/onTransitZ(old_z, new_z, same_z_layer, notify_contents) + . = ..() + + if(!old_z || !new_z || SSmapping.gravity_by_z_level[old_z] != SSmapping.gravity_by_z_level[new_z]) + refresh_gravity() + +/// Living Mob use event based gravity +/// We check here to ensure we haven't dropped any gravity changes +/mob/living/proc/gravity_setup() + on_negate_gravity(src) + refresh_gravity() + +/// Handles gravity effects. Call if something about our gravity has potentially changed! +/mob/living/proc/refresh_gravity() + var/old_grav_state = gravity_state + gravity_state = has_gravity() + if(gravity_state == old_grav_state) + return + + update_gravity(gravity_state) + + if(gravity_state > STANDARD_GRAVITY) + gravity_animate() + else if(old_grav_state > STANDARD_GRAVITY) + remove_filter("gravity") + +/mob/living/mob_negates_gravity() + return HAS_TRAIT_FROM(src, TRAIT_IGNORING_GRAVITY, IGNORING_GRAVITY_NEGATION) /mob/living/CanAllowThrough(atom/movable/mover, border_dir) . = ..() diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 81e5ff91e12a8..aacc8ed8cb00d 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -3,8 +3,6 @@ return //Being dead doesn't mean your temperature never changes - update_gravity(has_gravity()) - handle_status_effects(delta_time) handle_traits(delta_time) diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm b/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm index c9bee4c254854..6ded2491d4a6e 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/mega_arachnid.dm @@ -58,7 +58,7 @@ /obj/projectile/mega_arachnid/on_hit(atom/target, blocked = FALSE) if(iscarbon(target) && blocked < 100) var/obj/item/restraints/legcuffs/beartrap/mega_arachnid/B = new /obj/item/restraints/legcuffs/beartrap/mega_arachnid(get_turf(target)) - B.spring_trap(null, target) + B.spring_trap(target) return ..() /obj/item/restraints/legcuffs/beartrap/mega_arachnid diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index b089c1bde7df3..289f149f9561e 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -354,6 +354,9 @@ continue return rebound +/mob/has_gravity(turf/gravity_turf) + return mob_negates_gravity() || ..() + /** * Does this mob ignore gravity */ @@ -372,14 +375,6 @@ /mob/proc/slip(knockdown, paralyze, forcedrop, w_amount, obj/O, lube) return -/// Update the gravity status of this mob -/mob/proc/update_gravity(has_gravity, override=FALSE) - var/speed_change = max(0, has_gravity - STANDARD_GRAVITY) - if(!speed_change) - remove_movespeed_modifier(/datum/movespeed_modifier/gravity) - else - add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/gravity, multiplicative_slowdown=speed_change) - //bodypart selection verbs - Cyberboss //8:repeated presses toggles through head - eyes - mouth //4: r-arm 5: chest 6: l-arm diff --git a/code/modules/movespeed/modifiers/mobs.dm b/code/modules/movespeed/modifiers/mobs.dm index 7a4e3ba20d20b..c6f604069e801 100644 --- a/code/modules/movespeed/modifiers/mobs.dm +++ b/code/modules/movespeed/modifiers/mobs.dm @@ -83,6 +83,7 @@ /datum/movespeed_modifier/limbless variable = TRUE movetypes = GROUND + blacklisted_movetypes = FLOATING|FLYING flags = IGNORE_NOSLOW /datum/movespeed_modifier/simplemob_varspeed diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 4f91bdd2f00c7..1106020078cd1 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -187,6 +187,20 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne // Interaction +/obj/machinery/gravity_generator/main/examine(mob/user) + . = ..() + if(!(machine_stat & BROKEN)) + return + switch(broken_state) + if(GRAV_NEEDS_SCREWDRIVER) + . += "The entire frame is barely holding together, the screws need to be refastened." + if(GRAV_NEEDS_WELDING) + . += "There's lots of broken seals on the framework, it could use some welding." + if(GRAV_NEEDS_PLASTEEL) + . += "Some of this damaged plating needs full replacement. 10 plasteel should be enough." + if(GRAV_NEEDS_WRENCH) + . += "The new plating just needs to be bolted into place now." + // Fixing the gravity generator. /obj/machinery/gravity_generator/main/attackby(obj/item/I, mob/user, params) switch(broken_state) @@ -365,11 +379,13 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne /obj/machinery/gravity_generator/main/proc/shake_everyone() var/turf/T = get_turf(src) var/sound/alert_sound = sound('sound/effects/alert.ogg') - for(var/i in GLOB.mob_list) - var/mob/M = i + for(var/mobs in GLOB.mob_list) + var/mob/M = mobs if(M.get_virtual_z_level() != get_virtual_z_level() && !(ztrait && SSmapping.level_trait(z, ztrait) && SSmapping.level_trait(M.z, ztrait))) continue - M.update_gravity(M.has_gravity()) + if(isliving(M)) + var/mob/living/grav_update = M + grav_update.refresh_gravity() if(M.client) shake_camera(M, 15, 1) M.playsound_local(T, null, 100, 1, 0.5, S = alert_sound) @@ -399,6 +415,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne GLOB.gravity_generators["[theZ]"] |= src else GLOB.gravity_generators["[theZ]"] -= src + SSmapping.calculate_z_level_gravity(z) /obj/machinery/gravity_generator/main/proc/change_setting(value) if(value != setting) diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm index 04e496aa21786..5a3bdb9df2b5a 100644 --- a/code/modules/projectiles/projectile/energy/net_snare.dm +++ b/code/modules/projectiles/projectile/energy/net_snare.dm @@ -83,7 +83,7 @@ new/obj/item/restraints/legcuffs/beartrap/energy(get_turf(loc)) else if(iscarbon(target)) var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy(get_turf(target)) - B.spring_trap(null, target) + B.spring_trap(target) . = ..() /obj/projectile/energy/trap/on_range() @@ -104,7 +104,7 @@ qdel(src) if(iscarbon(target)) var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy/cyborg(get_turf(target)) - B.spring_trap(null, target) + B.spring_trap(target) QDEL_IN(src, 10) . = ..() diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 0b6df82332fec..b9c133c5fbdb3 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -61,8 +61,8 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/docking_port) else return QDEL_HINT_LETMELIVE -/obj/docking_port/has_gravity(turf/T) - return FALSE +/obj/docking_port/has_gravity(turf/current_turf) + return TRUE /obj/docking_port/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir, armour_penetration = 0) return diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi index dc9f39b99ec45..13d032eeee32e 100644 Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ