diff --git a/data/schema/units/abilities.cfg b/data/schema/units/abilities.cfg
index 785e03c4d3a..7caf6fc0a60 100644
--- a/data/schema/units/abilities.cfg
+++ b/data/schema/units/abilities.cfg
@@ -5,6 +5,8 @@
 		max=infinite
 		super="units/unit_type/abilities/~generic~,units/unit_type/attack/specials/" + {NAME}
 		{FILTER_TAG "filter_student" unit {FILTER_TAG "filter_weapon" weapon ()}}
+		{FILTER_TAG "filter_adjacent_student" adjacent ()}
+		{FILTER_TAG "filter_adjacent_student_location" adjacent_location ()}
 	[/tag]
 #enddef
 
diff --git a/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_active.cfg b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_active.cfg
new file mode 100644
index 00000000000..2abffc32160
--- /dev/null
+++ b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_active.cfg
@@ -0,0 +1,49 @@
+#textdomain wesnoth-test
+
+#####
+# API(s) being tested: ability[filter_adjacent]adjacent,count=
+##
+# Actions:
+# Give Alice an ability specialX, which is only active if one adjacent unit is bob.
+# Test whether the ability is active.
+##
+# Expected end state:
+# specialX should be active.
+#####
+{COMMON_KEEP_A_B_C_D_UNIT_TEST "filter_adjacent_active" (
+    [event]
+        name=start
+
+        [object]
+            silent=yes
+            [effect]
+                apply_to=new_ability
+                [abilities]
+                    [damage]
+                        id=specialX
+                        name=_ "specialX"
+                        description=_ "specialX is active if and only if one of the adjacents units is bob"
+                        value=100
+                        apply_to=self
+                        [filter_adjacent]
+                            adjacent=n,ne,se,s,sw,nw
+                            count=1-6
+                            id=bob
+                        [/filter_adjacent]
+                    [/damage]
+                [/abilities]
+            [/effect]
+            [filter]
+                id=alice
+            [/filter]
+        [/object]
+
+        {ASSERT (
+            [have_unit]
+                ability_id_active=specialX
+            [/have_unit]
+        )}
+
+        {SUCCEED}
+    [/event]
+)}
diff --git a/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_direction_active.cfg b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_direction_active.cfg
new file mode 100644
index 00000000000..8abdbc096b4
--- /dev/null
+++ b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_direction_active.cfg
@@ -0,0 +1,48 @@
+#textdomain wesnoth-test
+
+#####
+# API(s) being tested: ability[filter_adjacent]adjacent,count=
+##
+# Actions:
+# Give Alice an ability specialX, which is only active if one adjacent unit is bob, and bob is in correct location.
+# Test whether the ability is active.
+##
+# Expected end state:
+# specialX should be active.
+#####
+{COMMON_KEEP_A_B_C_D_UNIT_TEST "filter_adjacent_direction_active" (
+    [event]
+        name=start
+
+        [object]
+            silent=yes
+            [effect]
+                apply_to=new_ability
+                [abilities]
+                    [damage]
+                        id=specialX
+                        name=_ "specialX"
+                        description=_ "specialX is active if and only if one of the adjacents units is bob, and bob is in correct location"
+                        value=100
+                        apply_to=self
+                        [filter_adjacent]
+                            adjacent=se,s,sw
+                            id=bob
+                        [/filter_adjacent]
+                    [/damage]
+                [/abilities]
+            [/effect]
+            [filter]
+                id=alice
+            [/filter]
+        [/object]
+
+        {ASSERT (
+            [have_unit]
+                ability_id_active=specialX
+            [/have_unit]
+        )}
+
+        {SUCCEED}
+    [/event]
+)}
diff --git a/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_direction_inactive.cfg b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_direction_inactive.cfg
new file mode 100644
index 00000000000..c94ba8a1ffe
--- /dev/null
+++ b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_direction_inactive.cfg
@@ -0,0 +1,50 @@
+#textdomain wesnoth-test
+
+#####
+# API(s) being tested: ability[filter_adjacent]adjacent,count=
+##
+# Actions:
+# Give Alice an ability specialX, which is only active if one adjacent unit is bob, and bob is in correct location.
+# Test whether the ability is active.
+##
+# Expected end state:
+# specialX shouldn't be active.
+#####
+{COMMON_KEEP_A_B_C_D_UNIT_TEST "filter_adjacent_direction_inactive" (
+    [event]
+        name=start
+
+        [object]
+            silent=yes
+            [effect]
+                apply_to=new_ability
+                [abilities]
+                    [damage]
+                        id=specialX
+                        name=_ "specialX"
+                        description=_ "specialX is active if and only if one of the adjacents units is bob, and bob is in correct location"
+                        value=100
+                        apply_to=self
+                        [filter_adjacent]
+                            adjacent=n,ne,nw
+                            id=bob
+                        [/filter_adjacent]
+                    [/damage]
+                [/abilities]
+            [/effect]
+            [filter]
+                id=alice
+            [/filter]
+        [/object]
+
+        {ASSERT (
+            [not]
+                [have_unit]
+                    ability_id_active=specialX
+                [/have_unit]
+            [/not]
+        )}
+
+        {SUCCEED}
+    [/event]
+)}
diff --git a/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_inactive.cfg b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_inactive.cfg
new file mode 100644
index 00000000000..ccbbbf5c876
--- /dev/null
+++ b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_inactive.cfg
@@ -0,0 +1,51 @@
+#textdomain wesnoth-test
+
+#####
+# API(s) being tested: ability[filter_adjacent]adjacent,count=
+##
+# Actions:
+# Give Alice an ability specialX, which is only active if one adjacent unit is Loki.
+# Test whether the ability is active.
+##
+# Expected end state:
+# specialX shouldn't be active.
+#####
+{COMMON_KEEP_A_B_C_D_UNIT_TEST "filter_adjacent_inactive" (
+    [event]
+        name=start
+
+        [object]
+            silent=yes
+            [effect]
+                apply_to=new_ability
+                [abilities]
+                    [damage]
+                        id=specialX
+                        name=_ "specialX"
+                        description=_ "specialX is active if and only if one of the adjacents units is Loki"
+                        value=100
+                        apply_to=self
+                        [filter_adjacent]
+                            adjacent=n,ne,se,s,sw,nw
+                            count=1-6
+                            id=Loki
+                        [/filter_adjacent]
+                    [/damage]
+                [/abilities]
+            [/effect]
+            [filter]
+                id=alice
+            [/filter]
+        [/object]
+
+        {ASSERT (
+            [not]
+                [have_unit]
+                    ability_id_active=specialX
+                [/have_unit]
+            [/not]
+        )}
+
+        {SUCCEED}
+    [/event]
+)}
diff --git a/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_location_count_three_active.cfg b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_location_count_three_active.cfg
new file mode 100644
index 00000000000..7e9a753fbd1
--- /dev/null
+++ b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_location_count_three_active.cfg
@@ -0,0 +1,49 @@
+#textdomain wesnoth-test
+
+#####
+# API(s) being tested: ability[filter_adjacent_location]adjacent,count=
+##
+# Actions:
+# Give Alice an ability specialX, which is only active if exactly three of adjacents terrains are Gg.
+# Test whether the ability is active.
+##
+# Expected end state:
+# specialX should be active.
+#####
+{COMMON_KEEP_A_B_C_D_UNIT_TEST "filter_adjacent_location_count_three_active" (
+    [event]
+        name=start
+
+        [object]
+            silent=yes
+            [effect]
+                apply_to=new_ability
+                [abilities]
+                    [damage]
+                        id=specialX
+                        name=_ "specialX"
+                        description=_ "specialX is active if and only if 3 terrains hexes are Gg"
+                        value=100
+                        apply_to=self
+                        [filter_adjacent_location]
+                            adjacent=n,ne,se,s,sw,nw
+                            count=3
+                            terrain=Gg
+                        [/filter_adjacent_location]
+                    [/damage]
+                [/abilities]
+            [/effect]
+            [filter]
+                id=alice
+            [/filter]
+        [/object]
+
+        {ASSERT (
+            [have_unit]
+                ability_id_active=specialX
+            [/have_unit]
+        )}
+
+        {SUCCEED}
+    [/event]
+)}
diff --git a/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_location_count_zero_active.cfg b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_location_count_zero_active.cfg
new file mode 100644
index 00000000000..3c8f392d1e5
--- /dev/null
+++ b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_location_count_zero_active.cfg
@@ -0,0 +1,49 @@
+#textdomain wesnoth-test
+
+#####
+# API(s) being tested: ability[filter_adjacent_location]adjacent,count=
+##
+# Actions:
+# Give Alice an ability specialX, which is only active if zero of the adjacent terrains are Ww.
+# Test whether the ability is active.
+##
+# Expected end state:
+# specialX should be active.
+#####
+{COMMON_KEEP_A_B_C_D_UNIT_TEST "filter_adjacent_location_count_zero_active" (
+    [event]
+        name=start
+
+        [object]
+            silent=yes
+            [effect]
+                apply_to=new_ability
+                [abilities]
+                    [damage]
+                        id=specialX
+                        name=_ "specialX"
+                        description=_ "specialX is active if and only if 0 terrains hexes are Ww"
+                        value=100
+                        apply_to=self
+                        [filter_adjacent_location]
+                            adjacent=n,ne,se,s,sw,nw
+                            count=0
+                            terrain=Ww
+                        [/filter_adjacent_location]
+                    [/damage]
+                [/abilities]
+            [/effect]
+            [filter]
+                id=alice
+            [/filter]
+        [/object]
+
+        {ASSERT (
+            [have_unit]
+                ability_id_active=specialX
+            [/have_unit]
+        )}
+
+        {SUCCEED}
+    [/event]
+)}
diff --git a/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_location_count_zero_inactive.cfg b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_location_count_zero_inactive.cfg
new file mode 100644
index 00000000000..6d5d1fbec74
--- /dev/null
+++ b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_adjacent_location_count_zero_inactive.cfg
@@ -0,0 +1,49 @@
+#####
+# API(s) being tested: ability[filter_adjacent_location]adjacent,count=
+##
+# Actions:
+# Give Alice an ability specialX, which is only active if zero of the adjacent terrains are Gg.
+# Test whether specialX ability is active.
+##
+# Expected end state:
+# specialX isn't active.
+#####
+{COMMON_KEEP_A_B_C_D_UNIT_TEST "filter_adjacent_location_count_zero_inactive" (
+    [event]
+        name=start
+
+        [object]
+            silent=yes
+            [effect]
+                apply_to=new_ability
+                [abilities]
+                    [damage]
+                        id=specialX
+                        name=_ "specialX"
+                        description=_ "specialX is active if and only if 0 terrains hexes are Gg"
+                        value=100
+                        apply_to=self
+                        [filter_adjacent_location]
+                            adjacent=n,ne,se,s,sw,nw
+                            count=0
+                            terrain=Gg
+                        [/filter_adjacent_location]
+                    [/damage]
+                [/abilities]
+            [/effect]
+            [filter]
+                id=alice
+            [/filter]
+        [/object]
+
+        {ASSERT (
+            [not]
+                [have_unit]
+                    ability_id_active=specialX
+                [/have_unit]
+            [/not]
+        )}
+
+        {SUCCEED}
+    [/event]
+)}
diff --git a/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_student_adjacent_active.cfg b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_student_adjacent_active.cfg
new file mode 100644
index 00000000000..5b5b2e71109
--- /dev/null
+++ b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_student_adjacent_active.cfg
@@ -0,0 +1,105 @@
+#textdomain wesnoth-test
+
+#####
+# API(s) being tested: ability[filter_adjacent_student]
+##
+# Actions:
+# place a unit alex adjacent to alice and only alice.
+# Give alex an ability specialX who affect alice, which is only active in fight if one adjacent unit is bob.
+# alice attack bob.
+##
+# Expected end state:
+# attack event trigered if specialX active because alice is adjacent to bob.
+#####
+{GENERIC_UNIT_TEST "filter_adjacent_student_active" (
+    [event]
+        name=start
+
+        [unit]
+            id=alex
+            name=_"Alex"
+            x,y=12,4
+            type=Elvish Hero
+            side=1
+        [/unit]
+        [object]
+            silent=yes
+            [effect]
+                apply_to=new_ability
+                [abilities]
+                    [damage]
+                        id=specialX
+                        name=_ "specialX"
+                        description=_ "specialX is active if and only if one of the adjacents units is bob"
+                        value=1
+                        apply_to=self
+                        affect_self=no
+                        affect_allies=yes
+                        affect_enemies=yes
+                        [affect_adjacent]
+                            [filter]
+                                id=alice
+                            [/filter]
+                        [/affect_adjacent]
+                        [filter_adjacent_student]
+                            id=bob
+                        [/filter_adjacent_student]
+                    [/damage]
+                [/abilities]
+            [/effect]
+            [filter]
+                id=alex
+            [/filter]
+        [/object]
+        {VARIABLE triggers_on_attack 0}
+    [/event]
+    [event]
+        name=side 1 turn 1
+        [do_command]
+            [move]
+                x=7,13
+                y=3,4
+            [/move]
+            [attack]
+                [source]
+                    x,y=13,4
+                [/source]
+                [destination]
+                    x,y=13,3
+                [/destination]
+            [/attack]
+        [/do_command]
+        [end_turn][/end_turn]
+    [/event]
+
+    [event]
+        name=side 2 turn
+        [do_command]
+            [attack]
+                [source]
+                    x,y=13,3
+                [/source]
+                [destination]
+                    x,y=13,4
+                [/destination]
+            [/attack]
+        [/do_command]
+        [end_turn][/end_turn]
+    [/event]
+    # Event when Alice attacks
+    [event]
+        name=attack
+        first_time_only=no
+        [filter_attack]
+            special_id_active=specialX
+        [/filter_attack]
+        {ASSERT ({VARIABLE_CONDITIONAL side_number equals 1})}
+        {VARIABLE_OP triggers_on_attack add 1}
+    [/event]
+
+    [event]
+        name=turn 2
+        {ASSERT ({VARIABLE_CONDITIONAL triggers_on_attack equals 1})}
+        {SUCCEED}
+    [/event]
+)}
diff --git a/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_student_adjacent_inactive.cfg b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_student_adjacent_inactive.cfg
new file mode 100644
index 00000000000..c65db61f962
--- /dev/null
+++ b/data/test/scenarios/wml_tests/UnitsWML/AbilitiesWML/filter_student_adjacent_inactive.cfg
@@ -0,0 +1,113 @@
+#textdomain wesnoth-test
+
+#####
+# API(s) being tested: ability[filter_adjacent_student]
+##
+# Actions:
+# place a unit alex adjacent to alice and only alice.
+# place loki adjacent to alex and only alex
+# Give alex an ability specialX who affect alice, which is only active in fight if one adjacent unit is loki.
+# alice attack bob.
+##
+# Expected end state:
+# attack event no trigered if specialX active because alice is no adjacent to loki, [filter_adjacent_student] filter the units adjacent to student, and not owner of ability.
+#####
+{GENERIC_UNIT_TEST "filter_adjacent_student_inactive" (
+    [event]
+        name=start
+
+        [unit]
+            id=alex
+            name=_"Alex"
+            x,y=12,4
+            type=Elvish Hero
+            side=1
+        [/unit]
+        [unit]
+            id=loki
+            name=_"Loki"
+            x,y=11,4
+            type=Elvish Hero
+            side=1
+        [/unit]
+        [object]
+            silent=yes
+            [effect]
+                apply_to=new_ability
+                [abilities]
+                    [damage]
+                        id=specialX
+                        name=_ "specialX"
+                        description=_ "specialX is active if and only if one of the adjacents units is bob"
+                        value=1
+                        apply_to=self
+                        affect_self=no
+                        affect_allies=yes
+                        affect_enemies=yes
+                        [affect_adjacent]
+                            [filter]
+                                id=alice
+                            [/filter]
+                        [/affect_adjacent]
+                        [filter_adjacent_student]
+                            id=loki
+                        [/filter_adjacent_student]
+                    [/damage]
+                [/abilities]
+            [/effect]
+            [filter]
+                id=alex
+            [/filter]
+        [/object]
+        {VARIABLE triggers_on_attack 0}
+    [/event]
+    [event]
+        name=side 1 turn 1
+        [do_command]
+            [move]
+                x=7,13
+                y=3,4
+            [/move]
+            [attack]
+                [source]
+                    x,y=13,4
+                [/source]
+                [destination]
+                    x,y=13,3
+                [/destination]
+            [/attack]
+        [/do_command]
+        [end_turn][/end_turn]
+    [/event]
+
+    [event]
+        name=side 2 turn
+        [do_command]
+            [attack]
+                [source]
+                    x,y=13,3
+                [/source]
+                [destination]
+                    x,y=13,4
+                [/destination]
+            [/attack]
+        [/do_command]
+        [end_turn][/end_turn]
+    [/event]
+    # Event when Alice attacks
+    [event]
+        name=attack
+        first_time_only=no
+        [filter_attack]
+            special_id_active=specialX
+        [/filter_attack]
+        {ASSERT ({VARIABLE_CONDITIONAL side_number equals 1})}
+        {VARIABLE_OP triggers_on_attack add 1}
+    [/event]
+
+    [event]
+        name=turn 2
+        {ASSERT ({VARIABLE_CONDITIONAL triggers_on_attack equals 0})}
+        {SUCCEED}
+    [/event]
+)}
diff --git a/src/units/abilities.cpp b/src/units/abilities.cpp
index 80c41763418..62b1eabce11 100644
--- a/src/units/abilities.cpp
+++ b/src/units/abilities.cpp
@@ -446,18 +446,16 @@ bool unit::ability_active_impl(const std::string& ability,const config& cfg,cons
 		std::size_t count = 0;
 		unit_filter ufilt{ vconfig(i) };
 		ufilt.set_use_flat_tod(illuminates);
-		std::vector<map_location::direction> dirs = map_location::parse_directions(i["adjacent"]);
+		std::vector<map_location::direction> dirs = i["adjacent"].empty() ? map_location::all_directions() : map_location::parse_directions(i["adjacent"]);
 		for (const map_location::direction index : dirs)
 		{
-			if (index == map_location::direction::indeterminate)
-				continue;
 			unit_map::const_iterator unit = units.find(adjacent[static_cast<int>(index)]);
 			if (unit == units.end())
-				return false;
+				continue;
 			if (!ufilt(*unit, *this))
-				return false;
+				continue;
 			if((*this).id() == (*unit).id())
-				return false;
+				continue;
 			if (i.has_attribute("is_enemy")) {
 				const display_context& dc = resources::filter_con->get_disp_context();
 				if (i["is_enemy"].to_bool() != dc.get_team(unit->side()).is_enemy(side_)) {
@@ -466,10 +464,9 @@ bool unit::ability_active_impl(const std::string& ability,const config& cfg,cons
 			}
 			count++;
 		}
-		if (i["count"].empty() && count != dirs.size()) {
-			return false;
-		}
-		if (!in_ranges<int>(count, utils::parse_ranges_unsigned(i["count"].str()))) {
+		static std::vector<std::pair<int,int>> default_counts = utils::parse_ranges_unsigned("1-6");
+		config::attribute_value i_count =i["count"];
+		if(!in_ranges<int>(count, !i_count.blank() ? utils::parse_ranges_unsigned(i_count) : default_counts)){
 			return false;
 		}
 	}
@@ -480,21 +477,17 @@ bool unit::ability_active_impl(const std::string& ability,const config& cfg,cons
 		terrain_filter adj_filter(vconfig(i), resources::filter_con, false);
 		adj_filter.flatten(illuminates);
 
-		std::vector<map_location::direction> dirs = map_location::parse_directions(i["adjacent"]);
+		std::vector<map_location::direction> dirs = i["adjacent"].empty() ? map_location::all_directions() : map_location::parse_directions(i["adjacent"]);
 		for (const map_location::direction index : dirs)
 		{
-			if (index == map_location::direction::indeterminate) {
-				continue;
-			}
 			if(!adj_filter.match(adjacent[static_cast<int>(index)])) {
-				return false;
+				continue;
 			}
 			count++;
 		}
-		if (i["count"].empty() && count != dirs.size()) {
-			return false;
-		}
-		if (!in_ranges<int>(count, utils::parse_ranges_unsigned(i["count"].str()))) {
+		static std::vector<std::pair<int,int>> default_counts = utils::parse_ranges_unsigned("1-6");
+		config::attribute_value i_count =i["count"];
+		if(!in_ranges<int>(count, !i_count.blank() ? utils::parse_ranges_unsigned(i_count) : default_counts)){
 			return false;
 		}
 	}
@@ -1554,13 +1547,13 @@ unit_ability_list attack_type::get_weapon_ability(const std::string& ability) co
 	unit_ability_list abil_list(loc);
 	if(self_) {
 		abil_list.append_if((*self_).get_abilities(ability, self_loc_), [&](const unit_ability& i) {
-			return special_active(*i.ability_cfg, AFFECT_SELF, ability, "filter_student");
+			return special_active(*i.ability_cfg, AFFECT_SELF, ability, true);
 		});
 	}
 
 	if(other_) {
 		abil_list.append_if((*other_).get_abilities(ability, other_loc_), [&](const unit_ability& i) {
-			return special_active_impl(other_attack_, shared_from_this(), *i.ability_cfg, AFFECT_OTHER, ability, "filter_student");
+			return special_active_impl(other_attack_, shared_from_this(), *i.ability_cfg, AFFECT_OTHER, ability, true);
 		});
 	}
 
@@ -1757,7 +1750,7 @@ bool attack_type::check_self_abilities_impl(const const_attack_ptr& self_attack,
 		}
 	}
 	if((*u).checking_tags().count(tag_name) != 0){
-		if((*u).get_self_ability_bool(special, tag_name, loc) && special_active_impl(self_attack, other_attack, special, whom, tag_name, "filter_student")) {
+		if((*u).get_self_ability_bool(special, tag_name, loc) && special_active_impl(self_attack, other_attack, special, whom, tag_name, true)) {
 			return true;
 		}
 	}
@@ -1777,7 +1770,7 @@ bool attack_type::check_adj_abilities_impl(const const_attack_ptr& self_attack,
 		}
 	}
 	if((*u).checking_tags().count(tag_name) != 0){
-		if((*u).get_adj_ability_bool(special, tag_name, dir, loc, from) && special_active_impl(self_attack, other_attack, special, whom, tag_name, "filter_student")) {
+		if((*u).get_adj_ability_bool(special, tag_name, dir, loc, from) && special_active_impl(self_attack, other_attack, special, whom, tag_name, true)) {
 			return true;
 		}
 	}
@@ -2197,9 +2190,9 @@ bool attack_type::has_special_or_ability_with_filter(const config & filter) cons
 }
 
 bool attack_type::special_active(const config& special, AFFECTS whom, const std::string& tag_name,
-                                 const std::string& filter_self) const
+                                 bool in_abilities_tag) const
 {
-	return special_active_impl(shared_from_this(), other_attack_, special, whom, tag_name, filter_self);
+	return special_active_impl(shared_from_this(), other_attack_, special, whom, tag_name, in_abilities_tag);
 }
 
 /**
@@ -2210,7 +2203,7 @@ bool attack_type::special_active(const config& special, AFFECTS whom, const std:
  * @param special           a weapon special WML structure
  * @param whom              specifies which combatant we care about
  * @param tag_name          tag name of the special config
- *  @param filter_self      the filter to use
+ * @param in_abilities_tag  if special coded in [specials] or [abilities] tags
  */
 bool attack_type::special_active_impl(
 	const const_attack_ptr& self_attack,
@@ -2218,7 +2211,7 @@ bool attack_type::special_active_impl(
 	const config& special,
 	AFFECTS whom,
 	const std::string& tag_name,
-	const std::string& filter_self)
+	bool in_abilities_tag)
 {
 	assert(self_attack || other_attack);
 	bool is_attacker = self_attack ? self_attack->is_attacker_ : !other_attack->is_attacker_;
@@ -2320,6 +2313,7 @@ bool attack_type::special_active_impl(
 	//the function of this special in matches_filter()
 	//In apply_to=both case, tag_name must be checked in all filter because special applied to both self and opponent.
 	bool applied_both = special["apply_to"] == "both";
+	const std::string& filter_self = in_abilities_tag ? "filter_student" : "filter_self";
 	std::string self_check_if_recursion = (applied_both || whom_is_self) ? tag_name : "";
 	if (!special_unit_matches(self, other, self_loc, self_attack, special, is_for_listing, filter_self, self_check_if_recursion))
 		return false;
@@ -2337,21 +2331,25 @@ bool attack_type::special_active_impl(
 	if (!special_unit_matches(def, att, def_loc, def_weapon, special, is_for_listing, "filter_defender", def_check_if_recursion))
 		return false;
 
+	//if filter_self != "filter_self" then it's in [abilities] tags and
+	//[filter_student_adjacent] and [filter_student_adjacent] then designate 'the student' (which may be different from the owner of the ability),
+	//while in the tags[specials] the usual names are kept.
+	const std::string& filter_adjacent = in_abilities_tag ? "filter_adjacent_student" : "filter_adjacent";
+	const std::string& filter_adjacent_location = in_abilities_tag ? "filter_adjacent_student_location" : "filter_adjacent_location";
+
 	const auto adjacent = get_adjacent_tiles(self_loc);
 
 	// Filter the adjacent units.
-	for (const config &i : special.child_range("filter_adjacent"))
+	for (const config &i : special.child_range(filter_adjacent))
 	{
 		std::size_t count = 0;
-		std::vector<map_location::direction> dirs = map_location::parse_directions(i["adjacent"]);
+		std::vector<map_location::direction> dirs = i["adjacent"].empty() ? map_location::all_directions() : map_location::parse_directions(i["adjacent"]);
 		unit_filter filter{ vconfig(i) };
 		for (const map_location::direction index : dirs)
 		{
-			if (index == map_location::direction::indeterminate)
-				continue;
 			unit_map::const_iterator unit = units.find(adjacent[static_cast<int>(index)]);
 			if (unit == units.end() || !filter.matches(*unit, adjacent[static_cast<int>(index)], *self))
-				return false;
+				continue;
 			if (i.has_attribute("is_enemy")) {
 				const display_context& dc = resources::filter_con->get_disp_context();
 				if (i["is_enemy"].to_bool() != dc.get_team(unit->side()).is_enemy(self->side())) {
@@ -2360,33 +2358,29 @@ bool attack_type::special_active_impl(
 			}
 			count++;
 		}
-		if (i["count"].empty() && count != dirs.size()) {
-			return false;
-		}
-		if (!in_ranges<int>(count, utils::parse_ranges_unsigned(i["count"].str()))) {
+		static std::vector<std::pair<int,int>> default_counts = utils::parse_ranges_unsigned("1-6");
+		config::attribute_value i_count =i["count"];
+		if(!in_ranges<int>(count, !i_count.blank() ? utils::parse_ranges_unsigned(i_count) : default_counts)){
 			return false;
 		}
 	}
 
 	// Filter the adjacent locations.
-	for (const config &i : special.child_range("filter_adjacent_location"))
+	for (const config &i : special.child_range(filter_adjacent_location))
 	{
 		std::size_t count = 0;
-		std::vector<map_location::direction> dirs = map_location::parse_directions(i["adjacent"]);
+		std::vector<map_location::direction> dirs = i["adjacent"].empty() ? map_location::all_directions() : map_location::parse_directions(i["adjacent"]);
 		terrain_filter adj_filter(vconfig(i), resources::filter_con, false);
 		for (const map_location::direction index : dirs)
 		{
-			if (index == map_location::direction::indeterminate)
-				continue;
 			if(!adj_filter.match(adjacent[static_cast<int>(index)])) {
-				return false;
+				continue;
 			}
 			count++;
 		}
-		if (i["count"].empty() && count != dirs.size()) {
-			return false;
-		}
-		if (!in_ranges<int>(count, utils::parse_ranges_unsigned(i["count"].str()))) {
+		static std::vector<std::pair<int,int>> default_counts = utils::parse_ranges_unsigned("1-6");
+		config::attribute_value i_count =i["count"];
+		if(!in_ranges<int>(count, !i_count.blank() ? utils::parse_ranges_unsigned(i_count) : default_counts)){
 			return false;
 		}
 	}
diff --git a/src/units/attack_type.hpp b/src/units/attack_type.hpp
index a6c2c8ca1dd..cf80d0580a2 100644
--- a/src/units/attack_type.hpp
+++ b/src/units/attack_type.hpp
@@ -272,7 +272,7 @@ private:
 	 */
 	bool check_adj_abilities(const config& cfg, const std::string& special, int dir, const unit& from) const;
 	bool special_active(const config& special, AFFECTS whom, const std::string& tag_name,
-	                    const std::string& filter_self ="filter_self") const;
+	                    bool in_abilities_tag = false) const;
 
 /** weapon_specials_impl_self and weapon_specials_impl_adj : check if special name can be added.
 	 * @param[in,out] temp_string the string modified and returned
@@ -364,7 +364,7 @@ private:
 		const config& special,
 		AFFECTS whom,
 		const std::string& tag_name,
-		const std::string& filter_self ="filter_self"
+		bool in_abilities_tag = false
 	);
 
 	// Used via specials_context() to control which specials are
diff --git a/wml_test_schedule b/wml_test_schedule
index bd55a88f4ae..ec5555b79ec 100644
--- a/wml_test_schedule
+++ b/wml_test_schedule
@@ -411,6 +411,15 @@
 0 taught_resistance_with_three_attack_types
 0 swarms_filter_student_by_type
 0 swarms_effects_not_checkable
+0 filter_adjacent_location_count_three_active
+0 filter_adjacent_location_count_zero_active
+0 filter_adjacent_location_count_zero_inactive
+0 filter_adjacent_active
+0 filter_adjacent_inactive
+0 filter_adjacent_student_active
+0 filter_adjacent_student_inactive
+0 filter_adjacent_direction_active
+0 filter_adjacent_direction_inactive
 0 filter_special_id_active
 0 filter_ability_special_id_active
 0 filter_special_id_not_exists