Files
CHOMPStation2/code/_helpers/mobs.dm
CHOMPStation2StaffMirrorBot e61bebfbb3 [MIRROR] Axes do_mob and replaces with do_after (#11938)
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
2025-11-08 04:26:50 -05:00

350 lines
12 KiB
Plaintext

/atom/movable/proc/get_mob()
if(buckled_mobs) return buckled_mobs.Copy()
/obj/mecha/get_mob()
return occupant
/obj/vehicle_old/train/get_mob()
return buckled_mobs
/mob/get_mob()
return src
/mob/living/bot/mulebot/get_mob()
if(load && isliving(load))
return list(src, load)
return src
/proc/mobs_in_view(range, source)
var/list/mobs = list()
for(var/atom/movable/AM in view(range, source))
var/M = AM.get_mob()
if(M)
mobs += M
return mobs
/// This gets a list of mobs ALL around us as if we had xray vision and can see through walls.
/// Currently only used in portable_turret.dm if you wish to see an example of how to use it.
/proc/mobs_in_xray_view(range, source)
var/list/mobs = list()
for(var/atom/movable/AM in orange(range, source))
var/M = AM.get_mob()
if(M)
mobs += M
return mobs
/proc/random_hair_style(gender, species = SPECIES_HUMAN)
var/h_style = "Bald"
var/list/valid_hairstyles = list()
for(var/hairstyle in GLOB.hair_styles_list)
var/datum/sprite_accessory/S = GLOB.hair_styles_list[hairstyle]
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if(S.name == DEVELOPER_WARNING_NAME)
continue
if( !(species in S.species_allowed))
continue
valid_hairstyles[hairstyle] = GLOB.hair_styles_list[hairstyle]
if(valid_hairstyles.len)
h_style = pick(valid_hairstyles)
return h_style
/proc/random_facial_hair_style(gender, species = SPECIES_HUMAN)
var/f_style = "Shaved"
var/list/valid_facialhairstyles = list()
for(var/facialhairstyle in GLOB.facial_hair_styles_list)
var/datum/sprite_accessory/S = GLOB.facial_hair_styles_list[facialhairstyle]
if(gender == MALE && S.gender == FEMALE)
continue
if(gender == FEMALE && S.gender == MALE)
continue
if(S.name == DEVELOPER_WARNING_NAME)
continue
if( !(species in S.species_allowed))
continue
valid_facialhairstyles[facialhairstyle] = GLOB.facial_hair_styles_list[facialhairstyle]
if(valid_facialhairstyles.len)
f_style = pick(valid_facialhairstyles)
return f_style
/proc/sanitize_name(name, species = SPECIES_HUMAN, robot = 0)
var/datum/species/current_species
if(species)
current_species = GLOB.all_species[species]
return current_species ? current_species.sanitize_name(name, robot) : sanitizeName(name, MAX_NAME_LEN, robot)
/proc/random_name(gender, species = SPECIES_HUMAN)
var/datum/species/current_species
if(species)
current_species = GLOB.all_species[species]
if(!current_species || current_species.name_language == null)
if(gender==FEMALE)
return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
else
return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
else
return current_species.get_random_name(gender)
/proc/random_skin_tone()
switch(pick(60;"caucasian", 15;"afroamerican", 10;"african", 10;"latino", 5;"albino"))
if("caucasian") . = -10
if("afroamerican") . = -115
if("african") . = -165
if("latino") . = -55
if("albino") . = 34
else . = rand(-185,34)
return min(max( .+rand(-25, 25), -185),34)
/proc/skintone2racedescription(tone)
switch (tone)
if(30 to INFINITY) return "albino"
if(20 to 30) return "pale"
if(5 to 15) return "light skinned"
if(-10 to 5) return "white"
if(-25 to -10) return "tan"
if(-45 to -25) return "darker skinned"
if(-65 to -45) return "brown"
if(-INFINITY to -65) return "black"
else return "unknown"
/proc/age2agedescription(age)
switch(age)
if(0 to 1) return "infant"
if(1 to 3) return "toddler"
if(3 to 13) return "child"
if(13 to 19) return "teenager"
if(19 to 30) return "young adult"
if(30 to 45) return "adult"
if(45 to 60) return "middle-aged"
if(60 to 70) return "aging"
if(70 to INFINITY) return "elderly"
else return "unknown"
/proc/RoundHealth(health)
var/list/icon_states = cached_icon_states(GLOB.ingame_hud_med)
for(var/icon_state in icon_states)
if(health >= text2num(icon_state))
return icon_state
return icon_states[icon_states.len] // If we had no match, return the last element
/*
Proc for attack log creation, because really why not
1 argument is the actor
2 argument is the target of action
3 is the description of action(like punched, throwed, or any other verb)
4 should it make adminlog note or not
5 is the tool with which the action was made(usually item) 5 and 6 are very similar(5 have "by " before it, that it) and are separated just to keep things in a bit more in order
6 is additional information, anything that needs to be added
*/
/proc/add_attack_logs(mob/user, mob/target, what_done, var/admin_notify = TRUE)
if(islist(target)) //Multi-victim adding
var/list/targets = target
for(var/mob/M in targets)
add_attack_logs(user,M,what_done,admin_notify)
return
var/user_str = key_name(user)
var/target_str = key_name(target)
if(ismob(user))
user.attack_log += text("\[[time_stamp()]\] [span_red("Attacked [target_str]: [what_done]")]")
if(ismob(target))
target.attack_log += text("\[[time_stamp()]\] [span_orange("Attacked by [user_str]: [what_done]")]")
log_combat(user, target, what_done)
if(admin_notify)
msg_admin_attack("[key_name_admin(user)] vs [target_str]: [what_done]")
//checks whether this item is a module of the robot it is located in.
/proc/is_robot_module(var/obj/item/thing)
if (!thing || !isrobot(thing.loc))
return 0
var/mob/living/silicon/robot/R = thing.loc
return (thing in R.module.modules)
/proc/get_exposed_defense_zone(var/atom/movable/target)
var/obj/item/grab/G = locate() in target
if(G && G.state >= GRAB_NECK) //works because mobs are currently not allowed to upgrade to NECK if they are grabbing two people.
return pick(BP_HEAD, BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG)
else
return pick(BP_TORSO, BP_GROIN)
/**
* Timed action involving one mob user. Target is optional.
*
* Checks that `user` does not move, change hands, get stunned, etc. for the
* given `delay`. Returns `TRUE` on success or `FALSE` on failure.
*
* @param {mob} user - The mob performing the action.
*
* @param {number} delay - The time in deciseconds. Use the SECONDS define for readability. `1 SECONDS` is 10 deciseconds.
*
* @param {atom} target - The target of the action. This is where the progressbar will display.
*
* @param {flag} timed_action_flags - Flags to control the behavior of the timed action.
*
* @param {boolean} progress - Whether to display a progress bar / cogbar.
*
* @param {datum/callback} extra_checks - Additional checks to perform before the action is executed.
*
* @param {string} interaction_key - The assoc key under which the do_after is capped, with max_interact_count being the cap. Interaction key will default to target if not set.
*
* @param {number} max_interact_count - The maximum amount of interactions allowed.
*
* @param {boolean} hidden - By default, any action 1 second or longer shows a cog over the user while it is in progress. If hidden is set to TRUE, the cog will not be shown.
*
* @param {icon} icon - The icon file of the cog. Default: 'icons/effects/progressbar.dmi'
*
* @param {iconstate} iconstate - The icon state of the cog. Default: "Cog"
*
* @param {string} target_zone - The target zone of the user. See _defines/mobs.dm. If the user swaps from this zone, we break the do_after
*
* @param {number} max_distance - The maximum distance we can be away from the target before the do_after breaks. Default to 1.
*/
/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, hidden = FALSE, icon = 'icons/effects/progressbar.dmi', iconstate = "cog", target_zone, max_distance = null)
if(!user)
return FALSE
if(!isnum(delay))
CRASH("do_after was passed a non-number delay: [delay || "null"].")
if(!isatom(target))
CRASH("do_after was given a non-atom target! [target]")
if(!interaction_key && target)
interaction_key = target //Use the direct ref to the target
if(interaction_key) //Do we have a interaction_key now?
var/current_interaction_count = LAZYACCESS(user.do_afters, interaction_key) || 0
if(current_interaction_count >= max_interact_count) //We are at our peak
return
LAZYSET(user.do_afters, interaction_key, current_interaction_count + 1)
var/atom/user_loc = user.loc
var/atom/target_loc = target?.loc
var/drifting = FALSE
/* //We don't have a drift handler yet, sadly.
if(!isnull(user.drift_handler))
drifting = TRUE*/
var/holding = user.get_active_hand()
/* //Disabling for now. Meant to be used for modifier slowdowns.
if(!(timed_action_flags & IGNORE_SLOWDOWNS))
var/slowdown = user.calculate_item_encumbrance()
if(slowdown)
//Let's not be TOO evil. You can be up to 4x faster, but never more than 3x slower.
delay *= CLAMP(slowdown, 0.25, 3)
*/
var/datum/progressbar/progbar
var/datum/cogbar/cog
if(progress)
if(user.client)
progbar = new(user, delay, target || user)
if(!hidden && delay >= 1 SECONDS)
cog = new(user, icon, iconstate)
SEND_SIGNAL(user, COMSIG_DO_AFTER_BEGAN)
var/endtime = world.time + delay
var/starttime = world.time
. = TRUE
while (world.time < endtime)
stoplag(1)
if(!QDELETED(progbar))
progbar.update(world.time - starttime)
/*if(drifting && isnull(user.drift_handler)) //We don't have a drift handler yet, sadly.
drifting = FALSE
user_loc = user.loc*/
if(QDELETED(user) \
|| (!(timed_action_flags & IGNORE_USER_LOC_CHANGE) && !drifting && user.loc != user_loc) \
|| (!(timed_action_flags & IGNORE_HELD_ITEM) && user.get_active_hand() != holding) \
|| (!(timed_action_flags & IGNORE_INCAPACITATED) && HAS_TRAIT(user, TRAIT_INCAPACITATED)) \
|| (max_distance && target && get_dist(user, target) > max_distance) \
|| (target_zone && user.zone_sel?.selecting != target_zone) \
|| (extra_checks && !extra_checks.Invoke()))
. = FALSE
break
if(target && (user != target) && \
(QDELETED(target) \
|| (!(timed_action_flags & IGNORE_TARGET_LOC_CHANGE) && target.loc != target_loc)))
. = FALSE
break
if(!QDELETED(progbar))
progbar.end_progress()
cog?.remove()
if(interaction_key)
var/reduced_interaction_count = (LAZYACCESS(user.do_afters, interaction_key) || 0) - 1
if(reduced_interaction_count > 0) // Not done yet!
LAZYSET(user.do_afters, interaction_key, reduced_interaction_count)
return
// all out, let's clear er out fully
LAZYREMOVE(user.do_afters, interaction_key)
SEND_SIGNAL(user, COMSIG_DO_AFTER_ENDED)
/atom/proc/living_mobs(var/range = world.view, var/count_held = FALSE) //CHOMPEdit Start
var/list/viewers = oviewers(src,range)
if(count_held)
viewers = viewers(src,range)
var/list/living = list()
for(var/mob/living/L in viewers)
living += L
if(count_held)
for(var/obj/item/holder/H in L.contents)
if(istype(H.held_mob, /mob/living))
living += H.held_mob //CHOMPEdit End
return living
/atom/proc/human_mobs(var/range = world.view)
var/list/viewers = oviewers(src,range)
var/list/humans = list()
for(var/mob/living/carbon/human/H in viewers)
humans += H
return humans
/proc/cached_character_icon(var/mob/desired)
var/cachekey = "\ref[desired][desired.real_name]"
if(GLOB.cached_character_icons[cachekey])
. = GLOB.cached_character_icons[cachekey]
else
. = getCompoundIcon(desired)
GLOB.cached_character_icons[cachekey] = .
/proc/not_has_ooc_text(mob/user)
if (CONFIG_GET(flag/allow_metadata) && (!user.client?.prefs?.read_preference(/datum/preference/text/living/ooc_notes) || length(user.client.prefs.read_preference(/datum/preference/text/living/ooc_notes)) < 15))
to_chat(user, span_warning("Please set informative OOC notes related to RP/ERP preferences. Set them using the 'OOC Notes' button on the 'General' tab in character setup."))
return TRUE
return FALSE
///Makes a call in the context of a different usr. Use sparingly
/world/proc/push_usr(mob/user_mob, datum/callback/invoked_callback, ...)
var/temp = usr
usr = user_mob
if (length(args) > 2)
. = invoked_callback.Invoke(arglist(args.Copy(3)))
else
. = invoked_callback.Invoke()
usr = temp