diff --git a/code/datums/spell_targeting/cone.dm b/code/datums/spell_targeting/cone.dm new file mode 100644 index 000000000000..7cc9b7a95610 --- /dev/null +++ b/code/datums/spell_targeting/cone.dm @@ -0,0 +1,74 @@ +/datum/spell_targeting/cone + max_targets = INFINITY + use_intercept_click = TRUE + /// This controls how many levels the cone has. Increase this value to make a bigger cone. + var/cone_levels = 3 + /// This value determines if the cone penetrates walls. + var/respect_density = FALSE + +/datum/spell_targeting/cone/choose_targets(mob/user, datum/spell/spell, params, atom/clicked_atom) + var/list/turfs_to_return = list() + var/turf/turf_to_use = get_turf(user) + var/turf/left_turf + var/turf/right_turf + var/dir_to_use = get_dir(user, clicked_atom) + var/right_dir + var/left_dir + switch(dir_to_use) + if(NORTH) + left_dir = WEST + right_dir = EAST + if(SOUTH) + left_dir = EAST + right_dir = WEST + if(EAST) + left_dir = NORTH + right_dir = SOUTH + if(WEST) + left_dir = SOUTH + right_dir = NORTH + + // Go though every level of the cone levels and generate the cone. + for(var/level in 1 to cone_levels) + var/list/level_turfs = list() + // Our center turf always exists, it's straight ahead of the caster. + turf_to_use = get_step(turf_to_use, dir_to_use) + level_turfs += turf_to_use + // Level 1 only ever has 1 turf, it's a cone. + if(level != 1) + var/level_width_in_each_direction = round((calculate_cone_shape(level) - 1) / 2) + left_turf = turf_to_use + right_turf = turf_to_use + // Check turfs to the left... + for(var/left_of_center in 1 to level_width_in_each_direction) + if(respect_density && left_turf.density) + break + left_turf = get_step(left_turf, left_dir) + level_turfs += left_turf + // And turfs to the right. + for(var/right_of_enter in 1 to level_width_in_each_direction) + if(respect_density && right_turf.density) + break + right_turf = get_step(right_turf, right_dir) + level_turfs += right_turf + // Add the list of all turfs on this level to the turfs to return + turfs_to_return += list(level_turfs) + + // If we're at the last level, we're done + if(level == cone_levels) + break + // But if we're not at the last level, we should check that we can keep going + if(respect_density && turf_to_use.density) + break + + return turfs_to_return + +/** + * Adjusts the width of the cone at the passed level. + * This is never called on the first level of the cone (level 1 is always 1 width) + * + * Return a number - the TOTAL width of the cone at the passed level. + */ +/datum/spell_targeting/cone/proc/calculate_cone_shape(current_level) + // Default formula: (1 (innate) -> 3 -> 5 -> 5 -> 7 -> 7 -> 9 -> 9 -> ...) + return current_level + (current_level % 2) + 1 diff --git a/code/datums/spells/cones/cone_spell.dm b/code/datums/spells/cones/cone_spell.dm new file mode 100644 index 000000000000..11b249c9f0d3 --- /dev/null +++ b/code/datums/spells/cones/cone_spell.dm @@ -0,0 +1,45 @@ +/datum/spell/cone + + +/datum/spell/cone/create_new_targeting() + return new /datum/spell_targeting/cone + +/datum/spell/cone/cast(list/targets, mob/user) + var/level_counter = 1 + for(var/list/turf_list in targets) + do_cone_effects(turf_list, user, level_counter) + level_counter++ + +/datum/spell/cone/proc/do_cone_effects(list/targets, mob/user, level) + for(var/turf/target_turf as anything in targets) + if(QDELETED(target_turf)) //if turf is no longer there + continue + + do_turf_cone_effect(target_turf, user, level) + if(iswallturf(target_turf)) + continue + + for(var/atom/movable/movable_content as anything in target_turf) + if(isobj(movable_content)) + do_obj_cone_effect(movable_content, user, level) + else if(isliving(movable_content)) + do_mob_cone_effect(movable_content, user, level) + +/datum/spell/cone/proc/do_turf_cone_effect(turf/target_turf, mob/caster, level) + return + +/datum/spell/cone/proc/do_obj_cone_effect(obj/target_obj, mob/caster, level) + return + +/datum/spell/cone/proc/do_mob_cone_effect(mob/target_mob, mob/caster, level) + return + +/datum/spell/cone/staggered + /// The delay between each cone level triggering. + var/delay_between_level = 0.2 SECONDS + +/datum/spell/cone/staggered/cast(list/targets, mob/user) + var/level_counter = 0 + for(var/list/turf_list in targets) + level_counter++ + addtimer(CALLBACK(src, PROC_REF(do_cone_effects), turf_list, user, level_counter), delay_between_level * level_counter) diff --git a/code/datums/spell.dm b/code/datums/spells/spell_base.dm similarity index 100% rename from code/datums/spell.dm rename to code/datums/spells/spell_base.dm diff --git a/code/modules/mob/dead/observer/spells.dm b/code/modules/mob/dead/observer/observer_spells.dm similarity index 100% rename from code/modules/mob/dead/observer/spells.dm rename to code/modules/mob/dead/observer/observer_spells.dm diff --git a/paradise.dme b/paradise.dme index 90e5468b4264..faabc0767d37 100644 --- a/paradise.dme +++ b/paradise.dme @@ -418,7 +418,6 @@ #include "code\datums\ruins.dm" #include "code\datums\shuttles.dm" #include "code\datums\spawners_menu.dm" -#include "code\datums\spell.dm" #include "code\datums\station_state.dm" #include "code\datums\tgs_event_handler.dm" #include "code\datums\verb_callbacks.dm" @@ -593,6 +592,7 @@ #include "code\datums\spell_targeting\aoe.dm" #include "code\datums\spell_targeting\click_spell_targeting.dm" #include "code\datums\spell_targeting\clicked_atom.dm" +#include "code\datums\spell_targeting\cone.dm" #include "code\datums\spell_targeting\matter_eater_targeting.dm" #include "code\datums\spell_targeting\reachable_turfs.dm" #include "code\datums\spell_targeting\remoteview_targeting.dm" @@ -635,6 +635,7 @@ #include "code\datums\spells\sentient_sword_lunge.dm" #include "code\datums\spells\shapeshift.dm" #include "code\datums\spells\spacetime_dist.dm" +#include "code\datums\spells\spell_base.dm" #include "code\datums\spells\summon_supermatter.dm" #include "code\datums\spells\summonitem.dm" #include "code\datums\spells\touch_attacks.dm" @@ -653,6 +654,7 @@ #include "code\datums\spells\alien_spells\tail_lash.dm" #include "code\datums\spells\alien_spells\transfer_plasma.dm" #include "code\datums\spells\alien_spells\whisper.dm" +#include "code\datums\spells\cones\cone_spell.dm" #include "code\datums\station_traits\_station_trait.dm" #include "code\datums\station_traits\admin_panel.dm" #include "code\datums\station_traits\negative_traits.dm" @@ -2217,8 +2219,8 @@ #include "code\modules\mob\dead\observer\observer_login.dm" #include "code\modules\mob\dead\observer\observer_logout.dm" #include "code\modules\mob\dead\observer\observer_say.dm" +#include "code\modules\mob\dead\observer\observer_spells.dm" #include "code\modules\mob\dead\observer\orbit.dm" -#include "code\modules\mob\dead\observer\spells.dm" #include "code\modules\mob\living\autohiss.dm" #include "code\modules\mob\living\damage_procs.dm" #include "code\modules\mob\living\death.dm"