Skip to content

Commit d26ce21

Browse files
authored
Refactor do_after() into a datum. (#1149)
* refactor do_after into a datum * remove shitcode * Wake up github * subsystemize * i may be tarded
1 parent 8205d94 commit d26ce21

File tree

9 files changed

+262
-196
lines changed

9 files changed

+262
-196
lines changed

code/__DEFINES/flags.dm

+3-1
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,10 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
291291
#define IGNORE_INCAPACITATED (1<<3)
292292
/// Used to prevent important slowdowns from being abused by drugs like kronkaine
293293
#define IGNORE_SLOWDOWNS (1<<4)
294+
/// If the user has their next_move value changed (usually by clicking), fail.
295+
#define DO_RESTRICT_CLICKING (1<<5)
294296
/// Shown to all mobs not just the user
295-
#define DO_PUBLIC (1<<5)
297+
#define DO_PUBLIC (1<<6)
296298

297299

298300

code/__DEFINES/subsystems.dm

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@
192192
#define FIRE_PRIORITY_CHAT 400
193193
#define FIRE_PRIORITY_SPEECH_CONTROLLER 300
194194
#define FIRE_PRIORITY_RUNECHAT 250
195+
#define FIRE_PRIORITY_DO_AFTERS 100
195196
#define FIRE_PRIORITY_THROWING 20
196197
/* DEFAULT WOULD BE HERE */
197198
#define FIRE_PRIORITY_SPACEDRIFT 15

code/__HELPERS/mobs.dm

-191
Original file line numberDiff line numberDiff line change
@@ -245,197 +245,6 @@ GLOBAL_LIST_EMPTY(species_list)
245245
else
246246
return "unknown"
247247

248-
//some additional checks as a callback for for do_afters that want to break on losing health or on the mob taking action
249-
/mob/proc/break_do_after_checks(list/checked_health, check_clicks)
250-
if(check_clicks && next_move > world.time)
251-
return FALSE
252-
return TRUE
253-
254-
//pass a list in the format list("health" = mob's health var) to check health during this
255-
/mob/living/break_do_after_checks(list/checked_health, check_clicks)
256-
if(islist(checked_health))
257-
if(health < checked_health["health"])
258-
return FALSE
259-
checked_health["health"] = health
260-
return ..()
261-
262-
263-
/**
264-
* Timed action involving one mob user. Target is optional, defaulting to user.
265-
*
266-
* Checks that `user` does not move, change hands, get stunned, etc. for the
267-
* given `time`. Returns `TRUE` on success or `FALSE` on failure.
268-
* 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.
269-
*/
270-
/proc/do_after(atom/movable/user, atom/target, time, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, image/display)
271-
if(!user)
272-
return FALSE
273-
274-
if(!target)
275-
target = user
276-
if(isnum(target))
277-
CRASH("a do_after created by [user] had a target set as [target]- probably intended to be the time instead.")
278-
if(isatom(time))
279-
CRASH("a do_after created by [user] had a timer of [time]- probably intended to be the target instead.")
280-
281-
if(!interaction_key)
282-
interaction_key = target //Use the direct ref to the target
283-
if(interaction_key) //Do we have a interaction_key now?
284-
var/current_interaction_count = LAZYACCESS(user.do_afters, interaction_key) || 0
285-
if(current_interaction_count >= max_interact_count) //We are at our peak
286-
return
287-
LAZYSET(user.do_afters, interaction_key, current_interaction_count + 1)
288-
289-
var/atom/user_loc = user.loc
290-
var/atom/target_loc = target.loc
291-
292-
var/drifting = FALSE
293-
if(SSmove_manager.processing_on(user, SSspacedrift))
294-
drifting = TRUE
295-
296-
var/holding
297-
if(ismob(user))
298-
var/mob/mobuser = user
299-
holding = mobuser.get_active_held_item()
300-
if(!(timed_action_flags & IGNORE_SLOWDOWNS))
301-
time *= mobuser.cached_multiplicative_actions_slowdown
302-
else
303-
timed_action_flags |= IGNORE_HELD_ITEM|IGNORE_INCAPACITATED|IGNORE_SLOWDOWNS|DO_PUBLIC
304-
305-
var/datum/progressbar/progbar
306-
if(progress)
307-
if(timed_action_flags & DO_PUBLIC)
308-
progbar = new /datum/world_progressbar(user, time, display)
309-
else
310-
progbar = new(user, time, target || user)
311-
312-
var/endtime = world.time + time
313-
var/starttime = world.time
314-
. = TRUE
315-
while (world.time < endtime)
316-
stoplag(1)
317-
318-
if(!QDELETED(progbar))
319-
progbar.update(world.time - starttime)
320-
321-
if(drifting && !SSmove_manager.processing_on(user, SSspacedrift))
322-
drifting = FALSE
323-
user_loc = user.loc
324-
325-
if(
326-
QDELETED(user) \
327-
|| (!(timed_action_flags & IGNORE_USER_LOC_CHANGE) && !drifting && user.loc != user_loc) \
328-
|| (!(timed_action_flags & IGNORE_HELD_ITEM) && user:get_active_held_item() != holding) \
329-
|| (!(timed_action_flags & IGNORE_INCAPACITATED) && HAS_TRAIT(user, TRAIT_INCAPACITATED)) \
330-
|| (extra_checks && !extra_checks.Invoke()) \
331-
)
332-
. = FALSE
333-
break
334-
335-
if(user != target && \
336-
(QDELETED(target) || (!(timed_action_flags & IGNORE_TARGET_LOC_CHANGE) && target.loc != target_loc)))
337-
. = FALSE
338-
break
339-
340-
if(!QDELETED(progbar))
341-
progbar.end_progress()
342-
343-
if(interaction_key)
344-
var/reduced_interaction_count = (LAZYACCESS(user.do_afters, interaction_key)) - 1
345-
if(reduced_interaction_count > 0) // Not done yet!
346-
LAZYSET(user.do_afters, interaction_key, reduced_interaction_count)
347-
return
348-
LAZYREMOVE(user.do_afters, interaction_key)
349-
350-
351-
///Timed action involving at least one mob user and a list of targets. interaction_key is the assoc key under which the do_after is capped under, and the max interaction count is how many of this interaction you can do at once.
352-
/proc/do_after_mob(mob/user, list/targets, time = 3 SECONDS, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1)
353-
if(!user)
354-
return FALSE
355-
if(!islist(targets))
356-
targets = list(targets)
357-
if(!length(targets))
358-
return FALSE
359-
var/user_loc = user.loc
360-
361-
if(!(timed_action_flags & IGNORE_SLOWDOWNS))
362-
time *= user.cached_multiplicative_actions_slowdown
363-
364-
var/drifting = FALSE
365-
if(SSmove_manager.processing_on(user, SSspacedrift))
366-
drifting = TRUE
367-
368-
var/list/originalloc = list()
369-
370-
for(var/atom/target in targets)
371-
originalloc[target] = target.loc
372-
373-
if(interaction_key)
374-
var/current_interaction_count = LAZYACCESS(user.do_afters, interaction_key) || 0
375-
if(current_interaction_count >= max_interact_count) //We are at our peak
376-
to_chat(user, span_warning("You can't do this at the moment!"))
377-
return
378-
LAZYSET(user.do_afters, interaction_key, current_interaction_count + 1)
379-
380-
381-
var/holding = user.get_active_held_item()
382-
var/datum/progressbar/progbar
383-
if(progress)
384-
progbar = new(user, time, targets[1])
385-
386-
var/endtime = world.time + time
387-
var/starttime = world.time
388-
. = TRUE
389-
while(world.time < endtime)
390-
stoplag(1)
391-
392-
if(!QDELETED(progbar))
393-
progbar.update(world.time - starttime)
394-
if(QDELETED(user) || !length(targets))
395-
. = FALSE
396-
break
397-
398-
if(drifting && !SSmove_manager.processing_on(user, SSspacedrift))
399-
drifting = FALSE
400-
user_loc = user.loc
401-
402-
if(
403-
(!(timed_action_flags & IGNORE_USER_LOC_CHANGE) && !drifting && user_loc != user.loc) \
404-
|| (!(timed_action_flags & IGNORE_HELD_ITEM) && user.get_active_held_item() != holding) \
405-
|| (!(timed_action_flags & IGNORE_INCAPACITATED) && HAS_TRAIT(user, TRAIT_INCAPACITATED)) \
406-
|| (extra_checks && !extra_checks.Invoke()) \
407-
)
408-
. = FALSE
409-
break
410-
411-
for(var/atom/target as anything in targets)
412-
if(
413-
(QDELETED(target)) \
414-
|| (!(timed_action_flags & IGNORE_TARGET_LOC_CHANGE) && originalloc[target] != target.loc) \
415-
)
416-
. = FALSE
417-
break
418-
419-
if(!.) // In case the for-loop found a reason to break out of the while.
420-
break
421-
422-
if(!QDELETED(progbar))
423-
progbar.end_progress()
424-
425-
if(interaction_key)
426-
var/reduced_interaction_count = (LAZYACCESS(user.do_afters, interaction_key)) - 1
427-
if(reduced_interaction_count > 0) // Not done yet!
428-
LAZYSET(user.do_afters, interaction_key, reduced_interaction_count)
429-
return
430-
LAZYREMOVE(user.do_afters, interaction_key)
431-
432-
/// Returns the total amount of do_afters this mob is taking part in
433-
/mob/proc/do_after_count()
434-
var/count = 0
435-
for(var/key in do_afters)
436-
count += do_afters[key]
437-
return count
438-
439248
/proc/is_species(A, species_datum)
440249
. = FALSE
441250
if(ishuman(A))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
PROCESSING_SUBSYSTEM_DEF(timed_action)
2+
name = "Timed Actions"
3+
priority = FIRE_PRIORITY_DO_AFTERS
4+
flags = SS_TICKER|SS_NO_INIT|SS_HIBERNATE
5+
wait = 1

code/game/objects/structures/crates_lockers/closets.dm

+1-1
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ DEFINE_INTERACTABLE(/obj/structure/closet)
512512
span_warning("You [actuallyismob ? "try to ":""]stuff [O] into [src]."), \
513513
span_hear("You hear clanging."))
514514
if(actuallyismob)
515-
if(do_after_mob(user, targets, 40))
515+
if(do_after(user, targets, 40))
516516
user.visible_message(span_notice("[user] stuffs [O] into [src]."), \
517517
span_notice("You stuff [O] into [src]."), \
518518
span_hear("You hear a loud metal bang."))

code/modules/antagonists/cult/rune_spawn_action.dm

+17-3
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,22 @@
5858
cooldown = base_cooldown + world.time
5959
owner?.update_mob_action_buttons()
6060
addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_mob_action_buttons)), base_cooldown)
61-
var/list/health
61+
62+
var/mob_health = null
6263
if(damage_interrupt && isliving(owner))
6364
var/mob/living/L = owner
64-
health = list("health" = L.health)
65+
mob_health = L.health
66+
6567
var/scribe_mod = scribe_time
6668
if(istype(T, /turf/open/floor/engine/cult))
6769
scribe_mod *= 0.5
70+
6871
playsound(T, 'sound/magic/enter_blood.ogg', 100, FALSE)
69-
if(do_after(owner, owner, scribe_mod, extra_checks = CALLBACK(owner, TYPE_PROC_REF(/mob, break_do_after_checks), health, action_interrupt)))
72+
73+
var/flags = action_interrupt ? DO_RESTRICT_CLICKING : NONE
74+
var/datum/callback/cb = mob_health ? CALLBACK(src, PROC_REF(check_health_changed), owner, list(mob_health)) : null
75+
76+
if(do_after(owner, owner, scribe_mod, flags, extra_checks = cb))
7077
new rune_type(owner.loc, chosen_keyword)
7178
else
7279
qdel(R1)
@@ -79,6 +86,13 @@
7986
cooldown = 0
8087
owner?.update_mob_action_buttons()
8188

89+
/datum/action/innate/cult/create_rune/proc/check_health_changed(mob/living/user, list/old_health)
90+
if(user.health < old_health[1])
91+
return FALSE
92+
93+
old_health[1] = user.health
94+
return TRUE
95+
8296
//teleport rune
8397
/datum/action/innate/cult/create_rune/tele
8498
name = "Summon Teleport Rune"

code/modules/do_after/do_after.dm

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Timed action involving one mob user. Target is optional, defaulting to user.
3+
* Returns TRUE if the action succeeded and was not interrupted.
4+
*
5+
* Args:
6+
* * user: The one performing the action.
7+
* * target: An atom or list of atoms to perform the action on. If null, defaults to user.
8+
* * timed_action_flags: A bitfield defining the behavior of the action.
9+
* * progress: Boolean value, if TRUE, show a progress bar over the target's head.
10+
* * extra_checks: An optional callback to check in addition to the default checks.
11+
* * interaction_key: An optional non-numeric value to disamibiguate the action, to be used with DOING_INTERACTION() macros. Defaults to target.
12+
* * max_interact_count: The action will automatically fail if they are already performing this many or more actions with the given interaction_key.
13+
* * display: An atom or image to display over the user's head. Only works with DO_PUBLIC flag.
14+
*/
15+
/proc/do_after(atom/movable/user, atom/target, time, timed_action_flags = NONE, progress = TRUE, datum/callback/extra_checks, interaction_key, max_interact_count = 1, image/display)
16+
if(!user)
17+
return FALSE
18+
19+
if(time == 0)
20+
return TRUE
21+
22+
if(!target)
23+
target = user
24+
25+
if(isnum(target))
26+
CRASH("a do_after created by [user] had a target set as [target]- probably intended to be the time instead.")
27+
if(isatom(time))
28+
CRASH("a do_after created by [user] had a timer of [time]- probably intended to be the target instead.")
29+
30+
if(!interaction_key)
31+
if(!islist(target))
32+
interaction_key = target
33+
else
34+
var/list/temp = list()
35+
for(var/atom/atom as anything in target)
36+
temp += ref(atom)
37+
38+
sortTim(temp, GLOBAL_PROC_REF(cmp_text_asc))
39+
interaction_key = jointext(temp, "-")
40+
41+
if(interaction_key) //Do we have a interaction_key now?
42+
var/current_interaction_count = LAZYACCESS(user.do_afters, interaction_key) || 0
43+
if(current_interaction_count >= max_interact_count) //We are at our peak
44+
return
45+
LAZYSET(user.do_afters, interaction_key, current_interaction_count + 1)
46+
47+
var/datum/timed_action/action = new(user, target, time, progress, timed_action_flags, extra_checks, display)
48+
49+
. = action.wait()
50+
51+
if(interaction_key)
52+
var/reduced_interaction_count = (LAZYACCESS(user.do_afters, interaction_key)) - 1
53+
if(reduced_interaction_count > 0) // Not done yet!
54+
LAZYSET(user.do_afters, interaction_key, reduced_interaction_count)
55+
return
56+
LAZYREMOVE(user.do_afters, interaction_key)
57+
58+
59+
/// Returns the total amount of do_afters this mob is taking part in
60+
/mob/proc/do_after_count()
61+
var/count = 0
62+
for(var/key in do_afters)
63+
count += do_afters[key]
64+
return count

0 commit comments

Comments
 (0)