mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-12 00:27:31 +01:00
217 lines
10 KiB
Plaintext
217 lines
10 KiB
Plaintext
// VENTCRAWLING
|
|
|
|
/mob/living/proc/notify_ventcrawler_on_login()
|
|
var/ventcrawler = HAS_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS) || HAS_TRAIT(src, TRAIT_VENTCRAWLER_NUDE)
|
|
if(!ventcrawler)
|
|
return
|
|
to_chat(src, span_notice("You can ventcrawl! Use alt+click on vents to quickly travel about the station."))
|
|
|
|
/mob/living/carbon/human/notify_ventcrawler_on_login()
|
|
if(!ismonkey(src))
|
|
return ..()
|
|
if(!istype(head, /obj/item/clothing/head/helmet/monkey_sentience)) //don't notify them about ventcrawling if they're wearing the sentience helmet, because they can't ventcrawl with it on, and if they take it off they'll no longer be in control of the mob.
|
|
return ..()
|
|
|
|
|
|
|
|
/// Checks if the mob is able to enter the vent, and provides feedback if they are unable to.
|
|
/mob/living/proc/can_enter_vent(obj/machinery/atmospherics/components/ventcrawl_target, provide_feedback = TRUE)
|
|
// Being able to always ventcrawl trumps being only able to ventcrawl when wearing nothing
|
|
var/required_nudity = HAS_TRAIT(src, TRAIT_VENTCRAWLER_NUDE) && !HAS_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS)
|
|
// Cache the vent_movement bitflag var from atmos machineries
|
|
var/vent_movement = ventcrawl_target.vent_movement
|
|
|
|
if(!Adjacent(ventcrawl_target))
|
|
return
|
|
// BUBBER ADDITION START - VENTCRAWLING SIGNAL
|
|
var/signal_result = SEND_SIGNAL(src, COMSIG_CAN_VENTCRAWL, ventcrawl_target, provide_feedback)
|
|
if(!HAS_TRAIT(src, TRAIT_VENTCRAWLER_NUDE) && !HAS_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS) && !signal_result)
|
|
return
|
|
// BUBBER ADDITION END - VENTCRAWLING SIGNAL
|
|
if(stat)
|
|
if(provide_feedback)
|
|
to_chat(src, span_warning("You must be conscious to do this!"))
|
|
return
|
|
if(HAS_TRAIT(src, TRAIT_IMMOBILIZED))
|
|
if(provide_feedback)
|
|
to_chat(src, span_warning("You currently can't move into the vent!"))
|
|
return
|
|
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
|
if(provide_feedback)
|
|
to_chat(src, span_warning("You need to be able to use your hands to ventcrawl!"))
|
|
return
|
|
if(has_buckled_mobs())
|
|
if(provide_feedback)
|
|
to_chat(src, span_warning("You can't vent crawl with other creatures on you!"))
|
|
return
|
|
if(buckled)
|
|
if(provide_feedback)
|
|
to_chat(src, span_warning("You can't vent crawl while buckled!"))
|
|
return
|
|
if(iscarbon(src) && required_nudity && !signal_result) // BUBBER CHANGE - VENTCRAWLING SIGNAL
|
|
if(length(get_equipped_items(INCLUDE_POCKETS|INCLUDE_HELD)))
|
|
if(provide_feedback)
|
|
to_chat(src, span_warning("You can't crawl around in the ventilation ducts with items!"))
|
|
return
|
|
if(ventcrawl_target.welded)
|
|
if(provide_feedback)
|
|
// Add cooldown to prevent welded vent message spam during movement
|
|
if(COOLDOWN_FINISHED(src, welded_vent_message_cd))
|
|
to_chat(src, span_warning("You can't crawl around a welded vent!"))
|
|
COOLDOWN_START(src, welded_vent_message_cd, 2 SECONDS)
|
|
return
|
|
|
|
if(!(vent_movement & VENTCRAWL_ENTRANCE_ALLOWED))
|
|
if(provide_feedback)
|
|
to_chat(src, span_warning("You can't enter this vent!"))
|
|
return
|
|
|
|
return TRUE
|
|
|
|
/// Handles the entrance and exit on ventcrawling
|
|
/mob/living/proc/handle_ventcrawl(obj/machinery/atmospherics/components/ventcrawl_target)
|
|
if(!can_enter_vent(ventcrawl_target))
|
|
return
|
|
|
|
var/has_client = !isnull(client) // clientless mobs can do this too! this is just stored in case the client disconnects while we sleep in do_after.
|
|
|
|
//Handle the exit here
|
|
if(HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING) && istype(loc, /obj/machinery/atmospherics) && movement_type & VENTCRAWLING)
|
|
// BUBBER ADDITION START - VENTCRAWLING SIGNAL
|
|
var/exit_time = SEND_SIGNAL(src, COMSIG_VENTCRAWL_PRE_EXIT, ventcrawl_target)
|
|
if(!exit_time)
|
|
exit_time = 1 SECONDS
|
|
// BUBBER ADDITION END - VENTCRAWLING SIGNAL
|
|
to_chat(src, span_notice("You begin climbing out from the ventilation system..."))
|
|
if(has_client && isnull(client))
|
|
return
|
|
if(!do_after(src, exit_time, target = ventcrawl_target)) // BUBBER CHANGE - VENTCRAWLING SIGNAL
|
|
SEND_SIGNAL(src, COMSIG_VENTCRAWL_PRE_CANCEL, ventcrawl_target) // BUBBER ADDITION - VENTCRAWLING SIGNAL
|
|
return
|
|
if(ventcrawl_target.welded) // in case it got welded during our sleep
|
|
to_chat(src, span_warning("You can't crawl around a welded vent!"))
|
|
return
|
|
visible_message(span_notice("[src] scrambles out from the ventilation ducts!"), span_notice("You scramble out from the ventilation ducts."))
|
|
forceMove(ventcrawl_target.loc)
|
|
REMOVE_TRAIT(src, TRAIT_MOVE_VENTCRAWLING, VENTCRAWLING_TRAIT)
|
|
update_pipe_vision()
|
|
SEND_SIGNAL(src, COMSIG_VENTCRAWL_EXIT, ventcrawl_target) // BUBBER ADDITION - VENTCRAWLING SIGNAL
|
|
|
|
//Entrance here
|
|
else
|
|
var/datum/pipeline/vent_parent = ventcrawl_target.parents[1]
|
|
if(vent_parent && (vent_parent.members.len || vent_parent.other_atmos_machines))
|
|
// BUBBER ADDITION START - VENTCRAWLING SIGNAL
|
|
var/enter_time = SEND_SIGNAL(src, COMISG_VENTCRAWL_PRE_ENTER, ventcrawl_target)
|
|
if(!enter_time)
|
|
enter_time = 2.5 SECONDS // Default time if the signal doesn't return anything
|
|
// BUBBER ADDITION END - VENTCRAWLING SIGNAL
|
|
ventcrawl_target.flick_overlay_static(image('icons/effects/vent_indicator.dmi', "arrow", ABOVE_MOB_LAYER, dir = get_dir(src.loc, ventcrawl_target.loc)), 2 SECONDS)
|
|
visible_message(span_notice("[src] begins climbing into the ventilation system...") ,span_notice("You begin climbing into the ventilation system..."))
|
|
if(!do_after(src, enter_time, target = ventcrawl_target, extra_checks = CALLBACK(src, PROC_REF(can_enter_vent), ventcrawl_target))) // BUBBER CHANGE - VENTCRAWLING SIGNAL
|
|
SEND_SIGNAL(src, COMSIG_VENTCRAWL_PRE_CANCEL, ventcrawl_target) // BUBBER ADDITION - VENTCRAWLING SIGNAL
|
|
return
|
|
if(has_client && isnull(client))
|
|
return
|
|
if(ventcrawl_target.welded) // in case it got welded during our sleep
|
|
to_chat(src, span_warning("You can't crawl around a welded vent!"))
|
|
return
|
|
ventcrawl_target.flick_overlay_static(image('icons/effects/vent_indicator.dmi', "insert", ABOVE_MOB_LAYER), 1 SECONDS)
|
|
visible_message(span_notice("[src] scrambles into the ventilation ducts!"), span_notice("You climb into the ventilation ducts."))
|
|
move_into_vent(ventcrawl_target)
|
|
SEND_SIGNAL(src, COMSIG_VENTCRAWL_ENTER, ventcrawl_target) // BUBBER ADDITION - VENTCRAWLING SIGNAL
|
|
else
|
|
to_chat(src, span_warning("This ventilation duct is not connected to anything!"))
|
|
|
|
/mob/living/basic/slime/can_enter_vent(obj/machinery/atmospherics/components/ventcrawl_target, provide_feedback = TRUE)
|
|
if(buckled)
|
|
if(provide_feedback)
|
|
to_chat(src, span_warning("You can't vent crawl while feeding!"))
|
|
return
|
|
return ..()
|
|
|
|
/**
|
|
* Moves living mob directly into the vent as a ventcrawler
|
|
*
|
|
* Arguments:
|
|
* * ventcrawl_target - The vent into which we are moving the mob
|
|
*/
|
|
/mob/living/proc/move_into_vent(obj/machinery/atmospherics/components/ventcrawl_target)
|
|
forceMove(ventcrawl_target)
|
|
ADD_TRAIT(src, TRAIT_MOVE_VENTCRAWLING, VENTCRAWLING_TRAIT)
|
|
update_pipe_vision()
|
|
|
|
/**
|
|
* Everything related to pipe vision on ventcrawling is handled by update_pipe_vision().
|
|
* Called on exit, entrance, and pipenet differences (e.g. moving to a new pipenet).
|
|
* One important thing to note however is that the movement of the client's eye is handled by the relaymove() proc in /obj/machinery/atmospherics.
|
|
* We move first and then call update. Dont flip this around
|
|
*/
|
|
/mob/living/proc/update_pipe_vision(full_refresh = FALSE)
|
|
if(!isnull(ai_controller) && isnull(client)) // we don't care about pipe vision if we have an AI controller with no client (typically means we are clientless).
|
|
return
|
|
|
|
// Take away all the pipe images if we're not doing anything with em
|
|
if(isnull(client) || !HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING) || !istype(loc, /obj/machinery/atmospherics) || !(movement_type & VENTCRAWLING))
|
|
for(var/image/current_image in pipes_shown)
|
|
client.images -= current_image
|
|
pipes_shown.len = 0
|
|
pipetracker = null
|
|
for(var/atom/movable/screen/plane_master/lighting as anything in hud_used.get_true_plane_masters(LIGHTING_PLANE))
|
|
lighting.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#4d4d4d")
|
|
for(var/atom/movable/screen/plane_master/pipecrawl as anything in hud_used.get_true_plane_masters(PIPECRAWL_IMAGES_PLANE))
|
|
pipecrawl.hide_plane(src)
|
|
return
|
|
|
|
// We're gonna color the lighting plane to make it darker while ventcrawling, so things look nicer
|
|
// This is a bit hacky but it makes the background darker, which has a nice effect
|
|
for(var/atom/movable/screen/plane_master/lighting as anything in hud_used.get_true_plane_masters(LIGHTING_PLANE))
|
|
lighting.add_atom_colour("#4d4d4d", TEMPORARY_COLOUR_PRIORITY)
|
|
|
|
for(var/atom/movable/screen/plane_master/pipecrawl as anything in hud_used.get_true_plane_masters(PIPECRAWL_IMAGES_PLANE))
|
|
pipecrawl.unhide_plane(src)
|
|
|
|
var/obj/machinery/atmospherics/current_location = loc
|
|
var/list/our_pipenets = current_location.return_pipenets()
|
|
|
|
// We on occasion want to do a full rebuild. this lets us do that
|
|
if(full_refresh)
|
|
for(var/image/current_image in pipes_shown)
|
|
client.images -= current_image
|
|
pipes_shown.len = 0
|
|
pipetracker = null
|
|
|
|
if(!pipetracker)
|
|
pipetracker = new()
|
|
|
|
var/turf/our_turf = get_turf(src)
|
|
// We're getting the smallest "range" arg we can pass to the spatial grid and still get all the stuff we need
|
|
// We preload a bit more then we need so movement looks ok
|
|
var/list/view_range = getviewsize(client.view)
|
|
pipetracker.set_bounds(view_range[1] + 1, view_range[2] + 1)
|
|
|
|
var/list/entered_exited_pipes = pipetracker.recalculate_type_members(our_turf, SPATIAL_GRID_CONTENTS_TYPE_ATMOS)
|
|
var/list/pipes_gained = entered_exited_pipes[1]
|
|
var/list/pipes_lost = entered_exited_pipes[2]
|
|
|
|
for(var/obj/machinery/atmospherics/pipenet_part as anything in pipes_lost)
|
|
if(!pipenet_part.pipe_vision_img)
|
|
continue
|
|
client.images -= pipenet_part.pipe_vision_img
|
|
pipes_shown -= pipenet_part.pipe_vision_img
|
|
|
|
for(var/obj/machinery/atmospherics/pipenet_part as anything in pipes_gained)
|
|
// If the machinery is not part of our net or is not meant to be seen, continue
|
|
var/list/thier_pipenets = pipenet_part.return_pipenets()
|
|
if(!length(thier_pipenets & our_pipenets))
|
|
continue
|
|
if(!(pipenet_part.vent_movement & VENTCRAWL_CAN_SEE))
|
|
continue
|
|
|
|
if(!pipenet_part.pipe_vision_img)
|
|
var/turf/their_turf = get_turf(pipenet_part)
|
|
pipenet_part.pipe_vision_img = image(pipenet_part, pipenet_part.loc, dir = pipenet_part.dir)
|
|
SET_PLANE(pipenet_part.pipe_vision_img, PIPECRAWL_IMAGES_PLANE, their_turf)
|
|
client.images += pipenet_part.pipe_vision_img
|
|
pipes_shown += pipenet_part.pipe_vision_img
|