Skip to content

Commit

Permalink
Ports Dramatic Shuttles (#8883)
Browse files Browse the repository at this point in the history
* Ports shuttle clinging and hyperspace drifting

* removes something that doesn't seem to work

* allows a few things to move freely in hyperspace

* fixes conflict

* should work

---------

Co-authored-by: EvilDragonfiend <[email protected]>
  • Loading branch information
AgentCitrus and EvilDragonfiend authored Sep 19, 2023
1 parent aa1bfb7 commit dc91339
Show file tree
Hide file tree
Showing 17 changed files with 255 additions and 29 deletions.
2 changes: 2 additions & 0 deletions beestation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@
#include "code\controllers\subsystem\zclear.dm"
#include "code\controllers\subsystem\zcopy.dm"
#include "code\controllers\subsystem\movement\ai_movement.dm"
#include "code\controllers\subsystem\movement\hyperspace_drift.dm"
#include "code\controllers\subsystem\movement\conveyors.dm"
#include "code\controllers\subsystem\movement\move_handler.dm"
#include "code\controllers\subsystem\movement\movement.dm"
Expand Down Expand Up @@ -634,6 +635,7 @@
#include "code\datums\components\rotation.dm"
#include "code\datums\components\shell.dm"
#include "code\datums\components\shielded.dm"
#include "code\datums\components\shuttle_cling.dm"
#include "code\datums\components\singularity.dm"
#include "code\datums\components\sizzle.dm"
#include "code\datums\components\slippery.dm"
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/signals_movable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone" //! from base of mob/living/hitby(): (mob/living/target, hit_zone)
#define COMSIG_MOVABLE_BUCKLE "buckle" //! from base of atom/movable/buckle_mob(): (mob, force)
#define COMSIG_MOVABLE_UNBUCKLE "unbuckle" //! from base of atom/movable/unbuckle_mob(): (mob, force)
#define COMSIG_MOVABLE_PULLED "movable_pulled" //! signal sent out by an atom when it is being pulled by something else : (atom/puller)
#define COMSIG_MOVABLE_NO_LONGER_PULLED "movable_no_longer_pulled" //! signal sent out by an atom when it is no longer being pulled by something else : (atom/puller)
#define COMSIG_MOVABLE_PRE_THROW "movable_pre_throw" //! from base of atom/movable/throw_at(): (list/args)
#define COMPONENT_CANCEL_THROW 1
#define COMSIG_MOVABLE_POST_THROW "movable_post_throw" //! from base of atom/movable/throw_at(): (datum/thrownthing, spin)
Expand Down
1 change: 1 addition & 0 deletions code/__DEFINES/dcs/signals/signals_turf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
#define COMSIG_TURF_HAS_GRAVITY "turf_has_gravity" //! from base of atom/has_gravity(): (atom/asker, list/forced_gravities)
#define COMSIG_TURF_MULTIZ_NEW "turf_multiz_new" //! from base of turf/New(): (turf/source, direction)
#define COMSIG_TURF_AFTER_SHUTTLE_MOVE "turf_after_shuttle_move" //! from base of turf/proc/afterShuttleMove: (turf/new_turf)
#define COMSIG_TURF_RESERVATION_RELEASED "turf_reservation_released"//! from base of /datum/turf_reservation/proc/Release: (datum/turf_reservation/reservation)
2 changes: 2 additions & 0 deletions code/__DEFINES/movement.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#define MOVEMENT_LOOP_START_FAST (1<<0)
///Do we not use the priority system?
#define MOVEMENT_LOOP_IGNORE_PRIORITY (1<<1)
///Should we not update our movables dir on move?
#define MOVEMENT_LOOP_NO_DIR_UPDATE (1<<3)

//Index defines for movement bucket data packets
#define MOVEMENT_BUCKET_TIME 1
Expand Down
2 changes: 1 addition & 1 deletion code/__DEFINES/shuttles.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#define TRANSIT_REQUEST 1
#define TRANSIT_READY 2

#define SHUTTLE_TRANSIT_BORDER 8
#define SHUTTLE_TRANSIT_BORDER 16

#define PARALLAX_LOOP_TIME 25
#define HYPERSPACE_END_TIME 5
Expand Down
1 change: 1 addition & 0 deletions code/__DEFINES/subsystems.dm
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
#define FIRE_PRIORITY_WET_FLOORS 20
#define FIRE_PRIORITY_AIR 20
#define FIRE_PRIORITY_NPC 20
#define FIRE_PRIORITY_HYPERSPACE_DRIFT 20
#define FIRE_PRIORITY_NPC_MOVEMENT 21
#define FIRE_PRIORITY_NPC_ACTIONS 22
#define FIRE_PRIORITY_PROCESS 25
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_MOTH_BURNT "moth_burnt"
#define TRAIT_SPECIAL_TRAUMA_BOOST "special_trauma_boost" ///Increases chance of getting special traumas, makes them harder to cure
#define TRAIT_METALANGUAGE_KEY_ALLOWED "metalanguage_key_allowed" // you can use language key for metalanguage (,`) and but also you see lang icon
#define TRAIT_HYPERSPACED "hyperspaced" // Sanity trait to keep track of when we're in hyperspace and add the appropriate element if we werent
#define TRAIT_FREE_HYPERSPACE_MOVEMENT "free_hyperspace_movement" // Gives the movable free hyperspace movement without being pulled during shuttle transit

// You can stare into the abyss, but it does not stare back.
// You're immune to the hallucination effect of the supermatter, either
Expand Down
6 changes: 6 additions & 0 deletions code/controllers/subsystem/movement/hyperspace_drift.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//This subsystem handles the hyperspace shuttle pull movement loops
MOVEMENT_SUBSYSTEM_DEF(hyperspace_drift)
name = "Hyperspace Drift"
priority = FIRE_PRIORITY_HYPERSPACE_DRIFT
flags = SS_NO_INIT|SS_TICKER
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
22 changes: 21 additions & 1 deletion code/controllers/subsystem/movement/movement_types.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
///Used primarially as a hint to be reasoned about by our [controller], and as the id of our bucket
///Should not be modified directly outside of [start_loop]
var/timer = 0
///Track if we're currently paused
var/paused = FALSE
///Used for the COMSIG_MOVELOOP_REACHED_TARGET signal
var/atom/destination

Expand Down Expand Up @@ -110,6 +112,24 @@
/datum/move_loop/proc/move()
return FALSE

///Pause our loop untill restarted with resume_loop()
/datum/move_loop/proc/pause_loop()
if(!controller || paused) //we dead
return

//Dequeue us from our current bucket
controller.dequeue_loop(src)
paused = TRUE

///Resume our loop after being paused by pause_loop()
/datum/move_loop/proc/resume_loop()
if(!controller || !paused)
return

controller.queue_loop(src)
timer = world.time
paused = FALSE

///Removes the atom from some movement subsystem. Defaults to SSmovement
/datum/controller/subsystem/move_manager/proc/stop_looping(atom/movable/moving, datum/controller/subsystem/movement/subsystem = SSmovement)
var/datum/movement_packet/our_info = moving.move_packet
Expand Down Expand Up @@ -151,7 +171,7 @@

/datum/move_loop/move/move()
var/atom/old_loc = moving.loc
moving.Move(get_step(moving, direction), direction)
moving.Move(get_step(moving, direction), direction, FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
// We cannot rely on the return value of Move(), we care about teleports and it doesn't
return old_loc != moving?.loc

Expand Down
166 changes: 166 additions & 0 deletions code/datums/components/shuttle_cling.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@

//Below defines are for the is_holding_on proc to see how well they're holding on and respond accordingly
///Instead of a high move force we just get launched away dramatically because we're that hopeless
#define SUPER_NOT_HOLDING_ON 0
///We're not holdin on and will get thrown off
#define NOT_HOLDING_ON 1
///We're holding on, but will be pulled slowly
#define CLINGING 2
///We're holding on really well and aren't suffering from any pull
#define ALL_GOOD 3

///Gets added to all movables that enter hyperspace and are supposed to suffer from "hyperspace drift"
///This lets people fly around shuttles during transit using jetpacks, or cling to the side if they got a spacesuit
///Dumping into deepspace is handled by the hyperspace turf, not the component.
///Not giving something this component while on hyperspace is safe, it just means free movement like carps
/datum/component/shuttle_cling
///The direction we push stuff towards
var/direction
///Path to the hyperspace tile, so we know if we're in hyperspace
var/hyperspace_type = /turf/open/space/transit

///Our moveloop, handles the transit pull
var/datum/move_loop/move/hyperloop

///If we can "hold on", how often do we move?
var/clinging_move_delay = 1 SECONDS
///If we can't hold onto anything, how fast do we get pulled away?
var/not_clinging_move_delay = 0.2 SECONDS
var/super_not_clinging_move_delay = 0.1 SECONDS

/datum/component/shuttle_cling/Initialize(direction)
. = ..()

if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE

src.direction = direction

ADD_TRAIT(parent, TRAIT_HYPERSPACED, src)

RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UNBUCKLE, COMSIG_MOVABLE_NO_LONGER_PULLED, COMSIG_MOVABLE_POST_THROW), PROC_REF(update_state))

//Items have this cool thing where they're first put on the floor if you grab them from storage, and then into your hand, which isn't caught by movement signals that well
if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_PICKUP, PROC_REF(do_remove))

hyperloop = SSmove_manager.move(moving = parent, direction = direction, delay = not_clinging_move_delay, subsystem = SShyperspace_drift, priority = MOVEMENT_ABOVE_SPACE_PRIORITY, flags = MOVEMENT_LOOP_NO_DIR_UPDATE)

update_state(parent) //otherwise we'll get moved 1 tile before we can correct ourselves, which isnt super bad but just looks jank

///Check if we're in hyperspace and our state in hyperspace
/datum/component/shuttle_cling/proc/update_state()
SIGNAL_HANDLER

if(!is_on_hyperspace(parent))
qdel(src)
return

var/should_loop = FALSE

switch(is_holding_on(parent))
if(SUPER_NOT_HOLDING_ON)
hyperloop.set_delay(super_not_clinging_move_delay)
should_loop = TRUE
hyperloop.direction = direction
if(NOT_HOLDING_ON)
hyperloop.set_delay(not_clinging_move_delay)
should_loop = TRUE
hyperloop.direction = direction //we're not close to anything so reset direction if we got diagonalized
if(CLINGING)
hyperloop.set_delay(clinging_move_delay)
should_loop = TRUE
update_drift_direction(parent)
if(ALL_GOOD)
should_loop = FALSE

//Do pause/unpause/nothing for the hyperloop
if(should_loop && hyperloop.paused)
hyperloop.resume_loop()
else if(!should_loop && !hyperloop.paused)
hyperloop.pause_loop()

///Check if we're "holding on" to the shuttle
/datum/component/shuttle_cling/proc/is_holding_on(atom/movable/movee)
if(movee.pulledby || !isturf(movee.loc))
return ALL_GOOD

if(!isliving(movee))
if(is_tile_solid(get_step(movee, direction))) //something is blocking us so do the cool drift
return CLINGING
return SUPER_NOT_HOLDING_ON

var/mob/living/living = movee

//Check if we can interact with stuff (checks for alive, arms, stun, etc)
if(!living.canUseTopic(living, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
return NOT_HOLDING_ON

if(living.buckled)
return ALL_GOOD

for(var/atom/handlebar in range(living, 1))
if(isclosedturf(handlebar))
return CLINGING
if(isobj(handlebar))
var/obj/object = handlebar
if(object.anchored && object.density)
return CLINGING
return NOT_HOLDING_ON

///Are we on a hyperspace tile? There's some special bullshit with lattices so we just wrap this check
/datum/component/shuttle_cling/proc/is_on_hyperspace(atom/movable/clinger)
if(istype(clinger.loc, hyperspace_type) && !(locate(/obj/structure/lattice) in clinger.loc))
return TRUE
return FALSE

///Check if we arent just being blocked, and if we are give us some diagonal push so we cant just infinitely cling to the front
/datum/component/shuttle_cling/proc/update_drift_direction(atom/movable/clinger)
var/turf/potential_blocker = get_step(clinger, direction)
//We are not being blocked, so just give us cardinal drift
if(!is_tile_solid(potential_blocker))
hyperloop.direction = direction
return

//We're already moving diagonally
if(hyperloop.direction != direction)
var/side_dir = hyperloop.direction - direction

if(is_tile_solid(get_step(clinger, side_dir)))
hyperloop.direction = direction + turn(side_dir, 180) //We're bumping a wall to the side, so switch to the other side_dir (yes this adds pingpong protocol)
return

//Get the directions from the side of our current drift direction (so if we have drift south, get all cardinals and remove north and south, leaving only east and west)
var/side_dirs = shuffle(GLOB.cardinals - direction - turn(direction, 180))

//We check if one side is solid
if(!is_tile_solid(get_step(clinger, side_dirs[1])))
hyperloop.direction = direction + side_dirs[1]
else //if one side isnt solid, send it to the other side (it can also be solid but we dont care cause we're boxed in then and not like itll matter much then)
hyperloop.direction = direction + side_dirs[2]

///Check if it's a closed turf or contains a dense object
/datum/component/shuttle_cling/proc/is_tile_solid(turf/maybe_solid)
if(isclosedturf(maybe_solid))
return TRUE
for(var/obj/blocker in maybe_solid.contents)
if(blocker.density)
return TRUE
return FALSE

///This is just for signals and doesn't run for most removals, so dont add behaviour here expecting it to do much
/datum/component/shuttle_cling/proc/do_remove()
SIGNAL_HANDLER

qdel(src)

/datum/component/shuttle_cling/Destroy(force, silent)
REMOVE_TRAIT(parent, TRAIT_HYPERSPACED, src)
QDEL_NULL(hyperloop)

return ..()

#undef SUPER_NOT_HOLDING_ON
#undef NOT_HOLDING_ON
#undef CLINGING
#undef ALL_GOOD
2 changes: 2 additions & 0 deletions code/game/atoms_movable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@
if(!supress_message)
M.visible_message("<span class='warning'>[src] grabs [M] passively.</span>", \
"<span class='danger'>[src] grabs you passively.</span>")
SEND_SIGNAL(pulling, COMSIG_MOVABLE_PULLED)
return TRUE

/atom/movable/proc/stop_pulling()
Expand All @@ -187,6 +188,7 @@
if(isliving(ex_pulled))
var/mob/living/L = ex_pulled
L.update_mobility()// mob gets up if it was lyng down in a chokehold
SEND_SIGNAL(ex_pulled, COMSIG_MOVABLE_NO_LONGER_PULLED)

/atom/movable/proc/Move_Pulled(atom/A)
if(!pulling)
Expand Down
70 changes: 43 additions & 27 deletions code/game/turfs/open/space/transit.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,53 @@
flags_1 = NOJAUNT_1 //This line goes out to every wizard that ever managed to escape the den. I'm sorry.
explosion_block = INFINITY

/turf/open/space/transit/Initialize(mapload)
. = ..()
update_icon()
RegisterSignal(src, COMSIG_TURF_RESERVATION_RELEASED, PROC_REF(launch_contents))

for(var/atom/movable/movable in src)
throw_atom(movable)

/turf/open/space/transit/clear_signal_refs()
//Signals are NOT removed from turfs upon replacement, and we get replaced ALOT, so unregister our signal
UnregisterSignal(src, COMSIG_TURF_RESERVATION_RELEASED)

/turf/open/space/transit/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
. = ..()
underlay_appearance.icon_state = "speedspace_ns_[get_transit_state(asking_turf)]"
underlay_appearance.transform = turn(matrix(), get_transit_angle(asking_turf))

/turf/open/space/transit/south
dir = SOUTH
/turf/open/space/transit/update_icon()
. = ..()
transform = turn(matrix(), get_transit_angle(src))

/turf/open/space/transit/north
dir = NORTH
/turf/open/space/transit/update_icon_state()
icon_state = "speedspace_ns_[get_transit_state(src)]"
return ..()

/turf/open/space/transit/horizontal
dir = WEST
/turf/open/space/transit/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
. = ..()
if(!HAS_TRAIT(arrived, TRAIT_HYPERSPACED) && !HAS_TRAIT(arrived, TRAIT_FREE_HYPERSPACE_MOVEMENT))
arrived.AddComponent(/datum/component/shuttle_cling, turn(dir, 180), old_loc)

/turf/open/space/transit/west
dir = WEST
/turf/open/space/transit/Exited(atom/movable/gone, direction)
. = ..()
var/turf/location = gone.loc
if(istype(location, /turf/open/space) && !istype(location, src.type))//they got forced out of transit area into default space tiles
throw_atom(gone) //launch them into game space, away from transitspace

/turf/open/space/transit/east
dir = EAST
///Get rid of all our contents, called when our reservation is released (which in our case means the shuttle arrived)
/turf/open/space/transit/proc/launch_contents(datum/turf_reservation/reservation)
SIGNAL_HANDLER

/turf/open/space/transit/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
. = ..()
if(!locate(/obj/structure/lattice) in src)
throw_atom(arrived, old_loc)
for(var/atom/movable/movable in contents)
throw_atom(movable)

/turf/open/space/transit/proc/throw_atom(atom/movable/AM, atom/OldLoc)
set waitfor = FALSE
if(!AM || istype(AM, /obj/docking_port) || istype(AM, /obj/effect/abstract))
return
if(AM.loc != src) // Multi-tile objects are "in" multiple locs but its loc is it's true placement.
return // Don't move multi tile objects if their origin isn't in transit
var/max = world.maxx-TRANSITIONEDGE
var/min = 1+TRANSITIONEDGE

Expand Down Expand Up @@ -103,20 +119,20 @@
/turf/open/space/transit/CanBuildHere()
return SSshuttle.is_in_shuttle_bounds(src)

/turf/open/space/transit/north
dir = NORTH

/turf/open/space/transit/Initialize(mapload)
. = ..()
transform = turn(matrix(), get_transit_angle(src))
for(var/atom/movable/AM in src)
throw_atom(AM, src)
/turf/open/space/transit/south
dir = SOUTH

/turf/open/space/transit/update_icon()
. = ..()
transform = turn(matrix(), get_transit_angle(src))
/turf/open/space/transit/horizontal
dir = WEST

/turf/open/space/transit/update_icon_state()
icon_state = "speedspace_ns_[get_transit_state(src)]"
return ..()
/turf/open/space/transit/west
dir = WEST

/turf/open/space/transit/east
dir = EAST

/proc/get_transit_state(turf/T)
var/p = 9
Expand Down
Loading

0 comments on commit dc91339

Please sign in to comment.