Files
Bubberstation/code/datums/components/hazard_area.dm
SkyratBot 067188d366 [MIRROR] Micro-optimize qdel by only permitting one parameter [MDB IGNORE] (#25889)
* Micro-optimize qdel by only permitting one parameter (#80628)

Productionizes #80615.

The core optimization is this:

```patch
-	var/hint = to_delete.Destroy(arglist(args.Copy(2))) // Let our friend know they're about to get fucked up.
+	var/hint = to_delete.Destroy(force) // Let our friend know they're about to get fucked up.
```

We avoid a heap allocation in the form of copying the args over to a new
list. A/B testing shows this results in 33% better overtime, and in a
real round shaving off a full second of self time and 0.4 seconds of
overtime--both of these would be doubled in the event this is merged as
the new proc was only being run 50% of the time.

* Micro-optimize qdel by only permitting one parameter

---------

Co-authored-by: Mothblocks <35135081+Mothblocks@users.noreply.github.com>
2023-12-29 14:41:12 +00:00

173 lines
7.2 KiB
Plaintext

/**
* This is a relatively simple component that attempts to deter the parent of the component away
* from a specific area or areas. By default it simply applies a penalty where all movement is
* four times slower than usual and any action that would affect your 'next move' has a penalty
* multiplier of 4 attached.
*/
/datum/component/hazard_area
/// The blacklist of areas that the parent will be penalized for entering
var/list/area_blacklist
/// The whitelist of areas that the parent is allowed to be in. If set this overrides the blacklist
var/list/area_whitelist
/// A list of areas that have been created and are considered to not be hazardous
var/list/area_created
/// A variable storing the typepath of the last checked area to prevent any further logic running if it has not changed
VAR_PRIVATE/last_parent_area
/datum/component/hazard_area/Initialize(area_blacklist, area_whitelist)
. = ..()
if(!ismob(parent))
return COMPONENT_INCOMPATIBLE
if(!islist(area_blacklist) && !islist(area_whitelist))
stack_trace("[type] - neither area_blacklist nor area_whitelist were provided.")
return COMPONENT_INCOMPATIBLE
src.area_blacklist = area_blacklist
src.area_whitelist = area_whitelist
area_created = new
/datum/component/hazard_area/RegisterWithParent()
var/mob/parent_mob = parent
parent_mob.become_area_sensitive(type)
RegisterSignal(parent_mob, COMSIG_ENTER_AREA, PROC_REF(handle_parent_area_change))
RegisterSignal(parent_mob, COMSIG_LADDER_TRAVEL, PROC_REF(reject_ladder_movement))
RegisterSignal(parent_mob, COMSIG_VEHICLE_RIDDEN, PROC_REF(reject_vehicle))
RegisterSignal(SSdcs, COMSIG_AREA_CREATED, PROC_REF(on_area_creation))
/datum/component/hazard_area/UnregisterFromParent()
var/mob/parent_mob = parent
UnregisterSignal(parent_mob, list(COMSIG_ENTER_AREA, COMSIG_LADDER_TRAVEL, COMSIG_VEHICLE_RIDDEN))
UnregisterSignal(SSdcs, COMSIG_AREA_CREATED)
parent_mob.lose_area_sensitivity(type)
/datum/component/hazard_area/Destroy(force)
. = ..()
area_created = null
/**
* This signal handler checks the area the target ladder is in and if hazardous prevents them from using it
*/
/datum/component/hazard_area/proc/reject_ladder_movement(mob/source, obj/entrance_ladder, exit_ladder, going_up)
SIGNAL_HANDLER
if(check_area_hazardous(get_area(exit_ladder)))
entrance_ladder.balloon_alert(parent, "the path is too dangerous for you!")
return LADDER_TRAVEL_BLOCK
/**
* A simple signal handler that informs the parent they cannot ride a vehicle and ejects them
*/
/datum/component/hazard_area/proc/reject_vehicle(mob/source, obj/vehicle/vehicle)
SIGNAL_HANDLER
if(!check_area_hazardous(last_parent_area))
return
vehicle.balloon_alert(parent, "you slip and fall off!")
if(isliving(parent)) // We don't know for certain if we are a mob/living subtype
var/mob/living/parent_living = parent
parent_living.Stun(0.5 SECONDS)
return EJECT_FROM_VEHICLE
/**
* Checks if the area being checked is considered hazardous
* The whitelist is checked first if it exists, otherwise it checks if it is in the blacklist
*
* * checking - This should be the typepath of the area being checked, but there is a conversion handler if you pass in a reference instead
*/
/datum/component/hazard_area/proc/check_area_hazardous(area/checking)
if(LAZYFIND(area_created, checking))
return FALSE
if(!ispath(checking))
checking = checking.type
if(area_whitelist)
return !(checking in area_whitelist)
return checking in area_blacklist
/**
* This signal handler does a few house cleaning tasks when a new area is created.
* If the created area already exists in the blacklist or whitelist it simply returns,
* however if it isn't we check for an overwritten area and if non-hazardous setup the area to
* allow the parent.
* If there aren't any overwritten area's it assumes it to be non-hazardous, abuse it and you will weep -ZephyrTFA
*/
/datum/component/hazard_area/proc/on_area_creation(datum/source, area/created, list/area/overwritten, mob/creator)
SIGNAL_HANDLER
if(created.type in area_whitelist)
return // in whitelist, probably expanded an already whitelisted area
if(created.type in area_blacklist)
return // in blacklist, expanding a blacklisted area doesnt magically give you permission to enter
if(length(overwritten))
for(var/area/overwritten_area in overwritten)
if(check_area_hazardous(overwritten_area.type))
return // Overwrote a hazardous area, still hazardous fool
area_created -= overwritten_area // While its not guaranteed to be in the area_created list it's a good idea to ensure we dont have handing refs
area_created += created // Congrats, you are now allowed in this area
return
// No overwritten area, which means its a brand new area, for now we are going to be nice and assume its non-hazardous
// If people abuse this in the future to put rooms right next to the station add an is_station_level check
area_created += created
/**
* This proc handles the status effect applied to the parent, most noteably applying or removing it as required
*/
/datum/component/hazard_area/proc/update_parent_status_effect()
if(QDELETED(parent))
return
var/mob/living/parent_living = parent
var/datum/status_effect/hazard_area/effect = parent_living.has_status_effect(/datum/status_effect/hazard_area)
var/should_have_status_effect = check_area_hazardous(last_parent_area)
if(should_have_status_effect && !effect) // Should have the status - and doesnt
parent_living.apply_status_effect(/datum/status_effect/hazard_area)
if(parent_living.buckled)
parent_living.buckled.balloon_alert(parent, "you fall off!")
parent_living.buckled.unbuckle_mob(parent_living, force=TRUE)
return
if(!should_have_status_effect && effect) // Shouldn't have the status - and does
parent_living.remove_status_effect(/datum/status_effect/hazard_area)
/**
* This signal should be called whenever our parent moves.
*/
/datum/component/hazard_area/proc/handle_parent_area_change(mob/source, area/new_area)
SIGNAL_HANDLER
if(new_area.type == last_parent_area)
return
last_parent_area = new_area.type
INVOKE_ASYNC(src, PROC_REF(update_parent_status_effect))
/// The dedicated status effect for the hazard_area component - use with caution and know what it does!
/datum/status_effect/hazard_area
id = "hazard_area"
status_type = STATUS_EFFECT_UNIQUE
alert_type = /atom/movable/screen/alert/status_effect/hazard_area
/datum/status_effect/hazard_area/nextmove_modifier()
return 4
/datum/status_effect/hazard_area/on_apply()
. = ..()
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/hazard_area, update=TRUE)
owner.add_actionspeed_modifier(/datum/actionspeed_modifier/status_effect/hazard_area, update=TRUE)
/datum/status_effect/hazard_area/on_remove()
. = ..()
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/hazard_area, update=TRUE)
owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/status_effect/hazard_area, update=TRUE)
/datum/status_effect/hazard_area/get_examine_text()
return span_notice("[owner.p_They()] appear[owner.p_s()] to be largely immobilized through unknown means.")
/atom/movable/screen/alert/status_effect/hazard_area
name = "Hazardous Area"
desc = "The area you are currently within is incredibly hazardous to you. Check your surroundings and vacate as soon as possible."
icon_state = "hazard_area"