Merge pull request #14482 from silicons/combat_v7
Combat v7 - Sprint removal, automatic block/parry, turns combat mode into a pure UI/interaction toggle with no side effects, and a truckload of other stuff.
This commit is contained in:
+26
-21
@@ -1,23 +1,24 @@
|
||||
/**
|
||||
* Higher overhead "advanced" version of do_after.
|
||||
* @params
|
||||
* - atom/user is the atom doing the action or the "physical" user
|
||||
* - delay is time in deciseconds
|
||||
* - atom/target is the atom the action is being done to, defaults to user
|
||||
* - do_after_flags see __DEFINES/flags/do_after.dm for details.
|
||||
* - datum/callback/extra_checks - Every time this ticks, extra_checks() is invoked with (user, delay, target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool).
|
||||
* Stage can be DO_AFTER_STARTING, DO_AFTER_PROGRESSING, DO_AFTER_FINISHING
|
||||
* If it returns DO_AFTER_STOP, this breaks.
|
||||
* If it returns nothing, all other checks are done.
|
||||
* If it returns DO_AFTER_PROCEED, all other checks are ignored.
|
||||
* - required_mobility_flags is checked with CHECK_ALL_MOBILITY. Will immediately fail if the user isn't a mob.
|
||||
* - requried_combat_flags is checked with CHECK_MULTIPLE_BITFIELDS. Will immediately fail if the user isn't a mob.
|
||||
* - mob/living/mob_redirect - advanced option: If this is specified, movement and mobility/combat flag checks will use this instead of user. Progressbars will also go to this.
|
||||
* - obj/item/tool - The tool we're using. See do_after flags for details.
|
||||
*/
|
||||
#define INVOKE_CALLBACK cb_return = extra_checks?.Invoke(user, delay, target, world.time - starttime, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool)
|
||||
* Higher overhead "advanced" version of do_after.
|
||||
* @params
|
||||
* - atom/user is the atom doing the action or the "physical" user
|
||||
* - delay is time in deciseconds
|
||||
* - atom/target is the atom the action is being done to, defaults to user
|
||||
* - do_after_flags see __DEFINES/flags/do_after.dm for details.
|
||||
* - datum/callback/extra_checks - Every time this ticks, extra_checks() is invoked with (user, delay, target, time_left, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, passed_in).
|
||||
* Stage can be DO_AFTER_STARTING, DO_AFTER_PROGRESSING, DO_AFTER_FINISHING
|
||||
* If it returns DO_AFTER_STOP, this breaks.
|
||||
* If it returns nothing, all other checks are done.
|
||||
* If it returns DO_AFTER_PROCEED, all other checks are ignored.
|
||||
* passed_in is a list[PROGRESS_MULTIPLIER], for modification.
|
||||
* - required_mobility_flags is checked with CHECK_ALL_MOBILITY. Will immediately fail if the user isn't a mob.
|
||||
* - requried_combat_flags is checked with CHECK_MULTIPLE_BITFIELDS. Will immediately fail if the user isn't a mob.
|
||||
* - mob/living/mob_redirect - advanced option: If this is specified, movement and mobility/combat flag checks will use this instead of user. Progressbars will also go to this.
|
||||
* - obj/item/tool - The tool we're using. See do_after flags for details.
|
||||
*/
|
||||
#define INVOKE_CALLBACK cb_return = extra_checks?.Invoke(user, delay, target, timeleft, do_after_flags, required_mobility_flags, required_combat_flags, mob_redirect, stage, initially_held_item, tool, passed_in)
|
||||
#define CHECK_FLAG_FAILURE ((required_mobility_flags || required_combat_flags) && (!living_user || (required_mobility_flags && !CHECK_ALL_MOBILITY(living_user, required_mobility_flags)) || (required_combat_flags && !CHECK_MULTIPLE_BITFIELDS(living_user.combat_flags, required_combat_flags))))
|
||||
#define TIMELEFT (world.time - starttime)
|
||||
#define TIMELEFT (timeleft)
|
||||
/proc/do_after_advanced(atom/user, delay, atom/target, do_after_flags, datum/callback/extra_checks, required_mobility_flags, required_combat_flags, mob/living/mob_redirect, obj/item/tool)
|
||||
// CHECK AND SET VARIABLES
|
||||
if(!user)
|
||||
@@ -40,8 +41,7 @@
|
||||
return FALSE
|
||||
if(!(do_after_flags & DO_AFTER_NO_COEFFICIENT) && living_user)
|
||||
delay *= living_user.cached_multiplicative_actions_slowdown
|
||||
var/starttime = world.time
|
||||
var/endtime = world.time + delay
|
||||
var/timeleft = delay
|
||||
var/obj/item/initially_held_item = mob_redirect?.get_active_held_item()
|
||||
var/atom/movable/AM_user = ismovable(user) && user
|
||||
var/drifting = AM_user?.Process_Spacemove(NONE) && AM_user.inertia_dir
|
||||
@@ -51,6 +51,7 @@
|
||||
var/dy = initial_dy
|
||||
// DO OUR STARTING CHECKS
|
||||
var/cb_return
|
||||
var/list/passed_in = list(1)
|
||||
INVOKE_CALLBACK
|
||||
if(cb_return == DO_AFTER_STOP)
|
||||
return FALSE
|
||||
@@ -70,13 +71,17 @@
|
||||
var/locchanged
|
||||
var/ctu
|
||||
var/ctt
|
||||
while(world.time < endtime)
|
||||
var/tick_time = world.time
|
||||
while(timeleft > 0)
|
||||
stoplag(1)
|
||||
var/timepassed = world.time - tick_time
|
||||
timepassed = world.time
|
||||
progbar?.update(TIMELEFT)
|
||||
if(QDELETED(user) || QDELETED(target) || (user.loc == null) || (target.loc == null))
|
||||
. = FALSE
|
||||
break
|
||||
INVOKE_CALLBACK
|
||||
timeleft -= timepassed * passed_in[1]
|
||||
if(cb_return == DO_AFTER_STOP)
|
||||
. = FALSE
|
||||
break
|
||||
|
||||
@@ -270,6 +270,20 @@
|
||||
SEND_SIGNAL(A, COMSIG_ATOM_HEARER_IN_VIEW, processing, .)
|
||||
processing += A.contents
|
||||
|
||||
/proc/get_hearers_in_range(R, atom/source)
|
||||
var/turf/T = get_turf(source)
|
||||
. = list()
|
||||
if(!T)
|
||||
return
|
||||
var/list/processing = range(R, source)
|
||||
var/i = 0
|
||||
while(i < length(processing))
|
||||
var/atom/A = processing[++i]
|
||||
if(A.flags_1 & HEAR_1)
|
||||
. += A
|
||||
SEND_SIGNAL(A, COMSIG_ATOM_HEARER_IN_VIEW, processing, .)
|
||||
processing += A.contents
|
||||
|
||||
//viewers() but with a signal, for blacklisting.
|
||||
/proc/fov_viewers(depth = world.view, atom/center)
|
||||
if(!center)
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
/datum/yelling_wavefill
|
||||
var/stop = FALSE
|
||||
var/list/atom/collected
|
||||
|
||||
/datum/yelling_wavefill/Destroy(force, ...)
|
||||
stop = TRUE
|
||||
collected = null // don't cut it, something else is probably using it now!
|
||||
return ..()
|
||||
|
||||
/datum/yelling_wavefill/proc/run_wavefill(atom/source, dist = 50)
|
||||
collected = list()
|
||||
do_run(source, dist)
|
||||
// to_chat(world, "DEBUG: collected [english_list(collected)]")
|
||||
|
||||
// blatantly copied from wave explosion code
|
||||
// check explosion2.dm for what this does and how it works.
|
||||
/datum/yelling_wavefill/proc/do_run(atom/source, dist)
|
||||
source = get_turf(source)
|
||||
var/list/edges = list()
|
||||
edges[source] = (NORTH|SOUTH|EAST|WEST)
|
||||
collected += typecache_filter_list(source.contents, GLOB.typecache_living)
|
||||
var/list/powers = list()
|
||||
powers[source] = dist
|
||||
var/list/processed = list()
|
||||
var/turf/T
|
||||
var/turf/expanding
|
||||
var/power
|
||||
var/dir
|
||||
var/returned
|
||||
#define RUN_YELL(_T, _P, _D) \
|
||||
returned = max(_P - max(_T.get_yelling_resistance(_P), 0) - 1, 0); \
|
||||
processed[_T] = returned;
|
||||
// _T.maptext = "[returned]";
|
||||
|
||||
var/list/turf/edges_next
|
||||
var/list/turf/powers_next
|
||||
var/list/turf/powers_returned
|
||||
var/list/turf/diagonals
|
||||
var/list/turf/diagonal_powers
|
||||
var/list/turf/diagonal_powers_max
|
||||
var/safety = 1000
|
||||
|
||||
#define CALCULATE_DIAGONAL_POWER(existing, adding, maximum) min(maximum, existing + adding)
|
||||
#define CALCULATE_DIAGONAL_CROSS_POWER(existing, adding) max(existing, adding)
|
||||
#define CARDINAL_MARK(ndir, cdir, edir) \
|
||||
if(edir & cdir) { \
|
||||
expanding = get_step(T,ndir); \
|
||||
if(expanding && (isnull(processed[expanding]) || (processed[expanding] < (power - 3)))) { \
|
||||
powers_next[expanding] = max(powers_next[expanding], returned); \
|
||||
edges_next[expanding] = (cdir | edges_next[expanding]); \
|
||||
}; \
|
||||
};
|
||||
|
||||
#define DIAGONAL_SUBSTEP(ndir, cdir, edir) \
|
||||
expanding = get_step(T,ndir); \
|
||||
if(expanding && (isnull(processed[expanding]) || (processed[expanding] < (power - 3)))) { \
|
||||
if(!edges_next[expanding]) { \
|
||||
diagonal_powers_max[expanding] = max(diagonal_powers_max[expanding], returned, powers[T]); \
|
||||
diagonal_powers[expanding] = CALCULATE_DIAGONAL_POWER(diagonal_powers[expanding], returned, diagonal_powers_max[expanding]); \
|
||||
diagonals[expanding] = (cdir | diagonals[expanding]); \
|
||||
}; \
|
||||
else { \
|
||||
powers_next[expanding] = CALCULATE_DIAGONAL_CROSS_POWER(powers_next[expanding], returned); \
|
||||
}; \
|
||||
};
|
||||
|
||||
#define DIAGONAL_MARK(ndir, cdir, edir) \
|
||||
if(edir & cdir) { \
|
||||
DIAGONAL_SUBSTEP(turn(ndir, 90), turn(cdir, 90), edir); \
|
||||
DIAGONAL_SUBSTEP(turn(ndir, -90), turn(cdir, -90), edir); \
|
||||
};
|
||||
|
||||
while(edges.len)
|
||||
edges_next = list()
|
||||
powers_next = list()
|
||||
powers_returned = list()
|
||||
diagonals = list()
|
||||
diagonal_powers = list()
|
||||
diagonal_powers_max = list()
|
||||
// to_chat(world, "DEBUG: cycle start edges [english_list_assoc(edges)]")
|
||||
|
||||
// process cardinals
|
||||
for(var/i in edges)
|
||||
T = i
|
||||
power = powers[T]
|
||||
dir = edges[T]
|
||||
RUN_YELL(T, power, dir)
|
||||
powers_returned[T] = returned
|
||||
if(returned >= 1)
|
||||
collected |= typecache_filter_list(T.contents, GLOB.typecache_living)
|
||||
else
|
||||
continue
|
||||
|
||||
CARDINAL_MARK(NORTH, NORTH, dir)
|
||||
CARDINAL_MARK(SOUTH, SOUTH, dir)
|
||||
CARDINAL_MARK(EAST, EAST, dir)
|
||||
CARDINAL_MARK(WEST, WEST, dir)
|
||||
|
||||
// to_chat(world, "DEBUG: cycle mid edges_next [english_list_assoc(edges_next)]")
|
||||
|
||||
// Sweep after cardinals for diagonals
|
||||
for(var/i in edges)
|
||||
T = i
|
||||
power = powers[T]
|
||||
dir = edges[T]
|
||||
returned = powers_returned[T]
|
||||
DIAGONAL_MARK(NORTH, NORTH, dir)
|
||||
DIAGONAL_MARK(SOUTH, SOUTH, dir)
|
||||
DIAGONAL_MARK(EAST, EAST, dir)
|
||||
DIAGONAL_MARK(WEST, WEST, dir)
|
||||
|
||||
// to_chat(world, "DEBUG: cycle mid diagonals [english_list_assoc(diagonals)]")
|
||||
|
||||
// Process diagonals:
|
||||
for(var/i in diagonals)
|
||||
T = i
|
||||
power = diagonal_powers[T]
|
||||
dir = diagonals[T]
|
||||
RUN_YELL(T, power, dir)
|
||||
if(returned >= 1)
|
||||
collected |= typecache_filter_list(T.contents, GLOB.typecache_living)
|
||||
else
|
||||
continue
|
||||
CARDINAL_MARK(NORTH, NORTH, dir)
|
||||
CARDINAL_MARK(SOUTH, SOUTH, dir)
|
||||
CARDINAL_MARK(EAST, EAST, dir)
|
||||
CARDINAL_MARK(WEST, WEST, dir)
|
||||
|
||||
// to_chat(world, "DEBUG: cycle end edges_next [english_list_assoc(edges_next)]")
|
||||
|
||||
// flush lists
|
||||
edges = edges_next
|
||||
powers = powers_next
|
||||
|
||||
// sleep(2.5)
|
||||
if(!--safety)
|
||||
CRASH("Yelling ran out of safety.")
|
||||
|
||||
#undef RUN_YELL
|
||||
#undef DIAGONAL_SUBSTEP
|
||||
#undef CALCULATE_DIAGONAL_POWER
|
||||
#undef CALCULATE_DIAGONAL_CROSS_POWER
|
||||
#undef DIAGONAL_MARK
|
||||
#undef CARDINAL_MARK
|
||||
|
||||
/proc/yelling_wavefill(atom/source, dist = 50)
|
||||
var/datum/yelling_wavefill/Y = new
|
||||
Y.run_wavefill(source, dist)
|
||||
. = Y.collected
|
||||
qdel(Y)
|
||||
Reference in New Issue
Block a user