Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions code/__DEFINES/flags.dm
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,17 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204

/// 33554431 (2^24 - 1) is the maximum value our bitflags can reach.
#define MAX_BITFLAG_DIGITS 8

// timed_action_flags parameter for `/proc/do_after`
/// Can do the action even if mob moves location
#define IGNORE_USER_LOC_CHANGE (1<<0)
/// Can do the action even if the target moves location
#define IGNORE_TARGET_LOC_CHANGE (1<<1)
/// Can do the action even if the item is no longer being held
#define IGNORE_HELD_ITEM (1<<2)
/// Can do the action even if the mob is incapacitated (ex. handcuffed)
#define IGNORE_INCAPACITATED (1<<3)
/// Used to prevent important slowdowns from being abused by drugs like kronkaine
#define IGNORE_SLOWDOWNS (1<<4)

#define IGNORE_ALL (IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_HELD_ITEM|IGNORE_INCAPACITATED|IGNORE_SLOWDOWNS)
6 changes: 3 additions & 3 deletions code/__DEFINES/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,10 @@
//this should be in the ai defines, but out ai defines are actual ai, not simplemob ai
#define IS_DEAD_OR_INCAP(source) (source.incapacitated() || source.stat)

#define INTERACTING_WITH(X, Y) (Y in X.do_afters)


#define DOING_INTERACTION(user, interaction_key) (LAZYACCESS(user.do_afters, interaction_key))
#define DOING_INTERACTION_LIMIT(user, interaction_key, max_interaction_count) ((LAZYACCESS(user.do_afters, interaction_key) || 0) >= max_interaction_count)
#define DOING_INTERACTION_WITH_TARGET(user, target) (LAZYACCESS(user.do_afters, target))
#define DOING_INTERACTION_WITH_TARGET_LIMIT(user, target, max_interaction_count) ((LAZYACCESS(user.do_afters, target) || 0) >= max_interaction_count)

///Define for spawning megafauna instead of a mob for cave gen
#define SPAWN_MEGAFAUNA "bluh bluh huge boss"
Expand Down
198 changes: 41 additions & 157 deletions code/__HELPERS/mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -269,64 +269,6 @@ GLOBAL_LIST_EMPTY(species_list)
else
return "unknown"


/mob/var/action_speed_modifier = 1 //Value to multiply action delays by //yogs start: fuck
/mob/var/action_speed_adjust = 0 //Value to add or remove to action delays //yogs end

/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null)
if(!user || !target)
return 0
var/user_loc = user.loc

if(target)
LAZYADD(user.do_afters, target)
LAZYADD(target.targeted_by, user)

var/drifting = 0
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = 1

var/target_loc = target.loc

var/holding = user.get_active_held_item()
time = ((time + user.action_speed_adjust) * user.action_speed_modifier) //yogs: darkspawn
var/datum/progressbar/progbar
if (progress)
progbar = new(user, time, target)

var/endtime = world.time+time
var/starttime = world.time
. = 1
while (world.time < endtime)
stoplag(1)
if (progress)
progbar.update(world.time - starttime)
if(QDELETED(user) || QDELETED(target))
. = 0
break

if(target && !(target in user.do_afters))
. = FALSE
break

if(uninterruptible)
continue

if(drifting && !user.inertia_dir)
drifting = 0
user_loc = user.loc

if((!drifting && user.loc != user_loc) || target.loc != target_loc || user.get_active_held_item() != holding || user.incapacitated() || (extra_checks && !extra_checks.Invoke()))
. = 0
break
if (progress)
qdel(progbar)

if(!QDELETED(target))
LAZYREMOVE(user.do_afters, target)
LAZYREMOVE(target.targeted_by, user)


//some additional checks as a callback for for do_afters that want to break on losing health or on the mob taking action
/mob/proc/break_do_after_checks(list/checked_health, check_clicks)
if(check_clicks && next_move > world.time)
Expand All @@ -341,139 +283,81 @@ GLOBAL_LIST_EMPTY(species_list)
checked_health["health"] = health
return ..()

/proc/do_after(mob/user, delay, atom/target = null, needhand = TRUE, progress = TRUE, datum/callback/extra_checks = null, stayStill = TRUE)
/**
* 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.
* Interaction_key is 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.
*/
/proc/do_after(mob/user, delay, atom/target, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1)
if(!user)
return FALSE
var/atom/target_loc = null
if(target && !isturf(target))
target_loc = target.loc

if(target)
LAZYADD(user.do_afters, target)
LAZYADD(target.targeted_by, user)
if(!isnum(delay))
CRASH("do_after was passed a non-number delay: [delay || "null"].")

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
if(!user.Process_Spacemove() && user.inertia_dir)
drifting = TRUE

var/holding = user.get_active_held_item()

var/holdingnull = TRUE //User's hand started out empty, check for an empty hand
if(holding)
holdingnull = FALSE //Users hand started holding something, check to see if it's still holding that

delay = ((delay + user.action_speed_adjust) * user.action_speed_modifier * user.do_after_coefficent()) //yogs: darkspawn
if(!(timed_action_flags & IGNORE_SLOWDOWNS))
delay *= user.action_speed_modifier * user.do_after_coefficent() //yogs: darkspawn

var/datum/progressbar/progbar
if (progress)
progbar = new(user, delay, target)
if(progress)
progbar = new(user, delay, target || user)

SEND_SIGNAL(user, COMSIG_DO_AFTER_BEGAN)

var/endtime = world.time + delay
var/starttime = world.time
. = TRUE
while (world.time < endtime)
stoplag(1)
if (progress)

if(!QDELETED(progbar))
progbar.update(world.time - starttime)

if(drifting && !user.inertia_dir)
drifting = FALSE
user_loc = user.loc

if(QDELETED(user) || user.stat || (!drifting && user.loc != user_loc && stayStill) || (extra_checks && !extra_checks.Invoke()))
if(QDELETED(user) \
|| (!(timed_action_flags & IGNORE_USER_LOC_CHANGE) && !drifting && user.loc != user_loc) \
|| (!(timed_action_flags & IGNORE_HELD_ITEM) && user.get_active_held_item() != holding) \
|| (!(timed_action_flags & IGNORE_INCAPACITATED) && HAS_TRAIT(user, TRAIT_INCAPACITATED)) \
|| (extra_checks && !extra_checks.Invoke()))
. = FALSE
break

if(isliving(user))
var/mob/living/L = user
if(L.IsStun() || L.IsParalyzed())
. = FALSE
break

if(!QDELETED(target_loc) && (QDELETED(target) || target_loc != target.loc))
if((user_loc != target_loc || target_loc != user) && !drifting && stayStill)
. = FALSE
break

if(target && !(target in user.do_afters))
if(target && (user != target) && \
(QDELETED(target) \
|| (!(timed_action_flags & IGNORE_TARGET_LOC_CHANGE) && target.loc != target_loc)))
. = FALSE
break

if(needhand)
//This might seem like an odd check, but you can still need a hand even when it's empty
//i.e the hand is used to pull some item/tool out of the construction
if(!holdingnull)
if(!holding)
. = FALSE
break
if(user.get_active_held_item() != holding)
. = FALSE
break
if (progress)
qdel(progbar)

if(!QDELETED(target))
LAZYREMOVE(user.do_afters, target)
LAZYREMOVE(target.targeted_by, user)
if(!QDELETED(progbar))
progbar.end_progress()

/mob/proc/do_after_coefficent() // This gets added to the delay on a do_after, default 1
. = 1
return

/proc/do_after_mob(mob/user, list/targets, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks, required_mobility_flags = MOBILITY_STAND)
if(!user || !targets)
return 0
if(!islist(targets))
targets = list(targets)
var/user_loc = user.loc
if(interaction_key)
LAZYREMOVE(user.do_afters, interaction_key)
SEND_SIGNAL(user, COMSIG_DO_AFTER_ENDED)

var/drifting = 0
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = 1

var/list/originalloc = list()
for(var/atom/target in targets)
originalloc[target] = target.loc

var/holding = user.get_active_held_item()
time = ((time + user.action_speed_adjust) * user.action_speed_modifier) //yogs: darkspawn
var/datum/progressbar/progbar
if(progress)
progbar = new(user, time, targets[1])

var/endtime = world.time + time
var/starttime = world.time
var/mob/living/L
if(isliving(user))
L = user
/mob/proc/do_after_coefficent() // This gets added to the delay on a do_after, default 1
. = 1
mainloop:
while(world.time < endtime)
stoplag(1)
if(progress)
progbar.update(world.time - starttime)
if(QDELETED(user) || !targets)
. = 0
break
if(uninterruptible)
continue

if(drifting && !user.inertia_dir)
drifting = 0
user_loc = user.loc

if(L && !CHECK_MULTIPLE_BITFIELDS(L.mobility_flags, required_mobility_flags))
. = 0
break

for(var/atom/target in targets)
if((!drifting && user_loc != user.loc) || QDELETED(target) || originalloc[target] != target.loc || user.get_active_held_item() != holding || user.incapacitated() || (extra_checks && !extra_checks.Invoke()))
. = 0
break mainloop
if(progbar)
qdel(progbar)

/proc/is_species(A, species_datum)
. = FALSE
Expand Down
38 changes: 0 additions & 38 deletions code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -1290,44 +1290,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
temp = ((temp + (temp>>3))&29127) % 63 //070707
return temp

//same as do_mob except for movables and it allows both to drift and doesn't draw progressbar
/proc/do_atom(atom/movable/user , atom/movable/target, time = 30, uninterruptible = 0,datum/callback/extra_checks = null)
if(!user || !target)
return TRUE
var/user_loc = user.loc

var/drifting = FALSE
if(!user.Process_Spacemove(0) && user.inertia_dir)
drifting = TRUE

var/target_drifting = FALSE
if(!target.Process_Spacemove(0) && target.inertia_dir)
target_drifting = TRUE

var/target_loc = target.loc

var/endtime = world.time+time
. = TRUE
while (world.time < endtime)
stoplag(1)
if(QDELETED(user) || QDELETED(target))
. = 0
break
if(uninterruptible)
continue

if(drifting && !user.inertia_dir)
drifting = FALSE
user_loc = user.loc

if(target_drifting && !target.inertia_dir)
target_drifting = FALSE
target_loc = target.loc

if((!drifting && user.loc != user_loc) || (!target_drifting && target.loc != target_loc) || (extra_checks && !extra_checks.Invoke()))
. = FALSE
break

// \ref behaviour got changed in 512 so this is necesary to replicate old behaviour.
// If it ever becomes necesary to get a more performant REF(), this lies here in wait
// #define REF(thing) (thing && istype(thing, /datum) && (thing:datum_flags & DF_USE_TAG) && thing:tag ? "[thing:tag]" : "\ref[thing]")
Expand Down
3 changes: 0 additions & 3 deletions code/_onclick/hud/alert.dm
Original file line number Diff line number Diff line change
Expand Up @@ -716,9 +716,6 @@ so as to remain in compliance with the most up-to-date laws."
mymob?.client?.screen |= alert
return 1

/mob
var/list/alerts = list() // contains /atom/movable/screen/alert only // On /mob so clientless mobs will throw alerts properly

/atom/movable/screen/alert/Click(location, control, params)
if(!usr || !usr.client)
return
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/item_attack.dm
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
if(butchering && butchering.butchering_enabled)
to_chat(user, span_notice("You begin to butcher [src]..."))
playsound(loc, butchering.butcher_sound, 50, TRUE, -1)
if(do_mob(user, src, butchering.speed) && Adjacent(I))
if(do_after(user, butchering.speed, src) && Adjacent(I))
butchering.Butcher(user, src)
return TRUE
else if(I.is_sharp() && !butchering) //give sharp objects butchering functionality, for consistency
Expand Down
2 changes: 1 addition & 1 deletion code/datums/components/chasm.dm
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@
if(!HAS_TRAIT(rod, TRAIT_WIELDED))
to_chat(user, span_warning("You need to wield the rod in both hands before you can fish in the chasm!"))
return
if(do_after(user, 3 SECONDS, src.parent))
if(do_after(user, 3 SECONDS, parent))
if(!HAS_TRAIT(rod, TRAIT_WIELDED))
return

Expand Down
Loading