From 36def0fc7e15fcb6315ffa39858950ad51b334aa Mon Sep 17 00:00:00 2001 From: Sun-Soaked <45698967+Sun-Soaked@users.noreply.github.com> Date: Sun, 26 May 2024 23:48:15 -0400 Subject: [PATCH] Movable Physics Subsystem (#2880) Ports some mojave code (originally written on Daedalus by Spyroshark) hat allows you to fling ingame objects with a simple, bouncing physics quality. This is currently implemented on bullet casings. Technical issues currently: - [x] Makes the bouncing less dramatic - [x] Physics must have a "low grav" version for tiles without gravity, since mojave didn't think gravity was real - [x] The code handling the angle physics objects travel at is fucky and needs to be fixed up the hit feature from 2003, coming to a shiptest near you :cl: Spyroshark, Sun-Soaked add: A movable physics subsystem, deployed using a component. add: Bullet casings now drop using movable physics code: ports NO_PIXEL_RANDOM_DROP from TG. /:cl: --------- Co-authored-by: Sun-Soaked <45698967+MemedHams@users.noreply.github.com> --- code/__DEFINES/obj_flags.dm | 1 + code/__DEFINES/subsystems.dm | 1 + code/_globalvars/bitfields.dm | 1 + .../subsystem/processing/movable_physics.dm | 24 +++ code/datums/components/movable_physics.dm | 151 ++++++++++++++++++ code/game/objects/items.dm | 2 +- code/game/objects/items/devices/powersink.dm | 1 + code/modules/mob/inventory.dm | 2 +- .../projectiles/ammunition/_ammunition.dm | 10 +- .../ammunition/caseless/_caseless.dm | 2 +- code/modules/projectiles/gun.dm | 6 +- code/modules/projectiles/guns/ballistic.dm | 13 +- .../projectiles/guns/ballistic/revolver.dm | 11 +- .../projectiles/guns/ballistic/rifle.dm | 4 +- .../projectiles/guns/ballistic/shotgun.dm | 4 +- .../modules/projectiles/guns/ballistic/toy.dm | 4 +- code/modules/projectiles/guns/energy.dm | 2 +- .../projectiles/guns/energy/special.dm | 2 +- code/modules/projectiles/guns/magic.dm | 2 +- .../modules/projectiles/guns/misc/chem_gun.dm | 2 +- .../projectiles/guns/misc/syringe_gun.dm | 2 +- shiptest.dme | 2 + 22 files changed, 222 insertions(+), 27 deletions(-) create mode 100644 code/controllers/subsystem/processing/movable_physics.dm create mode 100644 code/datums/components/movable_physics.dm diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 865470774039..d9ca63008c1d 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -33,6 +33,7 @@ #define IN_STORAGE (1<<11) //is this item in the storage item, such as backpack? used for tooltips #define SURGICAL_TOOL (1<<12) //Tool commonly used for surgery: won't attack targets in an active surgical operation on help intent (in case of mistakes) #define EYE_STAB (1<<13) /// Item can be used to eyestab +#define NO_PIXEL_RANDOM_DROP (1<<14) //if dropped, it wont have a randomized pixel_x/pixel_y // Flags for the clothing_flags var on /obj/item/clothing diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 629755487849..36aa57e48625 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -174,6 +174,7 @@ #define FIRE_PRIORITY_PARALLAX 65 #define FIRE_PRIORITY_INSTRUMENTS 80 #define FIRE_PRIORITY_MOBS 100 +#define FIRE_PRIORITY_MOVABLE_PHYSICS 105 #define FIRE_PRIORITY_TGUI 110 #define FIRE_PRIORITY_TICKER 200 #define FIRE_PRIORITY_ATMOS_ADJACENCY 300 diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index ca2520fc1b23..be5713d4ad0c 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -152,6 +152,7 @@ DEFINE_BITFIELD(item_flags, list( "NOBLUDGEON" = NOBLUDGEON, "NO_MAT_REDEMPTION" = NO_MAT_REDEMPTION, "SLOWS_WHILE_IN_HAND" = SLOWS_WHILE_IN_HAND, + "NO_PIXEL_RANDOM_DROP" = NO_PIXEL_RANDOM_DROP, )) DEFINE_BITFIELD(machine_stat, list( diff --git a/code/controllers/subsystem/processing/movable_physics.dm b/code/controllers/subsystem/processing/movable_physics.dm new file mode 100644 index 000000000000..65015edbd668 --- /dev/null +++ b/code/controllers/subsystem/processing/movable_physics.dm @@ -0,0 +1,24 @@ +///Real fast ticking subsystem for moving movables via modifying pixel_x/y/z +PROCESSING_SUBSYSTEM_DEF(movablephysics) + name = "Movable Physics" + wait = 0.05 SECONDS + stat_tag = "MP" + priority = FIRE_PRIORITY_MOVABLE_PHYSICS + +/datum/controller/subsystem/processing/movablephysics/fire(resumed = FALSE) + if (!resumed) + currentrun = processing.Copy() + //cache for sanic speed (lists are references anyways) + var/list/current_run = currentrun + + while(current_run.len) + var/datum/component/thing = current_run[current_run.len] + current_run.len-- + if(QDELETED(thing)) + processing -= thing + else + if(thing.process(wait * 0.1) == PROCESS_KILL) + // fully stop so that a future START_PROCESSING will work + STOP_PROCESSING(src, thing) + if (MC_TICK_CHECK) + return diff --git a/code/datums/components/movable_physics.dm b/code/datums/components/movable_physics.dm new file mode 100644 index 000000000000..55686bb1e259 --- /dev/null +++ b/code/datums/components/movable_physics.dm @@ -0,0 +1,151 @@ +#define PHYSICS_GRAV_STANDARD 9.80665 + +///Remove the component as soon as there's zero velocity, useful for movables that will no longer move after being initially moved (blood splatters) +#define QDEL_WHEN_NO_MOVEMENT (1<<0) + +///Stores information related to the movable's physics and keeping track of relevant signals to trigger movement +/datum/component/movable_physics + ///Modifies the pixel_x/pixel_y of an object every process() + var/horizontal_velocity + ///Modifies the pixel_z of an object every process(), movables aren't Move()'d into another turf if pixel_z exceeds 16, so try not to supply a super high vertical value if you don't want the movable to clip through multiple turfs + var/vertical_velocity + ///The horizontal_velocity is reduced by this every process(), this doesn't take into account the object being in the air vs gravity pushing it against the ground + var/horizontal_friction + ///The vertical_velocity is reduced by this every process() + var/z_gravity + ///The pixel_z that the object will no longer be influenced by gravity for a 32x32 turf, keep this value between -16 to 0 so it's visuals matches up with it physically being in the turf + var/z_floor + ///The angle of the path the object takes on the x/y plane + var/angle_of_movement + ///Flags for turning on certain physic properties, see the top of the file for more information on flags + var/physic_flags + ///The cached animate_movement of the parent; any kind of gliding when doing Move() makes the physics look derpy, so we'll just make Move() be instant + var/cached_animate_movement + ///The sound effect to play when bouncing off of something + var/bounce_sound + + var/numbounce = 1 + +/datum/component/movable_physics/Initialize(_horizontal_velocity = 0, _vertical_velocity = 0, _horizontal_friction = 0, _z_gravity = 0, _z_floor = 0, _angle_of_movement = 0, _physic_flags = 0, _bounce_sound) + . = ..() + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + RegisterSignal(parent, COMSIG_MOVABLE_IMPACT, PROC_REF(throw_impact_ricochet), override = TRUE) + horizontal_velocity = _horizontal_velocity + vertical_velocity = _vertical_velocity + horizontal_friction = _horizontal_friction + z_gravity = _z_gravity + z_floor = _z_floor + angle_of_movement = _angle_of_movement + physic_flags = _physic_flags + bounce_sound = _bounce_sound + if(vertical_velocity || horizontal_velocity) + start_movement() + +///Let's get moving +/datum/component/movable_physics/proc/start_movement() + var/atom/movable/moving_atom = parent + cached_animate_movement = moving_atom.animate_movement + moving_atom.animate_movement = NO_STEPS + START_PROCESSING(SSmovablephysics, src) + moving_atom.SpinAnimation(speed = 1 SECONDS, loops = 1) + +///Alright it's time to stop +/datum/component/movable_physics/proc/stop_movement() + var/atom/movable/moving_atom = parent + moving_atom.animate_movement = cached_animate_movement + STOP_PROCESSING(SSmovablephysics, src) + if(physic_flags & QDEL_WHEN_NO_MOVEMENT) + qdel(src) + +/datum/component/movable_physics/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_MOVABLE_IMPACT) + +/datum/component/movable_physics/proc/throw_impact_ricochet(datum/source, atom/hit_atom, datum/thrownthing/throwingdatum) + SIGNAL_HANDLER + var/atom/movable/atom_source = source + ricochet(atom_source, Get_Angle(atom_source, throwingdatum.target_turf)) + +/datum/component/movable_physics/proc/z_floor_bounce(atom/movable/moving_atom) + angle_of_movement += rand(-3000, 3000) / 100 + var/turf/a_turf = get_turf(moving_atom) + if(istype(moving_atom, /obj/item/ammo_casing)) + playsound(moving_atom, a_turf.bullet_bounce_sound, 50, TRUE) + else + playsound(moving_atom, bounce_sound, 50, TRUE) + moving_atom.SpinAnimation(speed = 1 SECONDS / numbounce, loops = 1) + moving_atom.pixel_z = z_floor + horizontal_velocity = max(0, horizontal_velocity + (vertical_velocity * -0.8)) + vertical_velocity = max(0, ((vertical_velocity * -0.8) - 0.2)) + numbounce += 0.5 + +/datum/component/movable_physics/proc/ricochet(atom/movable/moving_atom, bounce_angle) + angle_of_movement = ((180 - bounce_angle) - angle_of_movement) + if(angle_of_movement < 0) + angle_of_movement += 360 + //var/turf/a_turf = get_turf(moving_atom) + //playsound(src, a_turf.bullet_bounce_sound, 50, TRUE) + +/datum/component/movable_physics/proc/fix_angle(angle, atom/moving_atom)//fixes an angle below 0 or above 360 + if(!(angle_of_movement > 360) && !(angle_of_movement < 0)) + return angle //early return if it doesn't need to change + var/new_angle + if(angle_of_movement > 360) + new_angle = angle_of_movement - 360 + if(angle_of_movement < 0) + new_angle = angle_of_movement + 360 + return new_angle + +/datum/component/movable_physics/process(delta_time) + var/atom/movable/moving_atom = parent + var/turf/location = get_turf(moving_atom) + + angle_of_movement = fix_angle(angle_of_movement, moving_atom) + if(horizontal_velocity <= 0 && moving_atom.pixel_z == 0) + horizontal_velocity = 0 + stop_movement() + return + + moving_atom.pixel_x += (horizontal_velocity * (sin(angle_of_movement))) + moving_atom.pixel_y += (horizontal_velocity * (cos(angle_of_movement))) + + horizontal_velocity = max(0, horizontal_velocity - horizontal_friction) + + moving_atom.pixel_z = max(z_floor, moving_atom.pixel_z + vertical_velocity) + if(moving_atom.pixel_z > z_floor) + vertical_velocity -= (z_gravity * 0.05) + + if(moving_atom.pixel_z <= z_floor && (vertical_velocity != 0) && moving_atom.has_gravity(location)) //z bounce + z_floor_bounce(moving_atom) + + if(moving_atom.pixel_x > 16) + if(moving_atom.Move(get_step(moving_atom, EAST))) + moving_atom.pixel_x = -16 + else + moving_atom.pixel_x = 16 + ricochet(moving_atom, 0) + return + + if(moving_atom.pixel_x < -16) + if(moving_atom.Move(get_step(moving_atom, WEST))) + moving_atom.pixel_x = 16 + else + moving_atom.pixel_x = -16 + ricochet(moving_atom, 0) + return + + if(moving_atom.pixel_y > 16) + if(moving_atom.Move(get_step(moving_atom, NORTH))) + moving_atom.pixel_y = -16 + else + moving_atom.pixel_y = 16 + ricochet(moving_atom, 180) + return + + if(moving_atom.pixel_y < -16) + if(moving_atom.Move(get_step(moving_atom, SOUTH))) + moving_atom.pixel_y = 16 + else + moving_atom.pixel_y = -16 + ricochet(moving_atom, 180) + diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 00943573a12e..75cc7c0556fb 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -694,7 +694,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb if (callback) //call the original callback . = callback.Invoke() item_flags &= ~IN_INVENTORY - if(!pixel_y && !pixel_x) + if(!pixel_y && !pixel_x && !(item_flags & NO_PIXEL_RANDOM_DROP)) pixel_x = rand(-8,8) pixel_y = rand(-8,8) diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 3a6ba2f73950..5b69cab9cc7b 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -10,6 +10,7 @@ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi' w_class = WEIGHT_CLASS_BULKY flags_1 = CONDUCT_1 + item_flags = NO_PIXEL_RANDOM_DROP throwforce = 5 throw_speed = 1 throw_range = 2 diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index de07b3d4f0fd..0d9dab7a035f 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -275,7 +275,7 @@ */ /mob/proc/dropItemToGround(obj/item/I, force = FALSE, silent = FALSE) . = doUnEquip(I, force, drop_location(), FALSE, silent = silent) - if(. && I) //ensure the item exists and that it was dropped properly. + if(. && I && !(I.item_flags & NO_PIXEL_RANDOM_DROP)) //ensure the item exists and that it was dropped properly. I.pixel_x = rand(-6,6) I.pixel_y = rand(-6,6) diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm index 5120bf761f9e..c9697aa4e80f 100644 --- a/code/modules/projectiles/ammunition/_ammunition.dm +++ b/code/modules/projectiles/ammunition/_ammunition.dm @@ -51,6 +51,7 @@ BB = new projectile_type(src) pixel_x = base_pixel_x + rand(-10, 10) pixel_y = base_pixel_y + rand(-10, 10) + item_flags |= NO_PIXEL_RANDOM_DROP if(auto_rotate) transform = transform.Turn(pick(0, 90, 180, 270)) update_appearance() @@ -107,9 +108,14 @@ bounce_away(FALSE, NONE) . = ..() -/obj/item/ammo_casing/proc/on_eject() +/obj/item/ammo_casing/proc/on_eject(atom/shooter) forceMove(drop_location()) //Eject casing onto ground. - bounce_away(TRUE) + pixel_x = rand(-4, 4) + pixel_y = rand(-4, 4) + pixel_z = 8 //bounce time + var/angle_of_movement = !isnull(shooter) ? (rand(-3000, 3000) / 100) + dir2angle(turn(shooter.dir, 180)) : rand(-3000, 3000) / 100 + AddComponent(/datum/component/movable_physics, _horizontal_velocity = rand(400, 450) / 100, _vertical_velocity = rand(400, 450) / 100, _horizontal_friction = rand(20, 24) / 100, _z_gravity = PHYSICS_GRAV_STANDARD, _z_floor = 0, _angle_of_movement = angle_of_movement) + /obj/item/ammo_casing/proc/bounce_away(still_warm = FALSE, bounce_delay = 3) if(!heavy_metal) diff --git a/code/modules/projectiles/ammunition/caseless/_caseless.dm b/code/modules/projectiles/ammunition/caseless/_caseless.dm index 78525277f28c..230f5f9a9969 100644 --- a/code/modules/projectiles/ammunition/caseless/_caseless.dm +++ b/code/modules/projectiles/ammunition/caseless/_caseless.dm @@ -3,7 +3,7 @@ firing_effect_type = null heavy_metal = FALSE -/obj/item/ammo_casing/caseless/on_eject() +/obj/item/ammo_casing/caseless/on_eject(atom/shooter) // [CELADON-EDIT] - CELADON_FIXES // qdel(src) // CELADON-EDIT - ORIGINAL if(BB) // Проверяем, что гильза не пустая diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 5cd55858537a..ca4d0217b380 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -209,7 +209,7 @@ zoom(user, user.dir, FALSE) //we can only stay zoomed in if it's in our hands //yeah and we only unzoom if we're actually zoomed using the gun!! //called after the gun has successfully fired its chambered ammo. -/obj/item/gun/proc/process_chamber() +/obj/item/gun/proc/process_chamber(atom/shooter) SEND_SIGNAL(src, COMSIG_GUN_CHAMBER_PROCESSED) return FALSE @@ -357,7 +357,7 @@ shoot_with_empty_chamber(user) firing_burst = FALSE return FALSE - process_chamber() + process_chamber(shooter = user) update_appearance() return TRUE @@ -408,7 +408,7 @@ else shoot_with_empty_chamber(user) return - process_chamber() + process_chamber(shooter = user) update_appearance() if(fire_delay) semicd = TRUE diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 227abceffa01..4f3b80bf478a 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -144,13 +144,13 @@ if(!chambered && empty_indicator) . += "[icon_state]_empty" -/obj/item/gun/ballistic/process_chamber(empty_chamber = TRUE, from_firing = TRUE, chamber_next_round = TRUE) +/obj/item/gun/ballistic/process_chamber(empty_chamber = TRUE, from_firing = TRUE, chamber_next_round = TRUE, atom/shooter) if(!semi_auto && from_firing) return var/obj/item/ammo_casing/casing = chambered //Find chambered round if(istype(casing)) //there's a chambered round if(casing_ejector || !from_firing) - casing.on_eject() + casing.on_eject(shooter) chambered = null else if(empty_chamber) chambered = null @@ -179,7 +179,7 @@ bolt_locked = FALSE if (user) to_chat(user, "You rack the [bolt_wording] of \the [src].") - process_chamber(!chambered, FALSE) + process_chamber(!chambered, FALSE, shooter = user) if (bolt_type == BOLT_TYPE_LOCKING && !chambered) bolt_locked = TRUE playsound(src, lock_back_sound, lock_back_sound_volume, lock_back_sound_vary) @@ -267,7 +267,7 @@ if (istype(A, /obj/item/ammo_casing) || istype(A, /obj/item/ammo_box)) if (bolt_type == BOLT_TYPE_NO_BOLT || internal_magazine) if (chambered && !chambered.BB) - chambered.on_eject() + chambered.on_eject(shooter = user) chambered = null var/num_loaded = magazine.attackby(A, user, params) if (num_loaded) @@ -364,7 +364,10 @@ var/num_unloaded = 0 for(var/obj/item/ammo_casing/CB in get_ammo_list(FALSE, TRUE)) CB.forceMove(drop_location()) - CB.bounce_away(FALSE, NONE) + + var/angle_of_movement =(rand(-3000, 3000) / 100) + dir2angle(turn(user.dir, 180)) + CB.AddComponent(/datum/component/movable_physics, _horizontal_velocity = rand(350, 450) / 100, _vertical_velocity = rand(400, 450) / 100, _horizontal_friction = rand(20, 24) / 100, _z_gravity = PHYSICS_GRAV_STANDARD, _z_floor = 0, _angle_of_movement = angle_of_movement) + num_unloaded++ SSblackbox.record_feedback("tally", "station_mess_created", 1, CB.name) if (num_unloaded) diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index b08e156927fa..4f76267752a1 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -57,7 +57,7 @@ . += "[base_icon_state || initial(icon_state)][safety ? "_hammer_up" : "_hammer_down"]" -/obj/item/gun/ballistic/revolver/process_chamber(empty_chamber = TRUE, from_firing = TRUE, chamber_next_round = TRUE) +/obj/item/gun/ballistic/revolver/process_chamber(empty_chamber = TRUE, from_firing = TRUE, chamber_next_round = TRUE, atom/shooter) SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD) return ..() @@ -84,7 +84,9 @@ if(!casing_to_eject) continue casing_to_eject.forceMove(drop_location()) - casing_to_eject.bounce_away(FALSE, NONE) + var/angle_of_movement =(rand(-3000, 3000) / 100) + dir2angle(turn(user.dir, 180)) + casing_to_eject.AddComponent(/datum/component/movable_physics, _horizontal_velocity = rand(450, 550) / 100, _vertical_velocity = rand(400, 450) / 100, _horizontal_friction = rand(20, 24) / 100, _z_gravity = PHYSICS_GRAV_STANDARD, _z_floor = 0, _angle_of_movement = angle_of_movement) + num_unloaded++ SSblackbox.record_feedback("tally", "station_mess_created", 1, casing_to_eject.name) chamber_round(FALSE) @@ -120,8 +122,9 @@ to_chat(user, "There's nothing in the gate to eject from [src]!") return FALSE playsound(src, eject_sound, eject_sound_volume, eject_sound_vary) - casing_to_eject.forceMove(drop_location()) - casing_to_eject.bounce_away(FALSE, NONE) + var/angle_of_movement =(rand(-3000, 3000) / 100) + dir2angle(turn(user.dir, 180)) + casing_to_eject.AddComponent(/datum/component/movable_physics, _horizontal_velocity = rand(350, 450) / 100, _vertical_velocity = rand(400, 450) / 100, _horizontal_friction = rand(20, 24) / 100, _z_gravity = PHYSICS_GRAV_STANDARD, _z_floor = 0, _angle_of_movement = angle_of_movement) + SSblackbox.record_feedback("tally", "station_mess_created", 1, casing_to_eject.name) if(!gate_loaded) magazine.stored_ammo[casing_index] = null diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm index 1632e175fd8e..24cf3323048a 100644 --- a/code/modules/projectiles/guns/ballistic/rifle.dm +++ b/code/modules/projectiles/guns/ballistic/rifle.dm @@ -33,11 +33,11 @@ . = ..() . += "[icon_state]_bolt[bolt_locked ? "_locked" : ""]" -/obj/item/gun/ballistic/rifle/rack(mob/user = null) +/obj/item/gun/ballistic/rifle/rack(mob/living/user) if (bolt_locked == FALSE) to_chat(user, "You open the bolt of \the [src].") playsound(src, rack_sound, rack_sound_volume, rack_sound_vary) - process_chamber(FALSE, FALSE, FALSE) + process_chamber(FALSE, FALSE, FALSE, shooter = user) bolt_locked = TRUE update_appearance() if (magazine && !magazine?.ammo_count() && empty_autoeject && !internal_magazine) diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 0b7e526c8a2b..4502f7fe9b2c 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -303,7 +303,9 @@ var/num_unloaded = 0 for(var/obj/item/ammo_casing/casing_bullet in get_ammo_list(FALSE, TRUE)) casing_bullet.forceMove(drop_location()) - casing_bullet.bounce_away(FALSE, NONE) + var/angle_of_movement =(rand(-3000, 3000) / 100) + dir2angle(turn(user.dir, 180)) + casing_bullet.AddComponent(/datum/component/movable_physics, _horizontal_velocity = rand(450, 550) / 100, _vertical_velocity = rand(400, 450) / 100, _horizontal_friction = rand(20, 24) / 100, _z_gravity = PHYSICS_GRAV_STANDARD, _z_floor = 0, _angle_of_movement = angle_of_movement) + num_unloaded++ SSblackbox.record_feedback("tally", "station_mess_created", 1, casing_bullet.name) if (num_unloaded) diff --git a/code/modules/projectiles/guns/ballistic/toy.dm b/code/modules/projectiles/guns/ballistic/toy.dm index 95911c9269bc..5f62b8c7ca78 100644 --- a/code/modules/projectiles/guns/ballistic/toy.dm +++ b/code/modules/projectiles/guns/ballistic/toy.dm @@ -59,8 +59,8 @@ . = ..() . += "[icon_state]_toy" -/obj/item/gun/ballistic/shotgun/toy/process_chamber(empty_chamber = 0) - ..() +/obj/item/gun/ballistic/shotgun/toy/process_chamber(empty_chamber = 0, from_firing = TRUE, chamber_next_round = TRUE, atom/shooter) + . = ..() if(chambered && !chambered.BB) qdel(chambered) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index a6e424901d5e..705789b3484a 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -204,7 +204,7 @@ if(!chambered.BB) chambered.newshot() -/obj/item/gun/energy/process_chamber() +/obj/item/gun/energy/process_chamber(atom/shooter) if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired... var/obj/item/ammo_casing/energy/shot = chambered cell.use(shot.e_cost)//... drain the cell cell diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 27b7b65b622d..d84655fb5813 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -221,7 +221,7 @@ if(istype(WH)) WH.gun = WEAKREF(src) -/obj/item/gun/energy/wormhole_projector/process_chamber() +/obj/item/gun/energy/wormhole_projector/process_chamber(atom/shooter) ..() select_fire() diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm index 9360c24be499..1f8be937b645 100644 --- a/code/modules/projectiles/guns/magic.dm +++ b/code/modules/projectiles/guns/magic.dm @@ -41,7 +41,7 @@ if (charges && chambered && !chambered.BB) chambered.newshot() -/obj/item/gun/magic/process_chamber() +/obj/item/gun/magic/process_chamber(atom/shooter) if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired... charges--//... drain a charge recharge_newshot() diff --git a/code/modules/projectiles/guns/misc/chem_gun.dm b/code/modules/projectiles/guns/misc/chem_gun.dm index fef47121af5f..7c99b7156000 100644 --- a/code/modules/projectiles/guns/misc/chem_gun.dm +++ b/code/modules/projectiles/guns/misc/chem_gun.dm @@ -29,7 +29,7 @@ /obj/item/gun/chem/can_shoot() return syringes_left -/obj/item/gun/chem/process_chamber() +/obj/item/gun/chem/process_chamber(atom/shooter) if(chambered && !chambered.BB && syringes_left) chambered.newshot() diff --git a/code/modules/projectiles/guns/misc/syringe_gun.dm b/code/modules/projectiles/guns/misc/syringe_gun.dm index 96927eb91afc..84d00b226371 100644 --- a/code/modules/projectiles/guns/misc/syringe_gun.dm +++ b/code/modules/projectiles/guns/misc/syringe_gun.dm @@ -29,7 +29,7 @@ /obj/item/gun/syringe/can_shoot() return syringes.len -/obj/item/gun/syringe/process_chamber() +/obj/item/gun/syringe/process_chamber(atom/shooter) if(chambered && !chambered.BB) //we just fired recharge_newshot() diff --git a/shiptest.dme b/shiptest.dme index 80206e3f3c61..9f044e024f08 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -378,6 +378,7 @@ #include "code\controllers\subsystem\processing\fastprocess.dm" #include "code\controllers\subsystem\processing\fluids.dm" #include "code\controllers\subsystem\processing\instruments.dm" +#include "code\controllers\subsystem\processing\movable_physics.dm" #include "code\controllers\subsystem\processing\nanites.dm" #include "code\controllers\subsystem\processing\networks.dm" #include "code\controllers\subsystem\processing\obj.dm" @@ -502,6 +503,7 @@ #include "code\datums\components\material_container.dm" #include "code\datums\components\mirv.dm" #include "code\datums\components\mood.dm" +#include "code\datums\components\movable_physics.dm" #include "code\datums\components\nanites.dm" #include "code\datums\components\ntnet_interface.dm" #include "code\datums\components\orbiter.dm"