diff --git a/src/nature/nature.jl b/src/nature/nature.jl
index 4003ed1b4d05091003d3c49e856e2678685db8ac..bae14283b4809845a8caf4fd5e116f65991fd36c 100644
--- a/src/nature/nature.jl
+++ b/src/nature/nature.jl
@@ -126,13 +126,14 @@ animal is in the relevant phase. When it is called, it has access to the followi
 variables:
 - `animal` a reference to the animal itself. This provides access to `animal.age`,
     `animal.sex`, and `animal.traits` (a dict that gives access to all species parameters).
+- `pos` gives the animal's current position as a coordinate tuple.
 - `model` a reference to the model world (an object of type `AgentBasedModel`).
     This allows access to `model.date` (the current simulation date) and
     `model.landscape` (a two-dimensional array of pixels containing geographic
     information).
 
 Several utility macros can be used within the body of `@phase` as a short-hand for
-common expressions: `@respond`, `@trait`, `@here`, `@kill`, `@reproduce`.
+common expressions: `@respond`, `@trait`, `@here`, `@kill`, `@reproduce`, `@neighbours`.
 
 To transition an individual to another phase, simply redefine its phase variable:
 `@trait(phase) = "newphase"`.
@@ -140,7 +141,12 @@ To transition an individual to another phase, simply redefine its phase variable
 macro phase(name, body)
     #XXX make this documentable?
     #FIXME Somehow, errors in the phase body are not shown?
-    :($(esc(name)) = function(animal::Animal, model::AgentBasedModel) $body end)
+    quote
+        $(esc(name)) = function(animal::Animal, model::AgentBasedModel)
+            $(esc(:pos)) = animal.pos
+            $body
+        end
+    end
 end
 
 """
@@ -201,9 +207,15 @@ macro reproduce(args...)
     :(reproduce!(animal, model, $(args...)))
 end
 
-#XXX add a macro @f to call a function with animal and model as first parameters?
-# e.g. @f(nearby_agents, distance)
-# -> rather create wrapper macros
+"""
+    @neighbours(radius)
+
+Return an iterator over all animals in the given radius around this animal, excluding itself.
+This can only be used nested within `@phase`.
+"""
+macro neighbours(radius)
+    :(nearby_animals(animal, model, $radius))
+end
 
 """
     @habitat
@@ -236,11 +248,7 @@ circumvented by directly creating an equivalent function.
 macro habitat(body)
     quote
         function($(esc(:pos)), $(esc(:model)))
-            if $(esc(body))
-                return true
-            else
-                return false
-            end
+            ($(esc(body))) ? return true : return false
         end
     end
 end
@@ -249,7 +257,7 @@ end
     @landcover
 
 Returns the local landcover. This is a utility wrapper that can only be used
-nested within `@habitat`.
+nested within `@phase` or `@habitat`.
 """
 macro landcover()
     :(landcover($(esc(:pos)), $(esc(:model))))
@@ -259,7 +267,7 @@ end
     @croptype
 
 Return the local croptype, or nothing if there is no crop here.
-This is a utility wrapper that can only be used nested within `@habitat`.
+This is a utility wrapper that can only be used nested within `@phase` or `@habitat`.
 """
 macro croptype()
     :(croptype($(esc(:pos)), $(esc(:model))))
@@ -269,27 +277,27 @@ end
     @cropheight
 
 Return the height of the crop at this position, or 0 if there is no crop here.
-This is a utility wrapper that can only be used nested within `@habitat`.
+This is a utility wrapper that can only be used nested within `@phase` or `@habitat`.
 """
 macro cropheight()
     :(cropheight($(esc(:pos)), $(esc(:model))))
 end
 
 """
-    @distanceto(habitattype)
+    @distanceto(habitat)
 
-Calculate the distance to the closest habitat of the specified type.
-This is a utility wrapper that can only be used nested within `@habitat`.
+Calculate the distance to the closest habitat of the specified type or descriptor.
+This is a utility wrapper that can only be used nested within `@phase` or `@habitat`.
 """
-macro distanceto(habitattype)
-    :(distanceto($(esc(:pos)), $(esc(:model)), $habitattype))
+macro distanceto(habitat)
+    :(distanceto($(esc(:pos)), $(esc(:model)), $habitat))
 end
 
 """
     @distancetoedge
 
 Calculate the distance to the closest neighbouring habitat.
-This is a utility wrapper that can only be used nested within `@habitat`.
+This is a utility wrapper that can only be used nested within `@phase` or `@habitat`.
 """
 macro distancetoedge()
     :(distancetoedge($(esc(:pos)), $(esc(:model))))
@@ -299,7 +307,7 @@ end
     @countanimals(speciesname)
 
 Count the number of animals of the given species in this location.
-This is a utility wrapper that can only be used nested within `@habitat`.
+This is a utility wrapper that can only be used nested within `@phase` or `@habitat`.
 """
 macro countanimals(speciesname)
     #XXX this also counts the enquiring agent
diff --git a/src/nature/populations.jl b/src/nature/populations.jl
index d08d40473c7f12b33dfcdd2215b412ffa4af39f8..28b9528ba4ea486116a9d9dac99eb5c910749977 100644
--- a/src/nature/populations.jl
+++ b/src/nature/populations.jl
@@ -60,14 +60,35 @@ function kill!(animal::Animal, model::AgentBasedModel, probability::Float64=1.0,
 end
 
 """
-    countanimals(model, pos, speciesname)
+    nearby_animals(pos, model, radius)
 
-Count the number of animals of the given species in this location.
+Return an iterator over all animals in the given radius around this position.
 """
-macro countanimals(model::AgentBasedModel, pos::Tuple{Int64,Int64}, speciesname::String)
+function nearby_animals(pos::Tuple{Int64,Int64}, model::AgentBasedModel, radius::Int64)
+    neighbours = (model[id] for id in nearby_ids(pos, model, radius))
+    Iterators.filter(a -> typeof(a) == Animal, neighbours)
+end
+
+"""
+    nearby_animals(animal, model, radius)
+
+Return an iterator over all animals in the given radius around this animal, excluding itself.
+"""
+function nearby_animals(animal::Animal, model::AgentBasedModel, radius::Int64)
+    neighbours = (model[id] for id in nearby_ids(animal.pos, model, radius))
+    Iterators.filter(a -> typeof(a) == Animal && a.id != animal.id, neighbours)
+end
+
+"""
+    countanimals(pos, model, speciesname, radius=0)
+
+Count the number of animals of the given species in this location (optionally supplying a radius).
+"""
+function countanimals(pos::Tuple{Int64,Int64}, model::AgentBasedModel,
+                      speciesname::String, radius::Int64=0)
     n = 0
-    for a in nearby_ids(pos, model, 0)
-        typeof(model[a]) == Animal && model[a].traits.name == speciesname && (n += 1)
+    for a in nearby_animals(pos, model, radius)
+        model[a].traits.name == speciesname && (n += 1)
     end
     return n
 end