
/* This file contains those functions that deal with the behaviour and
graphics of the animal */


#include <stdio.h>
#include <math.h>
/*gn*/
#include <suntool/sunview.h>
/*gn*/
#include <suntool/panel.h>
/*gn*/
#include <suntool/canvas.h>
#include "structures.h"
#include "util_fns.h"
#include "env_spec.h"
#include "env_defs.h"
#include "animal_defs.h"
#include "animal_decs.h"
#include "ext_env_decs.h"


/* function to initialise the animal and all consequent variables */
void set_up_animal()
{

  int i, j, k;
  char text[50];

  animal_alive = TRUE;

  /* put the animal in its den to start off with */
  animal_c = first_den_c;
  animal_r = first_den_r;
  prev_animal_c = first_den_c;
  prev_animal_r = first_den_r;
  c_change = 0;
  r_change = 0;
  env_arr[animal_c][animal_r].p_arr[ANIMAL_N] = (void *)NOT_NULL;
/*g*/
/*g*/  /* draw the animal on that square */
/*g*/  redraw_square(animal_c, animal_r);
  /* give the animal an initial action (sleeping) */
  animal_action = SLEEPING;

  /* animal starts with age of 0.0 */
  animal_age = 0.0;

  /* initialise the 'internal variables' of the animal */
  animal_water    		 = 0.30;
  animal_fat     		 = 0.30;
  animal_carbo     		 = 0.30;
  animal_protein   		 = 0.30;
  animal_temp     		 = 0.50;
  animal_health  		 = 1.0;
  animal_perm_inj		 = 0.0;
  animal_max_health 	 = 1.0;
  genetic_fitness 		 = 0.0;		/* none yet since no offspring */
  animal_cleanliness	 = 0.5;
  animal_conspicuousness = 0.0;
  animal_escape_prob	 = 1.0;

  prev_animal_temp = animal_temp;

  direction_of_look = N;

  /* set number of toxic delayed effects impending to zero */
  toxic_counter = 0;

  animal_eating = FALSE;
  animal_drinking = FALSE;

  time_since_useless_cereal_food = 10000;
  time_since_useless_fruit_food = 10000;
  time_since_useless_water = 10000;

  time_since_animal_mated = 100;
  time_since_animal_courting_rejected = 100;

  for (i = 0; i < NUM_LOW_LEVEL_ACTIONS; i++)
	action_record[i] = 0;

  time_since_scanned = 0;

  min_distance_to_cover = 0.0;
  est_last_cover_c = 0.0;
  est_last_cover_r = 0.0;

  for (i = 0; i < 100; i++) {
	toxic_array[i].delay = -1;
	toxic_array[i].strength = -100.0;
	toxic_array[i].type = -1;
  }

  toxic_counter = 0;

  sqr_temp = -10.0;

  animal_eating = FALSE;
  animal_drinking = FALSE;

  prey_in_animal_square = FALSE;
  cf_in_animal_square = FALSE;
  ff_in_animal_square = FALSE;

  time_since_predator_perceived = 100;

  zero_property_values();

  /* initialise some pointers in the animal's perception array */
  for (i = 0; i < (2*M_A_P+1); i++)
    for (j = 0; j < (2*M_A_P+1); j++)
      for (k = 0; k < NUM_FEATURE_TYPES; k++)
		anim_perc.contents[i][j][k] = (SQR_C_LLE *) NULL;
}


/*g*//* function to create a display on which to show the state of the internal
/*g*//*variables and genetic fitness of the animal */
/*g*/void set_up_animal_display()
/*g*/{
/*g*/
/*g*/  int health_w, gen_fit_w, clean_h;
/*g*/
/*g*/  animal_frame = window_create(NULL, FRAME,
/*g*/    WIN_SHOW, FALSE,
/*g*/    FRAME_LABEL, "Animal Statistics",
/*g*/    WIN_X, 50,
/*g*/    WIN_Y, 20,
/*g*/    WIN_WIDTH, 460,
/*g*/    WIN_HEIGHT, 300,
/*g*/    0);
/*g*/
/*g*/  animal_canvas = window_create(animal_frame, CANVAS,
/*g*/    WIN_SHOW, TRUE,
/*g*/    CANVAS_AUTO_SHRINK, TRUE,
/*g*/    CANVAS_AUTO_EXPAND, TRUE,
/*g*/    WIN_X, 0,
/*g*/    WIN_Y, 3,
/*g*/    WIN_WIDTH, 450,
/*g*/    WIN_HEIGHT, 274,
/*g*/    0);
/*g*/
/*g*/  animal_pw = canvas_pixwin(animal_canvas);
/*g*/
/*g*/  /* attach colourmap to pixwin */
/*g*/  pw_setcmsname(animal_pw, "doesntmatter");
/*g*/  pw_putcolormap(animal_pw, 0, CMAP_SIZE, red, green, blue);
/*g*/
/*g*/  /* give the 'boolean' variables for the displays initial values */
/*g*/  animal_display_on = FALSE;
/*g*/  perc_display_on = FALSE;
/*g*/  map_display_on = FALSE;
/*g*/  nav_display_on = FALSE;
/*g*/
/*g*/  /* write the titles of the six bars */
/*g*/  pw_text(animal_pw, 5, 40, (PIX_SRC|PIX_COLOR(30)), serif_r_14, " FAT");
/*g*/  pw_text(animal_pw, 75, 40, (PIX_SRC|PIX_COLOR(30)), serif_r_14, " CARBO-");
/*g*/  pw_text(animal_pw, 75, 55, (PIX_SRC|PIX_COLOR(30)), serif_r_14, " HYDRATE");
/*g*/  pw_text(animal_pw, 145, 40, (PIX_SRC|PIX_COLOR(30)), serif_r_14, " PROTEIN");
/*g*/  pw_text(animal_pw, 215, 40, (PIX_SRC|PIX_COLOR(30)), serif_r_14, " WATER");
/*g*/  pw_text(animal_pw, 285, 40, (PIX_SRC|PIX_COLOR(30)), serif_r_14, " TEMPER-");
/*g*/  pw_text(animal_pw, 285, 55, (PIX_SRC|PIX_COLOR(30)), serif_r_14, " ATURE");
/*g*/  pw_text(animal_pw, 355, 40, (PIX_SRC|PIX_COLOR(30)), serif_r_14, " CLEAN-");
/*g*/  pw_text(animal_pw, 355, 55, (PIX_SRC|PIX_COLOR(30)), serif_r_14, " LINESS");
/*g*/
/*g*/  /* draw on the axes for the six bars */
/*g*/  pw_vector(animal_pw, 30, 180, 30, 75, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 100, 180, 100, 75, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 170, 180, 170, 75, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 240, 180, 240, 75, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 310, 180, 310, 75, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 380, 180, 380, 75, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/
/*g*/  pw_vector(animal_pw, 25, 175, 40, 175, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 95, 175, 110, 175, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 165, 175, 180, 175, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 235, 175, 250, 175, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 305, 175, 320, 175, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 375, 175, 390, 175, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/
/*g*/  /* draw maximum and minimum acceptable and 1.0 markers on the six bars */
/*g*/  pw_vector(animal_pw, 25, (175-((int)(MIN_OK_FAT*100.0))), 30,
/*g*/	(175-((int)(MIN_OK_FAT*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 95, (175-((int)(MIN_OK_CARBO*100.0))), 100,
/*g*/	(175-((int)(MIN_OK_CARBO*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 165, (175-((int)(MIN_OK_PROTEIN*100.0))), 170,
/*g*/	(175-((int)(MIN_OK_PROTEIN*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 235, (175-((int)(MIN_OK_WATER*100.0))), 240,
/*g*/	(175-((int)(MIN_OK_WATER*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 305, (175-((int)(MIN_OK_TEMP*100.0))), 310,
/*g*/	(175-((int)(MIN_OK_TEMP*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/
/*g*/  pw_vector(animal_pw, 25, (175-((int)(MAX_OK_FAT*100.0))), 30,
/*g*/	(175-((int)(MAX_OK_FAT*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 95, (175-((int)(MAX_OK_CARBO*100.0))), 100,
/*g*/	(175-((int)(MAX_OK_CARBO*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 165, (175-((int)(MAX_OK_PROTEIN*100.0))), 170,
/*g*/	(175-((int)(MAX_OK_PROTEIN*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 235, (175-((int)(MAX_OK_WATER*100.0))), 240,
/*g*/	(175-((int)(MAX_OK_WATER*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 305, (175-((int)(MAX_OK_TEMP*100.0))), 310,
/*g*/	(175-((int)(MAX_OK_TEMP*100.0))), (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/
/*g*/  pw_vector(animal_pw, 25, 75, 30, 75, (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 95, 75, 100, 75, (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 165, 75, 170, 75, (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 235, 75, 240, 75, (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 305, 75, 310, 75, (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/  pw_vector(animal_pw, 375, 75, 380, 75, (PIX_SRC|PIX_COLOR(40)), 0); 
/*g*/
/*g*/  health_w = (int) (animal_health*99.0);
/*g*/  gen_fit_w =(int) ((((double) genetic_fitness)/MAX_LIKELY_G_F)*99.0);
/*g*/
/*g*/  /* draw and label a graph to show the health of the animal */
/*g*/  pw_vector(animal_pw, 60, 230, 60, 245, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 50, 240, 190, 240, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 160, 240, 160, 245, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_text (animal_pw, 85, 215, (PIX_SRC|PIX_COLOR(30)), serif_r_14, "HEALTH");
/*g*/  pw_text (animal_pw, 44, 261, (PIX_SRC|PIX_COLOR(30)), serif_r_12, "Fatal");
/*g*/  pw_text (animal_pw, 150, 261, (PIX_SRC|PIX_COLOR(30)), serif_r_12, "Max.");
/*g*/  pw_rop(animal_pw, 61, 231, health_w, 8,
/*g*/    op[(1+(int)(animal_health*4.9999))], NULL, 0, 0);
/*g*/
/*g*/  /* draw and label a graph to show the 'genetic fitness' of the animal */
/*g*/  pw_vector(animal_pw, 240, 230, 240, 245, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 230, 240, 370, 240, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_vector(animal_pw, 340, 240, 340, 245, (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/  pw_text (animal_pw, 238, 215, (PIX_SRC|PIX_COLOR(30)), serif_r_14,
/*g*/	"GENETIC FITNESS");
/*g*/  pw_text (animal_pw, 235, 261, (PIX_SRC|PIX_COLOR(30)), serif_r_12, "0");
/*g*/  sprintf(text, "%d", ((int) MAX_LIKELY_G_F));
/*g*/  pw_text (animal_pw, 330, 261, (PIX_SRC|PIX_COLOR(30)), serif_r_12, text);
/*g*/  pw_rop(animal_pw, 241, 231, gen_fit_w, 8,
/*g*/	op[(1+(int)(((double) genetic_fitness)/MAX_LIKELY_G_F*4.9999))],NULL,0,0);
/*g*/}
/*g*/
/*g*/
/*g*//* function to create a display on which to show what the animal can
/*g*//*perceive at each moment in time in the environment */
/*g*/void set_up_perc_display()
/*g*/{
/*g*/
/*g*/  int i, j;
/*g*/  char text[100];
/*g*/
/*g*/  perception_frame = window_create(NULL, FRAME,
/*g*/    WIN_SHOW, FALSE,
/*g*/    FRAME_LABEL, "Animal Perception",
/*g*/    WIN_X, 20,
/*g*/    WIN_Y, 50,
/*g*/    WIN_WIDTH, PERC_WIN_WIDTH+10,
/*g*/    WIN_HEIGHT, PERC_WIN_HEIGHT+26,
/*g*/    0);
/*g*/
/*g*/  perception_canvas = window_create(perception_frame, CANVAS,
/*g*/    WIN_SHOW, TRUE,
/*g*/    CANVAS_AUTO_SHRINK, TRUE,
/*g*/    CANVAS_AUTO_EXPAND, TRUE,
/*g*/    WIN_X, 0,
/*g*/    WIN_Y, 3,
/*g*/    WIN_WIDTH, PERC_WIN_WIDTH,
/*g*/    WIN_HEIGHT, PERC_WIN_HEIGHT,
/*g*/    0);
/*g*/
/*g*/  perception_pw = canvas_pixwin(perception_canvas);
/*g*/
/*g*/  /* attach colourmap to pixwin */
/*g*/  pw_setcmsname(perception_pw, "doesntmatter");
/*g*/  pw_putcolormap(perception_pw, 0, CMAP_SIZE, red, green, blue);
/*g*/
/*g*/  /* draw a grey colour over the whole of the window (grey will denote those
/*g*//*  areas that the animal does not know about) */
/*g*//*  pw_rop(perception_pw, 0, 0, PERC_WIN_WIDTH, PERC_WIN_HEIGHT,
/*g*//*    (PIX_SRC | PIX_COLOR(100)), NULL, 0, 0);
/*g*/
/*g*/
/*g*/  pw_rop(perception_pw, 0, 0, PERC_WIN_WIDTH, PERC_WIN_HEIGHT,
/*g*/	PIX_CLR, NULL, 0, 0);
/*g*/
/*g*/  /* put in a message to explain what border on square is for */
/*g*/  sprintf(text, "Solid border round square denotes");
/*g*/  pw_ttext (perception_pw, 5, 15, PIX_SRC, serif_r_12, text);
/*g*/  sprintf(text, "incorrect perception of the square");
/*g*/  pw_ttext (perception_pw, 5, 30, PIX_SRC, serif_r_12, text);
/*g*/
/*g*/}


/* function to initialise structures and variables to do with the animal's
navigation */
void set_up_navigation()
{

  int i;

/*g*/  nav_frame = window_create(NULL, FRAME,
/*g*/    WIN_SHOW, FALSE,
/*g*/    FRAME_LABEL, "Navigation",
/*g*/    WIN_X, 200,
/*g*/    WIN_Y, 200,
/*g*/    WIN_WIDTH, 400,
/*g*/    WIN_HEIGHT, 400,
/*g*/    0);
/*g*/
/*g*/  nav_canvas = window_create(nav_frame, CANVAS,
/*g*/    WIN_SHOW, TRUE,
/*g*/    CANVAS_AUTO_SHRINK, TRUE,
/*g*/    CANVAS_AUTO_EXPAND, TRUE,
/*g*/    WIN_X, 0,
/*g*/    WIN_Y, 3,
/*g*/    WIN_WIDTH, 400,
/*g*/    WIN_HEIGHT, 400,
/*g*/    0);
/*g*/
/*g*/  nav_pw = canvas_pixwin(nav_canvas);
/*g*/
/*g*/  /* attach colourmap to pixwin */
/*g*/  pw_setcmsname(nav_pw, "doesntmatter");
/*g*/  pw_putcolormap(nav_pw, 0, CMAP_SIZE, red, green, blue);
/*g*/
/*g*/  /* create frame to cover most of screen */
/*g*/  map_frame = window_create(NULL, FRAME,
/*g*/    WIN_SHOW, FALSE,
/*g*/    FRAME_LABEL, "Animal's Map of Environment",
/*g*/    WIN_WIDTH, (776+1),
/*g*/    WIN_HEIGHT, (776+3),
/*g*/    WIN_X, 0,
/*g*/    WIN_Y, 0,
/*g*/    0);
/*g*/
/*g*/  /* create canvas */
/*g*/  map_canvas = window_create(map_frame, CANVAS,
/*g*/    WIN_SHOW, TRUE,
/*g*/    WIN_X, 0,
/*g*/    WIN_Y, 0,
/*g*/	CANVAS_AUTO_SHRINK, FALSE,
/*g*/	CANVAS_AUTO_EXPAND, FALSE,
/*g*/    CANVAS_RETAINED, TRUE,
/*g*/    CANVAS_WIDTH, 776,
/*g*/    CANVAS_HEIGHT, 776,
/*g*/    WIN_WIDTH, 776,
/*g*/    WIN_HEIGHT, 776,
/*g*/    0);
/*g*/
/*g*/  /* create pixwin for program */
/*g*/  map_pw = canvas_pixwin(map_canvas);
/*g*/
/*g*/  /* attach colourmap to pixwin */
/*g*/  pw_setcmsname(map_pw, "doesntmatter");
/*g*/  pw_putcolormap(map_pw, 0, CMAP_SIZE, red, green, blue);
/*g*/
/*g*/  /* draw the den */
/*g*/  pw_stencil(map_pw, (first_den_c*SQUARE_SIZE), (first_den_r*SQUARE_SIZE),
/*g*/	SQUARE_SIZE, SQUARE_SIZE, (PIX_SRC|PIX_COLOR(DEN_N*5+5)),
/*g*/	feature_pr[DEN_N], 0, 0, NULL, 0, 0);

  map_sze = MAP_SIZE;
  if (sim_env_version == V2)
	map_sze /= 2;

  nav_err = NAV_ERROR;
  if (sim_env_version == V2)
    nav_err *= 3.0;

  est_an_c = 0.0;
  est_an_r = 0.0;
  prev_est_an_c = 0.0;
  prev_est_an_r = 0.0;

  num_active_memories = 0;

  num_uncertain_steps = 0.0;

  an_pos_variance = 0.0;

  this_place_recognised = FALSE;
  this_place_now_in_map = FALSE;
  this_place = -1;

  /* allocate memory for map */
  for (i = 0; i < map_sze; i++)
	map[i] = (PLACE_MEMORY *) malloc(sizeof(PLACE_MEMORY));
}


/* function to decide and display what the animal can perceive at each
moment in time */
void animal_perception()
{

  int c, r;				/* coordinates relative to animal of square */
  int *c_ptr, *r_ptr;	/* pointers to the above */
  int ac, ar;			/* array coordinates of square */
  double correct_ext_perc_prob;		/* the probability of the animal correctly
				perceiving the contents of a square (this will be affected
				by whether other squares (eg cover) obscure it, how far it
				is away, etc) */
  double correct_int_perc_prob;		/* as above but for animals hidden in
								vegetation in the square */
  double obscures_list[15];       /* list which shows which squares obscure
        others and (roughly) to what degreee.  This is important in deciding
        how reliably the animal can perceive what is in each square */
  double perception_factor[(M_A_P*2+1)*(M_A_P*2+1)];
                /* how easy it is to see through the squares in the vicinity*/
  int i, j, k;
  int sqr_number;    /* the number (as in number returned by get_adj_square)
						of a square */ 
  int interv_sqr;    /* the number (as in number returned by get_adj_square)
						of a square that obscures another */ 
  char text[50];
  int target_direction;         /* direction from animal to target square */
  int ext_perception_correct;   /* 'boolean' to show whether perception of the
								whole of a square is correct or not */
  int int_perception_correct;	/* 'boolean' to show whether perception of the 
								interior of a square (eg animals not
                                vegetation) is correct or not */
  int max_ap;			/* maximum animal perception at this time of day */
  int feature_counters[NUM_FEATURE_TYPES];
  int nft;

  c_ptr = &c; r_ptr = &r;

  /* decrease distance animal can see with time of day */
  if (sim_env_version == V1) {
	switch(part_of_day) {
      case(NIGHT) : max_ap = (int) (((double) M_A_P) *
		(NIGHT_PERCEPTION_FACTOR+0.1));
				    break;
      case(SUNRISE) : max_ap = (int) (((double) M_A_P) *
		(DUSK_PERCEPTION_FACTOR-0.20));
				      break;
      case(SUNSET) : max_ap = (int) (((double) M_A_P) *
		(DUSK_PERCEPTION_FACTOR-0.20));
				     break;
	  default : max_ap = (int) (((double) M_A_P) *
		(DAY_PERCEPTION_FACTOR-0.20));
		        break;
	}
  }
  else {
	switch(part_of_day) {
      case(NIGHT) : max_ap = (int) (((double) M_A_P) *
		NIGHT_PERCEPTION_FACTOR); 
				    break;
      case(SUNRISE) : max_ap = (int) (((double) M_A_P) *
		DUSK_PERCEPTION_FACTOR); 
				      break;
      case(SUNSET) : max_ap = (int) (((double) M_A_P) *
		DUSK_PERCEPTION_FACTOR); 
				     break;
	  default : max_ap = (int) (((double) M_A_P) * DAY_PERCEPTION_FACTOR);
		        break;
	}
  }

  /* effect of action ``looking around'' is to increase distance of
  perception by 1.0 */
  if ((max_ap > 0) &&
	  (look_action_chosen() == FALSE))
	max_ap -= 1;

  /* reinitialise the perception structure so that all perception from the
  last timestep is removed */
  init_perc_struct();

/*g*/  /* draw a grey colour over the whole of the perception window (grey will
/*g*//*  denote those areas that the animal does not know about) */
/*g*/	pw_rop(perception_pw, 0, 40, PERC_WIN_WIDTH, (PERC_WIN_HEIGHT-40),
/*g*/	  PIX_CLR, NULL, 0, 0);
/*g*//*  pw_rop(perception_pw, 0, 40, PERC_WIN_WIDTH, (PERC_WIN_HEIGHT-40),
/*g*//*    (PIX_SRC | PIX_COLOR(100)), NULL, 0, 0);
/*g*/
  /* go through all the adjacent squares that can be seen by the animal and
  decide whether the animal perceives them correctly */
  for (i = 0; i < NUM_PERC_SQUARES; ++i) {

    sqr_number = get_adj_square(c_ptr, r_ptr, obscures_list);

    ac = animal_c + c;
    ar = animal_r + r;

    /* calculate the approximate direction from the animal's square to
    the target square */
    target_direction = get_target_dir(c, r);

    /* add this square's perception factor to the list */
    if (square_in_env(ac, ar)) 
      perception_factor[sqr_number] = env_arr[ac][ar].perception_factor;
    else
      perception_factor[sqr_number] = 1.0;

	/* calculate how likely animal is to correctly perceive each
	surrounding square.  There are seven factors - what time of day it is,
	how easy it is to see out of the animal's square, how easy it is to see
	through other obscuring squares, how far away the target square is, what
	the animal is doing (eg. is it looking in a direction), how far away the
	target square is and what the animal is doing.  Note that animals in  
	vegetation in a square are harder to see than the vegetation.
	Therefore the probability of correctly perceiving animals in a square is
	different from that for vegetation (it doesn't depend on the last factor
	mentioned) */
	correct_ext_perc_prob = 1.0;

	/* reduce perception if animal in vegetation */
	if (env_arr[animal_c][animal_r].p_arr[DEN_N] != NULL)
	  correct_ext_perc_prob = 0.70;
	else
	  correct_ext_perc_prob = 0.70 + (0.30 * 
		  env_arr[animal_c][animal_r].perception_factor);

    /* take into account obscuring squares */
    for (j = 1; j <= ((int) obscures_list[0]); ++j) {

	  /* get the number of this intervening square */
      interv_sqr = (int) (obscures_list[2*j-1]);

      /* for each square obscuring it, reduce the likelihood of correct
      perception of the target square by the perception factor of the
      intervening square, modified by a factor for how much the square
      obscures the target */
	  if (sim_env_version == V1)
		correct_ext_perc_prob -= 3.0 * (((1.0-perception_factor[interv_sqr]) *
		  obscures_list[2*j]) * 0.68);
	  else
		correct_ext_perc_prob -= (((1.0-perception_factor[interv_sqr]) *
		  obscures_list[2*j]) * 0.68);
	}

	/* take into account distance (and time of day indirectly by max_ap) */
	correct_ext_perc_prob *= (1.0 - (((double)(c*c + r*r))/
	  ((double)((max_ap+1)*(max_ap+1)))));

    /* if perception very uncertain already (with only some factors taken
	into account) then don't bother with rest */
	if (correct_ext_perc_prob > 0.01) {

	  /* take into account effect of action on perception */
	  correct_ext_perc_prob *= action_effect_on_perc(target_direction);

      /* only take target square into account for animals in the square */
      correct_int_perc_prob = correct_ext_perc_prob *
		perception_factor[sqr_number];
	}

	else {		/* if perception probability very low */
	  /* set them both to zero */
	  correct_ext_perc_prob = 0.0;
	  correct_int_perc_prob = 0.0;
	}

	/* make sure internal perception probability not < 0.0 */
	if (correct_int_perc_prob < 0.01)
	  correct_int_perc_prob = 0.0;

	/* make sure animal can always see own square */
	if ((c == 0) && (r == 0)) {
	  correct_ext_perc_prob = 1.0;
      correct_int_perc_prob = 1.0;
	}

    ext_perception_correct = TRUE;
	int_perception_correct = TRUE;

	/* decide if the animal misperceives the whole square (usually when
	animal can only see the square very badly, but very occasionally
	when the animal can see a square very well) */
	if ((rnd(0.25) > correct_ext_perc_prob) ||
	     ((drand48() < 0.005) && (drand48() > correct_ext_perc_prob))) {

	  ext_perception_correct = FALSE;
	  int_perception_correct = FALSE;
	}

	/* decide if the animal misperceives just the animals in vegetation
	in the square (usually when	animal can only see the area very badly,
	but very occasionally when the animal can see an area very well) */
	else if ((rnd(0.25) > correct_int_perc_prob) ||
		     ((drand48() < 0.005) && (drand48() > correct_int_perc_prob)))

	  int_perception_correct = FALSE;

    /* transfer contents (if any) of square to perception array */
    sqr_to_perc_struct(c, r, ac, ar, correct_ext_perc_prob,
        correct_int_perc_prob);

    /* if whole of square incorrectly perceived then change the contents
    of the square so that what is perceived is different from the
    contents of env_arr */
    if (ext_perception_correct == FALSE)

	  rearrange_sqr(ac, ar, c, r);

    /* if just interior of square incorrectly perceived then change SOME
    (ie. animal parts) of the contents of the square so that what is
    perceived is different from the contents of env_arr */
    else if (int_perception_correct == FALSE)

	  rearrange_int_sqr(ac, ar, c, r);

    /* as well as changing which features are present in a square, change
    the values of the attributes or properties of the features in the square
    according to how well the square can be perceived */
    change_feature_props(c, r, correct_int_perc_prob, correct_ext_perc_prob);

/*g*/    /* if the perception display is on ... */
/*g*/    if (perc_display_on)
/*g*/
/*g*/      /* if this square is within the bounds of the environment */
/*g*/      if (square_in_env(ac, ar)) {
/*g*/
/*g*/		/* draw the contents of the square as perceived by the animal */
/*g*/		draw_perc_square(c, r, correct_ext_perc_prob,
/*g*/		ext_perception_correct, int_perception_correct);
/*g*/      }
/*g*/
/*g*/      else { 	/* if animal outside nvironment */
/*g*/
/*g*/		/* Draw a white square onto the perception display */
/*g*/		pw_rop(perception_pw, ((c+M_A_P)*SQUARE_SIZE + 15),
/*g*/		      ((r+M_A_P)*SQUARE_SIZE + 45), SQUARE_SIZE, SQUARE_SIZE,
/*g*/			  (PIX_SRC | PIX_COLOR(27)), NULL, 0, 0); 
/*g*/	  }
  }

  /* initialise feature_counters */
  for (i = 0; i < NUM_FEATURE_TYPES; i++)
    feature_counters[i] = 0;

  /* "feature_instance_indexs" is a 2D array, one vector for each type of
  feature.  Each vector contains a list of indexs to "perc_fs", denoting the
  positions of entries of that feature type.  This will allow quick scanning
  of all entries of a particular feature type */
  for (i = 0; i < anim_perc.perc_f_count; i++) {

    /* get number of feature type */
    nft = anim_perc.perc_fs[i].nft;

    /* put index into right place in "feature_instance_indexs" */
    anim_perc.feature_instance_indexs[nft][feature_counters[nft]] = i;

    /* increment counter for feature type */
    feature_counters[nft]++;
  }    
}


/* function to make any changes to the environment caused by the animal's
actions (such as eating, drinking, etc) */
void animal_change_to_env()
{

  double animal_exertion;
  double grnd;

  prev_animal_c = animal_c;
  prev_animal_r = animal_r;

  /* move the animal to its new position (assuming it decided to move in the
  last timestep) */
  if ((move_action_chosen() == TRUE) ||
	  (move_fast_action_chosen() == TRUE)) { 

    if (square_in_env(animal_c, animal_r)) {
      env_arr[animal_c][animal_r].p_arr[ANIMAL_N] = (void *) NULL;
/*g*/      redraw_square(animal_c, animal_r);
    }

    animal_c += c_change;
    animal_r += r_change;

    if (square_in_env(animal_c, animal_r)) {
      env_arr[animal_c][animal_r].p_arr[ANIMAL_N] = (void *) NOT_NULL;
/*g*/      add_to_square(ANIMAL_N, animal_c, animal_r);
    }
  }

  /* increase animal's age */
  animal_age += 1.0 / ((double) DAY_LENGTH);

  /* calculate the values of the animal's fat, carbohydrate, protein, water
  and temperature */ 

  /* the temperature in the square equals the temperature in the environment
  modified by a factor for the vegetation, etc in the square */
  if (square_in_env(animal_c, animal_r))
    sqr_temp = env_temp * env_arr[animal_c][animal_r].temp_factor;
  else
    sqr_temp = env_temp;

  /* food and temperature changes depend on animal's action */
  if (sim_env_version == V3) {
    if (animal_action == SLEEPING)
	  animal_exertion = 0.0;
    else if (animal_action == RESTING)
	  animal_exertion = 0.1;
    else if (animal_action == FREEZING)
	  animal_exertion = 0.4;
    else if (animal_action == EATING_CF)
	  animal_exertion = 0.3;
    else if (animal_action == EATING_FF)
	  animal_exertion = 0.3;
    else if (animal_action == POUNCING)
	  animal_exertion = 0.2;
    else if (animal_action == DRINKING)
	  animal_exertion = 0.3;
    else if (animal_action == CLEANING)
	  animal_exertion = 0.4;
    else if (animal_action == COURT_DISPLAYING)
	  animal_exertion = 0.3;
    else if (animal_action == MATING)
	  animal_exertion = 0.5;
    else if (look_action_chosen() == TRUE)
	  animal_exertion = 0.1;
    else if (move_action_chosen() == TRUE)
	  animal_exertion = 0.2;
    else if (move_fast_action_chosen() == TRUE)
	  animal_exertion = 0.3;
  }
  else {
    if (animal_action == SLEEPING)
	  animal_exertion = 0.0;
    else if (animal_action == RESTING)
	  animal_exertion = 0.1;
    else if (animal_action == FREEZING)
	  animal_exertion = 0.5;
    else if (animal_action == EATING_CF)
	  animal_exertion = 0.6;
    else if (animal_action == EATING_FF)
	  animal_exertion = 0.6;
    else if (animal_action == POUNCING)
	  animal_exertion = 0.9;
    else if (animal_action == DRINKING)
	  animal_exertion = 0.6;
    else if (animal_action == CLEANING)
	  animal_exertion = 0.3;
    else if (animal_action == COURT_DISPLAYING)
	  animal_exertion = 0.7;
    else if (animal_action == MATING)
	  animal_exertion = 1.0;
    else if (look_action_chosen() == TRUE)
	  animal_exertion = 0.3;
    else if (move_action_chosen() == TRUE)
	  animal_exertion = 0.7;
    else if (move_fast_action_chosen() == TRUE)
	  animal_exertion = 0.9;
  }

  animal_fat -= MAX_FAT_DECREMENT * animal_exertion;
  animal_carbo -= MAX_CARBO_DECREMENT * animal_exertion;
  animal_protein -= MAX_PROTEIN_DECREMENT * animal_exertion;
  animal_water -= MAX_WATER_DECREMENT * animal_exertion;

  /* transfer animal_temp to 0.0-1.0 scale and add factor for exertion */
  animal_temp = ((sqr_temp+1.0)/2.0) - 0.20 + (0.40 * animal_exertion);

  /* animal temperature not allowed to change too drastically in a single
  timestep */
  if ((prev_animal_temp - animal_temp) > MAX_AN_TEMP_DECREASE)
	animal_temp = prev_animal_temp - MAX_AN_TEMP_DECREASE;
  if ((animal_temp - prev_animal_temp) > MAX_AN_TEMP_INCREASE)
	animal_temp = prev_animal_temp + MAX_AN_TEMP_INCREASE;

  /* animal's fat level cannot be less than zero (fatal) */
  if (animal_fat < 0.0)
    animal_fat = 0.0;

  /* animal's carbo level cannot be less than zero (fatal) */
  if (animal_carbo < 0.0)
    animal_carbo = 0.0;

  /* animal's protein level cannot be less than zero (fatal) */
  if (animal_protein < 0.0)
    animal_protein = 0.0;

  /* animal's water level cannot be less than zero (fatal) */
  if (animal_water < 0.0)
    animal_water = 0.0;

  /* animal's temperature cannot be greater than 1.0 (fatal) */
  if (animal_temp < 0.0)
	animal_temp = 0.0;

  /* animal's temperature cannot be greater than 1.0 (fatal) */
  if (animal_temp > 1.0)
	animal_temp = 1.0;

  /* if animal is cleaning itself then increase its cleanliness.  Make it
  increasingly harder to improve cleanliness as it gets towards 1.0 */
  /* decrease the animal's cleanliness unless it is cleaning itself */
  if (animal_action == CLEANING) {
	grnd = g_rnd(0.0,0.03);
	animal_cleanliness += ((1.0 - animal_cleanliness) * 0.15) +
	  grnd; 
  }
  else {
	grnd = g_rnd(0.0,0.0001);
	animal_cleanliness -= (0.001 + grnd);
	if (animal_cleanliness < 0.0)
	  animal_cleanliness = 0.0;
  }

  calc_animal_health();

  animal_eating = FALSE;
  animal_drinking = FALSE;

  /* if the animal is currently in the environment ... */
  if (square_in_env(animal_c, animal_r)) {

    /* calculate how conspicuous the animal is */
    get_conspicuousness();

	/* calculate what the probability of the animal being able to escape if
	attacked is */
	get_escape_prob();

	/* calculate effects on animal of different features in square */
    if (env_arr[animal_c][animal_r].p_arr[CEREAL_FOOD_N] != ((void *) NULL))
	  animal_effect_on_cereal_food();
    if (env_arr[animal_c][animal_r].p_arr[FRUIT_FOOD_N] != ((void *) NULL))
	  animal_effect_on_fruit_food();
    if (env_arr[animal_c][animal_r].p_arr[IRRELEVANT_N] != ((void *) NULL))
	  irrelevant_effect_on_animal();
    if (env_arr[animal_c][animal_r].p_arr[WATER_N] != ((void *) NULL))
	  animal_effect_on_water();
    if (env_arr[animal_c][animal_r].p_arr[MATE_N] != ((void *) NULL))
	  animal_effect_on_mate();
    if (env_arr[animal_c][animal_r].p_arr[PREY_N] != ((void *) NULL))
	  animal_effect_on_prey();
  }

  else {        /* if animal is outside environemnt */

	/* do nothing */
  }

  /* if health <= zero then animal dies */
  if (animal_health <= 0.0)
    animal_alive = FALSE;

  prev_animal_temp = animal_temp;
}


/* function to update the animal's map, if it has just visited a feature */
void update_animal_map()
{

  int i;
  int match;	/* index to entry in spatial memory that is matched with
				feature in current square */
  static int last_place;
  int nft;
  int *ptr_to_nft, *ptr_to_match;
  char text[50];

  prev_est_an_c = est_an_c;  
  prev_est_an_r = est_an_r;

  this_place = -1;
  this_place_now_in_map = FALSE;
  this_place_recognised = FALSE;

  ptr_to_nft = &nft;
  ptr_to_match = &match;

  /* if the animal is back at the den then reset its coordinates and make
  its position completely certain */
  if (((animal_c == first_den_c) && (animal_r == first_den_r)) ||
	  (env_arr[animal_c][animal_r].p_arr[DEN_N] != ((void *) NULL))) {

	est_an_c = 0.0;
	est_an_r = 0.0;
	num_uncertain_steps = 0.0;
	an_pos_variance = 0.0;
  }

  else {				/* animal not in den */

	/* if animal is moving */
	if (((animal_c - prev_animal_c) != 0) ||
		((animal_r - prev_animal_r) != 0)) {

	  /* add a normally distributed random error to the animal's estimate of
	  where it moved */
	  est_an_c += ((double) (animal_c-prev_animal_c)) + g_rnd(0.0, NAV_ERROR);
	  est_an_r += ((double) (animal_r-prev_animal_r)) + g_rnd(0.0, NAV_ERROR);

	  num_uncertain_steps += 1.0;

	  an_pos_variance = num_uncertain_steps * NAV_ERROR;

	  /* make a new memory of this place or update an old one, if this place
	  has got a feature in the square and if the animal's variance is
	  reasonable (no point in forming a memory if the animal is "lost") */
	  if ((physical_feature_in_square(ptr_to_nft) == TRUE) &&
		  (an_pos_variance < 4.0)) {

		if (feature_matches_memory_entry(nft, ptr_to_match)) {

		  update_recognised_feature(match);
		  this_place_now_in_map = TRUE;
		  this_place_recognised = TRUE;
		}

		else {

		  create_new_feature_memory(nft);
		  this_place_now_in_map = TRUE;
		  this_place_recognised = FALSE;
		}
	  }

	  /* animal has moved on to new place, so keep a record of the position
	  of the entry in the map describing this new place */
	  last_place = this_place;
	}

	else {			/* if the animal is not moving */

	  if ((physical_feature_in_square(ptr_to_nft) == TRUE) &&
		  (an_pos_variance < 4.0)) {

		this_place = last_place;
		this_place_now_in_map = TRUE;
		this_place_recognised = TRUE;
	  }
	}
  }

  /* decay all memories */
  for (i = 0; i < num_active_memories; i++)
	map[i]->memory_strength *= MEMORY_DECAY_FACTOR;

  /* increase the time since each food/water source was visited */
  for (i = 0; i < num_active_memories; i++) {
	map[i]->time_since_consumed++;
	map[i]->time_since_unsuccessful_visit++;
  }

  time_since_useless_cereal_food++;
  time_since_useless_fruit_food++;
  time_since_useless_water++;

  /* increase the time since the animal mated or was rejected when courting */
  time_since_animal_mated++;
  time_since_animal_courting_rejected++;

  /* if the animal thinks it should be at a particular feature, but the
  feature in the current square (if there is one) is not matched with the
  feature in the memory, then decrease the strength of the memory and
  increase its variance so that it becomes less likely to be headed towards
  in the future */
  for (i = 0; i < num_active_memories; i++)
	if ((fabs(est_an_c-map[i]->est_c) < 0.5) &&
		(fabs(est_an_r-map[i]->est_r) < 0.5) &&
		((this_place_recognised == FALSE) ||
		 (this_place != i))) {
	  map[i]->memory_strength *= 0.5;
	  map[i]->variance *= 2.0;
	}

  /* if the animal has eaten or drunk a sizeable amount this timestep and
  the animal has formed a memory of this place then reset the
  time_since_consumed field for this memory */
  if (this_place_now_in_map && (animal_eating || animal_drinking))

	map[this_place]->time_since_consumed = 0;

  /* if the animal has visited a food or water source this go but the
  stimulus from it was very low (eg. from low value, toxicity, whatever)
  then record the fact that it was unsuccessfully visited */
  if ((physical_feature_in_square(ptr_to_nft) == TRUE) &&
	  (this_place_now_in_map == TRUE) &&
	  (this_place != -1)) { 

	if ((nft == CEREAL_FOOD_N) &&
		(food_toxic == TRUE) &&
	    (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][nft]
		 ->f_num].value > 0.20)) {
	  time_since_useless_cereal_food = 0;
	  map[this_place]->time_since_unsuccessful_visit = 0;
	}

	else if ((nft == FRUIT_FOOD_N) &&
			 (food_toxic == TRUE) &&
			 (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][nft]
			  ->f_num].value > 0.20)) {
	  time_since_useless_fruit_food = 0;
	  map[this_place]->time_since_unsuccessful_visit = 0;
	}

	/* if feature is water and remembered as toxic and also has a high
	perceived value then set time since useless to zero */
	else if ((nft == WATER_N) &&
			 (water_toxic == TRUE) &&
			 (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][nft]
			  ->f_num].value > 0.20)) {
	  time_since_useless_water = 0;
	  map[this_place]->time_since_unsuccessful_visit = 0;
	}
  }
/*g*/
/*g*/  if (nav_display_on) {
/*g*/
/*g*/	/* draw the animal's estimated trajectory in last timestep */
/*g*/  	pw_vector(nav_pw, (200+((int) (prev_est_an_c*15.0))),
/*g*/					  (200+((int) (prev_est_an_r*15.0))),
/*g*/					  (200+((int) (est_an_c*15.0))),
/*g*/					  (200+((int) (est_an_r*15.0))),
/*g*/					  (PIX_SRC|PIX_COLOR(40)), 0);
/*g*/
/*g*/	/* draw the animal's actual trajectory in last timestep */
/*g*/	pw_vector(nav_pw, (200+((prev_animal_c-first_den_c)*15)),
/*g*/					  (200+((prev_animal_r-first_den_r)*15)),
/*g*/    				  (200+((animal_c-first_den_c)*15)),
/*g*/					  (200+((animal_r-first_den_r)*15)),
/*g*/					  (PIX_SRC|PIX_COLOR(5)), 0);
/*g*/
/*g*/	sprintf(text, "variance is %g  ", an_pos_variance);
/*g*/	/* write the variance of the animal's coordinates onto the pixwin */
/*g*/	pw_text(nav_pw, 20, 20, (PIX_SRC|PIX_COLOR(30)), serif_r_14, text);
/*g*/  }

  /* update the value of distance_to_cover */
  update_distance_to_cover();
}


/* function which returns TRUE if the animal perceives a physical feature in
its square, or else FALSE */
int physical_feature_in_square(ptr_to_nft)
int *ptr_to_nft;
{

  int feature_type;

  for (feature_type = 0; feature_type < NUM_FEATURE_TYPES; feature_type++) {

	/* if the animal can perceive this feature fairly certainly in its
	square and if the feature is a physical one, but not the outside of the
	environment */
	if ((anim_perc.counters[M_A_P][M_A_P][feature_type] > 0) &&
		(PHYSICAL_FEATURE(feature_type)) &&
		(feature_type != OUTSIDE_ENV_N) &&
		(anim_perc.ext_perc_probs[M_A_P][M_A_P] > 0.5)) {

	  *ptr_to_nft = feature_type;
	  return(TRUE);
	}
  }

  return(FALSE);
}


/* function which returns TRUE if there is a feature in the animal's memory
which is close enough to the physical feature in the animal's square to
match with it, and FALSE otherwise.  Differences in property values are not
used to determine the likelihood of a match (nearly all variable), except
for landmarks, cover and shade */
int feature_matches_memory_entry(nft, match_index_ptr)
int nft;
int *match_index_ptr;
{

  int i;
  double c_diff, r_diff;
  double combined_variance;
  double mahalanobis_distance_sqrd_c, mahalanobis_distance_sqrd_r;
  int no_match_due_to_properties;
  double closeness_of_match_measure_c, closeness_of_match_measure_r;

  for (i = 0; i < num_active_memories; i++) {

	if (nft == map[i]->nft) {

	  no_match_due_to_properties = FALSE;

	  switch(nft) {

		case(COVER_N)      : if (drand48() < 
		  (fabs(anim_perc.perc_fs[anim_perc.contents
		  [M_A_P][M_A_P][nft]->f_num].thickness - map[i]->est_thickness)))
							   no_match_due_to_properties = TRUE;
						     break;
		case(FRUIT_FOOD_N)      : if (drand48() < 
		  (fabs(anim_perc.perc_fs[anim_perc.contents
		  [M_A_P][M_A_P][nft]->f_num].conditions - map[i]->est_conditions)))
							   no_match_due_to_properties = TRUE;
						     break;
		case(LANDMARK_N): /* if landmark same as one in memory then force a
						  match, otherwise don't allow a match */
						  if (anim_perc.perc_fs[anim_perc.contents
		  [M_A_P][M_A_P][nft]->f_num].number != map[i]->est_number)

							   no_match_due_to_properties = TRUE;

						  else {

							*match_index_ptr = i;
							return(TRUE);
						  }
						  break;
		case(SHADE_N): if (drand48() < 
		  (fabs(anim_perc.perc_fs[anim_perc.contents
		  [M_A_P][M_A_P][nft]->f_num].thickness - map[i]->est_thickness)))
							   no_match_due_to_properties = TRUE;
							 break;
		default:			 break;
	  }

	  if (no_match_due_to_properties == FALSE) {

		c_diff  = fabs(est_an_c - map[i]->est_c);
		r_diff  = fabs(est_an_r - map[i]->est_r);

		/* combined variance = sum of both, but also multiplied by two since
		considering sum of differences in both x and y directions */
		combined_variance = an_pos_variance + map[i]->variance;

		/* calculate difference divided by standard deviation = Mahalanobis
		distance = how many standard deviations away from mean of normal
		distribution */
		if (combined_variance > 0.1) {

		  mahalanobis_distance_sqrd_c = (c_diff*c_diff)/combined_variance;
		  mahalanobis_distance_sqrd_r = (r_diff*r_diff)/combined_variance;

		  /* add in term to Mahalanobis distance squared to prejudice
		  against large variances, even for small difference in positions */ 
		  closeness_of_match_measure_c = mahalanobis_distance_sqrd_c +
			log(combined_variance);
		  closeness_of_match_measure_r = mahalanobis_distance_sqrd_r +
			log(combined_variance);

		  /* accept match if good probability of perceived and remembered
		  feature being one and the same, and if the sum of the variances of
		  the animal's position and the feature's position is not too high*/
		  if (((combined_variance < 0.50) &&
				(c_diff < 0.7) &&
				(r_diff < 0.7)) ||
			  ((closeness_of_match_measure_c < 7.0) &&
		  	   (closeness_of_match_measure_r < 7.0) &&
			   (combined_variance < 3.0) &&
			   (c_diff < 0.9) && (r_diff < 0.9))) {

			*match_index_ptr = i;
			return(TRUE);
		  }
		}

		else {			/* if combined variance < 0.1 */

		  if ((c_diff < 0.4) && (r_diff < 0.4)) {

			*match_index_ptr = i;
			return(TRUE);
		  }
		}
	  }
	}
  }

  return(FALSE);
}


/* function to update a memory of a feature when the animal encounters it
for a second time (or THINKS it does) */
void update_recognised_feature(match)
int match;
{

  int ft;		/* feature type */
  double init_mem_strength, old_mem_strength;
  double old_map_variance;
  double one_over_apv, one_over_fpv;

  old_map_variance = map[match]->variance;

  if (an_pos_variance < 0.00001) {

	map[match]->est_c = est_an_c;
	map[match]->est_r = est_an_r;
	map[match]->variance = an_pos_variance;
  }

  else if (map[match]->variance < 0.00001) {

	/* do nothing */
  }

  else {		/* neither known perfectly */

	one_over_apv = 1.0 / ((double) an_pos_variance);
	one_over_fpv = 1.0 / ((double) map[match]->variance);

	map[match]->est_c = (double)
						(((double) map[match]->est_c) * one_over_fpv +
					     ((double) est_an_c) * one_over_apv) /
					    (one_over_apv + one_over_fpv);

	map[match]->est_r = (double)
						(((double) map[match]->est_r) * one_over_fpv +
					     ((double) est_an_r) * one_over_apv) /
					    (one_over_apv + one_over_fpv);

	map[match]->variance = 1.0 / (one_over_apv + one_over_fpv);
  }

  map[match]->num_recognitions++;

  ft = map[match]->nft;

  old_mem_strength = map[match]->memory_strength;

  /* calculate what the initial memory strength of this memory would be */
  if (map[match]->variance < 0.00001)
	init_mem_strength = 50.0;

  else {

	init_mem_strength = (5.0 / map[match]->variance);

	if (init_mem_strength > 50.0)
	  init_mem_strength = 50.0;
  }

  switch(ft) {

	case(CEREAL_FOOD_N): init_mem_strength *= (0.1 + 0.9 *
  anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value);
						   break;
	case(COVER_N)      : init_mem_strength *=
  (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].thickness);
						   break;
	case(FRUIT_FOOD_N): init_mem_strength *= (0.5 + 0.5 * 
  anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value);
						  break;
	case(SHADE_N): init_mem_strength *= 
  (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].thickness);
					 break;
	case(WATER_N): init_mem_strength *= (0.5 + 0.5 * 
  anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value);
					 break;
	default: break;
  }

  map[match]->memory_strength += init_mem_strength;

  switch(ft) {

	case(CEREAL_FOOD_N): map[match]->est_value =
	((map[match]->est_value*old_mem_strength) + 
  (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value
		* (map[match]->memory_strength - old_mem_strength)))
	  / map[match]->memory_strength;
						   break;
	case(COVER_N)      : map[match]->est_thickness =
	((map[match]->est_thickness*old_mem_strength) *
  (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].thickness
		* (map[match]->memory_strength - old_mem_strength)))
	  / map[match]->memory_strength;
						   break;
	case(FRUIT_FOOD_N): map[match]->est_conditions=
	((map[match]->est_conditions*old_mem_strength) + 
  (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].conditions
		* (map[match]->memory_strength - old_mem_strength)))
	  / map[match]->memory_strength;
						map[match]->est_value =
	((map[match]->est_value*old_mem_strength) + 
  (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value
		* (map[match]->memory_strength - old_mem_strength)))
	  / map[match]->memory_strength;
						  break;
	case(SHADE_N): map[match]->est_thickness =
	((map[match]->est_thickness*old_mem_strength) + 
  (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].thickness
		* (map[match]->memory_strength - old_mem_strength)))
	  / map[match]->memory_strength;
					 break;
	case(WATER_N): map[match]->est_value =
	((map[match]->est_value*old_mem_strength) + 
  (anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value
		* (map[match]->memory_strength - old_mem_strength)))
	  / map[match]->memory_strength;
					 break;
	default: break;
  }

  /* make the animal's estimate of where it is equal to the estimate of the
  position of the feature, unless there is a reasonable chance of a bad
  match, in which case don't change the animal's estimate of where it is */
  if ((old_map_variance+an_pos_variance) < 1.0) {
	est_an_c = map[match]->est_c;
	est_an_r = map[match]->est_r;

  	/* change the variance of the animal's position and the equivalent
	number of uncertain steps it must have taken to get that variance */
	an_pos_variance = map[match]->variance;
	if (NAV_ERROR != 0.0)
	  num_uncertain_steps = an_pos_variance / NAV_ERROR;
	else
	  num_uncertain_steps = 0;
  }

  else {
	/* don't change anything if not very sure of match */
  }

  this_place = match;

  /* sort the list of memories so that the current one gets moved up the
  list according to its change in memory strength */
  sort_map();
}


/* function to create a new memory when the animal comes across something it
does not recognise */
void create_new_feature_memory(ft)
int ft;		/* type of feature in square */
{

  int index;
  double init_mem_strength;

  if (an_pos_variance < 0.00001)
	init_mem_strength = 50.0;

  else {

	init_mem_strength = (5.0/an_pos_variance);

	switch(ft) {

	  case(CEREAL_FOOD_N): init_mem_strength *= 0.1 + 0.9 *
	anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value;
						   break;
	  case(COVER_N)      : init_mem_strength *=
	anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].thickness;
						   break;
	  case(FRUIT_FOOD_N): init_mem_strength *= 0.5 + 0.5 * 
	anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value;
						  break;
	  case(SHADE_N): init_mem_strength *= 
	anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].thickness;
					 break;
	  case(WATER_N): init_mem_strength *= 0.5 + 0.5 * 
	anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value;
					 break;
	  default: break;
	}
  }

  /* decide where to put this memory into the "map" */
  if (num_active_memories < map_sze)

	index = num_active_memories;

  else

	index = map_sze-1;

  /* if the memory is not yet full then increment the counter for active
  memories */
  if (num_active_memories < map_sze)
	num_active_memories++;

  /* copy the new details into the relevant memory slot */
  map[index]->nft = ft;
  map[index]->num_recognitions = 1;
  map[index]->variance = an_pos_variance;
  map[index]->memory_strength = init_mem_strength;
  map[index]->est_c = est_an_c;
  map[index]->est_r = est_an_r;

  /* set values for all fields of map entry, even if they will not be used*/
  map[index]->est_number = 0;
  map[index]->est_value = 0.0;
  map[index]->est_thickness = 0.0;
  map[index]->est_conditions = 0.0;
  map[index]->est_toxicity = 0.0;
  map[index]->time_since_consumed = 100000;
  map[index]->time_since_unsuccessful_visit = 100000;

  switch(ft) {

	case(CEREAL_FOOD_N): map[index]->est_value =
anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value;
						   break;
	case(COVER_N)      : map[index]->est_thickness =
anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].thickness;
						   break;
	case(FRUIT_FOOD_N): map[index]->est_value =
anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value;
						map[index]->est_conditions =
anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].conditions;
						  break;
	case(LANDMARK_N): map[index]->est_number =
anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].number;
						break;
	case(SHADE_N): map[index]->est_thickness =
anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].thickness;
					 break;
	case(WATER_N): map[index]->est_value =
anim_perc.perc_fs[anim_perc.contents[M_A_P][M_A_P][ft]->f_num].value;
					 break;
	default: break;
  }

  this_place = index;

  /* sort the list so that the new memory gets put in the correct place */
  sort_map();

/*g*/  /* draw where the animal thinks this feature is */
/*g*/  if (map_display_on)
/*g*/	draw_memory(this_place);
}


/* function to make any changes to the animal as a result of the changes in
the environment (e.g. predators moving into same square and attacking
animal) */
void env_change_to_animal()
{

  int i;
  int total_num;

  double clean_p, move_p, move_fast_p, eat_p, sleep_p, rest_p, freeze_p,
  drink_p, mate_p, look_p; 

  /* if the animal is currently in the environment ... */
  if (square_in_env(animal_c, animal_r)) {

	/* calculate effects on animal of different features in square */
    if (env_arr[animal_c][animal_r].p_arr[COVER_N] != ((void *) NULL))
	  cover_effect_on_animal();
    if (env_arr[animal_c][animal_r].p_arr[DANGEROUS_PLACE_N]!=((void *) NULL))
	  dangerous_place_effect_on_animal();
    if (env_arr[animal_c][animal_r].p_arr[DEN_N] != ((void *) NULL))
	  den_effect_on_animal();
    if (env_arr[animal_c][animal_r].p_arr[SHADE_N] != ((void *) NULL))
	  shade_effect_on_animal();
    if (env_arr[animal_c][animal_r].p_arr[LANDMARK_N] != ((void *) NULL))
	  landmark_effect_on_animal();
    if (env_arr[animal_c][animal_r].p_arr[PREDATOR_1_N] != ((void *) NULL))
	  predator_1_effect_on_animal();
    if (env_arr[animal_c][animal_r].p_arr[PREDATOR_2_N] != ((void *) NULL))
	  predator_2_effect_on_animal();
  }

  else {		/* animal outside environment */

    outside_env_effect_on_animal();
  }

  /* if health <= zero then animal dies */
  if (animal_health <= 0.0)
    animal_alive = FALSE;

/*g*/  update_animal_display();
}


/*g*//* function to update the display for the animal variables */
/*g*/void update_animal_display()
/*g*/{
/*g*/
/*g*/  int health_w;
/*g*/  int gen_fit_w;
/*g*/  static int old_health_w;
/*g*/  static int old_gen_fit_w;
/*g*/
/*g*/  if (animal_display_on) {
/*g*/
/*g*/    /* work out positions on graph for new health and genetic fitness
/*g*//*	variable values */
/*g*/    health_w = (int) (animal_health*99.0);
/*g*/    gen_fit_w = (int) ((((double) genetic_fitness)/MAX_LIKELY_G_F)*99.0);
/*g*/
/*g*/	/* draw blank over where the old bars were */
/*g*/	pw_rop(animal_pw, 31, 75, 7, 100, PIX_CLR, NULL, 0, 0);
/*g*/	pw_rop(animal_pw, 101, 75, 7, 100, PIX_CLR, NULL, 0, 0);
/*g*/	pw_rop(animal_pw, 171, 75, 7, 100, PIX_CLR, NULL, 0, 0);
/*g*/	pw_rop(animal_pw, 241, 75, 7, 100, PIX_CLR, NULL, 0, 0);
/*g*/	pw_rop(animal_pw, 311, 75, 7, 100, PIX_CLR, NULL, 0, 0);
/*g*/	pw_rop(animal_pw, 381, 75, 7, 100, PIX_CLR, NULL, 0, 0);
/*g*/
/*g*/	/* draw on bars to show values of the six shown variables */
/*g*/	pw_rop(animal_pw, 31, 175-((int) (100.0*animal_fat)), 7,
/*g*/	  ((int) (100.0*animal_fat)), op[5], NULL, 0, 0); 
/*g*/	pw_rop(animal_pw, 101, 175-((int) (100.0*animal_carbo)), 7,
/*g*/	  ((int) (100.0*animal_carbo)), op[5], NULL, 0, 0); 
/*g*/	pw_rop(animal_pw, 171, 175-((int) (100.0*animal_protein)), 7,
/*g*/	  ((int) (100.0*animal_protein)), op[5], NULL, 0, 0); 
/*g*/	pw_rop(animal_pw, 241, 175-((int) (100.0*animal_water)), 7,
/*g*/	  ((int) (100.0*animal_water)), op[5], NULL, 0, 0); 
/*g*/	pw_rop(animal_pw, 311, 175-((int) (100.0*animal_temp)), 7,
/*g*/	  ((int) (100.0*animal_temp)), op[5], NULL, 0, 0);
/*g*/	pw_rop(animal_pw, 381, 175-((int) (100.0*animal_cleanliness)), 7,
/*g*/	  ((int) (100.0*animal_cleanliness)), op[5], NULL, 0, 0); 
/*g*/
/*g*/    /* only redraw the health value if it has changed */
/*g*/    if (health_w != old_health_w) {
/*g*/      pw_rop(animal_pw, 61, 231, 99, 8, PIX_CLR, NULL, 0, 0);
/*g*/      pw_rop(animal_pw, 61, 231, health_w, 8,
/*g*/ 		op[(1+(int)(animal_health*4.9999))], NULL, 0, 0);
/*g*/    }
/*g*/
/*g*/    /* only redraw the genetic fitness value if it has changed */
/*g*/    if (gen_fit_w != old_gen_fit_w) {
/*g*/      pw_rop(animal_pw, 241, 231, 99, 8, PIX_CLR, NULL, 0, 0);
/*g*/      pw_rop(animal_pw, 241, 231, gen_fit_w, 8, 
/*g*/		op[(1+(int)(((double)genetic_fitness)/MAX_LIKELY_G_F*4.9999))], NULL,
/*g*/		0, 0);
/*g*/    }
/*g*/  }
/*g*/
/*g*/  old_health_w = health_w;
/*g*/  old_gen_fit_w = gen_fit_w;
/*g*/}
/*g*/
/*g*/
/*g*//* function to display information about the animal at any moment in time */
/*g*/void animal_change_proc()
/*g*/{
/*g*/
/*g*/  if (window_get(animal_frame, WIN_SHOW) == FALSE) {
/*g*/	turn_on(animal_frame);
/*g*/	animal_display_on = TRUE;
/*g*/  }
/*g*/  else {
/*g*/	turn_off(animal_frame);
/*g*/	animal_display_on = FALSE;
/*g*/  }
/*g*/}
/*g*/
/*g*/
/*g*//* function to display information about what the animal can perceive */
/*g*/void perception_change_proc()
/*g*/{
/*g*/
/*g*/  if (window_get(perception_frame, WIN_SHOW) == FALSE) {
/*g*/	turn_on(perception_frame);
/*g*/	perc_display_on = TRUE;
/*g*/  }
/*g*/  else {
/*g*/	turn_off(perception_frame);
/*g*/	perc_display_on = FALSE;
/*g*/  }
/*g*/}
/*g*/
/*g*/
/*g*//* function to display information about the map at any moment in time */
/*g*/void map_change_proc()
/*g*/{
/*g*/
/*g*/  if (window_get(map_frame, WIN_SHOW) == FALSE) {
/*g*/	turn_on(map_frame);
/*g*/	map_display_on = TRUE;
/*g*/  }
/*g*/  else {
/*g*/	turn_off(map_frame);
/*g*/	map_display_on = FALSE;
/*g*/  }
/*g*/}
/*g*/
/*g*/
/*g*//* function to display information about navigation at any moment in */
/*g*//* time */ 
/*g*/void nav_change_proc()
/*g*/{
/*g*/
/*g*/  if (window_get(nav_frame, WIN_SHOW) == FALSE) {
/*g*/	turn_on(nav_frame);
/*g*/	nav_display_on = TRUE;
/*g*/  }
/*g*/  else {
/*g*/	turn_off(nav_frame);
/*g*/	nav_display_on = FALSE;
/*g*/  }
/*g*/}


/* function to return, in sequence squares around (0,0) which spiral outwards
from the adjacent ones to further away ones.  So if wanting squares up to
range 2, then results returned, via pointers, will successively be {(0,0),
(0,1), (1,1), (1,0), (1,-1), (-1,-1), (-1,0), (-1,1), (0,2) ....... (-2,0)}
since squares such as (-2,2), (-1,2) out of range.  (This function can not
handle ranges greater than 4 at present) */
int get_adj_square(ptr_c, ptr_r, obscures_list)
int *ptr_c;
int *ptr_r;
double obscures_list[15];        /* list to show which squares obscure this
        one, and by how much. max size = 1 count + 7*(1 number + 1 degree)*/ 
{

  static int call_number;		/* number of times function called since
								beginning of this sequence */

  *ptr_c = 100; *ptr_r = 100;

  while (((*ptr_c)*(*ptr_c) + (*ptr_r)*(*ptr_r)) >
		 (M_A_P*M_A_P)) {

	/* for each square, list the squares that obscure it, together with a
	`blocking measure', i.e how much they block it (first number is count of
	number of obscuring squares) */
    switch((call_number+1)) {
      case(1):  *ptr_c = 0;
      		    *ptr_r = 0;
                obscures_list[0] = 0.0;
			    break;
      case(2):  *ptr_c = 0;
			    *ptr_r = -1;
                obscures_list[0] = 1.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
			    break;
      case(3):  *ptr_c = 1;
			    *ptr_r = 0;
                obscures_list[0] = 1.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
			    break;
      case(4):  *ptr_c = 0;
			    *ptr_r = 1;
                obscures_list[0] = 1.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
			    break;
      case(5):  *ptr_c = -1;
			    *ptr_r = 0;
                obscures_list[0] = 1.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
			    break;
      case(6):  *ptr_c = 1;
			    *ptr_r = -1;
                obscures_list[0] = 3.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 2.0;
                obscures_list[4] = 0.25;
                obscures_list[5] = 3.0;
                obscures_list[6] = 0.25;
			    break;
      case(7):  *ptr_c = 1;
			    *ptr_r = 1;
                obscures_list[0] = 3.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 3.0;
                obscures_list[4] = 0.25;
                obscures_list[5] = 4.0;
                obscures_list[6] = 0.25;
			    break;
      case(8):  *ptr_c = -1;
			    *ptr_r = 1;
                obscures_list[0] = 3.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 4.0;
                obscures_list[4] = 0.25;
                obscures_list[5] = 5.0;
                obscures_list[6] = 0.25;
			    break;
      case(9):  *ptr_c = -1;
			    *ptr_r = -1;
                obscures_list[0] = 3.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 2.0;
                obscures_list[4] = 0.25;
                obscures_list[5] = 5.0;
                obscures_list[6] = 0.25;
			    break;
      case(10): *ptr_c = 0;
			    *ptr_r = -2;
                obscures_list[0] = 2.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 2.0;
                obscures_list[4] = 1.0;
			    break;
      case(11): *ptr_c = 2;
			    *ptr_r = 0;
                obscures_list[0] = 2.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 3.0;
                obscures_list[4] = 1.0;
			    break;
      case(12): *ptr_c = 0;
			    *ptr_r = 2;
                obscures_list[0] = 2.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 4.0;
                obscures_list[4] = 1.0;
			    break;
      case(13): *ptr_c = -2;
			    *ptr_r = 0;
                obscures_list[0] = 2.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 5.0;
                obscures_list[4] = 1.0;
			    break;
      case(14): *ptr_c = 1;
			    *ptr_r = -2;
                obscures_list[0] = 4.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 2.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 6.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 10.0;
                obscures_list[8] = 0.25;
			    break;
      case(15): *ptr_c = 2;
			    *ptr_r = -1;
                obscures_list[0] = 4.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 6.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 3.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 11.0;
                obscures_list[8] = 0.25;
			    break;
      case(16): *ptr_c = 2;
			    *ptr_r = 1;
                obscures_list[0] = 4.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 3.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 7.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 11.0;
                obscures_list[8] = 0.25;
			    break;
      case(17): *ptr_c = 1;
			    *ptr_r = 2;
                obscures_list[0] = 4.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 7.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 4.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 12.0;
                obscures_list[8] = 0.25;
			    break;
      case(18): *ptr_c = -1;
			    *ptr_r = 2;
                obscures_list[0] = 4.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 4.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 8.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 12.0;
                obscures_list[8] = 0.25;
			    break;
      case(19): *ptr_c = -2;
			    *ptr_r = 1;
                obscures_list[0] = 4.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 8.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 5.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 13.0;
                obscures_list[8] = 0.25;
			    break;
      case(20): *ptr_c = -2;
			    *ptr_r = -1;
                obscures_list[0] = 4.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 5.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 9.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 13.0;
                obscures_list[8] = 0.25;
			    break;
      case(21): *ptr_c = -1;
			    *ptr_r = -2;
                obscures_list[0] = 4.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 9.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 2.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 10.0;
                obscures_list[8] = 0.25;
			    break;
      case(22): *ptr_c = 2;
			    *ptr_r = -2;
                obscures_list[0] = 6.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 6.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 14.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 15.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 2.0;
                obscures_list[10] = 0.25;
                obscures_list[11] = 3.0;
                obscures_list[12] = 0.25;
			    break;
      case(23): *ptr_c = 2;
			    *ptr_r = 2;
                obscures_list[0] = 6.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 7.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 16.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 17.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 3.0;
                obscures_list[10] = 0.25;
                obscures_list[11] = 4.0;
                obscures_list[12] = 0.25;
			    break;
	  case(24): *ptr_c = -2;
			    *ptr_r = 2;
                obscures_list[0] = 6.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 8.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 18.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 19.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 4.0;
                obscures_list[10] = 0.25;
                obscures_list[11] = 5.0;
                obscures_list[12] = 0.25;
			    break;
      case(25): *ptr_c = -2;
			    *ptr_r = -2;
                obscures_list[0] = 6.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 9.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 20.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 21.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 5.0;
                obscures_list[10] = 0.25;
                obscures_list[11] = 2.0;
                obscures_list[12] = 0.25;
			    break;
      case(26): *ptr_c = 0;
			    *ptr_r = -3;
                obscures_list[0] = 3.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 2.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 10.0;
                obscures_list[6] = 1.0;
			    break;
      case(27): *ptr_c = 3;
   			    *ptr_r = 0;
                obscures_list[0] = 3.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 3.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 11.0;
                obscures_list[6] = 1.0;
			    break;
      case(28): *ptr_c = 0;
			    *ptr_r = 3;
                obscures_list[0] = 3.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 4.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 12.0;
                obscures_list[6] = 1.0;
			    break;
      case(29): *ptr_c = -3;
			    *ptr_r = 0;
                obscures_list[0] = 3.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 5.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 13.0;
                obscures_list[6] = 1.0;
			    break;
      case(30): *ptr_c = 1;
			    *ptr_r = -3;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 2.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 6.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 10.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 14.0;
                obscures_list[10] = 0.5;
			    break;
      case(31): *ptr_c = 3;
			    *ptr_r = -1;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 3.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 6.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 11.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 15.0;
                obscures_list[10] = 0.5;
			    break;
      case(32): *ptr_c = 3;
			    *ptr_r = 1;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 3.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 7.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 11.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 16.0;
                obscures_list[10] = 0.5;
			    break;
      case(33): *ptr_c = 1;
			    *ptr_r = 3;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 4.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 7.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 12.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 17.0;
                obscures_list[10] = 0.5;
			    break;
      case(34): *ptr_c = -1;
			    *ptr_r = 3;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 4.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 8.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 12.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 18.0;
                obscures_list[10] = 0.5;
			    break;
      case(35): *ptr_c = -3;
			    *ptr_r = 1;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 5.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 8.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 13.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 19.0;
                obscures_list[10] = 0.5;
			    break;
      case(36): *ptr_c = -3;
			    *ptr_r = -1;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 5.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 9.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 13.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 20.0;
                obscures_list[10] = 0.5;
			    break;
      case(37): *ptr_c = -1;
			    *ptr_r = -3;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 2.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 9.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 10.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 21.0;
                obscures_list[10] = 0.5;
			    break;
      case(38): *ptr_c = 2;
			    *ptr_r = -3;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 2.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 6.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 14.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 22.0;
                obscures_list[10] = 0.5;
			    break;
      case(39): *ptr_c = 3;
			    *ptr_r = -2;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 3.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 6.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 15.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 22.0;
                obscures_list[10] = 0.5;
			    break;
      case(40): *ptr_c = 3;
			    *ptr_r = 2;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 3.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 7.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 16.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 23.0;
                obscures_list[10] = 0.5;
			    break;
      case(41): *ptr_c = 2;
			    *ptr_r = 3;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 4.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 7.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 17.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 23.0;
                obscures_list[10] = 0.5;
			    break;
      case(42): *ptr_c = -2;
			    *ptr_r = 3;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 4.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 8.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 18.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 24.0;
                obscures_list[10] = 0.5;
			    break;
      case(43): *ptr_c = -3;
			    *ptr_r = 2;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 5.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 8.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 19.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 24.0;
                obscures_list[10] = 0.5;
			    break;
      case(44): *ptr_c = -3;
			    *ptr_r = -2;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 5.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 9.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 20.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 25.0;
                obscures_list[10] = 0.5;
			    break;
      case(45): *ptr_c = -2;
			    *ptr_r = -3;
                obscures_list[0] = 5.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 2.0;
                obscures_list[4] = 0.5;
                obscures_list[5] = 9.0;
                obscures_list[6] = 0.5;
                obscures_list[7] = 21.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 25.0;
                obscures_list[10] = 0.5;
			    break;
      case(46): *ptr_c = 3;
			    *ptr_r = -3;
                obscures_list[0] = 7.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 6.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 22.0;
                obscures_list[6] = 1.0;
                obscures_list[7] = 14.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 15.0;
                obscures_list[10] = 0.5;
                obscures_list[11] = 38.0;
                obscures_list[12] = 0.5;
                obscures_list[13] = 39.0;
                obscures_list[14] = 0.5;
			    break;
      case(47): *ptr_c = 3;
			    *ptr_r = 3;
                obscures_list[0] = 7.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 7.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 23.0;
                obscures_list[6] = 1.0;
                obscures_list[7] = 16.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 17.0;
                obscures_list[10] = 0.5;
                obscures_list[11] = 40.0;
                obscures_list[12] = 0.5;
                obscures_list[13] = 41.0;
                obscures_list[14] = 0.5;
			    break;
      case(48): *ptr_c = -3;
			    *ptr_r = 3;
                obscures_list[0] = 7.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 8.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 24.0;
                obscures_list[6] = 1.0;
                obscures_list[7] = 18.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 19.0;
                obscures_list[10] = 0.5;
                obscures_list[11] = 42.0;
                obscures_list[12] = 0.5;
                obscures_list[13] = 43.0;
                obscures_list[14] = 0.5;
			    break;
      case(49): *ptr_c = -3;
			    *ptr_r = -3;
                obscures_list[0] = 7.0;
                obscures_list[1] = 1.0;
                obscures_list[2] = 1.0;
                obscures_list[3] = 9.0;
                obscures_list[4] = 1.0;
                obscures_list[5] = 25.0;
                obscures_list[6] = 1.0;
                obscures_list[7] = 20.0;
                obscures_list[8] = 0.5;
                obscures_list[9] = 21.0;
                obscures_list[10] = 0.5;
                obscures_list[11] = 44.0;
                obscures_list[12] = 0.5;
                obscures_list[13] = 45.0;
                obscures_list[14] = 0.5;
			    break;
    }

    call_number = (call_number + 1) % ((2*M_A_P+1)*
                   (2*M_A_P+1));
  }

  return(call_number);
}


/*g*//* a function to draw a square specified in the array sqr_ptrs in the
/*g*//*perception display */
/*g*/void draw_perc_square(c, r, correct_ext_perc_prob, ext_p_c, int_p_c)
/*g*/int c;
/*g*/int r;          /* coordinates of square */
/*g*/double correct_ext_perc_prob; 	/* probability of correct perception of
/*g*//*								exterior (eg. vegetation) of square */
/*g*/int ext_p_c;		            /* `boolean' denoting whether exterior of
/*g*//*								square has been correctly perceived or not */
/*g*/int int_p_c;		            /* `boolean' denoting whether interior of
/*g*//*								square has been correctly perceived or not */
/*g*/{
/*g*/
/*g*/  int i;
/*g*/  int colour;			/* colour for the image */
/*g*/  void *ptr;
/*g*/  int entry_pos;		/* pos. of description of feature in perc_fs */
/*g*/  int backg_colour;     /* colour for the background of the square */
/*g*/  int oldi;
/*g*/
/*g*/  /* decide a background colour for the square depending on
/*g*//*  how likely the animal is to perceive the square correctly or not */
/*g*/  backg_colour = (96+(int)((1.0-correct_ext_perc_prob)*4.999));
/*g*/
/*g*/  /* draw the background in that colour */
/*g*//*  pw_rop(perception_pw, ((c+M_A_P)*SQUARE_SIZE + 15),
/*g*//*    ((r+M_A_P)*SQUARE_SIZE + 45), SQUARE_SIZE, SQUARE_SIZE,
/*g*//*	PIX_SRC|PIX_COLOR(backg_colour), NULL, 0, 0); 
/*g*/
/*g*/  /* for each type of feature ... */
/*g*/  for (i = 0; i < NUM_FEATURE_TYPES; i++) {
/*g*/
/*g*/    oldi = i;
/*g*/
/*g*/    /* if there is an instance of this feature type in the square (except
/*g*//*	toxicity which the animal cannot perceive without tasting) .... */
/*g*/    if ((anim_perc.counters[c+M_A_P][r+M_A_P][i] != 0) &&
/*g*/		(i != TOXIC_N)) {
/*g*/
/*g*/	  /* get reference to entry in perc_fs (for first if more than one) */
/*g*/	  entry_pos = anim_perc.contents[c+M_A_P][r+M_A_P][i]->f_num;
/*g*/
/*g*/      switch(i) {
/*g*/ 	    case(CEREAL_FOOD_N): colour =
/*g*/          (int) (anim_perc.perc_fs[entry_pos].value * 5.0);
/*g*/	      break;
/*g*/	    case(COVER_N): colour =
/*g*/          (int) (anim_perc.perc_fs[entry_pos].thickness * 5.0);
/*g*/		  break;
/*g*/	  	case(FRUIT_FOOD_N): colour =
/*g*/          (int) (anim_perc.perc_fs[entry_pos].value * 5.0);
/*g*/		  break;
/*g*/	  	case(SHADE_N):colour =
/*g*/          (int) (anim_perc.perc_fs[entry_pos].thickness * 5.0);
/*g*/		  break;
/*g*/	    case(WATER_N):colour =
/*g*/		  (int) (anim_perc.perc_fs[entry_pos].value * 5.0);
/*g*/		  break;
/*g*/	  	default: colour = 4;
/*g*/	  }
/*g*/
/*g*/      colour += i*5 + 1;
/*g*/
/*g*/      /* draw the image of this feature over whatever's there */
/*g*/      pw_stencil(perception_pw, ((c+M_A_P)*SQUARE_SIZE + 15),
/*g*/        ((r+M_A_P)*SQUARE_SIZE + 45), SQUARE_SIZE, SQUARE_SIZE,
/*g*//*		(PIX_SRC|PIX_COLOR(colour)), feature_pr[i], 0, 0, NULL, 0, 0);
/*g*/		(PIX_SRC|PIX_SET), feature_pr[i], 0, 0, NULL, 0, 0);
/*g*/    }
/*g*/  }
/*g*/
/*g*/  /* if perception not correct then draw a red border round the square to
/*g*//*  mark this */
/*g*/  if ((!ext_p_c) || (!int_p_c)) {
/*g*/
/*g*/    pw_rop(perception_pw, ((c+M_A_P)*SQUARE_SIZE + 15),
/*g*/      ((r+M_A_P)*SQUARE_SIZE + 45), 2, SQUARE_SIZE, PIX_SRC|PIX_COLOR(40),
/*g*/	  NULL, 0, 0); 
/*g*/    pw_rop(perception_pw, ((c+M_A_P)*SQUARE_SIZE + 15),
/*g*/	  ((r+M_A_P)*SQUARE_SIZE + 45), SQUARE_SIZE, 2, PIX_SRC|PIX_COLOR(40),
/*g*/	  NULL, 0, 0); 
/*g*/    pw_rop(perception_pw, ((c+M_A_P+1)*SQUARE_SIZE + 13), 
/*g*/      ((r+M_A_P)*SQUARE_SIZE + 45), 2, SQUARE_SIZE, PIX_SRC|PIX_COLOR(40),
/*g*/	  NULL, 0, 0); 
/*g*/    pw_rop(perception_pw, ((c+M_A_P)*SQUARE_SIZE + 15),
/*g*/	  ((r+M_A_P+1)*SQUARE_SIZE + 43), SQUARE_SIZE, 2, PIX_SRC|PIX_COLOR(40),
/*g*/	  NULL, 0, 0); 
/*g*/  }
/*g*/}


/* a function to randomly alter a list of pointers referring to the contents
of a square of the environment */
void rearrange_sqr(abs_c, abs_r, c, r)
int abs_c;          /* square coordinates */
int abs_r;
int c;              /* square coordinates relative to animal */
int r;
{

  int i, j, k, nft;
  int new_number, old_number;
  double rnd_addition;
  int square_changed = FALSE;
  int num_physical_features = 0;

  /* if the square is inside the environment */
  if (square_in_env(abs_c, abs_r)) {

    while (square_changed == FALSE) {

	  /* count number of physical features already in square */
      num_physical_features = 0;
	  for (i = 0; i < NUM_FEATURE_TYPES; i++)
		if (PHYSICAL_FEATURE(i) &&
			(anim_perc.counters[c+M_A_P][r+M_A_P][i] > 0))
		  num_physical_features++;

      /* for one or a few random types of feature ... */
	  for (k = 0; k < ((int) (1.0 + rnd(2.5))); k++) {

		i = (int) rnd(((double) NUM_FEATURE_TYPES));

		/* have a probability of altering num. of this type of feature
		if it is a proper one */
		if ((drand48() < 0.5) && (i != ANIMAL_N) &&
			(i != OUTSIDE_ENV_N) && (i != TOXIC_N)) {

		  /* get current number of this type of feature in the square */
		  old_number = anim_perc.counters[c+M_A_P][r+M_A_P][i];

		  /* calculate random addition to add to current number.  This will
		  increase on average with the size of old_number so that larger
		  numbers subject to larger variation in perception */
		  rnd_addition = rnd(2.5);

		  /* random addition has equal probability of being +ve or -ve */
		  new_number = old_number +
					   (int) (((drand48()<0.5)?-1.0:1.0) * rnd_addition);

		  /* number cannot be less than zero */
		  if (new_number < 0)
		    new_number = 0;

		  /* if this is a physical feature then number cannot be greater
		  than 1 */
		  if ((new_number > 1) &&
			  (PHYSICAL_FEATURE(i)))
            new_number = 1;

		  /* repeat until new_number doesn't equal old one */
		  while (new_number == old_number) {

			rnd_addition = rnd(2.5);

			new_number = old_number +
					   (int) (((drand48()<0.5)?-1.0:1.0) * rnd_addition);

			if (new_number < 0)
              new_number = 0;

			if ((new_number > 1) &&
			    (PHYSICAL_FEATURE(i)))
              new_number = 1;
		  }

		  /* if this is a physical feature then there cannot be more than
		  one of it in the square, and there cannot be any if there is
		  already a physical feature in the square  */
		  if PHYSICAL_FEATURE(i)
			if (new_number > 1)
			  new_number = 1;
			if ((num_physical_features > 0) && (old_number == 0))
			  new_number = 0;

		  if (new_number != old_number)
		    square_changed = TRUE;

		  /* if need to delete instances ... */
		  if (new_number < old_number) {

		    for (j = 0; j < (old_number-new_number); ++j) {

			  delete_perc_instance(c, r, i);

			  if PHYSICAL_FEATURE(i)
				num_physical_features--;
			}
		  }

		  /* if need to add new instances ... */
		  else if (new_number > old_number) {

		    for (j = 0; j < (new_number-old_number); ++j) {

			  make_up_perc_instance(c, r, i);

			  if PHYSICAL_FEATURE(i)
				num_physical_features++;
			}
		  }
        }
	  }
    }
  }

  /* if there is now more than one physical feature in the square then
  delete them until there is only one left */
  while (num_physical_features > 1) {

    /* nft equals a random feature type */
    nft = (int) rnd(((double) NUM_FEATURE_TYPES));

    /* if nft is a physical feature type and there is an instance of it in
    the square then delete it */
    if (PHYSICAL_FEATURE(nft) &&
       (anim_perc.counters[c+M_A_P][r+M_A_P][nft] != 0)) {

	  delete_perc_instance(c, r, nft);

      num_physical_features--;
    }
  }
}


/* a function to randomly alter some of a list of pointers referring to the
contents of a square of the environment so that animals in that square
might be deleted or extra ones added in */
void rearrange_int_sqr(abs_c, abs_r, c, r)
int abs_c;          /* square coordinates */
int abs_r;
int c;
int r;
{

  int i, j, new_number, old_number, rnd_addition;
  int square_changed = FALSE;

  /* if the square is inside the environment */
  if (square_in_env(abs_c, abs_r))

    while (!square_changed)

      /* for each type of feature (except the outside of the env.) ... */
	  for (i = 0; i < (NUM_FEATURE_TYPES-1); ++i)

		/* have a small probability of altering number of this type of
		feature if it is an animal type of feature, but not actually equal
		to ANIMAL_N */
		if (ANIMAL_FEATURE(i) && (drand48() < 0.06) && (i != ANIMAL_N)) {
		
		  /* get current number of this type of feature in the square */
		  old_number = anim_perc.counters[c+M_A_P][r+M_A_P][i];

		  /* calculate random addition to add to current number.  This will
		  increase on average with the size of old_number so that larger
		  numbers subject to larger variation in perception */
		  rnd_addition = (int) rnd(((double) (0.3*((double)old_number)+2.2)));

		  /* random addition has equal probability of being +ve or -ve */
		  new_number = old_number +
            (((int) ((drand48() < 0.5) ? -1.0 : 1.0)) * rnd_addition);

		  /* number cannot be less than zero */
		  if (new_number < 0)
		    new_number = 0;

          /* this square is in the environment so there cannot be an
          instance of the feature `outside-env' */
          if (i == OUTSIDE_ENV_N)
             new_number = 0;

		  if (new_number != old_number)
		    square_changed = TRUE;

		  /* if need to delete instances ... */
		  if (new_number < old_number) {

		    for (j = 0; j < (old_number-new_number); ++j)

			  delete_perc_instance(c, r, i);
		  }

		  /* if need to add new instances ... */
		  else if (new_number > old_number) {

		    for (j = 0; j < (new_number-old_number); ++j)

			  make_up_perc_instance(c, r, i);
		  }
        }
}


/* a function to transfer any relevant information about the contents of
this square to the structure containing everything the animal can perceive
(stored in different forms) */
void sqr_to_perc_struct(c, r, abs_c, abs_r, c_e_p_p, c_i_p_p)
int c;                  /* coordinates of square relative to animal */
int r;
int abs_c;              /* coordinates of square (absolute) */
int abs_r;
double c_e_p_p;          /* correct perception probabilites for square */
double c_i_p_p;
{

  register int i;
  void *env_ptr;
  SQR_C_LLE *first_lle_addr;
  PERC_FEATURE *pf_ptr;

  /* if this square is within the bounds of the environment */
  if (square_in_env(abs_c, abs_r)) {

    /* for each type of feature ... */
    for (i = 0; i < NUM_FEATURE_TYPES; ++i) {

      /* if there is an instance of this feature type in the square (not
	  toxic entry though) .... */
      if ((i != TOXIC_N) &&
		  ((env_ptr = env_arr[abs_c][abs_r].p_arr[i]) != ((void *) NULL))) {

        /* copy perceiveable properties of the feature and its coordinates and
        feature type into the list of perceived features */
		pf_ptr = &(anim_perc.perc_fs[anim_perc.perc_f_count]);

  	    pf_ptr->c = c;
        pf_ptr->r = r;
        pf_ptr->nft = i;

  	    switch(i) {

          case(CEREAL_FOOD_N): pf_ptr->value =
									((CEREAL_FOOD *)env_ptr)->value;
							   break;
          case(COVER_N)      : pf_ptr->thickness =
									((COVER *)env_ptr)->thickness;
  							   break;
          case(FRUIT_FOOD_N): pf_ptr->value =
									((FRUIT_FOOD *)env_ptr)->value;
							  pf_ptr->conditions =
									((FRUIT_FOOD *)env_ptr)->conditions;
  							  break;
          case(LANDMARK_N): pf_ptr->number =
									((LANDMARK *)env_ptr)->number;
				  		    break;
          case(MATE_N): pf_ptr->receptive = ((MATE *)env_ptr)->receptive;
						pf_ptr->courted = ((MATE *)env_ptr)->courted;
					    break;
          case(PREDATOR_1_N): break;
          case(PREDATOR_2_N): break;
          case(PREY_N): pf_ptr->value = ((PREY *)env_ptr)->value;
                        break;
          case(SHADE_N): pf_ptr->thickness =
									((SHADE *)env_ptr)->thickness;
						 break;
      	  case(WATER_N): pf_ptr->value = ((WATER *)env_ptr)->value;
						 break;
          default: break;
        }

        /* add this instance to the storage by squares */
  
        /* add a reference to the beginning of the linked list for this type
  	    of feature in this square */

        /* get the address of the first linked list element */
        first_lle_addr = anim_perc.contents[c+M_A_P][r+M_A_P][i];

        /* create a new first linked list element */
  	    anim_perc.contents[c+M_A_P][r+M_A_P][i] =
		(SQR_C_LLE *) malloc(sizeof(SQR_C_LLE));

        /* make it point to former first linked list element */
	    anim_perc.contents[c+M_A_P][r+M_A_P][i]->next_ptr = first_lle_addr;
 
        /* put in reference to the feature description in perc_fs */
        anim_perc.contents[c+M_A_P][r+M_A_P][i]->f_num =
  		anim_perc.perc_f_count;

        /* finished adding to linked list */
 
        /* increment the counter for the number of perceived instances of this
        type of feature in this square */
        anim_perc.counters[c+M_A_P][r+M_A_P][i]++;

 		/* increment the counter for number of this type of feature perceived*/
		anim_perc.f_counter[i]++;

        /* increment the counter for the number of perceived features */
        anim_perc.perc_f_count++;
  	  }
    }
  }

  else {      /* if square outside environment */

    /* copy perceiveable properties of the square (ie. the fact that it is
    outside the environment) and its coordinates and feature type into the
    list of perceived features */ 
    anim_perc.perc_fs[anim_perc.perc_f_count].c = c;
    anim_perc.perc_fs[anim_perc.perc_f_count].r = r;
    anim_perc.perc_fs[anim_perc.perc_f_count].nft = OUTSIDE_ENV_N;

    /* add this instance to the storage by squares */

    /* add a reference to the beginning of the linked list (will only be
    one element) for this type of feature in this square */

    /* create a new first linked list element */
    anim_perc.contents[c+M_A_P][r+M_A_P][OUTSIDE_ENV_N] =
      (SQR_C_LLE *) malloc(sizeof(SQR_C_LLE));

    /* make it point to nothing */
    anim_perc.contents[c+M_A_P][r+M_A_P][OUTSIDE_ENV_N]->next_ptr =
      ((SQR_C_LLE *) NULL);

    /* put in reference to the feature description in perc_fs */
    anim_perc.contents[c+M_A_P][r+M_A_P][OUTSIDE_ENV_N]->f_num =
  	  anim_perc.perc_f_count;

    /* finished adding to linked list */

    /* increment counter for numbers of this feature perceived */
    anim_perc.f_counter[OUTSIDE_ENV_N]++;

    /* increment the counter for the number of perceived instances of this
    type of feature in this square */
    anim_perc.counters[c+M_A_P][r+M_A_P][OUTSIDE_ENV_N]++;

    /* increment the counter for the number of perceived features */
    anim_perc.perc_f_count++;
  }

  /* let animal know how well it can perceive each square (external and
  internal */
  anim_perc.ext_perc_probs[c+M_A_P][r+M_A_P] = c_e_p_p;
  anim_perc.int_perc_probs[c+M_A_P][r+M_A_P] = c_i_p_p;
}


/* function to delete an instance of a feature when the animal incorrectly
perceives that it is NOT there */
void delete_perc_instance(c, r, nft)
int c;			/* coordinates of square relative to animal */
int r;
int nft; 		/* number of the feature type */
{

  SQR_C_LLE *first_lle_addr, *ptr;
  register int entry_pos;		/* pos. of description of feature in perc_fs */
  int last_c, last_r, last_nft;

  /* get reference to entry in perc_fs (for first if more than one) */
  entry_pos = anim_perc.contents[c+M_A_P][r+M_A_P][nft]->f_num;

  /* get coordinates of last entry in perception array */
  last_c = anim_perc.perc_fs[anim_perc.perc_f_count-1].c;
  last_r = anim_perc.perc_fs[anim_perc.perc_f_count-1].r;
  last_nft = anim_perc.perc_fs[anim_perc.perc_f_count-1].nft;

  /* copy the last entry in anim_perc.perc_fs on top of this one, thereby
  removing this one */
  anim_perc.perc_fs[entry_pos].c = last_c;
  anim_perc.perc_fs[entry_pos].r = last_r;
  anim_perc.perc_fs[entry_pos].nft = last_nft;

  anim_perc.perc_fs[entry_pos].number =
    anim_perc.perc_fs[anim_perc.perc_f_count-1].number;
  anim_perc.perc_fs[entry_pos].courted =
    anim_perc.perc_fs[anim_perc.perc_f_count-1].courted;
  anim_perc.perc_fs[entry_pos].receptive =
    anim_perc.perc_fs[anim_perc.perc_f_count-1].receptive;

  anim_perc.perc_fs[entry_pos].value =
    anim_perc.perc_fs[anim_perc.perc_f_count-1].value;
  anim_perc.perc_fs[entry_pos].thickness =
    anim_perc.perc_fs[anim_perc.perc_f_count-1].thickness;

  /* find the contents entry referring to the last element and change
  the entry */
  ptr = anim_perc.contents[last_c+M_A_P][last_r+M_A_P][last_nft];
  while (ptr != ((SQR_C_LLE *) NULL)) {
    if (ptr->f_num == (anim_perc.perc_f_count-1)) {
      ptr->f_num = entry_pos;
      break;
    }
    ptr = ptr->next_ptr;
  }

  /* decrement the counter for the number of perceived features */
  anim_perc.perc_f_count--;

  /* take out this first element of the linked list */
  first_lle_addr = anim_perc.contents[c+M_A_P][r+M_A_P][nft];
  anim_perc.contents[c+M_A_P][r+M_A_P][nft] =
     anim_perc.contents[c+M_A_P][r+M_A_P][nft]->next_ptr;
  free(first_lle_addr);

  /* decrement counter for this type of feature in this square */
  anim_perc.counters[c+M_A_P][r+M_A_P][nft]--;

  /* decrement overall counter for perception of this type of feature */
  anim_perc.f_counter[nft]--;
}


/* function to make up an instance of a feature when the animal incorrectly
perceives that it is there */
void make_up_perc_instance(c, r, nft)
int c;			/* coordinates of square relative to animal */
int r;
int nft; 		/* number of the feature type */
{

  SQR_C_LLE *first_lle_addr;

  /* copy the coordinates of the feature instance and the number of its type
  into the list of perceived features */ 
  anim_perc.perc_fs[anim_perc.perc_f_count].c = c;
  anim_perc.perc_fs[anim_perc.perc_f_count].r = r;
  anim_perc.perc_fs[anim_perc.perc_f_count].nft = nft;

  /* make up properties for the new imaginary instance */
  switch(nft) {

	case(CEREAL_FOOD_N):	anim_perc.perc_fs[anim_perc.perc_f_count].value
							=
					get_cereal_food_value(get_cereal_food_conditions()); 
							break;
	case(COVER_N):			anim_perc.perc_fs[anim_perc.perc_f_count].thickness
							= get_cover_thickness();
							break;
	case(FRUIT_FOOD_N):		anim_perc.perc_fs[anim_perc.perc_f_count].value
							= rnd(0.8);
							anim_perc.perc_fs[anim_perc.perc_f_count].
							conditions = get_fruit_food_conditions();
							break;
	case(LANDMARK_N):		anim_perc.perc_fs[anim_perc.perc_f_count].number
							= (int) rnd(((double) INIT_NUM_LANDMARK));
							break;
	case(MATE_N):			anim_perc.perc_fs[anim_perc.perc_f_count].receptive
							= (drand48() < 0.5) ? TRUE : FALSE;
							anim_perc.perc_fs[anim_perc.perc_f_count].courted
							= (drand48() < 0.5) ? TRUE : FALSE;
							break;
	case(PREDATOR_1_N):		break;
    case(PREY_N):			anim_perc.perc_fs[anim_perc.perc_f_count].value
							= get_prey_value();
							break;
	case(SHADE_N):		anim_perc.perc_fs[anim_perc.perc_f_count].thickness
							= get_shade_thickness();
							break;
	case(WATER_N):			anim_perc.perc_fs[anim_perc.perc_f_count].value
							= get_water_value();
							break;
	default:				break;
  }

  /* increment counter for numbers of this feature perceived */
  anim_perc.f_counter[nft]++;

  /* add this instance to the storage by squares */
  
  /* add a reference to the beginning of the linked list for this type
  of feature in this square */

  /* get the address of the first linked list element */
  first_lle_addr = anim_perc.contents[c+M_A_P][r+M_A_P][nft];

  /* create a new first linked list element */
  anim_perc.contents[c+M_A_P][r+M_A_P][nft] =
  (SQR_C_LLE *) malloc(sizeof(SQR_C_LLE));

  /* make it point to former first linked list element */
  anim_perc.contents[c+M_A_P][r+M_A_P][nft]->next_ptr =
 	first_lle_addr;
 
  /* put in reference to the feature description in perc_fs */
  anim_perc.contents[c+M_A_P][r+M_A_P][nft]->f_num =
	anim_perc.perc_f_count;

  /* finished adding to linked list */
 
  /* increment the counter for the number of perceived instances of this
  type of feature in this square */
  anim_perc.counters[c+M_A_P][r+M_A_P][nft]++;

  /* increment the counter for the number of perceived features */
  anim_perc.perc_f_count++;
}


/* function to reinitalise the perception structure after each timestep */
void init_perc_struct()
{

  int i, j, k;
  SQR_C_LLE *ptr, *ptr1;

  /* initialise list of structures holding perceived features */
  /* for each feature in perception structure */
  for (i = 0; i < MAX_NUM_PERC_FEATURES; ++i) {

    anim_perc.perc_fs[i].c = -100;
    anim_perc.perc_fs[i].r = -100;
    anim_perc.perc_fs[i].nft = -1;
    anim_perc.perc_fs[i].number = -1;

    anim_perc.perc_fs[i].value = -1.0;
    anim_perc.perc_fs[i].thickness = -1.0;
    anim_perc.perc_fs[i].conditions = -1.0;
  }

  /* set count for number of perceived features to zero */
  anim_perc.perc_f_count = 0;

  /* initialise counters for different perceived features */
  for (i = 0; i < NUM_FEATURE_TYPES; i++)
    anim_perc.f_counter[i] = 0;

  /* reset array holding array indexs for each type of feature */
  for (i = 0; i < NUM_FEATURE_TYPES; i++)
	for (j = 0; j < MAX_NUM_SINGLE_PERC_FEATURE; j++)
	  anim_perc.feature_instance_indexs[i][j] = -1;

  /* reset all linked lists holding information about square contents */
  for (i = 0; i < (2*M_A_P+1); i++)

    for (j = 0; j < (2*M_A_P+1); j++) {

      anim_perc.ext_perc_probs[i][j] = 0.0;
      anim_perc.int_perc_probs[i][j] = 0.0;

      for (k = 0; k < NUM_FEATURE_TYPES; k++) {

        /* for each feature in each square .... */
		ptr = anim_perc.contents[i][j][k];
		while (ptr != ((SQR_C_LLE *) NULL)) {
		  ptr1 = ptr->next_ptr;
		  free(ptr);
		  ptr = ptr1;
		}

        anim_perc.counters[i][j][k] = 0;
        anim_perc.contents[i][j][k] = (SQR_C_LLE *) NULL;
      }
	}
}


/* function (returning TRUE or FALSE) which tests whether a particular
square is inside the environment or not */
int square_in_env(c, r)
int c;          /* square coordinates */
int r;
{

 if ((c>=0) && (c<ENV_ARR_COLS) && (r>=0) && (r<ENV_ARR_ROWS))

   return(TRUE);

  else

    return(FALSE);
}


/* function to take each feature in a square and to randomly rearrange the
values of its properties according to how well the animal can perceive the
inside and outside of the square */
void change_feature_props(c, r, c_int_p_p, c_ext_p_p)
int c;                  /* square coordinates relative to animal */
int r;
double c_int_p_p;  /* how well the animal can see the interior and */
double c_ext_p_p;  /* exterior of the square */
{

  int i;
  SQR_C_LLE *ptr, *ptr1;
  int entry_pos;

  for (i = 0; i < NUM_FEATURE_TYPES; ++i)

	if (anim_perc.contents[c+M_A_P][r+M_A_P][i] != 0) 

	  if (ANIMAL_FEATURE(i)) {

		ptr = anim_perc.contents[c+M_A_P][r+M_A_P][i];

		while (ptr != ((SQR_C_LLE *) NULL)) {

		  ptr1 = ptr->next_ptr;

		  entry_pos = ptr->f_num;

		  switch(i) {

      	    case(IRRELEVANT_N) : break;
	    	case(MATE_N) : /* small prob of not perceiving receptiveness ok*/ 
						   if (drand48() < (0.5 * c_int_p_p))
							 anim_perc.perc_fs[entry_pos].receptive =
							 (anim_perc.perc_fs[entry_pos].receptive == TRUE)
							 ? FALSE : TRUE;
                           break;
      	    case(PREDATOR_1_N) : break;
      	    case(PREDATOR_2_N) : break;
      	    case(PREY_N) : anim_perc.perc_fs[entry_pos].value *=
                             get_rnd_multiplier(c_int_p_p);
                           if (anim_perc.perc_fs[entry_pos].value > 1.0)
                             anim_perc.perc_fs[entry_pos].value = 0.99999;
                           break;
      	    case(ANIMAL_N) : break;
		  }

		  ptr = ptr1;
	    }
	  }

	  else if (PHYSICAL_FEATURE(i)) {

		/* get position of entry in list of features and properties */
		entry_pos = anim_perc.contents[c+M_A_P][r+M_A_P][i]->f_num;

    	switch(i) {

     	  case(WATER_N) : anim_perc.perc_fs[entry_pos].value *=
							get_rnd_multiplier(c_ext_p_p);
                          if (anim_perc.perc_fs[entry_pos].value > 1.0)
                            anim_perc.perc_fs[entry_pos].value = 0.99999;
						  break;

		  case(COVER_N) : anim_perc.perc_fs[entry_pos].thickness *=
                            get_rnd_multiplier(c_ext_p_p);
                          if (anim_perc.perc_fs[entry_pos].thickness > 1.0)
                            anim_perc.perc_fs[entry_pos].thickness = 0.99999;
                          break;

      	  case(SHADE_N) : anim_perc.perc_fs[entry_pos].thickness *=
                            get_rnd_multiplier(c_ext_p_p);
                          if (anim_perc.perc_fs[entry_pos].thickness > 1.0)
                            anim_perc.perc_fs[entry_pos].thickness = 0.99999;
                          break;

      	  case(DANGEROUS_PLACE_N) : break;

      	  case(LANDMARK_N) : if (rnd(0.01) > c_ext_p_p)
							   anim_perc.perc_fs[entry_pos].number =
								 (int) rnd(((double) INIT_NUM_LANDMARK));
                          break;

      	  case(CEREAL_FOOD_N) : anim_perc.perc_fs[entry_pos].value *=
                            	  get_rnd_multiplier(c_ext_p_p);
                                if (anim_perc.perc_fs[entry_pos].value > 1.0)
                                  anim_perc.perc_fs[entry_pos].value =
                                    0.99999;
                          		break;

      	  case(FRUIT_FOOD_N) : anim_perc.perc_fs[entry_pos].value *=
                            	 get_rnd_multiplier(c_ext_p_p);
                               if (anim_perc.perc_fs[entry_pos].value > 1.0)
                                 anim_perc.perc_fs[entry_pos].value =
                                   0.99999;
							   anim_perc.perc_fs[entry_pos].conditions *=
                            	 get_rnd_multiplier(c_ext_p_p);
                               if (anim_perc.perc_fs[entry_pos].conditions >
								 1.0)
								 anim_perc.perc_fs[entry_pos].conditions =
                                   0.99999;
                          	   break;

      	  case(DEN_N) : break;
		}
	  }

	  else {/* if toxicity or outside_env feature */

		/* do nothing */
	  }
}


/* function to return a semi-random multiplier with which to multiply a
feature value so as to simulate imperfect perception */
double get_rnd_multiplier(correct_perc_prob)
double correct_perc_prob;
{

  double result;

  /* get a number between 0.5 and 1.0 which is more likely to be closer to
  1.0 if the feature can be perceived clearly */
  result = 0.5 + (0.5 * correct_perc_prob);

  /* add in random element */
  result *= (0.8 + rnd(0.4));

  /* have a 50% chance of dividing instead of multiplying by this amount */
  if (drand48() < 0.5)
    result = 1.0 / result;

  return(result);
}


void animal_effect_on_cereal_food()
{

  CEREAL_FOOD *p_cf;

  p_cf = (CEREAL_FOOD *) env_arr[animal_c][animal_r].p_arr[CEREAL_FOOD_N];

  if (animal_action == EATING_CF) {

    /* add food to animal and take away from food source */
	if (p_cf->value > CEREAL_FOOD_EATEN_PER_TIMESTEP) {

	  animal_fat += CEREAL_FOOD_EATEN_PER_TIMESTEP * CEREAL_FOOD_FAT_RATIO;
	  animal_carbo += CEREAL_FOOD_EATEN_PER_TIMESTEP *
					  CEREAL_FOOD_CARBO_RATIO; 
	  animal_protein += CEREAL_FOOD_EATEN_PER_TIMESTEP *
						CEREAL_FOOD_PROTEIN_RATIO;

	  p_cf->value -= CEREAL_FOOD_EATEN_PER_TIMESTEP;

	  animal_eating = TRUE;
    }

	else {		/* if value of this instance of cereal food < 0.05 */

	  animal_fat += p_cf->value * CEREAL_FOOD_FAT_RATIO;
	  animal_carbo += p_cf->value * CEREAL_FOOD_CARBO_RATIO;
	  animal_protein += p_cf->value * CEREAL_FOOD_PROTEIN_RATIO;

	  p_cf->value = 0.0;
	}

    /* if food is toxic then since toxicity will take effect some time after
    eating, put entry in array that will cause onset of ill health later on*/ 
    if (p_cf->toxicity != 0.0) {

      toxic_array[toxic_counter].delay = p_cf->toxicity_delay;
      toxic_array[toxic_counter].strength = p_cf->toxicity;
      toxic_array[toxic_counter].type = CEREAL_FOOD_N;

	  toxic_counter++;
    }
  }
}


/* function to calculate the effects of the cover instance on the animal if
the animal is in the same square*/
void cover_effect_on_animal()
{

  /* all effects of shade should be taken into account by square variables */
}


/* function to calculate the effects of the dangerous place instance on the
animal if the animal is in the same square */
void dangerous_place_effect_on_animal()
{

  double perm_inj_incr, health_decr;

  /* have a probability of the animal incurring injury (eg. by falling
  over a cliff) */
  if (drand48() < 0.5) {

	/* decrement both the animal's current and permanent health (seriously) */
    perm_inj_incr = (drand48() < 0.5) ? rnd(0.5) : rnd(3.0);
    health_decr = (drand48() < 0.5) ? rnd(0.6) : drand48();
    animal_perm_inj += perm_inj_incr;
    animal_health -= health_decr;
    animal_health -= perm_inj_incr;

/*g*/    /* if the animal incurs a serious injury then write the details to the
/*g*//*    analysis file */
/*g*/    if (((perm_inj_incr>0.1)||(health_decr>0.2))&&(animal_alive==TRUE)) {
/*g*/
/*g*/      fprintf(analysis_info_f,
/*g*/        "dangerous place: recoverable decrement to health of %.3f\n",
/*g*/        health_decr);
/*g*/      fprintf(analysis_info_f,
/*g*/   "dangerous place: addition to permanent injury (not recoverable) of %.3f\n",
/*g*/        perm_inj_incr);
/*g*/		fprintf(analysis_info_f,
/*g*/		  "health gone from %.3f to %.3f (t = %.3f)\n",
/*g*/		  (animal_health+health_decr+perm_inj_incr), animal_health,
/*g*/		  (((double)daystep) + (((double)timestep)/((double)DAY_LENGTH)))); 
/*g*/    }

    /* if injury here has just caused the animal to die then print out
    details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f, "\n %d ULTIMATE CAUSE OF DEATH: due to visiting ", timestep);
      fprintf(tob_f, "dangerous place square\n");
	  fflush(tob_f);

	  animal_alive = FALSE;
    }
  }
}


/* function to calculate the effects of the den on the animal if the animal
is in the same square*/
void den_effect_on_animal()
{

  /* all effects of den should be taken into account by square variables */
}


/* function to calculate the effects of the animal on a fruit food source if
it is in the same square */
void animal_effect_on_fruit_food()
{

  FRUIT_FOOD *p_ff;

  p_ff = (FRUIT_FOOD *) env_arr[animal_c][animal_r].p_arr[FRUIT_FOOD_N];

  if (animal_action == EATING_FF) {

    /* add food to animal and take away from food source */
	if (p_ff->value > FRUIT_FOOD_EATEN_PER_TIMESTEP) {

	  animal_fat += FRUIT_FOOD_EATEN_PER_TIMESTEP * FRUIT_FOOD_FAT_RATIO;
	  animal_carbo += FRUIT_FOOD_EATEN_PER_TIMESTEP *
					  FRUIT_FOOD_CARBO_RATIO; 
	  animal_protein += FRUIT_FOOD_EATEN_PER_TIMESTEP *
						FRUIT_FOOD_PROTEIN_RATIO; 

	  p_ff->value -= FRUIT_FOOD_EATEN_PER_TIMESTEP;

	  animal_eating = TRUE;
    }

	else {		/* if value of this instance of fruit food < 0.05 */

	  animal_fat += p_ff->value * FRUIT_FOOD_FAT_RATIO;
	  animal_carbo += p_ff->value * FRUIT_FOOD_CARBO_RATIO;
	  animal_protein += p_ff->value * FRUIT_FOOD_PROTEIN_RATIO;

	  p_ff->value = 0.0;
	}

    /* if food is toxic then since toxicity will take effect some time after
    eating, put entry in array that will cause onset of ill health later on*/ 
    if (p_ff->toxicity != 0.0) {

      toxic_array[toxic_counter].delay = p_ff->toxicity_delay;
      toxic_array[toxic_counter].strength = p_ff->toxicity;
      toxic_array[toxic_counter].type = FRUIT_FOOD_N;

	  toxic_counter++;
    }
  }
}


/* function to calculate the effects of the landmark instance on the animal
if the animal is in the same square*/
void landmark_effect_on_animal()
{

  /* all effects of landmarks should be taken account of in navigation code*/
}


/* function to calculate the effects of the shade instance on the animal if
the animal is in the same square*/
void shade_effect_on_animal()
{

  /* all effects of shade should be taken into account by square variables */
}


/* function to calculate the effects of the animal on a water source if it
is in the same square */
void animal_effect_on_water()
{

  WATER *p_w;

  p_w = (WATER *) env_arr[animal_c][animal_r].p_arr[WATER_N];

  if (animal_action == DRINKING) {

    /* add water to animal and take away from watersource */
	if (p_w->value > WATER_DRUNK_PER_TIMESTEP) {

	  animal_water += WATER_DRUNK_PER_TIMESTEP;

	  p_w->value -= WATER_DRUNK_PER_TIMESTEP;

	  animal_drinking = TRUE;
    }

	else {		/* if value of this instance of water < 0.05 */

	  animal_water += p_w->value;

	  p_w->value = 0.0;
	}

    /* if water is toxic then since toxicity will take effect some time
	after eating, put entry in array that will cause onset of ill health
	later on */
    if (p_w->toxicity != 0.0) {

      toxic_array[toxic_counter].delay = p_w->toxicity_delay;
      toxic_array[toxic_counter].strength = p_w->toxicity;
      toxic_array[toxic_counter].type = WATER_N;

	  toxic_counter++;
    }
  }
}


/* function to calculate the effects of the irrelevant instance on the
animal if the animal is in the same square*/
void irrelevant_effect_on_animal()
{

  double perm_inj_incr, health_decr;
  IRRELEVANT *ptr;

  /* for each irrelevant in the square */
  ptr = (IRRELEVANT *) env_arr[animal_c][animal_r].p_arr[IRRELEVANT_N];

  while (ptr != ((IRRELEVANT *) NULL)) {

    /* if animal in same square as irrelevant and animal does not escape
    then have probability of animal being injured (irrelevants only attack
    if their square is invaded) */ 
    if ((drand48() > animal_escape_prob)) {

      perm_inj_incr = rnd(0.4);
      health_decr = rnd(0.4);
      animal_perm_inj += perm_inj_incr;
      animal_health -= health_decr;
      animal_health -= perm_inj_incr;

      /* if the animal incurs a serious injury then write the details to the
      analysis file */
      if (((perm_inj_incr>0.1)||(health_decr>0.2))&&(animal_alive==TRUE)) {

/*g*/        fprintf(analysis_info_f,
/*g*/          "irrelevant animal: recoverable decrement to health of %.3f\n",
/*g*/          health_decr);
/*g*/        fprintf(analysis_info_f,
/*g*/ "irrelevant animal: addition to permanent injury (not recoverable) of %.3f\n",
/*g*/          perm_inj_incr);
/*g*/        fprintf(analysis_info_f,
/*g*/          "health gone from %.3f to %.3f (t = %.3f)\n",
/*g*/          (animal_health+health_decr+perm_inj_incr), animal_health,
/*g*/          (((double)daystep) + (((double)timestep)/((double)DAY_LENGTH)))); 
      }
    }

    ptr = ptr->next_ptr;
  }

  /* if injury here has just caused the animal to die then print out
  details to the analysis file */
  if ((animal_health <= 0.0) && (animal_alive == TRUE)) {

    fprintf(tob_f, "\n %d ULTIMATE CAUSE OF DEATH: due to entering ", timestep);
    fprintf(tob_f, "same square as irrelevant animal\n");
	  fflush(tob_f);

    animal_alive = FALSE;
  }
}


/* function to calculate the effects of the animal on a mate if it is in the
same square */
void animal_effect_on_mate()
{

  MATE *ptr, *receptive_mate_ptr, *courted_mate_ptr;
  int receptive_mate_in_square, courted_mate_in_square;
  double perm_inj_incr = 0.0, health_decr = 0.0;

  if (animal_action == MATING) {

	/* find out if there is a courted mate in the square */
    courted_mate_in_square = FALSE;
    /* for each mate in the square */
    ptr = (MATE *) env_arr[animal_c][animal_r].p_arr[MATE_N];
    while (ptr != ((MATE *) NULL)) {
	  if (ptr->courted && ptr->receptive) {
		courted_mate_in_square = TRUE;
		courted_mate_ptr = ptr;
	  }
      ptr = ptr->next_ptr;
    }

	/* if the animal is copulating with a courted mate then increase
    genetic fitness counter (since probability of passing on genes) and then
	make mate not receptive and not courted */
    if (courted_mate_in_square) {

	  genetic_fitness += 1.0;

	  time_since_animal_mated = 0;

	  courted_mate_ptr->receptive = FALSE;
	  courted_mate_ptr->courted = FALSE;
	}

	/* if the animal is trying to copulate with an unreceptive or uncourted
	mate then reduce animal's health (possibly with some permanent injury as
	well) if it does not escape since mate will attack */
	else if ((courted_mate_in_square == FALSE) &&
			 (drand48() > animal_escape_prob)) {

	  /* take first mate in the list for the square (which can't be
	  courted) */
	  ptr = (MATE *) env_arr[animal_c][animal_r].p_arr[MATE_N];

	  health_decr = rnd(0.25);

	  if (drand48() < 0.05)
		perm_inj_incr = rnd(0.2);

      animal_health -= health_decr;
      animal_perm_inj += perm_inj_incr;
	  animal_health -= perm_inj_incr;

      /* if the animal incurs a serious injury then write the details to the
      analysis file */
      if (((perm_inj_incr>0.1)||(health_decr>0.2))&&(animal_alive==TRUE)) {

/*g*/        fprintf(analysis_info_f,
/*g*/          "unreceptive mate: recoverable decrement to health of %.3f\n",
/*g*/          health_decr);
/*g*/        fprintf(analysis_info_f,
/*g*/ "uncourted mate: addition to permanent injury (not recoverable) of %.3f\n",
/*g*/          perm_inj_incr);
/*g*/        fprintf(analysis_info_f,
/*g*/		  "health gone from %.3f to %.3f (t = %.3f)\n",
/*g*/	      (animal_health+health_decr+perm_inj_incr), animal_health,
/*g*/		  (((double)daystep) + (((double)timestep)/((double)DAY_LENGTH)))); 
      }

      /* if injury here has just caused the animal to die then print out
      details to the analysis file */
      if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
        fprintf(tob_f,
		  "\n %d ULTIMATE CAUSE OF DEATH: due to being attacked when trying to ", timestep);
        fprintf(tob_f, "copulate with an uncourted mate\n");
	  fflush(tob_f);

		animal_alive = FALSE;
      }
    }
  }

  /* if the animal is trying to court the mate instead */
  else if (animal_action == COURT_DISPLAYING) {

	/* find out if there is a receptive mate in the square */
    receptive_mate_in_square = FALSE;
    /* for each mate in the square */
    ptr = (MATE *) env_arr[animal_c][animal_r].p_arr[MATE_N];
    while (ptr != ((MATE *) NULL)) {
	  if (ptr->receptive) {
		receptive_mate_in_square = TRUE;
		receptive_mate_ptr = ptr;
	  }
      ptr = ptr->next_ptr;
    }

	if (receptive_mate_in_square)
	  receptive_mate_ptr->courted = TRUE;
	else
	  time_since_animal_courting_rejected = 0;
  }
}


/* function to calculate the effects of the predator_1 instance on the
animal if the animal is in the same square*/
void predator_1_effect_on_animal()
{

  double perm_inj_incr = 0.0, health_decr = 0.0;
  PREDATOR_1 *ptr;

  /* for each predator_1 in the square */
  ptr = (PREDATOR_1 *) env_arr[animal_c][animal_r].p_arr[PREDATOR_1_N];

  while (ptr != ((PREDATOR_1 *) NULL)) {

    /* if the predator is trying to catch the animal and the animal does not
	escape */
    if ((ptr->chasing_animal == TRUE) && (drand48() > animal_escape_prob)) {

      /* the animal suffers damage to it's current health */
      health_decr += (drand48() < 0.5) ? drand48() : rnd(0.3);

      /* have a smaller probability of the animal suffering permanent injury*/
      if (drand48() < 0.25)
        perm_inj_incr += rnd(0.5);
    }

    ptr = ptr->next_ptr;
  }

  animal_health -= health_decr;
  animal_perm_inj += perm_inj_incr;
  animal_health -= perm_inj_incr;

  /* if the animal incurs a serious injury then write the details to the
  analysis file */
  if (((perm_inj_incr>0.1)||(health_decr>0.2))&&(animal_alive==TRUE)) {

/*g*/    fprintf(analysis_info_f,
/*g*/      "predator type 1: recoverable decrement to health of %.3f\n",
/*g*/      health_decr);
/*g*/    fprintf(analysis_info_f,
/*g*/  "predator type 1: addition to permanent injury (not recoverable) of %.3f\n",
/*g*/      perm_inj_incr);
/*g*/		fprintf(analysis_info_f,
/*g*/		  "health gone from %.3f to %.3f (t = %.3f)\n",
/*g*/		  (animal_health+health_decr+perm_inj_incr), animal_health, 
/*g*/		  (((double)daystep) + (((double)timestep)/((double)DAY_LENGTH)))); 
  }

  /* if injury here has just caused the animal to die then print out
  details to the analysis file */
  if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
    fprintf(tob_f,
	  "\n %d ULTIMATE CAUSE OF DEATH: due to being attacked by ", timestep);
    fprintf(tob_f, "predator(s) (type 1)\n");
	  fflush(tob_f);

    animal_alive = FALSE;
  }
}


/* function to calculate the effects of the predator_2 instance on the
animal if the animal is in the same square*/
void predator_2_effect_on_animal()
{

  double perm_inj_incr = 0.0, health_decr = 0.0;
  PREDATOR_2 *ptr;

  /* for each predator_2 in the square */
  ptr = (PREDATOR_2 *) env_arr[animal_c][animal_r].p_arr[PREDATOR_2_N];

  while (ptr != ((PREDATOR_2 *) NULL)) {

    /* if the predator is trying to catch the animal and the animal does not
	manage to escape */
    if ((ptr->chasing_animal == TRUE) && (drand48() > animal_escape_prob)) {

      /* have a probability of the animal suffering damage to it's current
      health */
      health_decr += (drand48() < 0.5) ? rnd(0.5) : rnd(1.5);

      /* have a smaller probability of the animal suffering permanent injury*/
      if (drand48() < 0.25)
        perm_inj_incr += rnd(0.5);
    }

    ptr = ptr->next_ptr;
  }

  animal_health -= health_decr;
  animal_perm_inj += perm_inj_incr;
  animal_health -= perm_inj_incr;

  /* if the animal incurs a serious injury then write the details to the
  analysis file */
  if (((perm_inj_incr>0.1)||(health_decr>0.2))&&(animal_alive==TRUE)) {

/*g*/    fprintf(analysis_info_f,
/*g*/      "predator type 2: recoverable decrement to health of %.3f\n",
/*g*/      health_decr);
/*g*/    fprintf(analysis_info_f,
/*g*/  "predator type 2: addition to permanent injury (not recoverable) of %.3f\n",
/*g*/      perm_inj_incr);
/*g*/		fprintf(analysis_info_f,
/*g*/		  "health gone from %.3f to %.3f (t = %.3f)\n",
/*g*/		  (animal_health+health_decr+perm_inj_incr), animal_health,
/*g*/		  (((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
  }

  /* if injury here has just caused the animal to die then print out
  details to the analysis file */
  if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
    fprintf(tob_f,
	  "\n %d ULTIMATE CAUSE OF DEATH: due to being attacked by ", timestep);
    fprintf(tob_f, "predator(s) (type 2)\n");
	  fflush(tob_f);

    animal_alive = FALSE;
  }
}


/* function to calculate the effects of the animal on a prey instance if it
is in the same square */
void animal_effect_on_prey()
{

  int i;
  int nft = PREY_N;
  PREY *ptr, *ptr1;

  /* if animal in same square as prey then if animal catches it (dependent
  on whether prey manages to escape) */
  if ((animal_action == POUNCING) && (drand48() > animal_escape_prob)) {

	animal_fat += ((PREY *) env_arr[animal_c][animal_r].p_arr[nft])->value
				   * PREY_FAT_RATIO;
	animal_carbo += ((PREY *) env_arr[animal_c][animal_r].p_arr[nft])->value
				   * PREY_CARBO_RATIO;
	animal_protein += ((PREY *) env_arr[animal_c][animal_r].p_arr[nft])->value
				   * PREY_PROTEIN_RATIO;

	/* remove all references to this first instance of prey in the square
	and free memory */ 
	ptr = (PREY *) env_arr[animal_c][animal_r].p_arr[nft];

	/* remove this feature instance from env_array */
	env_arr[animal_c][animal_r].p_arr[nft] = (void *) ptr->next_ptr;
/*g*/
/*g*/	/* draw over the position the feature occupied */
/*g*/	redraw_square(animal_c, animal_r);

	/* remove this entry from the feature list */
	for (i = 0; i < f_list[nft].count; ++i)

	  if (((void *) ptr) == f_list[nft].f_ptr[i])
		f_list_remove(nft, i);

	/* free the memory that was used to hold this feature */
	free(ptr);
  }
}


/* function to calculate the effects on the animal of it being outside the
environment */
void outside_env_effect_on_animal()
{

  /* penalise the animal by twice as much as it can recover from so that it
  will not be beneficial to leave the environment */
  animal_health -= 2.0 * RECOVERY_RATE;

  /* if injury here has just caused the animal to die then print out
  details to the analysis file */
  if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
    fprintf(tob_f,
	  "\n %d ULTIMATE CAUSE OF DEATH: due to the animal going ", timestep);
    fprintf(tob_f, "outside the environment\n");
	  fflush(tob_f);

	animal_alive = FALSE;
  }

  /* move the animal back into the environment (change coordinates to
  previous ones) */
  animal_c = prev_animal_c;
  animal_r = prev_animal_r;
}


/* function to calculate the current value of the animal's health (this
value can also be decremented due to interactions between the animal and
features in the environment) */
void calc_animal_health()
{

  double prev_animal_health;		/* final value from last timestep */
  double max_recovery;
  double health_decr;
  static double tm1_fat, tm1_carbo, tm1_protein, tm1_water, tm1_cl;
  static double tm2_fat, tm2_carbo, tm2_protein, tm2_water, tm2_cl;
  register int i, j;
  double sum_probs;
  int total_num;
  double clean_p, move_p, move_fast_p, eat_p, sleep_p, rest_p, freeze_p,
	drink_p, mate_p, look_p; 

  prev_animal_health = animal_health;

  /* the animal's maximum attainable health if properly satiated with food,
  water, temp, etc is dependent on age and previous permanently damaging
  injury */
  if (animal_age < (MAX_ANIMAL_LIFESPAN/2.0))
	animal_max_health = 1.0;
  else
	animal_max_health = 2.0 - (2.0*animal_age/MAX_ANIMAL_LIFESPAN);

/*g*/  if (animal_max_health < 0.2)
/*g*/    fprintf(analysis_info_f,
/*g*/	  "major factor in animal's death will be old age\n");
/*g*/
  animal_max_health -= animal_perm_inj;

  /* calculate value of animal health equal to max. attainable health then
  decrement if homeostatic variables out of range */
  animal_health = animal_max_health;

  if (animal_fat < MIN_OK_FAT) {

    health_decr = ((MIN_OK_FAT-animal_fat)*(MIN_OK_FAT-animal_fat)/
	MIN_OK_FAT/MIN_OK_FAT);
    animal_health -= health_decr;

    /* if fat shortage serious and at peak (i.e. (t-1) was worse than
	now (t), as well as worse than (t-2)) then write details to file */
    if ((health_decr>0.2) && (tm1_fat<animal_fat) && (tm1_fat<tm2_fat)) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "lack of fat: recoverable decrement to health of %.3f",
/*g*/          health_decr);
/*g*/	  fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to lack of fat\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}
  }

  if (animal_fat > MAX_OK_FAT) {

    health_decr = pow(((animal_fat-MAX_OK_FAT)/(1.0-MAX_OK_FAT)), 3.0);
    animal_health -= health_decr;

    /* if overeating serious and at peak (i.e. (t-1) was worse than
	now (t), as well as worse than (t-2)) then write details to file */
    if ((health_decr>0.2) && (tm1_fat>animal_fat) && (tm1_fat>tm2_fat)) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "too much fat: recoverable decrement to health of %.3f",
/*g*/        health_decr);
/*g*/	  fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to too much fat\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}

	/* make animal regurgitate some food since too much at moment */
	regurgitate();
  }

  if (animal_carbo < MIN_OK_CARBO) {

    health_decr = ((MIN_OK_CARBO-animal_carbo)*(MIN_OK_CARBO-animal_carbo)/
	MIN_OK_CARBO/MIN_OK_CARBO);
    animal_health -= health_decr;

    /* if carbohydrate shortage serious and at peak (i.e. (t-1) was worse
	than now (t), as well as worse than (t-2)) then write details to file */
    if ((health_decr>0.2) && (tm1_carbo<animal_carbo) && (tm1_carbo<tm2_carbo)) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "lack of carbohydrate: recoverable decrement to health of %.3f",
/*g*/          health_decr);
/*g*/	  fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to lack of carbohydrate\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}
  }

  if (animal_carbo > MAX_OK_CARBO) {

    health_decr = pow(((animal_carbo-MAX_OK_CARBO)/(1.0-MAX_OK_CARBO)), 3.0);
    animal_health -= health_decr;

    /* if overeating serious and at peak (i.e. (t-1) was worse than
	now (t), as well as worse than (t-2)) then write details to file */
    if ((health_decr>0.2) && (tm1_carbo>animal_carbo) && (tm1_carbo>tm2_carbo)) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "too much carbo: recoverable decrement to health of %.3f",
/*g*/        health_decr);
/*g*/	  fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to too much carbohydrate\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}

	/* make animal regurgitate some food since too much at moment */
	regurgitate();
  }

  if (animal_protein < MIN_OK_PROTEIN) {

    health_decr = ((MIN_OK_PROTEIN-animal_protein) *
	  (MIN_OK_PROTEIN-animal_protein) / MIN_OK_PROTEIN / MIN_OK_PROTEIN);
    animal_health -= health_decr;

    /* if protein shortage serious and at peak (i.e. (t-1) was worse than
	now (t), as well as worse than (t-2)) then write details to file */
    if ((health_decr>0.2) && (tm1_protein<animal_protein) &&
		(tm1_protein<tm2_protein)) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "lack of protein: recoverable decrement to health of %.3f",
/*g*/          health_decr);
/*g*/	  fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to lack of protein\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}
  }

  if (animal_protein > MAX_OK_PROTEIN) {

    health_decr = pow(((animal_protein-MAX_OK_PROTEIN)/(1.0-MAX_OK_PROTEIN)),
	  3.0);
    animal_health -= health_decr;

    /* if overeating serious and at peak (i.e. (t-1) was worse than
	now (t), as well as worse than (t-2)) then write details to file */
    if ((health_decr>0.2) && (tm1_protein>animal_protein) &&
		(tm1_protein>tm2_protein)) { 
/*g*/      fprintf(analysis_info_f,
/*g*/        "too much protein: recoverable decrement to health of %.3f",
/*g*/        health_decr);
/*g*/	  fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to too much protein\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}

	/* make animal regurgitate some food since too much at moment */
	regurgitate();
  }

  if (animal_water < MIN_OK_WATER) {

    health_decr = ((MIN_OK_WATER-animal_water)*(MIN_OK_WATER-animal_water)/
	MIN_OK_WATER/MIN_OK_WATER);
    animal_health -= health_decr;

    /* if water shortage serious and at peak (i.e. (t-1) was worse than
	now (t), as well as worse than (t-2)) then write details to file */
    if ((health_decr>0.2)&&(tm1_water<animal_water)&&(tm1_water<tm2_water)) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "lack of water: recoverable decrement to health of %.3f",
/*g*/        health_decr);
/*g*/	  fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to lack of water\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}
  }

  if (animal_water > MAX_OK_WATER) {

    health_decr = ((animal_water-MAX_OK_WATER)/MIN_OK_WATER);
    animal_health -= health_decr;

    /* if overdrinking serious then write details to file */
    if (health_decr>0.1) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "overdrinking: recoverable decrement to health of %.3f",
/*g*/        health_decr);
/*g*/	  fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to overdrinking\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}

	/* make the animal get rid of the excess water */
	animal_water = MAX_OK_WATER;
  }

  if (animal_temp < MIN_OK_TEMP) {

    health_decr = (MIN_OK_TEMP-animal_temp) * (MIN_OK_TEMP-animal_temp)
			 		/ MIN_OK_TEMP / MIN_OK_TEMP;
    animal_health -= health_decr;

    /* if low temperature serious then write details to file */
    if (health_decr>0.2) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "low body temperature: recoverable decrement to health of %.3f",
/*g*/        health_decr);
/*g*/	  fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to low body temperature\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}
  }

  if (animal_temp > MAX_OK_TEMP) {

    health_decr = (animal_temp-MAX_OK_TEMP) * (animal_temp-MAX_OK_TEMP)
					/ MIN_OK_TEMP / MIN_OK_TEMP;
    animal_health -= health_decr;

    /* if high temperature serious then write details to file */
    if (health_decr>0.2) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "high body temperature: recoverable decrement to health of %.3f",
/*g*/        health_decr);
/*g*/      fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	}

    /* if health decrement here has just caused the animal to die then
    print out details to the analysis file */
    if ((animal_health <= 0.0) && (animal_alive == TRUE)) {
      fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to high body temperature\n", timestep);
	  fflush(tob_f);

	  animal_alive = FALSE;
	}
  }

  /* calculate the effect on the animal's health of lack of cleanliness (due
  to increased parasites, less efficient insulation, etc).  Lack of
  cleanliness will not kill, but will reduce health by up to 0.5 */ 
  health_decr = ((1.0 - animal_cleanliness) * 0.5);
  animal_health -= health_decr;

  /* if animal cleanliness serious and at peak (i.e. (t-1) was worse than
  now (t), as well as worse than (t-2)) then write details to file */
  if ((health_decr>0.2)&&(tm1_cl>animal_cleanliness)&&
	  (tm1_cl>tm2_cl)) {
/*g*/      fprintf(analysis_info_f,
/*g*/        "animal cleanliness: recoverable decrement to health of %.3f",
/*g*/        health_decr);
/*g*/      fprintf(analysis_info_f, " (t = %.3f)\n",
/*g*/		(((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
  }

  if (animal_health < 0.0) {

	fprintf(tob_f,
	  "\n %d ULTIMATE CAUSE OF DEATH: due to lack of cleaning\n", timestep);
	  fflush(tob_f);

	animal_alive = FALSE;
  }

  tm2_fat = tm1_fat;
  tm2_carbo = tm1_carbo;
  tm2_protein = tm1_protein;
  tm2_water = tm1_water;
  tm2_cl = tm1_cl;

  tm1_fat = animal_fat;
  tm1_carbo = animal_carbo;
  tm1_protein = animal_protein;
  tm1_water = animal_water;
  tm1_cl = animal_cleanliness;

  /* take into account any delayed effects of toxic food or water */
  for (i = 0; i < toxic_counter; i++) {

    /* if delayed effect happening now then change health and remove entry */
    if (toxic_array[i].delay == 0) {

      health_decr = 0.5 * toxic_array[i].strength;
      animal_health -= health_decr;

      /* if the animal's health is badly affected then write the details to
      the analysis file */
      if (health_decr > 0.2) {
/*g*/        fprintf(analysis_info_f, "toxicity due to ");
/*g*/        if (toxic_array[i].type == FRUIT_FOOD_N)
/*g*/          fprintf(analysis_info_f, "eating toxic fruit type food");
/*g*/        if (toxic_array[i].type == CEREAL_FOOD_N)
/*g*/          fprintf(analysis_info_f, "eating toxic cereal type food");
/*g*/        if (toxic_array[i].type == WATER_N)
/*g*/          fprintf(analysis_info_f, "drinking toxic water");
/*g*/        fprintf(analysis_info_f,
/*g*/        " taking effect (delayed) - value %.3f\n", health_decr);
/*g*/		fprintf(analysis_info_f,
/*g*/		  "health gone from %.3f to %.3f (t = %.3f)\n",
/*g*/		  (animal_health+health_decr), animal_health,
/*g*/		  (((double)daystep) + (((double)timestep)/((double)DAY_LENGTH))));
	  }

      /* if health decrement here has just caused the animal to die then
      print out details to the analysis file */
      if ((animal_health <= 0.0) && (animal_alive == TRUE)) {

        fprintf(tob_f,
		  "\n %d ULTIMATE CAUSE OF DEATH: due to delayed effects", timestep);

        if (toxic_array[i].type == CEREAL_FOOD_N)
          fprintf(tob_f, " of eating toxic cereal type food\n");
        if (toxic_array[i].type == WATER_N)
          fprintf(tob_f, " of drinking toxic water\n");
	  fflush(tob_f);

		animal_alive = FALSE;
      }

      /* remove entry by replacing with last */
      toxic_array[i].delay = toxic_array[toxic_counter-1].delay;
      toxic_array[i].strength = toxic_array[toxic_counter-1].strength;
      toxic_array[i].type = toxic_array[toxic_counter-1].type;
      toxic_counter--;

	  /* make animal suspicious of all food/water sources it has consumed
	  recently.  First make the probability of each food/water source having
	  caused the toxicity equal to (1.0 - fraction of day since visited),
	  but then divide all probabilities by the sum, so as to make the total
	  of all probabilities equal to 1.0 */
	  sum_probs = 0.0;

	  for (j = 0; j < num_active_memories; j++)

		if (map[j]->time_since_consumed < DAY_LENGTH)

		  sum_probs += (1.0 - (((double) map[j]->time_since_consumed)
						 / DAY_LENGTH)); 

	  for (j = 0; j < num_active_memories; j++)

		if (map[j]->time_since_consumed < DAY_LENGTH)

		  map[j]->est_toxicity +=
				((1.0 - (((double) map[j]->time_since_consumed) / DAY_LENGTH))
				/ sum_probs);
    }

    else /* else decrease time till `activation' by one timestep */

      toxic_array[i].delay--;
  }

  /* decrease the animal's health a small amount if it is exerting itself
  very heavily */
  if ((move_fast_action_chosen() == TRUE) ||
	  (animal_action == MATING)) {

	animal_health -= (RECOVERY_RATE * 0.3);

	/* if health decrement here has just caused the animal to die then
	print out details to the analysis file */
	if ((animal_health <= 0.0) && (animal_alive == TRUE)) {

	  fprintf(tob_f,
		"\n %d ULTIMATE CAUSE OF DEATH: due to over-exertion\n", timestep);
	  fflush(tob_f);
	  animal_alive = FALSE;
	}
  }

  /* only allow the animal to recover a certain amount during one timestep.
  The amount it is able to recover will depend on what it is doing */
  if (animal_action == SLEEPING)
	max_recovery = RECOVERY_RATE * 1.0;
  else if (animal_action == RESTING)
	max_recovery = RECOVERY_RATE * 0.8;
  else if (animal_action == CLEANING)
	max_recovery = RECOVERY_RATE * 0.7;
  else if (look_action_chosen() == TRUE)
	max_recovery = RECOVERY_RATE * 0.6;
  else if (animal_action == FREEZING)
	max_recovery = RECOVERY_RATE * 0.5;
  else if (eat_action_chosen() == TRUE)
	max_recovery = RECOVERY_RATE * 0.4;
  else if (animal_action == DRINKING)
	max_recovery = RECOVERY_RATE * 0.4;
  else if (animal_action == COURT_DISPLAYING)
	max_recovery = RECOVERY_RATE * 0.3;
  else if (move_action_chosen() == TRUE)
	max_recovery = RECOVERY_RATE * 0.3;
  else if (animal_action == POUNCING)
	max_recovery = RECOVERY_RATE * 0.1;
  else if (move_fast_action_chosen() == TRUE)
	max_recovery = RECOVERY_RATE * 0.1;
  else if (animal_action == MATING)
	max_recovery = RECOVERY_RATE * 0.0;

  if (animal_health > (prev_animal_health+max_recovery))
	animal_health = prev_animal_health + max_recovery;

  /* if health <= zero then animal dies */
  if (animal_health <= 0.0)
    animal_alive = FALSE;
}


/*g*//* function to update the message saying what the animal is doing */
/*g*/void update_action_message()
/*g*/{
/*g*/
/*g*/  char text[50];
/*g*/  int i, counter = 0;
/*g*/
/*g*/  /* display message about what animal is doing on panel */
/*g*/	switch(animal_action) {
/*g*/    case(SLEEPING):				sprintf(text, "sleeping");
/*g*/								break;
/*g*/    case(RESTING):				sprintf(text, "resting");
/*g*/								break;
/*g*/    case(FREEZING):				sprintf(text, "freezing");
/*g*/								break;
/*g*/    case(EATING_CF):			sprintf(text, "eating cf");
/*g*/								break;
/*g*/    case(EATING_FF):			sprintf(text, "eating ff");
/*g*/								break;
/*g*/    case(POUNCING):				sprintf(text, "pouncing");
/*g*/								break;
/*g*/    case(DRINKING):				sprintf(text, "drinking");
/*g*/								break;
/*g*/    case(COURT_DISPLAYING):		sprintf(text, "court displaying");
/*g*/								break;
/*g*/    case(CLEANING):			sprintf(text, "cleaning");
/*g*/								break;
/*g*/    case(MATING):				sprintf(text, "mating");
/*g*/								break;
/*g*/    case(LOOKING_N):		sprintf(text, "looking to the N");
/*g*/								break;
/*g*/    case(LOOKING_NW):		sprintf(text, "looking to the NW");
/*g*/								break;
/*g*/    case(LOOKING_W):		sprintf(text, "looking to the W");
/*g*/								break;
/*g*/    case(LOOKING_SW):		sprintf(text, "looking to the SW");
/*g*/								break;
/*g*/    case(LOOKING_S):		sprintf(text, "looking to the S");
/*g*/								break;
/*g*/    case(LOOKING_SE):		sprintf(text, "looking to the SE");
/*g*/								break;
/*g*/    case(LOOKING_E):		sprintf(text, "looking to the E");
/*g*/								break;
/*g*/    case(LOOKING_NE):		sprintf(text, "looking to the NE");
/*g*/								break;
/*g*/    case(LOOKING_AROUND):		sprintf(text, "looking around");
/*g*/								break;
/*g*/    default:					break;
/*g*/   }
/*g*/
/*g*/  if (move_action_chosen() == TRUE)
/*g*/	sprintf(text, "moving");
/*g*/  if (move_fast_action_chosen() == TRUE)
/*g*/	sprintf(text, "moving fast");
/*g*/
/*g*/    panel_set(action_message, PANEL_LABEL_STRING, text, 0);
/*g*/}


/* function to calculate how conspicuous the animal is (dependent on whether
the animal is in vegetation and on what the animal is doing) */
void get_conspicuousness()
{

  animal_conspicuousness = env_arr[animal_c][animal_r].perception_factor;

  if (sim_env_version == V3) {
    if (animal_action == SLEEPING)
	  animal_conspicuousness *= 0.6;
    else if (animal_action == RESTING)
	  animal_conspicuousness *= 0.4;
    else if (animal_action == FREEZING)
	  animal_conspicuousness *= 0.1;
    else if (eat_action_chosen() == TRUE)
	  animal_conspicuousness *= 0.4;
    else if (animal_action == DRINKING)
	  animal_conspicuousness *= 0.6;
    else if (animal_action == COURT_DISPLAYING)
	  animal_conspicuousness *= 0.8;
    else if (animal_action == MATING)
	  animal_conspicuousness *= 0.5;
    else if (animal_action == POUNCING)
	  animal_conspicuousness *= 1.0;
    else if (look_action_chosen() == TRUE)
	  animal_conspicuousness *= 0.6;
    else if (move_action_chosen() == TRUE)
	  animal_conspicuousness *= 0.3;
    else if (move_fast_action_chosen() == TRUE)
	  animal_conspicuousness *= 0.6;
  }
  else {
    if (animal_action == SLEEPING)
	  animal_conspicuousness *= 0.2;
    else if (animal_action == RESTING)
	  animal_conspicuousness *= 0.2;
    else if (animal_action == FREEZING)
	  animal_conspicuousness *= 0.1;
    else if (eat_action_chosen() == TRUE)
	  animal_conspicuousness *= 0.5;
    else if (animal_action == DRINKING)
	  animal_conspicuousness *= 0.5;
    else if (animal_action == COURT_DISPLAYING)
	  animal_conspicuousness *= 0.8;
    else if (animal_action == MATING)
	  animal_conspicuousness *= 0.8;
    else if (animal_action == POUNCING)
	  animal_conspicuousness *= 0.8;
    else if (look_action_chosen() == TRUE)
	  animal_conspicuousness *= 0.3;
    else if (move_action_chosen() == TRUE)
	  animal_conspicuousness *= 0.6;
    else if (move_fast_action_chosen() == TRUE)
	  animal_conspicuousness *= 1.0;
  }
}


/* function to calculate how the probability of the animal being able to
escape if it is attacked this timestep (dependent on vegetation/features in
the square and on the animal's action to an extent) */
void get_escape_prob()
{

  /* set it initially to square escape factor (0.0 if no vegetation or den,
  greater otherwise) */
  animal_escape_prob = env_arr[animal_c][animal_r].escape_factor;

  /* increment value if animal is doing something likely to make it more
  difficult for the attacker to catch it */
  if (animal_action == FREEZING)
	animal_escape_prob *= 2.0;		/* only relevant if in vegetation */
  if (move_action_chosen() == TRUE)
	animal_escape_prob += 0.3;
  if (move_fast_action_chosen() == TRUE)
	animal_escape_prob += 0.5;

  if (animal_escape_prob > 1.0)
	animal_escape_prob = 0.99999;
}


/* function to make the behavioural choice of the animal.  (this `dummy'
function is here so as to allow access to local variables) */ 
void strategy_choice()
{

  double distance_moved_sqrd;
  int i;
  double perc_fat_shortage, perc_carbo_shortage, perc_protein_shortage,
		 perc_water_shortage, perc_an_low_temp, perc_an_high_temp,
		 perc_sqr_low_temp, perc_sqr_high_temp, perc_animal_cleanliness;

  /* calculate various properties of the environment */
  calc_env_properties();

  /* add noise to perception of internal variables */
  perc_fat_shortage = fat_shortage + g_rnd(0.0,0.002);
  perc_carbo_shortage = carbo_shortage + g_rnd(0.0,0.002);
  perc_protein_shortage = protein_shortage + g_rnd(0.0,0.002);
  perc_water_shortage = water_shortage + g_rnd(0.0,0.002);
  perc_an_low_temp = an_low_temp + g_rnd(0.0,0.002);
  perc_an_high_temp = an_high_temp + g_rnd(0.0,0.002);
  perc_sqr_low_temp = sqr_low_temp + g_rnd(0.0,0.002);
  perc_sqr_high_temp = sqr_high_temp + g_rnd(0.0,0.002);
  perc_animal_cleanliness = animal_cleanliness + g_rnd(0.0,0.002);

  if (perc_fat_shortage < 0.0) perc_fat_shortage = 0.0;
  if (perc_carbo_shortage < 0.0) perc_carbo_shortage = 0.0;
  if (perc_protein_shortage < 0.0) perc_protein_shortage = 0.0;
  if (perc_water_shortage < 0.0) perc_water_shortage = 0.0;
  if (perc_an_low_temp < 0.0) perc_an_low_temp = 0.0;
  if (perc_an_high_temp < 0.0) perc_an_high_temp = 0.0;
  if (perc_sqr_low_temp < 0.0) perc_sqr_low_temp = 0.0;
  if (perc_sqr_high_temp < 0.0) perc_sqr_high_temp = 0.0;
  if (perc_animal_cleanliness < 0.0) perc_animal_cleanliness = 0.0;
  if (perc_fat_shortage > 1.0) perc_fat_shortage = 1.0;
  if (perc_carbo_shortage > 1.0) perc_carbo_shortage = 1.0;
  if (perc_protein_shortage > 1.0) perc_protein_shortage = 1.0;
  if (perc_water_shortage > 1.0) perc_water_shortage = 1.0;
  if (perc_an_low_temp > 1.0) perc_an_low_temp = 1.0;
  if (perc_an_high_temp > 1.0) perc_an_high_temp = 1.0;
  if (perc_sqr_low_temp > 1.0) perc_sqr_low_temp = 1.0;
  if (perc_sqr_high_temp > 1.0) perc_sqr_high_temp = 1.0;
  if (perc_animal_cleanliness > 1.0) perc_animal_cleanliness = 1.0;

  /* the only information available to the animal is its perception of the
  external world, the local weather, and the state of its internal variables*/
  animal_action = select_action(perc_fat_shortage, perc_carbo_shortage,
	perc_protein_shortage, perc_water_shortage, perc_an_low_temp,
	perc_an_high_temp, perc_sqr_low_temp, perc_sqr_high_temp, mate_courted,
	perc_animal_cleanliness, night_proximity, an_variance,
	distance_from_den, &(food_perc_stimulus[0]), &(food_memory_stimulus[0]),
	&(water_perc_stimulus[0]), &(water_memory_stimulus[0]),
	&(shelter_perc_stimulus[0]), &(shade_perc_stimulus[0]),
	&(p1_perc_stimulus[0]), &(p2_perc_stimulus[0]), &(dp_perc_stimulus1[0]),
	&(irr_perc_stimulus1[0]), &(mate_perc_stimulus[0]),
	&(den_perc_stimulus[0]), &(den_memory_stimulus[0]),
	&(edge_perc_stimulus[0]), time_since_last_scan, distance_to_cover,
	time_since_last_pred, animal_health, animal_perm_inj,
	&(dp_perc_stimulus2[0]), &(irr_perc_stimulus2[0])); 

  /* check that animal_action has an appropriate value */
  if ((animal_action < 0) || (animal_action >= NUM_LOW_LEVEL_ACTIONS)) {
	printf("bad value for animal_action (%d)\n", animal_action);
	animal_action = RESTING;
  }

  /* occasionally, especially if the health of the animal is very low then
  it does not perform its desired action correctly */
  if ((animal_health < 0.1) &&
	  (sim_env_version == V3) &&
	   ((rnd(0.1) > animal_health) ||
	   (drand48() < 0.05))) {

	animal_action = RESTING;

/*g*/	fprintf(analysis_info_f,
/*g*/	  "\n animal partially incapacitated (health < 0.1)\n");
  }

  /* occasionally, especially if the health of the animal is very low then
  it does not perform its desired action correctly */
  if ((animal_health < 0.1) &&
	  (sim_env_version != V3) &&
	   ((rnd(0.1) > animal_health) ||
	   (drand48() < 0.01))) {

	animal_action = RESTING;

/*g*/	fprintf(analysis_info_f,
/*g*/	  "\n animal partially incapacitated (health < 0.1)\n");
  }	

  /* some actions cannot be performed by the animal if its health is too
  low */
  if ((animal_health < 0.1) &&
	  ((animal_action == MATING) ||
	   (animal_action == POUNCING) ||
	   (move_fast_action_chosen() == TRUE)))
	animal_action = RESTING;

  /* check the values returned by the behavioural choice module */

  /* animal not allowed to perform various actions in den */
  if ((animal_c == first_den_c) && (animal_r == first_den_r) &&
	  ((animal_action == CLEANING) ||
	   (animal_action == COURT_DISPLAYING) ||
	   (animal_action == MATING) ||
	   (animal_action == POUNCING))) {
	   
	printf("animal is not allowed to do that (%d) while in its den\n",
	  animal_action);

	animal_action = RESTING;
  }

  /* assign proper values of c_change and r_change according to the action
  chosen */
  c_change = 0;
  r_change = 0;
  switch(animal_action) {
	case(MOVE_N):  c_change = 0;
				   r_change = -1;
				   break;
	case(MOVE_NW): c_change = -1;
				   r_change = -1;
				   break;
	case(MOVE_W):  c_change = -1;
				   r_change = 0;
				   break;
	case(MOVE_SW): c_change = -1;
				   r_change = 1;
				   break;
	case(MOVE_S):  c_change = 0;
				   r_change = 1;
				   break;
	case(MOVE_SE): c_change = 1;
				   r_change = 1;
				   break;
	case(MOVE_E):  c_change = 1;
				   r_change = 0;
				   break;
	case(MOVE_NE): c_change = 1;
				   r_change = -1;
				   break;
	case(MOVE2_N):  c_change = 0;
				   r_change = -2;
				   break;
	case(MOVE2_NW): c_change = -2;
				   r_change = -2;
				   break;
	case(MOVE2_W):  c_change = -2;
				   r_change = 0;
				   break;
	case(MOVE2_SW): c_change = -2;
				   r_change = 2;
				   break;
	case(MOVE2_S):  c_change = 0;
				   r_change = 2;
				   break;
	case(MOVE2_SE): c_change = 2;
				   r_change = 2;
				   break;
	case(MOVE2_E):  c_change = 2;
				   r_change = 0;
				   break;
	case(MOVE2_NE): c_change = 2;
				   r_change = -2;
				   break;
	default:       c_change = 0;
				   r_change = 0;
				   break;
  }

  /* check that desired action does not take animal outside of env, and
  disallow it if it does */
  if (((animal_c+c_change) < 0) ||
	  ((animal_c+c_change) > ENV_ARR_COLS) ||
	  ((animal_r+r_change) < 0) ||
	  ((animal_r+r_change) > ENV_ARR_ROWS)) {

	animal_action = RESTING;
	c_change = 0;
	r_change = 0;
  }

  /* update value of time_since_scanned */
  time_since_scanned++;
  if (animal_action == LOOKING_AROUND)
	time_since_scanned = 0;
  if (directed_look_action_chosen() == TRUE)
	time_since_scanned = 1;

  /* update the record of how often the animal performs each action */
  action_record[animal_action]++;
/*g*/
/*g*/  update_action_message();
}


/* function to calculate the values of various properties of the environment
which will then be used to determine the values of the various drives of the
animal */
void calc_env_properties()
{

  int i;

  time_since_predator_perceived++;

  /* set all property values to zero */
  zero_property_values();

  calc_fat_shortage();
  calc_carbo_shortage();
  calc_protein_shortage();
  calc_food_perc_stimulus();
  calc_food_memory_stimulus();
  calc_water_shortage();
  calc_water_perc_stimulus();
  calc_water_memory_stimulus();
  calc_low_temp(animal_temp);
  calc_shelter_perc_stimulus();
  calc_high_temp(animal_temp);
  calc_shade_perc_stimulus();
  calc_p1_perc_stimulus();
  calc_p2_perc_stimulus();
  calc_dp_perc_stimulus();
  calc_irr_perc_stimulus();
  calc_mate_perc_stimulus();
  calc_mate_courted();
  calc_night_proximity();
  calc_distance_from_den();
  calc_an_variance();
  /* animal cleanliness already calculated before here */
  calc_den_perc_stimulus();
  calc_den_memory_stimulus();
  calc_edge_perc_stimulus();

  /* transform into a variable in range 0.0 to 1.0 */
  time_since_last_scan = ((double) time_since_scanned) / 6.0;
  if (time_since_last_scan > 1.0)
	time_since_last_scan = 1.0;

  /* transform into a variable in range 0.0 to 1.0 */
  time_since_last_pred = ((double) time_since_predator_perceived) / 6.0;
  if (time_since_last_pred > 1.0)
	time_since_last_pred = 1.0;

  /* transform into a variable in range 0.0 to 1.0 */
  distance_to_cover = ((double) min_distance_to_cover) / 3.0;
  if (distance_to_cover > 1.0)
	distance_to_cover = 1.0;

  /* make sure all environment properties are in the range 0.0-1.0 */
  check_property_values();
}
/*g*/
/*g*/
/*g*//* function to destroy all windows to do with animal */
/*g*/void destroy_animal_windows()
/*g*/{
/*g*/
/*g*/  destroy(perception_frame);
/*g*/  destroy(animal_frame);
/*g*/}
/*g*/

/*g*//* function to print out details of contributory factors to animal`s death
/*g*//*to analysis file */
/*g*/void add_contrib_causes_to_analysis()
/*g*/{
/*g*/
/*g*/  fprintf(analysis_info_f, "\n contributory factors to animal's death:\n\n");
/*g*/
/*g*/  /* contribution of permanent injury */
/*g*/  if (animal_perm_inj > 0.0)
/*g*/    fprintf(analysis_info_f, "   decrement due to permanent injury: %.3f\n",
/*g*/      animal_perm_inj);
/*g*/
/*g*/  /* contribution of too much or too little fat */
/*g*/  if (animal_fat < MIN_OK_FAT)
/*g*/	fprintf(analysis_info_f, "   decrement due to fat imbalance:    %.3f\n",
/*g*/      ((MIN_OK_FAT-animal_fat) * (MIN_OK_FAT-animal_fat) /
/*g*/	  MIN_OK_FAT / MIN_OK_FAT));
/*g*/  else if (animal_fat > MAX_OK_FAT)
/*g*/	fprintf(analysis_info_f, "   decrement due to fat imbalance:    %.3f\n",
/*g*/      ((animal_fat-MAX_OK_FAT) * (animal_fat-MAX_OK_FAT) /
/*g*/	  MIN_OK_FAT / MIN_OK_FAT));
/*g*/
/*g*/  /* contribution of too much or too little carbohydrate */
/*g*/  if (animal_carbo < MIN_OK_CARBO)
/*g*/	fprintf(analysis_info_f, "   decrement due to carbohydrate imbalance:%.3f\n",
/*g*/      ((MIN_OK_CARBO-animal_carbo) * (MIN_OK_CARBO-animal_carbo) /
/*g*/	  MIN_OK_CARBO / MIN_OK_CARBO));
/*g*/  else if (animal_carbo > MAX_OK_CARBO)
/*g*/	fprintf(analysis_info_f, "   decrement due to carbohydrate imbalance:%.3f\n",
/*g*/      ((animal_carbo-MAX_OK_CARBO) * (animal_carbo-MAX_OK_CARBO) /
/*g*/	  MIN_OK_CARBO / MIN_OK_CARBO));
/*g*/
/*g*/  /* contribution of too much or too little protein */
/*g*/  if (animal_protein < MIN_OK_PROTEIN)
/*g*/	fprintf(analysis_info_f, "   decrement due to protein imbalance:%.3f\n",
/*g*/      ((MIN_OK_PROTEIN-animal_protein) * (MIN_OK_PROTEIN-animal_protein) /
/*g*/	  MIN_OK_PROTEIN / MIN_OK_PROTEIN));
/*g*/  else if (animal_protein > MAX_OK_PROTEIN)
/*g*/	fprintf(analysis_info_f, "   decrement due to protein imbalance:%.3f\n",
/*g*/      ((animal_protein-MAX_OK_PROTEIN) * (animal_protein-MAX_OK_PROTEIN) /
/*g*/	  MIN_OK_PROTEIN / MIN_OK_PROTEIN));
/*g*/
/*g*/  /* contribution of too much or too little water */
/*g*/  if (animal_water < MIN_OK_WATER)
/*g*/    fprintf(analysis_info_f, "   decrement due to water imbalance:  %.3f\n",
/*g*/	  ((MIN_OK_WATER-animal_water) * (MIN_OK_WATER-animal_water) /
/*g*/	  MIN_OK_WATER / MIN_OK_WATER));
/*g*/  else if (animal_water > MAX_OK_WATER)
/*g*/    fprintf(analysis_info_f, "   decrement due to water imbalance:  %.3f\n",
/*g*/	  ((animal_water-MAX_OK_WATER) * (animal_water-MAX_OK_WATER) /
/*g*/	  MIN_OK_WATER / MIN_OK_WATER));
/*g*/
/*g*/  /* contribution of too high or too low temperature */
/*g*/  if (animal_temp < MIN_OK_TEMP)
/*g*/	fprintf(analysis_info_f, "   decrement due to temp. imbalance:  %.3f\n",
/*g*/	  ((MIN_OK_TEMP-animal_temp) * (MIN_OK_TEMP-animal_temp) /
/*g*/	  MIN_OK_TEMP / MIN_OK_TEMP));
/*g*/  else if (animal_temp > MAX_OK_TEMP)
/*g*/	fprintf(analysis_info_f, "   decrement due to temp. imbalance:  %.3f\n",
/*g*/      ((animal_temp-MAX_OK_TEMP) * (animal_temp-MAX_OK_TEMP) /
/*g*/	  MIN_OK_TEMP / MIN_OK_TEMP));
/*g*/
/*g*/  /* contribution of not cleaning (not keeping skin/fur/feathers/scales/
/*g*//*  whatever in good condition and free from parasites) */
/*g*/  if (animal_cleanliness != 1.0)
/*g*/	fprintf(analysis_info_f, "   decrement due to uncleanliness:    %.3f\n",
/*g*/	  ((1.0 - animal_cleanliness) * 0.5));
/*g*/
/*g*/  /* contribution of aging */
/*g*/  if (animal_age > (MAX_ANIMAL_LIFESPAN/2.0))
/*g*/ 	fprintf(analysis_info_f, "   decrement due to age:              %.3f\n",
/*g*/	  (1.0 - (2.0 - (2.0*animal_age/MAX_ANIMAL_LIFESPAN))));
/*g*/}
/*g*/
/*g*/
/*g*//* function to draw all the animal's spatial memory entries onto a canvas */
/*g*/void draw_memory(index)
/*g*/int index;		/* memory entry */
/*g*/{
/*g*/
/*g*/  register int colour;	/* entry in colourmap to be used */
/*g*/
/*g*/  switch(map[index]->nft) {
/*g*/
/*g*/	case(CEREAL_FOOD_N): colour = map[index]->nft*5 + 1 +
/*g*/								((int) (map[index]->est_value * 5.0));
/*g*/	  					   break;
/*g*/	case(COVER_N): colour = map[index]->nft*5 + 1 +
/*g*/								((int) (map[index]->est_thickness * 5.0));
/*g*/	  					   break;
/*g*/	case(FRUIT_FOOD_N): colour = map[index]->nft*5 + 1 +
/*g*/								((int) (map[index]->est_value * 5.0));
/*g*/						   break;
/*g*/	case(SHADE_N): colour = map[index]->nft*5 + 1 +
/*g*/								((int) (map[index]->est_thickness * 5.0));
/*g*/						   break;
/*g*/	case(WATER_N): colour = map[index]->nft*5 + 1 +
/*g*/								((int) (map[index]->est_value * 5.0));
/*g*/						   break;
/*g*/	default: colour = (5 * (map[index]->nft+1));
/*g*/  }
/*g*/
/*g*/  if (map[index]->memory_strength > 0.0) {
/*g*/
/*g*/	/* draw the remembered feature */
/*g*/	pw_stencil(map_pw,
/*g*/	((int)((((double)first_den_c)+map[index]->est_c)*((double) SQUARE_SIZE))),
/*g*/	((int)((((double)first_den_r)+map[index]->est_r)*((double) SQUARE_SIZE))),
/*g*/	SQUARE_SIZE, SQUARE_SIZE, (PIX_SRC|PIX_COLOR(colour)),
/*g*/	feature_pr[map[index]->nft], 0, 0, NULL, 0, 0);
/*g*/  }
/*g*/
/*g*/  /* if the animal thinks the feature is toxic then draw that over as well*/
/*g*/  if (map[index]->est_toxicity > 0.3) {
/*g*/
/*g*/	/* draw the image of this feature over whatever's there */
/*g*/	pw_stencil(map_pw,
/*g*/	((int)((((double)first_den_c)+map[index]->est_c)*((double) SQUARE_SIZE))),
/*g*/	((int)((((double)first_den_r)+map[index]->est_r)*((double)SQUARE_SIZE))), 
/*g*/	SQUARE_SIZE, SQUARE_SIZE, (PIX_SRC|PIX_COLOR(colour)),
/*g*/	feature_pr[TOXIC_N], 0, 0, NULL, 0, 0);
/*g*/  }
/*g*/}
/*g*/
/*g*/
/*g*//* function to draw all the animal's spatial memory entries onto a canvas */
/*g*/void draw_map()
/*g*/{
/*g*/
/*g*/  int i;
/*g*/
/*g*/  /* clear whole of canvas */
/*g*/  pw_writebackground(map_pw, 0, 0, 776, 776, PIX_CLR);
/*g*/
/*g*/  /* draw the den */
/*g*/  pw_stencil(map_pw, (first_den_c*SQUARE_SIZE), (first_den_r*SQUARE_SIZE),
/*g*/	SQUARE_SIZE, SQUARE_SIZE, (PIX_SRC|PIX_COLOR(DEN_N*5+5)),
/*g*/	feature_pr[DEN_N], 0, 0, NULL, 0, 0);
/*g*/
/*g*/  /* draw all existing memory entries */
/*g*/  for (i = 0; i < num_active_memories; i++)
/*g*/	draw_memory(i);
/*g*/}
/*g*/

/* function to sort the memories in "map" into order, where the order is
such that higher memory strengths come higher up the list (ie. their index
is closer to zero).  It is assumed that if the list is unordered, then this
will be because a high strength memory is too low, rather than a
low strength memory being too high */
void sort_map()
{

  int i, j;
  int list_sorted = FALSE;
  PLACE_MEMORY *temp_ptr;

  /* while list has already got an element and while it is not sorted */
  while ((num_active_memories > 1) && (list_sorted == FALSE)) {

	/* make one sorting pass through the list */
	for (i = (num_active_memories-1); i > 0; i--) {

	  list_sorted = TRUE;

	  if (map[i]->memory_strength > map[i-1]->memory_strength) {

		/* swap memory entries */
		temp_ptr = map[i];
		map[i] = map[i-1];
		map[i-1] = temp_ptr;

		/* if just changed position of memory referring to current place
		then make a note of this */
		if (i == this_place) {

		  this_place = i-1;
		}

		/* show that list wasn't sorted on this sweep */
		list_sorted = FALSE;
	  }
	}
  }
}


/* void function to make the animal vomit if it has too much of a particular
constituent of food */
void regurgitate()
{

  double excess_fat, excess_carbo, excess_protein;

  /* calculate excess amounts of different constituents and then reduce
  amount by excess */

  /* fat */
  excess_fat = animal_fat - MAX_OK_FAT;
  if (excess_fat > 0.0)
	animal_fat -= excess_fat;

  /* carbohydrate */
  excess_carbo = animal_carbo - MAX_OK_CARBO;
  if (excess_carbo > 0.0)
	animal_carbo -= excess_carbo;

  /* protein */
  excess_protein = animal_protein - MAX_OK_PROTEIN;
  if (excess_protein > 0.0)
	animal_protein -= excess_protein;
}


double action_effect_on_perc(target_dir)
int target_dir;
{

  int direction_of_look;

  if (animal_action == SLEEPING)
	return(0.0);
  else if (animal_action == RESTING)
	return(0.7);
  else if (animal_action == FREEZING)
	return(0.9);
  else if (eat_action_chosen() == TRUE)
	return(0.2);
  else if (animal_action == DRINKING)
	return(0.2);
  else if (animal_action == CLEANING)
	return(0.5);
  else if (animal_action == COURT_DISPLAYING)
	return(0.3);
  else if (animal_action == MATING)
	return(0.2);
  else if (animal_action == POUNCING)
	return(0.2);

  /* note that any sort of looking action also allows the animal to perceive
  an extra square in distance */
  else if (animal_action == LOOKING_AROUND)
	  return(0.9);
  else if (directed_look_action_chosen() == TRUE) {

	switch(animal_action) {
	  case(LOOKING_N):  direction_of_look = 1;
						break;
	  case(LOOKING_NE): direction_of_look = 2;
						break;
	  case(LOOKING_E):  direction_of_look = 3;
						break;
	  case(LOOKING_SE): direction_of_look = 4;
						break;
	  case(LOOKING_S):  direction_of_look = 5;
						break;
	  case(LOOKING_SW): direction_of_look = 6;
						break;
	  case(LOOKING_W):  direction_of_look = 7;
						break;
	  case(LOOKING_NW): direction_of_look = 8;
						break;
	}

	if ((abs(direction_of_look-target_dir < 2) ||
	  (abs(direction_of_look-target_dir) == 7))) {
	  return(1.0);
	}
	else {
	  if (sim_env_version == V1)
	    return(0.2);
	  else
		return(0.5);
	}
  }
  else if (move_action_chosen() == TRUE)
	return(0.8);
  else if (move_fast_action_chosen() == TRUE)
	return(0.6);
}


/* void function to calculate the fat shortage of the animal, if there is
one, in the range 0.0 to 1.0 */
void calc_fat_shortage()
{

  if (animal_fat >= MAX_OK_FAT)
    fat_shortage = 0.0;
  else 
    fat_shortage = (MAX_OK_FAT - animal_fat) / MAX_OK_FAT;
}


/* void function to calculate the carbohydrate shortage of the animal, if there is
one, in the range 0.0 to 1.0 */
void calc_carbo_shortage()
{

  if (animal_carbo >= MAX_OK_CARBO)
    carbo_shortage = 0.0;
  else 
    carbo_shortage = (MAX_OK_CARBO - animal_carbo) / MAX_OK_CARBO;
}


/* void function to calculate the protein shortage of the animal, if there is
one, in the range 0.0 to 1.0 */
void calc_protein_shortage()
{

  if (animal_protein >= MAX_OK_PROTEIN)
    protein_shortage = 0.0;
  else 
    protein_shortage = (MAX_OK_PROTEIN - animal_protein) / MAX_OK_PROTEIN;
}


/* function to calculate the strength of the perceptual stimulus of food to
the animal (= combination of value, distance away and probability of it
being correctly perceived), in the range 0.0 to 1.0 */
void calc_food_perc_stimulus()
{

  int i;
  int dir;
  double food_importance;
  PERC_FEATURE *pf_ptr;

  prey_in_animal_square = FALSE;
  cf_in_animal_square = FALSE;
  ff_in_animal_square = FALSE;

  /* calculate if the food in the animal's square (if there is any) is
  remembered as toxic */
  find_toxic_food();

  /* for each feature in the animal's perception */
  for (i = 0; i < anim_perc.perc_f_count; i++) {

	pf_ptr = &(anim_perc.perc_fs[i]);

	/* if this feature is food */
	if ((pf_ptr->nft == CEREAL_FOOD_N) ||
		(pf_ptr->nft == FRUIT_FOOD_N) ||
		(pf_ptr->nft == PREY_N)) {

	  /* calculate what direction the food is in */
	  dir = get_target_dir(pf_ptr->c, pf_ptr->r);

	  /* make importance combination of value, closeness and reliability
	  of perception */

	  /* distance very important */
	  food_importance = 1.0 -
		sqrt((((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) / 
		((double)(2*M_A_P))));

	  /* if correct perception probability < 0.25, reduce the seriousness
	  of the perception proportionately */
	  if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.25)
		food_importance *= 
		(anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.25);

	  /* multiply by value of food to give importance (multiply by 2 times
	  food value for prey since get large amount of food in one shot) */ 
	  if (pf_ptr->nft == PREY_N)
		food_importance *= (2.0*pf_ptr->value);
	  else
		food_importance *= pf_ptr->value;

	  /* if the food's value is less than a certain minimum amount (if there
	  is any in the square) then make its importance equal to zero */
	  if (food_value_too_low(pf_ptr->c,pf_ptr->r) == TRUE)
		food_importance = 0.0;

	  /* if the food is in the animal's square but is remembered as toxic,
	  them make its importance equal to zero */
	  if ((pf_ptr->c == 0) && (pf_ptr->r == 0) && (food_toxic == TRUE))
		food_importance = 0.0;

	  /* if the animal has recently visited an attractive food source of
	  this type which turned out to be useless and is now perceiving some
	  more (maybe the same), then make importance equal to zero */
	  if (((pf_ptr->nft == CEREAL_FOOD_N) &&
		   (time_since_useless_cereal_food < IGNORE_USELESS_TIME)) ||
		  ((pf_ptr->nft == FRUIT_FOOD_N) &&
		   (time_since_useless_fruit_food < IGNORE_USELESS_TIME)))
		food_importance = 0.0;

	  /* if the animal is not desperate for food and this type of food would
	  increase its imbalance between fat, carbohydrate and protein, then
	  make the importance of the food equal to zero */
	  if ((desperate_for_food() == FALSE) &&
		  (will_increase_food_imbalance(pf_ptr->nft) == TRUE))
		food_importance = 0.0;
	  else if (will_increase_food_imbalance(pf_ptr->nft) == FALSE)
		food_importance += 0.1;

	  /* if the animal's levels of fat, carbohydrate and protein are badly
	  imbalanced then adjust importance of different stimuli according to
	  whether or not they will reduce the imbalance */
	  if (bad_food_imbalance() == TRUE) {
		if ((will_increase_food_imbalance(pf_ptr->nft) == TRUE))
		  food_importance /= 4.0;
		else
		  food_importance *= 4.0;
	  }

	  if (food_importance > 1.0)
		food_importance = 1.0;

	  if ((food_importance > 0.001) &&
		  (dir == SAME_SQUARE)) {
		if (pf_ptr->nft == PREY_N)
		  prey_in_animal_square = TRUE;
		if (pf_ptr->nft == CEREAL_FOOD_N)
		  cf_in_animal_square = TRUE;
		if (pf_ptr->nft == FRUIT_FOOD_N)
		  ff_in_animal_square = TRUE;
	  }

	  /* if the importance of this food is greater than for previous
	  then set importance to this value */
	  if (food_importance > food_perc_stimulus[dir])

	    food_perc_stimulus[dir] = food_importance;
	}
  }
}


/* function to calculate the strength of the stimulus from remembered food
to the animal (= combination of value, distance away and probability of it
being accuratedly remembered), in the range 0.0 to 1.0 */
void calc_food_memory_stimulus()
{

  int i;
  int dir;
  int animal_remembers_food = FALSE;
  double est_distance_to_animal;
  double food_importance;

  /* for each feature in the animal's memory */
  for (i = 0; i < num_active_memories; i++) {

	/* if this feature is food */
	if ((map[i]->nft == CEREAL_FOOD_N) ||
		(map[i]->nft == FRUIT_FOOD_N)) {

	  /* calculate distance to it */
	  est_distance_to_animal = fabs(map[i]->est_c - est_an_c) +
							   fabs(map[i]->est_r - est_an_r);

	  /* if this feature has a worthwhile remembered value, is a fairly
	  strong memory, is not too far away, has a small variance, is not too
	  definitely remembered as very toxic, and has not been unsuccessfully
	  visited recently.  If the animal has too large a variance then it is
	  not worth heading to a remembered feature either */
	  if ((map[i]->est_value > MIN_WORTHWHILE_VALUE) &&
		  (map[i]->memory_strength > 0.01) &&
		  (est_distance_to_animal < 10.0) &&
		  (map[i]->variance < 1.5) &&
		  (an_pos_variance < 1.5) &&
		  (map[i]->est_toxicity < MAX_ACCEPTABLE_TOXICITY) &&
		  (map[i]->time_since_unsuccessful_visit > (DAY_LENGTH/2))) {

		/* calculate what direction the food is in */
		dir = get_target_dir(((int)round(map[i]->est_c-est_an_c)),
			((int)round(map[i]->est_r-est_an_r)));

		/* "goodness" of target dependent on its estimated value, the
		distance to it, its estimated toxicity, how well it fits in with the
		animal's needs for fat v. carbohydrate, etc, and how likely it is to
		be found */
		food_importance = (10.0-est_distance_to_animal) / 10.0;

		food_importance *= map[i]->est_value;

		food_importance *= ((1.5 - map[i]->variance) / 1.5);

		food_importance *= ((1.5 - an_pos_variance) / 1.5);

		food_importance -= (1.5 * map[i]->est_toxicity);

		/* if the animal has recently visited an attractive food source of
		this type which turned out to be useless and is now remembering some
		more (maybe the same), then make importance equal to zero */
		if (((map[i]->nft == CEREAL_FOOD_N) &&
             (time_since_useless_cereal_food < IGNORE_USELESS_TIME)) ||
            ((map[i]->nft == FRUIT_FOOD_N) &&
             (time_since_useless_fruit_food < IGNORE_USELESS_TIME)))
		  food_importance = 0.0;

		/* if the animal is not desperate for food and this type of food
		would increase its imbalance between fat, carbohydrate and protein,
		then make the importance of the food equal to zero */
		if ((desperate_for_food() == FALSE) &&
		    (will_increase_food_imbalance(map[i]->nft) == TRUE))
		  food_importance = 0.0;

		/* if the animal's levels of fat, carbohydrate and protein are badly
		imbalanced then adjust importance of different stimuli according to
		whether or not they will reduce the imbalance */
		if (bad_food_imbalance() == TRUE) {
		  if ((will_increase_food_imbalance(map[i]->nft) == TRUE))
			food_importance /= 4.0;
		  else
			food_importance *= 4.0;
		}

		/* memories always much less reliable than perception, so reduce
		their importance */
		food_importance /= 3.0;

		if (food_importance > 1.0)
		  food_importance = 1.0;

		/* if the importance of this food is greater than for previous
		then set importance to this value */
		if (food_importance > food_memory_stimulus[dir])

	      food_memory_stimulus[dir] = food_importance;
	  }
	}
  }
}


/* function to calculate the water shortage of the animal, if there is
one, in the range 0.0 to 1.0 */
void calc_water_shortage()
{

  if (animal_water >= MAX_OK_WATER)
    water_shortage = 0.0;
  else 
    water_shortage = (MAX_OK_WATER - animal_water) / MAX_OK_WATER;
}


/* function to calculate the strength of the perceptual stimulus of water to
the animal (= combination of value, distance away and probability of it
being correctly perceived), in the range 0.0 to 1.0 */
void calc_water_perc_stimulus()
{

  int i;
  int dir;
  double water_importance;
  PERC_FEATURE *pf_ptr;

  /* calculate if the food in the animal's square (if there is any) is
  remembered as toxic */
  find_toxic_water();

  /* for each feature in the animal's perception */
  for (i = 0; i < anim_perc.perc_f_count; i++) {

	pf_ptr = &(anim_perc.perc_fs[i]);

	/* if this feature is water */
	if (pf_ptr->nft == WATER_N) {

	  /* calculate what direction the water is in */
	  dir = get_target_dir(pf_ptr->c, pf_ptr->r);

	  /* make importance combination of value, closeness and reliability
	  of perception */

	  /* distance important */
	  water_importance = 1.0 - 
		sqrt((((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) / 
		((double)(2*M_A_P))));

	  /* if correct perception probability < 0.25, reduce the seriousness
	  of the perception proportionately */
	  if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.25)
		water_importance *=
		(anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.25);

	  /* multiply by value of water to give importance */
	  water_importance *= pf_ptr->value;

	  /* if the water's value is less than a certain minimum amount (if there
	  is any in the square) then make its importance equal to zero */
	  if (water_value_too_low(pf_ptr->c,pf_ptr->r) == TRUE)
		water_importance = 0.0;

	  /* if the water is in the animal's square but is remembered as toxic,
	  them make its importance equal to zero */
	  if ((pf_ptr->c == 0) && (pf_ptr->r == 0) && (water_toxic == TRUE))
		water_importance = 0.0;

	  /* if the animal has recently visited an attractive water source which
	  turned out to be useless and is now perceiving some more (maybe the
	  same), then make importance equal to zero */ 
	  if (time_since_useless_water < IGNORE_USELESS_TIME)
		water_importance = 0.0;

	  if (water_importance > 1.0)
        water_importance = 1.0;

	  /* if the importance of this water is greater than for previous
	  then set importance to this value */
	  if (water_importance > water_perc_stimulus[dir])

	    water_perc_stimulus[dir] = water_importance;
	}
  }
}


/* function to calculate the strength of the stimulus from remembered water
to the animal (= combination of value, distance away and probability of it
being accuratedly remembered), in the range 0.0 to 1.0 */
void calc_water_memory_stimulus()
{

  int i;
  int dir;
  int animal_remembers_water = FALSE;
  double est_distance_to_animal;
  double water_importance;

  /* for each feature in the animal's memory */
  for (i = 0; i < num_active_memories; i++) {

	/* if this feature is water */
	if (map[i]->nft == WATER_N) {

	  /* calculate distance to it */
	  est_distance_to_animal = fabs(map[i]->est_c - est_an_c) +
							   fabs(map[i]->est_r - est_an_r);

	  /* if this feature has a worthwhile remembered value, is a fairly
	  strong memory, is not too far away, has a small variance, is not too
	  definitely remembered as very toxic, and has not been unsuccessfully
	  visited recently.  If the animal has too large a variance then it is
      not worth heading to a remembered feature either */
	  /* NB: water sources recuperate more quickly than food sources */
	  if ((map[i]->est_value > MIN_WORTHWHILE_VALUE) &&
		  (map[i]->memory_strength > 0.01) &&
		  (est_distance_to_animal < 10.0) &&
		  (map[i]->variance < 1.5) &&
		  (an_pos_variance < 1.5) &&
		  (map[i]->est_toxicity < MAX_ACCEPTABLE_TOXICITY) &&
		  (map[i]->time_since_unsuccessful_visit > 20)) {

		/* calculate what direction the water is in */
		dir = get_target_dir(((int)round(map[i]->est_c-est_an_c)),
			((int)round(map[i]->est_r-est_an_r)));

		/* "goodness" of target dependent on its estimated value, the
		distance to it, its estimated toxicity, and how likely it is to be
		found */ 
		water_importance = (10.0-est_distance_to_animal) / 10.0;

		water_importance *= map[i]->est_value;

		water_importance *= ((1.5 - map[i]->variance) / 1.5);

		water_importance *= ((1.5 - an_pos_variance) / 1.5);

		water_importance -= (1.5 * map[i]->est_toxicity);

		/* if the animal has recently visited an attractive water source
		which turned out to be useless and is now remembering some more
		(maybe the same), then make importance equal to zero */ 
		if ((map[i]->nft == WATER_N) &&
            (time_since_useless_water < IGNORE_USELESS_TIME))
		  water_importance = 0.0;

		/* memories always much less reliable than perception, so reduce
		their importance by a factor of two */
		water_importance /= 3.0;

		if (water_importance > 1.0)
		  water_importance = 1.0;

		/* if the importance of this water is greater than for previous
		then set importance to this value */
		if (water_importance > water_memory_stimulus[dir])

	      water_memory_stimulus[dir] = water_importance;
	  }
	}
  }
}


/* function to calculate whether the temperature of the animal is too low,
and if so how seriously (in the range 0.0 to 1.0).  Also external
temperature (pessimistic estimate - as if animal were resting) */
void calc_low_temp()
{

  double next_low_temp;

  /* next_low_temp represents lowest possible animal temperature next go
  (assuming no vegetation, minimum extertion and same current external
  temperature) */ 
  next_low_temp = (env_temp+1.0)/2.0 - 0.20;
  if ((animal_temp-next_low_temp) > MAX_AN_TEMP_DECREASE)
	next_low_temp = animal_temp - MAX_AN_TEMP_DECREASE;

  if (animal_temp >= MIN_OK_TEMP)
      an_low_temp = 0.0;
  else
      an_low_temp = (MIN_OK_TEMP-animal_temp) / MIN_OK_TEMP;

  if (next_low_temp >= MIN_OK_TEMP)
      sqr_low_temp = 0.0;
  else
      sqr_low_temp = (MIN_OK_TEMP-next_low_temp) / MIN_OK_TEMP;
}


/* function to calculate the strength of the visual stimulus of "shelter"
(protection from low temperatures by vegetation or the animal's den), in the
range 0.0 to 1.0.  Dependant on amount of protection, distance away and
probability of it being correctly perceived */
void calc_shelter_perc_stimulus()
{

  int i;
  int dir;
  double shelter_importance;
  PERC_FEATURE *pf_ptr;

  /* for each feature in the animal's perception */
  for (i = 0; i < anim_perc.perc_f_count; i++) {

	pf_ptr = &(anim_perc.perc_fs[i]);

	/* if this feature is shelter */
	if ((pf_ptr->nft == DEN_N) ||
		(pf_ptr->nft == SHADE_N) ||
		(pf_ptr->nft == COVER_N) ||
		(pf_ptr->nft == FRUIT_FOOD_N)) {

	  /* make importance combination of value, closeness and reliability
	  of perception */

	  /* distance not very important so divide effect by 3 */
	  shelter_importance = 1.0 - (((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) /
		((double)(2*M_A_P)) / 3.0);

	  /* if correct perception probability < 0.25, reduce the seriousness
	  of the perception proportionately */
	  if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.25)
		shelter_importance *=
		(anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.25);

	  /* multiply by value of shelter to give importance */
	  switch(pf_ptr->nft) {
		case(DEN_N): shelter_importance *= 1.0;
					 break;
		case(SHADE_N): shelter_importance *= pf_ptr->thickness;
					   break;
		case(COVER_N): shelter_importance *= (0.5 *
						 pf_ptr->thickness);
					   break;
		case(FRUIT_FOOD_N): shelter_importance *= (0.5 *
						 pf_ptr->conditions);
							break;
	  }

	  /* calculate what direction the shelter is in */
	  dir = get_target_dir(pf_ptr->c, pf_ptr->r);

	  /* if the importance of this shelter is greater than for previous
	  then set importance to this value */
	  if (shelter_importance > shelter_perc_stimulus[dir])

	    shelter_perc_stimulus[dir] = shelter_importance;
	}
  }
}


/* function to calculate whether the temperature of the animal is too high,
and if so how seriously (in the range 0.0 to 1.0).  Also of external
temperature (pessimist estimate - as if animal were mating) */
void calc_high_temp()
{

  double next_high_temp;

  /* next_high_temp represents highest possible animal temperature next go 
  (assuming no vegetation, maximum extertion and same current external
  temperature) */ 
  next_high_temp = (env_temp+1.0)/2.0 + 0.20;
  if ((next_high_temp - animal_temp) > MAX_AN_TEMP_INCREASE)
	next_high_temp = animal_temp + MAX_AN_TEMP_INCREASE;

  if (animal_temp <= MAX_OK_TEMP)
      an_high_temp = 0.0;
  else
      an_high_temp = (animal_temp-MAX_OK_TEMP) / (1.0-MAX_OK_TEMP);

  if (next_high_temp <= MAX_OK_TEMP)
      sqr_high_temp = 0.0;
  else
      sqr_high_temp = (next_high_temp-MAX_OK_TEMP) / (1.0-MAX_OK_TEMP);
}


/* function to calculate the strength of the visual stimulus of "shade"
(protection from high temperatures by vegetation or the animal's den), in
the range 0.0 to 1.0.  Dependant on amount of protection, distance away and
probability of it being correctly perceived */
void calc_shade_perc_stimulus()
{

  int i;
  int dir;
  double shade_importance;
  PERC_FEATURE *pf_ptr;

  /* for each feature in the animal's perception */
  for (i = 0; i < anim_perc.perc_f_count; i++) {

	pf_ptr = &(anim_perc.perc_fs[i]);

	/* if this feature is shade */
	if ((pf_ptr->nft == DEN_N) ||
		(pf_ptr->nft == SHADE_N) ||
		(pf_ptr->nft == COVER_N) ||
		(pf_ptr->nft == FRUIT_FOOD_N)) {

	  /* make importance combination of value, closeness and reliability
	  of perception */

	  /* distance not very important so divide effect by 3 */
	  shade_importance = 1.0 - (((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) /
		((double)(2*M_A_P)) / 3.0);

	  /* if correct perception probability < 0.25, reduce the seriousness
	  of the perception proportionately */
	  if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.25)
		shade_importance *=
		(anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.25);

	  /* multiply by value of shade to give importance */
	  switch(pf_ptr->nft) {
		case(DEN_N): shade_importance = (shade_importance * 0.7);
					 break;
		case(SHADE_N): shade_importance = (shade_importance *
			pf_ptr->thickness); 
					   break;
		case(COVER_N): shade_importance = (shade_importance *
			pf_ptr->thickness * 0.5); 
					   break;
		case(FRUIT_FOOD_N): shade_importance = (shade_importance *
			pf_ptr->conditions * 0.5);
							break;
	  }

	  /* calculate what direction the shade is in */
	  dir = get_target_dir(pf_ptr->c, pf_ptr->r);

	  /* if the importance of this shade is greater than for previous
	  then set importance to this value */
	  if (shade_importance > shade_perc_stimulus[dir])

	    shade_perc_stimulus[dir] = shade_importance;
	}
  }
}


/* function to calculate whether the animal perceives a predator_1, and if
so to calculate a figure that represents the seriousness of the perception
(ie. a combination of how far away the predator_1 is and how reliable the
perception is likely to be) */
void calc_p1_perc_stimulus()
{

  int i;
  int dir;
  double p1_importance;
  PERC_FEATURE *pf_ptr;

  /* if the animal perceives a predator_1 */
  if (anim_perc.f_counter[PREDATOR_1_N] > 0) {

    /* for each feature in the animal's perception */
    for (i = 0; i < anim_perc.perc_f_count; i++) {

	  pf_ptr = &(anim_perc.perc_fs[i]);

	  /* if this feature is a predator_1 */
	  if (pf_ptr->nft == PREDATOR_1_N) {

		/* make importance combination of closeness and reliability of 
		perception */
		p1_importance = 1.0 - ((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) /
		  ((double)(2*M_A_P));
		/* if correct perception probability < 0.35, reduce the seriousness
		of the perception proportionately */
		if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.35)
		  p1_importance *=
		  (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.35);

		/* calculate what direction the predator is in */
		dir = get_target_dir(pf_ptr->c, pf_ptr->r);

		/* if the importance of this predator is greater than for previous
		then set importance to this value */
		if (p1_importance > p1_perc_stimulus[dir])
	      p1_perc_stimulus[dir] = p1_importance;

		if (p1_importance > 0.30)
		  time_since_predator_perceived = 0;
	  }
	}
  }
}


/* function to calculate whether the animal perceives a predator_2, and if
so to calculate a figure that represents the seriousness of the perception
(ie. a combination of how far away the predator_2 is and how reliable the
perception is likely to be) */
void calc_p2_perc_stimulus()
{

  int i;
  int dir;
  double p2_importance;
  PERC_FEATURE *pf_ptr;

  /* if the animal perceives a predator_2 */
  if (anim_perc.f_counter[PREDATOR_2_N] > 0) {

    /* for each feature in the animal's perception */
    for (i = 0; i < anim_perc.perc_f_count; i++) {

	  pf_ptr = &(anim_perc.perc_fs[i]);

	  /* if this feature is a predator_2 */
	  if (pf_ptr->nft == PREDATOR_2_N) {

		/* make importance combination of closeness and reliability of 
		perception */
		p2_importance = 1.0 - ((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) /
		  ((double)(2*M_A_P));
		/* if correct perception probability < 0.35, reduce the seriousness
		of the perception proportionately */
		if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.35)
		  p2_importance *=
		  (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.35);

		/* calculate what direction the predator is in */
		dir = get_target_dir(pf_ptr->c, pf_ptr->r);

		/* if the importance of this predator is greater than for previous
		then set importance to this value */
		if (p2_importance > p2_perc_stimulus[dir])
	      p2_perc_stimulus[dir] = p2_importance;

		if (p2_importance > 0.30)
		  time_since_predator_perceived = 0;
	  }
	}
  }
}


/* function to calculate whether the animal perceives a dangerous_place, and
if so to calculate a figure that represents the seriousness of the
perception (ie. a combination of how far away the dangerous_place is and how
reliable the perception is likely to be) */
void calc_dp_perc_stimulus()
{

  int i;
  int dir;
  double dp_importance;
  double dp_importance2;
  PERC_FEATURE *pf_ptr;

  /* if the animal perceives a dangerous_place */
  if (anim_perc.f_counter[DANGEROUS_PLACE_N] > 0) {

    /* for each feature in the animal's perception */
    for (i = 0; i < anim_perc.perc_f_count; i++) {

	  pf_ptr = &(anim_perc.perc_fs[i]);

	  /* if this feature is a dangerous_place */
	  if (pf_ptr->nft == DANGEROUS_PLACE_N) {

		/* make importance combination of closeness and reliability of 
		perception */
		dp_importance = 1.0 - ((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) /
		  ((double)(2*M_A_P));
		/* if correct perception probability < 0.25, reduce the seriousness
		of the perception proportionately */
		if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.25)
		  dp_importance *=
		  (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.25);

		/* don't need to worry about instances not in adjacent squares so
		set importance to zero for those */
		if ((pf_ptr->c*pf_ptr->c + pf_ptr->r*pf_ptr->r) > 2) {
		  dp_importance2 = dp_importance;
		  dp_importance = 0.0;
		}
		else
		  dp_importance2 = 0.0;

		/* calculate what direction the dangerous_place is in */
		dir = get_target_dir(pf_ptr->c, pf_ptr->r);

		/* if the importance of this dangerous_place is greater than for
		previous then set importance to this value */
		if (dp_importance > dp_perc_stimulus1[dir])
	      dp_perc_stimulus1[dir] = dp_importance;
		if (dp_importance2 > dp_perc_stimulus2[dir])
	      dp_perc_stimulus2[dir] = dp_importance2;
	  }
	}
  }
}


/* function to calculate whether the animal perceives an irrelevant animal,
and if so to calculate a figure that represents the seriousness of the
perception (ie. a combination of how far away the irrelevant is and how
reliable the perception is likely to be) */
void calc_irr_perc_stimulus()
{

  int i;
  int dir;
  double irr_importance;
  double irr_importance2;
  PERC_FEATURE *pf_ptr;

  /* if the animal perceives an irrelevant */
  if (anim_perc.f_counter[IRRELEVANT_N] > 0) {

    /* for each feature in the animal's perception */
    for (i = 0; i < anim_perc.perc_f_count; i++) {

	  pf_ptr = &(anim_perc.perc_fs[i]);

	  /* if this feature is an irrelevant */
	  if (pf_ptr->nft == IRRELEVANT_N) {

		/* make importance combination of closeness and reliability of 
		perception */
		irr_importance = 1.0 - ((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) /
		  ((double)(2*M_A_P));
		/* if correct perception probability < 0.25, reduce the seriousness
		of the perception proportionately */
		if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.25)
		  irr_importance *=
		  (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.25);

		/* don't need to worry about instances not in adjacent squares so
		set importance to zero for those */
		if ((pf_ptr->c*pf_ptr->c + pf_ptr->r*pf_ptr->r) > 2) {
		  irr_importance2 = irr_importance;
		  irr_importance = 0.0;
		}
		else
		  irr_importance2 = 0.0;

		/* calculate what direction the irrelevant is in */
		dir = get_target_dir(pf_ptr->c, pf_ptr->r);

		/* if the importance of this irrelevant is greater than for previous
		then set importance to this value */
		if (irr_importance > irr_perc_stimulus1[dir])
	      irr_perc_stimulus1[dir] = irr_importance;
		if (irr_importance2 > irr_perc_stimulus2[dir])
	      irr_perc_stimulus2[dir] = irr_importance2;
	  }
	}
  }
}


/* function to calculate whether the animal perceives a mate, and if so to
calculate a figure that represents the seriousness of the perception (ie. a
combination of how far away the mate is and how reliable the perception is
likely to be) */
void calc_mate_perc_stimulus()
{

  int i;
  int dir;
  double mate_importance;
  PERC_FEATURE *pf_ptr;

  /* if the animal perceives a mate */
  if (anim_perc.f_counter[MATE_N] > 0) {

    /* for each feature in the animal's perception */
    for (i = 0; i < anim_perc.perc_f_count; i++) {

	pf_ptr = &(anim_perc.perc_fs[i]);

	  /* if this feature is a mate */
	  if (pf_ptr->nft == MATE_N) {

		/* make importance combination of closeness and reliability of 
		perception */
		mate_importance = 1.0 - ((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) /
		  ((double)(2*M_A_P));
		/* if correct perception probability < 0.25, reduce the seriousness
		of the perception proportionately */
		if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.25)
		  mate_importance *=
		  (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.25);

		/* if the mate does not seem to be receptive then ignore */
		if (pf_ptr->receptive == FALSE)
		  mate_importance = 0.0;

		/* calculate what direction the mate is in */
		dir = get_target_dir(pf_ptr->c, pf_ptr->r);

		/* make importance equal to zero if animal has just mated */
		if (time_since_animal_mated < 8)
		  mate_importance = 0.0;

		/* make importance equal to zero if animal has just been rejected
		when court_displaying (mate didn't go to receptive) */
		if (time_since_animal_courting_rejected < 8)
		  mate_importance = 0.0;

		/* if the importance of this mate is greater than for previous then
		set importance to this value */
		if (mate_importance > mate_perc_stimulus[dir])

	      mate_perc_stimulus[dir] = mate_importance;
	  }
	}
  }
}


/* function to calculate the probability of a mate in the animal's square
being courted, if there is one there */
void calc_mate_courted()
{

  int i;
  int courted_mate_perceived = FALSE;
  int cm_index;
  PERC_FEATURE *pf_ptr;

  /* if the animal perceives a mate */
  if (anim_perc.f_counter[MATE_N] > 0) {

    /* for each feature in the animal's perception */
    for (i = 0; i < anim_perc.perc_f_count; i++) {

	  pf_ptr = &(anim_perc.perc_fs[i]);

	  /* if this feature is a courted mate in the animal's square */
	  if ((pf_ptr->nft == MATE_N) && (pf_ptr->courted == TRUE) &&
		  (pf_ptr->c == 0) && (pf_ptr->r == 0)) {

		courted_mate_perceived = TRUE;
		cm_index = i;
	  }
	}
  }

  if ((courted_mate_perceived) &&
	  (anim_perc.int_perc_probs[anim_perc.perc_fs[cm_index].c]
	   [anim_perc.perc_fs[cm_index].r]
	   >= 0.25))
	mate_courted = 1.0;

  else if (courted_mate_perceived) {
	mate_courted = (1.0 / 0.25) * (0.25 -
  			anim_perc.int_perc_probs[anim_perc.perc_fs[cm_index].c]
  			[anim_perc.perc_fs[cm_index].r]);

	if (mate_courted < 0.5)
	  mate_courted = 0.5;
  }

  else
	mate_courted = 0.0;
}


/* function to calculate a number to represent the animal's variance (in the
range 0.0-1.0) */
void calc_an_variance()
{

  an_variance = an_pos_variance / 2.0;

  if (an_variance > 1.0)
	an_variance = 1.0;
}


/* function to calculate a value to signify how close it is to sunset */
void calc_night_proximity()
{

  /* if it is night already then set this value to one (max.) */
  if (part_of_day == NIGHT)
	night_proximity = 1.0;

  /* else value = proportion of time from sunrise to sunset.  Value
  increases as sunset approaches */
  else
	night_proximity = (((double)(timestep%DAY_LENGTH))-SUNRISE_TIME)
	  / (SUNSET_TIME-SUNRISE_TIME);

  if (night_proximity < 0.0)
	night_proximity = 0.0;
  if (night_proximity > 1.0)
	night_proximity = 1.0;

  /* cube term so that it only becomes large close to nightfall - otherwise
  animal will sit in den from early evening */
  night_proximity = (night_proximity * night_proximity * night_proximity);
}


/* function to calculate a value to signify how far away from the den the
animal is */
void calc_distance_from_den()
{

  distance_from_den = sqrt((est_an_c*est_an_c + est_an_r*est_an_r));

  /* translate it into a variable in the range 0.0-1.0 */
  distance_from_den /= mini((((double) ENV_ARR_ROWS)/2.0),
							(((double) ENV_ARR_COLS)/2.0));
  if (distance_from_den > 1.0)
	distance_from_den = 1.0;
}


/* function to calculate whether the animal perceives its den, and if so to
calculate a figure that represents the seriousness of the perception (ie. a
combination of how far away the den is and how reliable the perception is
likely to be) */
void calc_den_perc_stimulus()
{

  int i;
  int dir;
  double den_importance;
  PERC_FEATURE *pf_ptr;

  /* if the animal perceives a den */
  if (anim_perc.f_counter[DEN_N] > 0) {

    /* for each feature in the animal's perception */
    for (i = 0; i < anim_perc.perc_f_count; i++) {

	pf_ptr = &(anim_perc.perc_fs[i]);

	  /* if this feature is a den */
	  if (pf_ptr->nft == DEN_N) {

		/* make importance combination of closeness and reliability of 
		perception */
		den_importance = 1.0 - ((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) /
		  ((double)(2*M_A_P));
		/* if correct perception probability < 0.25, reduce the seriousness
		of the perception proportionately */
		if (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]<0.25)
		  den_importance *=
		  (anim_perc.int_perc_probs[M_A_P+pf_ptr->c][M_A_P+pf_ptr->r]/0.25);

		/* calculate what direction the den is in */
		dir = get_target_dir(pf_ptr->c, pf_ptr->r);

		/* if the importance of this den is greater than for previous then
		set importance to this value */
		if (den_importance > den_perc_stimulus[dir])

	      den_perc_stimulus[dir] = den_importance;
	  }
	}
  }
}


/* function to calculate the direction of the den according to the animal's
memory of where it is, and to record this in the array
den_memory_stimulus[] */
void calc_den_memory_stimulus()
{

  int dir;
  double den_importance;
  int rounded_est_c, rounded_est_r;

  /* round the animal's estimate of where it is to the nearest integer
  values */
  rounded_est_c = ((int) round(est_an_c));
  rounded_est_r = ((int) round(est_an_r));

  /* the direction of the den (according to the animal's memory of where it
  is) depends on these coordinates */
  if (rounded_est_c > 0) {
	if (rounded_est_r > 0)
	  dir = NW;
	else if (rounded_est_r == 0)
	  dir = W;
	else
	  dir = SW;
  }
  else if (rounded_est_c == 0) {
	if (rounded_est_r > 0)
	  dir = N;
	else if (rounded_est_r == 0)
	  dir = SAME_SQUARE;
	else
	  dir = S;
  }
  else {
	if (rounded_est_r > 0)
	  dir = NE;
	else if (rounded_est_r == 0)
	  dir = E;
	else
	  dir = SE;
  }

  /* the importance of the memory depends on the animal's variance: high
  variance means the animal has a poor memory of where it is in relation to 
  its den, low variance the opposite */
  den_memory_stimulus[dir] = (5.0 - an_pos_variance) / 5.0;

  if (den_memory_stimulus[dir] < 0.0)
	den_memory_stimulus[dir] = 0.0;
}


/* function to calculate whether the animal perceives an edge of the
environment, and if so to calculate a figure that represents the seriousness
of the perception (ie. how far away the edge is) */
void calc_edge_perc_stimulus()
{

  int i;
  int dir;
  double edge_importance;
  PERC_FEATURE *pf_ptr;

  /* if the animal perceives an edge */
  if (anim_perc.f_counter[OUTSIDE_ENV_N] > 0) {

    /* for each feature in the animal's perception */
    for (i = 0; i < anim_perc.perc_f_count; i++) {

	  pf_ptr = &(anim_perc.perc_fs[i]);

	  /* if this feature is an edge */
	  if (pf_ptr->nft == OUTSIDE_ENV_N) {

		/* make importance combination of closeness and reliability of 
		perception */
		edge_importance = 1.0 - ((double)(abs(pf_ptr->c)+abs(pf_ptr->r))) /
		  ((double)(2*M_A_P));

		/* calculate what direction the edge is in */
		dir = get_target_dir(pf_ptr->c,pf_ptr->r);

		/* if the proximity of this edge is greater than for previous then
		set proximity to this value */
		if (edge_importance > edge_perc_stimulus[dir])

	      edge_perc_stimulus[dir] = edge_importance;
	  }
	}
  }
}


/* function to determine if the animal has chosen one of the moving actions */
int move_action_chosen()
{

  int i;

  for (i = 0; i < NUM_LOW_LEVEL_ACTIONS; i++)
	if ((animal_action == i) && (MOVE_ACTION(i) == TRUE))
	  return(TRUE);

  return(FALSE);
}


/* function to determine if the animal has chosen one of the moving fast
actions */
int move_fast_action_chosen()
{

  int i;

  for (i = 0; i < NUM_LOW_LEVEL_ACTIONS; i++)
	if ((animal_action == i) && (MOVE_FAST_ACTION(i) == TRUE))
	  return(TRUE);

  return(FALSE);
}


/* function to determine if the animal has chosen one of the eating actions */
int eat_action_chosen()
{

  int i;

  for (i = 0; i < NUM_LOW_LEVEL_ACTIONS; i++)
	if ((animal_action == i) && (EAT_ACTION(i) == TRUE))
	  return(TRUE);

  return(FALSE);
}


/* function to determine if the animal has chosen one of the looking in a
particular direction actions */
int directed_look_action_chosen()
{

  int i;

  for (i = 0; i < NUM_LOW_LEVEL_ACTIONS; i++)
	if ((animal_action == i) && (DIRECTED_LOOK_ACTION(i) == TRUE))
	  return(TRUE);

  return(FALSE);
}


/* function to determine if the animal has chosen one of the looking
actions */  
int look_action_chosen()
{

  if (((animal_action >= LOOKING_N) && (animal_action <= LOOKING_NE)) ||
	  (animal_action == LOOKING_AROUND))
	return(TRUE);

  return(FALSE);
}


/* function to initialise all the environment property values */
void zero_property_values()
{

  int i;

  for (i = 0; i < NUM_DIRECTIONS; i++) {
	food_perc_stimulus[i] = 0.0;
	food_memory_stimulus[i] = 0.0;
	water_perc_stimulus[i] = 0.0;
	water_memory_stimulus[i] = 0.0;
	shelter_perc_stimulus[i] = 0.0;
	shade_perc_stimulus[i] = 0.0;
	p1_perc_stimulus[i] = 0.0;
	p2_perc_stimulus[i] = 0.0;
	dp_perc_stimulus1[i] = 0.0;
	irr_perc_stimulus1[i] = 0.0;
	mate_perc_stimulus[i] = 0.0;
	den_perc_stimulus[i] = 0.0;
	den_memory_stimulus[i] = 0.0;
	edge_perc_stimulus[i] = 0.0;
	dp_perc_stimulus2[i] = 0.0;
	irr_perc_stimulus2[i] = 0.0;
  }
}


/* function to make sure all the environment property values have valid
values */
void check_property_values()
{

  int i;

  for (i = 0; i < NUM_DIRECTIONS; i++) {
	if (food_perc_stimulus[i] < 0.0)
	  food_perc_stimulus[i] = 0.0;
	else if (food_perc_stimulus[i] > 1.0)
	  food_perc_stimulus[i] = 1.0;
	if (food_memory_stimulus[i] < 0.0)
	  food_memory_stimulus[i] = 0.0;
	else if (food_memory_stimulus[i] > 1.0)
	  food_memory_stimulus[i] = 1.0;
	if (water_perc_stimulus[i] < 0.0)
	  water_perc_stimulus[i] = 0.0;
	else if (water_perc_stimulus[i] > 1.0)
	  water_perc_stimulus[i] = 1.0;
	if (water_memory_stimulus[i] < 0.0)
	  water_memory_stimulus[i] = 0.0;
	else if (water_memory_stimulus[i] > 1.0)
	  water_memory_stimulus[i] = 1.0;
	if (shelter_perc_stimulus[i] < 0.0)
	  shelter_perc_stimulus[i] = 0.0;
	else if (shelter_perc_stimulus[i] > 1.0)
	  shelter_perc_stimulus[i] = 1.0;
	if (shade_perc_stimulus[i] < 0.0)
	  shade_perc_stimulus[i] = 0.0;
	else if (shade_perc_stimulus[i] > 1.0)
	  shade_perc_stimulus[i] = 1.0;
	if (p1_perc_stimulus[i] < 0.0)
	  p1_perc_stimulus[i] = 0.0;
	else if (p1_perc_stimulus[i] > 1.0)
	  p1_perc_stimulus[i] = 1.0;
	if (p2_perc_stimulus[i] < 0.0)
	  p2_perc_stimulus[i] = 0.0;
	else if (p2_perc_stimulus[i] > 1.0)
	  p2_perc_stimulus[i] = 1.0;
	if (dp_perc_stimulus1[i] < 0.0)
	  dp_perc_stimulus1[i] = 0.0;
	else if (dp_perc_stimulus1[i] > 1.0)
	  dp_perc_stimulus1[i] = 1.0;
	if (irr_perc_stimulus1[i] < 0.0)
	  irr_perc_stimulus1[i] = 0.0;
	else if (irr_perc_stimulus1[i] > 1.0)
	  irr_perc_stimulus1[i] = 1.0;
	if (dp_perc_stimulus2[i] < 0.0)
	  dp_perc_stimulus2[i] = 0.0;
	else if (dp_perc_stimulus2[i] > 1.0)
	  dp_perc_stimulus2[i] = 1.0;
	if (irr_perc_stimulus2[i] < 0.0)
	  irr_perc_stimulus2[i] = 0.0;
	else if (irr_perc_stimulus2[i] > 1.0)
	  irr_perc_stimulus2[i] = 1.0;
	if (mate_perc_stimulus[i] < 0.0)
	  mate_perc_stimulus[i] = 0.0;
	else if (mate_perc_stimulus[i] > 1.0)
	  mate_perc_stimulus[i] = 1.0;
	if (edge_perc_stimulus[i] < 0.0)
	  edge_perc_stimulus[i] = 0.0;
	else if (edge_perc_stimulus[i] > 1.0)
	  edge_perc_stimulus[i] = 1.0;
  }
}


/* function to calculate if there is a food feature in this square which is
remembered as toxic (if it is recognised) */
void find_toxic_food()
{

  if ((this_place_recognised == TRUE) &&
	  (this_place_now_in_map == TRUE) &&
	  (this_place != -1) &&
	  (map[this_place]->est_toxicity > MAX_ACCEPTABLE_TOXICITY) &&
	  (anim_perc.counters[M_A_P][M_A_P][CEREAL_FOOD_N] > 0)) {

	  food_toxic = TRUE;
  }

  else if ((this_place_recognised == TRUE) &&
		   (this_place_now_in_map == TRUE) &&
		   (this_place != -1) &&
		   (map[this_place]->est_toxicity > MAX_ACCEPTABLE_TOXICITY) &&
		   (anim_perc.counters[M_A_P][M_A_P][FRUIT_FOOD_N] > 0)) {

	  food_toxic = TRUE;
  }

  else
	  food_toxic = FALSE;
}


/* function to calculate if there is a water feature in this square which is
remembered as toxic (if it is recognised) */
void find_toxic_water()
{

  if ((this_place_recognised == TRUE) &&
	  (this_place_now_in_map == TRUE) &&
	  (this_place != -1) &&
	  (map[this_place]->est_toxicity > MAX_ACCEPTABLE_TOXICITY) &&
	  (anim_perc.counters[M_A_P][M_A_P][WATER_N] > 0)) {

	  water_toxic = TRUE;
  }

  else
	water_toxic = FALSE;
}


/* function to determine if the food in a particular square has sufficient
value to make it worthwhile */
int food_value_too_low(c, r)
int c;
int r;
{

  if ((anim_perc.counters[c+M_A_P][r+M_A_P][CEREAL_FOOD_N] > 0) &&
	  (anim_perc.perc_fs[anim_perc.contents[c+M_A_P][r+M_A_P]
		[CEREAL_FOOD_N]->f_num].value < MIN_WORTHWHILE_VALUE))
	return(TRUE);
	
  else if ((anim_perc.counters[c+M_A_P][r+M_A_P][FRUIT_FOOD_N] > 0) &&
		   (anim_perc.perc_fs[anim_perc.contents[c+M_A_P][r+M_A_P]
			[FRUIT_FOOD_N]->f_num].value < MIN_WORTHWHILE_VALUE))
	return(TRUE);
	
  else
	return(FALSE);
}

	
/* function to determine if the water in a particular square has sufficient
value to make it worthwhile */
int water_value_too_low(c, r)
int c;
int r;
{

  if ((anim_perc.counters[c+M_A_P][r+M_A_P][WATER_N] > 0) &&
	  (anim_perc.perc_fs[anim_perc.contents[c+M_A_P][r+M_A_P]
		[WATER_N]->f_num].value < MIN_WORTHWHILE_VALUE))
	return(TRUE);
	
  else
	return(FALSE);
}

	
/* function to obtain the approximate direction of a square from the
animal's square */
int get_target_dir(c, r)
int c;			/* coordinates relative to animal */
int r;
{

  if (c > 0) {
    if (r > 0)
      return(SE);
    else if (r == 0)
      return(E);
    else
      return(NE);
  }
  else if (c == 0) {
    if (r > 0)
      return(S);
    else if (r == 0)
      return(SAME_SQUARE);
    else
      return(N);
  }
  else {
    if (r > 0)
      return(SW);
    else if (r == 0)
      return(W);
    else
      return(NW);
  }
}


/* function to calculate whether eating a particular type of food will
increase the imbalance between the food constituents or not (not considered
to be important if the variable which will be imbalanced is fairly low
anyway) */
int will_increase_food_imbalance(food_type)
int food_type;
{

  int most_needed_constituent = FAT_N;

  /* calculate which constituent is needed most (ie. has lowest current
  level) */
  if ((carbo_shortage > fat_shortage) &&
	  (carbo_shortage > protein_shortage))
	most_needed_constituent = CARBO_N;
  if ((protein_shortage > fat_shortage) &&
	  (protein_shortage > carbo_shortage))
	most_needed_constituent = PROTEIN_N;

  /* if the most needed constituent corresponds to the constituent most
  provided by this type of food then return FALSE, else return TRUE */
  if ((food_type == CEREAL_FOOD_N) &&
	  (most_needed_constituent == CARBO_N))
	return(FALSE);
  else if ((food_type == FRUIT_FOOD_N) &&
		   (most_needed_constituent == FAT_N))
    return(FALSE);
  else if ((food_type == PREY_N) &&
		   (most_needed_constituent == PROTEIN_N))
    return(FALSE);

  else
	return(TRUE);
}


/* function to calculate if the animal is desperate for food (and so should
eat anything, no matter whether it will increase the imbalance between the
food constituents or not) */
int desperate_for_food()
{

  if ((animal_fat < (MIN_OK_FAT + (MAX_OK_FAT-MIN_OK_FAT)*0.4)) ||
	  (animal_carbo < (MIN_OK_CARBO + (MAX_OK_CARBO-MIN_OK_CARBO)*0.4)) ||
	  (animal_protein < (MIN_OK_PROTEIN +
		(MAX_OK_PROTEIN-MIN_OK_PROTEIN)*0.4))) 

	return(TRUE);

  else

	return(FALSE);
}


/* function to calculate whether or not there is a serious imbalance in the
amounts of the different constituents of food, and to return TRUE or FALSE
accordingly */
int bad_food_imbalance()
{

  if ((fabs(animal_carbo-animal_fat) > 0.20) ||
	  (fabs(animal_carbo-animal_protein) > 0.20) ||
	  (fabs(animal_protein-animal_fat) > 0.20))
	return(TRUE);
  else
	return(FALSE);
}


void update_distance_to_cover()
{

  double curr_str_protection;
  double distance_to_curr_cover;
  double c_dist, r_dist;
  int i;
  int found_perc_cover = FALSE;
  PERC_FEATURE f;

  min_distance_to_cover = 10000.0;

  /* find minimum distance to any reasonable instance of protection from
  predators */
  for (i = 0; i < anim_perc.perc_f_count; i++) {

	f = anim_perc.perc_fs[i];
	switch(f.nft) {
	  case(COVER_N): curr_str_protection = f.thickness;
					 break;
	  case(SHADE_N): curr_str_protection = (0.5 * f.thickness);
					 break;
	  case(FRUIT_FOOD_N): curr_str_protection = (0.5 * f.conditions);
					 break;
	  case(DEN_N): curr_str_protection = 1.0;
					 break;
	  default: curr_str_protection = 0.0;
	}

	/* if this is a reasonable instance and is reasonably certainly
	perceived */
	if ((curr_str_protection > 0.20) &&
		(anim_perc.int_perc_probs[f.c+M_A_P][f.r+M_A_P] > 0.14)) {

	  /* calculate distance to it */
	  c_dist = ((double) f.c);
	  r_dist = ((double) f.r);
	  distance_to_curr_cover = sqrt((c_dist*c_dist+r_dist*r_dist));

	  /* if the distance to it is less than the current minimum then set
	  variables */
	  if (distance_to_curr_cover < min_distance_to_cover) {
		found_perc_cover = TRUE;
		min_distance_to_cover = distance_to_curr_cover;
		est_last_cover_c = est_an_c + c_dist;
		est_last_cover_r = est_an_r + r_dist;
	  }
	}
  }

  /* if no cover perceived then update from coordinates of last perceived
  instance and present position */
  if (found_perc_cover == FALSE) {
	c_dist = est_an_c - est_last_cover_c;
	r_dist = est_an_r - est_last_cover_r;
	min_distance_to_cover = sqrt((c_dist*c_dist+r_dist*r_dist));
  }
}


void free_animal_memory()
{

  int i, j, k;
  SQR_C_LLE *ptr, *ptr1;

  /* free all memory for linked lists holding information about square
  contents */ 
  for (i = 0; i < (2*M_A_P+1); i++)
    for (j = 0; j < (2*M_A_P+1); j++)
      for (k = 0; k < NUM_FEATURE_TYPES; k++) {
		ptr = anim_perc.contents[i][j][k];
		while (ptr != ((SQR_C_LLE *) NULL)) {
		  ptr1 = ptr->next_ptr;
		  free(ptr);
		  ptr = ptr1;
		}
      }

  /* free map memory */
  for (i = 0; i < map_sze; i++)
	free(map[i]);
}

