
/* This file contains definitions for those functions which serve to update
the features in the environment at various time intervals */


#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 "ext_env_decs.h"
#include "animal_decs.h"


/* function to possibly change any instances of cereal type food */
void update_1_cereal_food()
{

  int i, col, row;
  int nft = CEREAL_FOOD_N;
  CEREAL_FOOD *ptr;

  /* for each instance of cereal_food */
  for (i = 0; i < f_list[nft].count; ++i) {

    ptr = (CEREAL_FOOD *) f_list[nft].f_ptr[i];

    col = f_list[nft].column[i];
    row = f_list[nft].row[i];

    /* have a small probability of removing each instance of cereal food
    each time this function is called */
    if (drand48() < CEREAL_FOOD_REMOVE_CREATE_PROB) {

      /* set pointer to feature from env_array to NULL */
      env_arr[col][row].p_arr[nft] = (void *) NULL;
      /* decrement counter for that area of the environment */
      env_arr[col][row].physical_f_count--;

      /* if this instance was toxic then make toxic entry null so that the
      toxic picture does not continue to get drawn on the square */
      if (ptr->toxicity > 0.0)
        env_arr[col][row].p_arr[TOXIC_N] = (void *) NULL;

      /* free the memory that was used to hold this feature */
      free(ptr);
/*g*/
/*g*/      /* remove image of feature from square */
/*g*/      redraw_square(col, row);

      /* transfer last entry of cereal_food_list to replace this one and
      then decrement the counter */
      f_list_remove(nft, i);
    }

    /* have the same probability of creating another instance of cereal food
	as of removing one */
    if (drand48() < CEREAL_FOOD_REMOVE_CREATE_PROB)
      get_cereal_food(1);

    /* also have a small probability of changing the conditions */
    if (drand48() < CEREAL_FOOD_CHANGE_CONDITIONS_PROB) {

      /* the conditions, ie suitability of the site for growth, can vary
      between 0.2 and 1.0 (though most cereal food less nutritious than
      fruit food) */ 
      ptr->conditions = get_cereal_food_conditions();

      /* the food value is a measure of the amount of food to be obtained
      at the source at a particular time (factor to reduce value of
      cereal_food with respect to fruit_food) */
	  ptr->value = get_cereal_food_value(ptr->conditions);
    }

    /* also have a small probability of changing the toxicity */
    if (drand48() < CEREAL_FOOD_CHANGE_TOXICITY_PROB) {

      if (drand48() < CEREAL_FOOD_TOXICITY_PROB) {

        /* give the food source a toxicity */
        ptr->toxicity = get_cereal_food_toxicity();

        /* make the toxic entry in the ptr array not null so will be drawn */
        env_arr[col][row].p_arr[TOXIC_N] = (void *) NOT_NULL;
      }
      else {

        ptr->toxicity = 0.0;

        /* make the toxic entry in the ptr array null so will not be drawn */
        env_arr[col][row].p_arr[TOXIC_N] = (void *) NULL;
      }
	}
  }
}


/* function to possibly change any instances of cover */
void update_1_cover()
{

  int i, col, row;
  COVER *ptr;
  int nft = COVER_N;

  /* for each instance of cover in the environment */
  for (i = 0; i < f_list[nft].count; ++i) {

    ptr = (COVER *) f_list[nft].f_ptr[i];

    /* have a small probability of removing each instance of cover each
    time this function is called */
    if (drand48() < COVER_REMOVE_CREATE_PROB) {

      col = f_list[nft].column[i];
      row = f_list[nft].row[i];

      /* set pointer to feature from env_array to NULL */
      env_arr[col][row].p_arr[nft] = (void *) NULL;
      /* decrement counter for that area of the environment */
      env_arr[col][row].physical_f_count--;
/*g*/
/*g*/      /* remove image of feature from square */
/*g*/      redraw_square(col, row);

      /* undo relevant changes to the temperature, ability to escape
      detection, perception, and ability to escape in square */
      env_arr[col][row].temp_factor += (0.5 * ptr->thickness);
      env_arr[col][row].perception_factor += ptr->thickness;
      env_arr[col][row].escape_factor -= ptr->thickness;

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

      /* remove this entry from the feature list */
      f_list_remove(nft, i);
    }

    /* have the same probability of creating another instance of cover as of
	removing one */ 
    if (drand48() < COVER_REMOVE_CREATE_PROB)
      get_cover(1);

    /* also have a small probability of changing the thickness */
    if (drand48() < COVER_CHANGE_THICKNESS_PROB) {

      col = f_list[nft].column[i];
      row = f_list[nft].row[i];

      /* undo relevant changes to the temperature, ability to escape
      detection, perception, and ability to escape in square */
      env_arr[col][row].temp_factor += (0.5 * ptr->thickness);
      env_arr[col][row].perception_factor += ptr->thickness;
      env_arr[col][row].escape_factor -= ptr->thickness;

	  /* change the thickness */
      ptr->thickness = get_cover_thickness();

      /* redo relevant changes to the temperature, ability to escape
      detection, perception, and ability to escape in square */
      env_arr[col][row].temp_factor -= (0.5 * ptr->thickness);
      env_arr[col][row].perception_factor -= ptr->thickness;
      env_arr[col][row].escape_factor += ptr->thickness;
    }
  }
}


/* function to possibly change any instances of fruit type food */
void update_1_fruit_food()
{

  int i, col, row;
  int nft = FRUIT_FOOD_N;
  FRUIT_FOOD *ptr;

  /* for each instance of fruit food */
  for (i = 0; i < f_list[nft].count; ++i) {

    ptr = (FRUIT_FOOD *) f_list[nft].f_ptr[i];

    col = f_list[nft].column[i];
    row = f_list[nft].row[i];

    /* have a small probability of removing each instance of fruit food
    each time this function is called */
    if (drand48() < FRUIT_FOOD_REMOVE_CREATE_PROB) {

      /* set pointer to feature from env_array to NULL */
      env_arr[col][row].p_arr[nft] = (void *) NULL;
      /* decrement counter for that area of the environment */
      env_arr[col][row].physical_f_count--;

      /* undo relevant changes to the temperature, ability to escape
      detection, perception, and ability to escape in square (assume
	  thickness proprtional to conditions) */
      env_arr[col][row].temp_factor += (0.5 * ptr->conditions);
      env_arr[col][row].perception_factor += (0.5 * ptr->conditions);
      env_arr[col][row].escape_factor -= (0.5 * ptr->conditions);

      /* if this instance was toxic then make toxic entry null so that the
      toxic picture does not continue to get drawn on the square */
      if (ptr->toxicity > 0.0)
        env_arr[col][row].p_arr[TOXIC_N] = (void *) NULL;

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

/*g*/      /* remove image of feature from square */
/*g*/      redraw_square(col, row);
/*g*/
      /* remove this entry from the feature list */
      f_list_remove(nft, i);
    }

    /* have the same probability of creating another instance of fruit food
	as of removing one */
    if (drand48() < FRUIT_FOOD_REMOVE_CREATE_PROB)
      get_fruit_food(1);

    /* also have a small probability of the conditions changing */
    if (drand48() < FRUIT_FOOD_CHANGE_CONDITIONS_PROB) {

      /* undo relevant changes to the temperature, ability to escape
      detection, perception, and ability to escape in square (assume
	  thickness proprtional to conditions) */
      env_arr[col][row].temp_factor += (0.5 * ptr->conditions);
      env_arr[col][row].perception_factor += (0.5 * ptr->conditions);
      env_arr[col][row].escape_factor -= (0.5 * ptr->conditions);

      ptr->conditions = get_fruit_food_conditions();

      /* redo relevant changes to the temperature, ability to escape
      detection, perception, and ability to escape in square (assume
	  thickness proprtional to conditions) */
      env_arr[col][row].temp_factor -= (0.5 * ptr->conditions);
      env_arr[col][row].perception_factor -= (0.5 * ptr->conditions);
      env_arr[col][row].escape_factor += (0.5 * ptr->conditions);

      /* the food value is a measure of the amount of food to be obtained at
      the source at a particular time */
	  ptr->value = get_fruit_food_value(ptr->cycle_state, ptr->ripe_time,
		  ptr->conditions);
    }

    /* also have a small probability of the toxicity changing */
    if (drand48() < FRUIT_FOOD_CHANGE_TOXICITY_PROB) {

      if (drand48() < FRUIT_FOOD_TOXICITY_PROB) {

        /* give the food source a toxicity */
        ptr->toxicity = get_fruit_food_toxicity();

        /* make the toxic entry in the ptr array not null so will be drawn */
        env_arr[col][row].p_arr[TOXIC_N] = (void *) NOT_NULL;
      }
      else {

        ptr->toxicity = 0.0;

        /* make the toxic entry in the ptr array null so will not be drawn */
        env_arr[col][row].p_arr[TOXIC_N] = (void *) NULL;
      }
	}
  }
}


/* function to possibly change any instances of shade */
void update_1_shade()
{

  int i, col, row;
  SHADE *ptr;
  int nft = SHADE_N;

  /* for each instance of shade in the environment */
  for (i = 0; i < f_list[nft].count; ++i) {

    ptr = (SHADE *) f_list[nft].f_ptr[i];

    /* have a small probability of removing each instance of shade each
    time this function is called */
    if (drand48() < SHADE_REMOVE_CREATE_PROB) {

      col = f_list[nft].column[i];
      row = f_list[nft].row[i];

      /* set pointer to feature from env_array to NULL */
      env_arr[col][row].p_arr[nft] = (void *) NULL;
      /* decrement counter for that area of the environment */
      env_arr[col][row].physical_f_count--;
/*g*/
/*g*/      /* remove image of feature from square */
/*g*/      redraw_square(col, row);

      /* undo relevant changes to the temperature, ability to escape
      detection, perception, and ability to escape in square */
      env_arr[col][row].temp_factor += ptr->thickness;
      env_arr[col][row].perception_factor += (0.5 * ptr->thickness);
      env_arr[col][row].escape_factor -= (0.5 * ptr->thickness);

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

      /* remove this entry from the feature list */
      f_list_remove(nft, i);
    }

    /* have the same probability of creating another instance of shade as of 
	removing one */ 
    if (drand48() < SHADE_REMOVE_CREATE_PROB)
      get_shade(1);

    /* also have a small probability of changing the thickness */
    if (drand48() < SHADE_CHANGE_THICKNESS_PROB) {

      col = f_list[nft].column[i];
      row = f_list[nft].row[i];

      /* undo relevant changes to the temperature, ability to escape
      detection, perception, and ability to escape in square */
      env_arr[col][row].temp_factor += ptr->thickness;
      env_arr[col][row].perception_factor += (0.5 * ptr->thickness);
      env_arr[col][row].escape_factor -= (0.5 * ptr->thickness);

	  /* change the thickness */
      ptr->thickness = get_shade_thickness();

      /* redo relevant changes to the temperature, ability to escape
      detection, perception, and ability to escape in square */
      env_arr[col][row].temp_factor -= ptr->thickness;
      env_arr[col][row].perception_factor -= (0.5 * ptr->thickness);
      env_arr[col][row].escape_factor += (0.5 * ptr->thickness);
    }
  }
}


/* function to possibly change any instances of water */
void update_1_water()
{

  int i, col, row;
  WATER *ptr;
  int nft = WATER_N;

  /* for each instance of water in the environment */
  for (i = 0; i < f_list[nft].count; ++i) {

    ptr = (WATER *) f_list[nft].f_ptr[i];

    col = f_list[nft].column[i];
    row = f_list[nft].row[i];

    /* have a small probability of removing each instance of water each
    time this function is called */
    if (drand48() < WATER_REMOVE_CREATE_PROB) {

      /* set pointer to feature from env_array to NULL */
      env_arr[col][row].p_arr[nft] = (void *) NULL;
      /* decrement counter for that area of the environment */
      env_arr[col][row].physical_f_count--;

      /* if this instance was toxic then make toxic entry null so that the
      toxic picture does not continue to get drawn on the square */
      if (ptr->toxicity > 0.0)
        env_arr[col][row].p_arr[TOXIC_N] = (void *) NULL;

      /* free the memory that was used to hold this feature */
      free(ptr);
/*g*/
/*g*/      /* remove image of feature from square */
/*g*/      redraw_square(col, row);

      /* remove this entry from the feature list */
      f_list_remove(nft, i);
    }

    /* have the same probability of creating another instance of water as of 
	removing one */ 
    if (drand48() < WATER_REMOVE_CREATE_PROB)
      get_water(1);

	/* also have a small probability of changing the average size */
    if (drand48() < WATER_CHANGE_SIZE_PROB) {

      ptr->average_size = get_water_average_size();

      /* the amount of water in this source is dependant on the amount of
      rainfall in the recent past, the temperature, and the average size of
      the source */
	  ptr->value = get_water_value(ptr->average_size);
    }

    /* also have a small probability of changing the toxicity */
    if (drand48() < WATER_CHANGE_TOXICITY_PROB) {

      if (drand48() < WATER_TOXICITY_PROB) {

        /* give the food source a toxicity */
        ptr->toxicity = get_water_toxicity();

        /* make the toxic entry in the ptr array not null so will be drawn */
        env_arr[col][row].p_arr[TOXIC_N] = (void *) NOT_NULL;
      }
      else {

        ptr->toxicity = 0.0;

        /* make the toxic entry in the ptr array null so will not be drawn */
        env_arr[col][row].p_arr[TOXIC_N] = (void *) NULL;
      }
	}
  }
}


/* function to control movement, etc of irrelevants */
void update_1_irrelevant()
{

  int i, j;
  int c, r, old_c, old_r;
  int nft = IRRELEVANT_N;
  double pack_move_prob;	/* make animals more likely to move together */
  int moved;                /* `boolean' to indicate if animal has moved*/
  IRRELEVANT *ptr, *ptr1;

  /* have a small probability of new irrelevants appearing */
  switch(part_of_day) {
    case(NIGHT) : if (drand48() < IRRELEVANT_NIGHT_APPEARANCE_PROB)
					get_irrelevants(IRRELEVANT_APPEARANCE_NUMBER());
    case(SUNRISE) : if (drand48() < IRRELEVANT_DUSK_APPEARANCE_PROB)
					  get_irrelevants(IRRELEVANT_APPEARANCE_NUMBER());
    case(MORNING) : if (drand48() < IRRELEVANT_DAY_APPEARANCE_PROB)
					  get_irrelevants(IRRELEVANT_APPEARANCE_NUMBER());
    case(MIDDAY) : if (drand48() < IRRELEVANT_DAY_APPEARANCE_PROB)
					 get_irrelevants(IRRELEVANT_APPEARANCE_NUMBER());
	case(AFTERNOON) : if (drand48() < IRRELEVANT_DAY_APPEARANCE_PROB)
					    get_irrelevants(IRRELEVANT_APPEARANCE_NUMBER());
	case(SUNSET) : if (drand48() < IRRELEVANT_DUSK_APPEARANCE_PROB)
					 get_irrelevants(IRRELEVANT_APPEARANCE_NUMBER());
  }

  /* make animals more likely to move at the same time */
  pack_move_prob = rnd(2.0 * IRRELEVANT_MOVE_PROB);

  /* for each irrelevant in the environment */
  for (i = 0; i < f_list[nft].count; ++i) {

    ptr = (IRRELEVANT *) f_list[nft].f_ptr[i];

    /* get the current position */
    c = f_list[nft].column[i];
    r = f_list[nft].row[i];
    old_c = c;
    old_r = r;

    moved = FALSE;

    /* if this irrelevant is the leader of the pack */
    if (ptr->pack_leader == TRUE) {

      /* have a probability of moving */
      if (drand48() < pack_move_prob) {

        moved = TRUE;

        /* decide which direction to move in */
        if (drand48() < ptr->east_prob)
          c++;
        if (drand48() < ptr->west_prob)
          c--;
        if (drand48() < ptr->north_prob)
          r--;
        if (drand48() < ptr->south_prob)
          r++;
      }

      /* change the pack leader's coordinates */
      irrelevant_pack[ptr->pack_number].pack_leader_c = c;
      irrelevant_pack[ptr->pack_number].pack_leader_r = r;
    }

    else {      /* if this instance not the pack leader */

      /* if the pack leader is not still in the environment */
      if (irrelevant_pack[ptr->pack_number].pack_leader_in_env == FALSE) {

        /* have a probability of moving */
        if (drand48() < pack_move_prob) {

          moved = TRUE;

          /* decide which direction to move in */
          if (drand48() < ptr->east_prob)
            c++;
          if (drand48() < ptr->west_prob)
            c--;
          if (drand48() < ptr->north_prob)
            r--;
          if (drand48() < ptr->south_prob)
            r++;
        }
      }

      else {    /* if the pack leader is still in the environment */

        /* have a probability of moving */
        if (drand48() < pack_move_prob) {

          moved = TRUE;

          /* decide which direction to move in */
          if (drand48() < ptr->east_prob)
            c++;
          if (drand48() < ptr->west_prob)
            c--;
          if (drand48() < ptr->north_prob)
            r--;
          if (drand48() < ptr->south_prob)
            r++;

          /* add an attraction towards where the leader of the pack is */
          if ((c < (irrelevant_pack[ptr->pack_number].pack_leader_c-1)) &&
              (drand48() < (0.05 * IRRELEVANT_PACK_CLOSENESS)))
            c++;
          else if ((c > (irrelevant_pack[ptr->pack_number].pack_leader_c+1))&&
              (drand48() < (0.05 * IRRELEVANT_PACK_CLOSENESS)))
            c--;
          if ((r < (irrelevant_pack[ptr->pack_number].pack_leader_r-1)) &&
              (drand48() < (0.05 * IRRELEVANT_PACK_CLOSENESS)))
            r++;
          else if ((r > (irrelevant_pack[ptr->pack_number].pack_leader_r+1))&&
              (drand48() < (0.05 * IRRELEVANT_PACK_CLOSENESS)))
            r--;
        }
      }
    }

    /* movement calculated, now do rest */

    /* if this irrelevant has just moved */
    if (moved == TRUE) {

      /* remove this feature instance from old position in env_array */
      if (env_arr[old_c][old_r].p_arr[nft] == ((void *) ptr)) {
        env_arr[old_c][old_r].p_arr[nft] = (void *) ptr->next_ptr;
        ptr->next_ptr = (IRRELEVANT *) NULL;
      }

      else {
        ptr1 = (IRRELEVANT *) env_arr[old_c][old_r].p_arr[nft];
        while (ptr1->next_ptr != ptr)
          ptr1 = ptr1->next_ptr;
        ptr1->next_ptr = ptr->next_ptr;
        ptr->next_ptr = (IRRELEVANT *) NULL;
      }

/*g*/      /* draw over the position the feature occupied originally */
/*g*/      redraw_square(old_c, old_r);
/*g*/
      /* if the new position is inside the environment then attach it to the
      square, redraw the square and update the coords in the feature list */
      if (square_in_env(c, r)) {

        /* put on beginning of `linked-list' through structures */
        ptr->next_ptr = (IRRELEVANT *) env_arr[c][r].p_arr[nft];
        env_arr[c][r].p_arr[nft] = (void *) ptr; 
/*g*/  
/*g*/        /* draw the image for the feature in its new position */
/*g*/        add_to_square(nft, c, r);

        /* change the entry in the list to reflect the new position */
        f_list[nft].column[i] = c;
        f_list[nft].row[i] = r;
      }

      else {	/* if the irrelevant has just moved outside the environment,
              then free memory and remove reference from feature list */

        /* remove from pack */
        if (ptr->pack_leader == TRUE) {    /* if this is a pack leader */
 
          irrelevant_pack[ptr->pack_number].pack_leader_in_env = FALSE;
          irrelevant_pack[ptr->pack_number].num_pack_in_env--;
        }

        else      /* not a pack leader */

          irrelevant_pack[ptr->pack_number].num_pack_in_env--;

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

        /* remove this entry from the feature list */
        f_list_remove(nft, i);
      }
    }
  }

  /* if all members of any pack have left the environment, then remove that
  pack structure */
  for (i = 0; i < current_num_irrelevant_packs; i++) {

    /* if all pack left env. */
    if (irrelevant_pack[i].num_pack_in_env == 0) {

      /* transfer details from last entry in array to current */
      irrelevant_pack[i].pack_leader_c =
        irrelevant_pack[current_num_irrelevant_packs-1].pack_leader_c;
      irrelevant_pack[i].pack_leader_r =
        irrelevant_pack[current_num_irrelevant_packs-1].pack_leader_r;
      irrelevant_pack[i].num_pack_in_env =
        irrelevant_pack[current_num_irrelevant_packs-1].num_pack_in_env;
      irrelevant_pack[i].pack_leader_in_env =
        irrelevant_pack[current_num_irrelevant_packs-1].pack_leader_in_env;

      /* go through all irrelevants, and change pack number if necessary */
      for (j = 0; j < f_list[nft].count; ++j)

        if (((IRRELEVANT *) f_list[nft].f_ptr[j])->pack_number ==
            (current_num_irrelevant_packs-1))

          ((IRRELEVANT *) f_list[nft].f_ptr[j])->pack_number = i;

      /* reduce counter by 1 */
      current_num_irrelevant_packs--;
    }
  }
}


/* function to control movement of mate and response to overtures, etc */
void update_1_mate()
{

  int i, j;
  int c, r, old_c, old_r;
  int nft = MATE_N;
  MATE *ptr, *ptr1;

  /* have a small probability of new mates appearing */
  switch(part_of_day) {
    case(NIGHT) : if (drand48() < MATE_NIGHT_APPEARANCE_PROB)
					get_mates(MATE_APPEARANCE_NUMBER());
    case(SUNRISE) : if (drand48() < MATE_DUSK_APPEARANCE_PROB)
					  get_mates(MATE_APPEARANCE_NUMBER());
    case(MORNING) : if (drand48() < MATE_DAY_APPEARANCE_PROB)
					  get_mates(MATE_APPEARANCE_NUMBER());
    case(MIDDAY) : if (drand48() < MATE_DAY_APPEARANCE_PROB)
					 get_mates(MATE_APPEARANCE_NUMBER());
	case(AFTERNOON) : if (drand48() < MATE_DAY_APPEARANCE_PROB)
					    get_mates(MATE_APPEARANCE_NUMBER());
	case(SUNSET) : if (drand48() < MATE_DUSK_APPEARANCE_PROB)
					 get_mates(MATE_APPEARANCE_NUMBER());
  }

  /* for each mate in the environment */
  for (i = 0; i < f_list[nft].count; ++i) {

    ptr = (MATE *) f_list[nft].f_ptr[i];

    /* get the current position */
    old_c = f_list[nft].column[i];
    old_r = f_list[nft].row[i];
    c = old_c;
    r = old_r;

	/* a mate cannot have status `courted' if the animal is not in the same
	square as it */ 
	if ((ptr->courted == TRUE) && (env_arr[c][r].p_arr[ANIMAL_N] == NULL))
	  ptr->courted = FALSE;

    /* have a probability of changing the receptive state of the mate */
    if ((ptr->receptive == TRUE) && (drand48() < 0.001)) {

	  ptr->receptive = FALSE;
	}
	else if ((ptr->receptive == FALSE) && (drand48() < 0.001)) {

	  ptr->receptive = TRUE;
	}

	/* if the mate has just been courted then make it remain in the same
	square so that it can mate with the animal */
	if ((ptr->courted == TRUE) && (env_arr[c][r].p_arr[ANIMAL_N] != NULL)) {

	  /* do nothing */
	}

    /* otherwise have a probability of moving */
    else if (drand48() < MATE_MOVE_PROB) {

      /* decide which direction to move in */
      if (drand48() < ptr->east_prob)
        c++;
      if (drand48() < ptr->west_prob)
        c--;
      if (drand48() < ptr->north_prob)
        r--;
      if (drand48() < ptr->south_prob)
        r++;
    }

    /* if the mate has just moved */
    if ((c != old_c) || (r != old_r)) {

      /* remove this feature instance from old position in env_array */
      if (env_arr[old_c][old_r].p_arr[nft] == ((void *) ptr)) {
        env_arr[old_c][old_r].p_arr[nft] = (void *) ptr->next_ptr;
        ptr->next_ptr = (MATE *) NULL;
      }
      else {
        ptr1 = (MATE *) env_arr[old_c][old_r].p_arr[nft];
        while (ptr1->next_ptr != ptr) {
          ptr1 = ptr1->next_ptr;
        }
        ptr1->next_ptr = ptr->next_ptr;
        ptr->next_ptr = (MATE *) NULL;
      }
/*g*/
/*g*/      /* draw over the position the feature occupied originally */
/*g*/      redraw_square(old_c, old_r);

      /* if the new position is inside the environment then attach it to the
      square, redraw the square and update the coords in the feature list */
      if (square_in_env(c, r)) {

        /* put on beginning of `linked-list' through structures */
        ptr->next_ptr = (MATE *) env_arr[c][r].p_arr[nft];
        env_arr[c][r].p_arr[nft] = (void *) ptr;

/*g*/		/* draw the image for the feature in its new position */
/*g*/        add_to_square(nft, c, r);
/*g*/
        /* change the entry in the list to reflect the new position */
        f_list[nft].column[i] = c;
        f_list[nft].row[i] = r;
      }

      else {	/* if the mate has just moved outside the environment, then
                free memory and remove reference from feature list */ 

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

        /* remove this entry from the feature list */
        f_list_remove(nft, i);
      }
	}
  }
}


/* function to control movement and behaviour of predator_1's */
void update_1_predator_1()
{

  int i, j;
  int c, r, old_c, old_r, *pc, *pr;
  int nft = PREDATOR_1_N;
  double pack_move_prob;	/* make animals more likely to move together */
  int moved;                /* `boolean' to indicate if animal has moved*/
  PREDATOR_1 *ptr, *ptr1;
  double xdist, ydist;
  double predator_animal_distance;
  double prob_spotting;
  int predator_animal_direction;
  int num_moves;

  /* have a small probability of new predator_1s appearing */
  switch(part_of_day) {
    case(NIGHT) : if (drand48() < PREDATOR_1_NIGHT_APPEARANCE_PROB)
					get_predator_1s(PREDATOR_1_APPEARANCE_NUMBER());
    case(SUNRISE) : if (drand48() < PREDATOR_1_DUSK_APPEARANCE_PROB)
					  get_predator_1s(PREDATOR_1_APPEARANCE_NUMBER());
    case(MORNING) : if (drand48() < PREDATOR_1_DAY_APPEARANCE_PROB)
					  get_predator_1s(PREDATOR_1_APPEARANCE_NUMBER());
    case(MIDDAY) : if (drand48() < PREDATOR_1_DAY_APPEARANCE_PROB)
					 get_predator_1s(PREDATOR_1_APPEARANCE_NUMBER());
	case(AFTERNOON) : if (drand48() < PREDATOR_1_DAY_APPEARANCE_PROB)
					    get_predator_1s(PREDATOR_1_APPEARANCE_NUMBER());
	case(SUNSET) : if (drand48() < PREDATOR_1_DUSK_APPEARANCE_PROB)
					 get_predator_1s(PREDATOR_1_APPEARANCE_NUMBER());
  }

  /* make animals more likely to move at the same time */
  pack_move_prob = rnd(2.0*PREDATOR_1_MOVE_PROB);

  /* for each predator_1 in the environment */
  for (i = 0; i < f_list[nft].count; ++i) {

    ptr = (PREDATOR_1 *) f_list[nft].f_ptr[i];

    /* get the current position */
    c = f_list[nft].column[i];
    r = f_list[nft].row[i];
    old_c = c;
    old_r = r;
	pc = &c;
	pr = &r;

    /* calculate distance between animal and predator */
    xdist = (double) (animal_c - c);
    ydist = (double) (animal_r - r);
    predator_animal_distance = sqrt(((xdist * xdist) + (ydist * ydist)));

    moved = FALSE;

    /* if the predator was previously chasing the animal */
    if (ptr->chasing_animal == TRUE) {

	  /* calculate probability of predator spotting the animal (greater than
      that below since predator knows animal is there).  This will be nil if
	  the animal is in its den */
      prob_spotting = (animal_conspicuousness * 1.5) *
          (M_P1_P - predator_animal_distance) / M_P1_P;
	  if (env_arr[animal_c][animal_r].p_arr[DEN_N] != ((void *) NULL))
		prob_spotting = 0.0;

      if (drand48() < prob_spotting)
        ptr->animal_spotted = TRUE;
	  else
		ptr->animal_spotted = FALSE;

      /* calculate if the predator is going to continue trying to chase the
      animal */
      if (ptr->time_chasing > (ptr->persistence * (0.7+rnd(0.6)))) {
		ptr->chasing_animal = FALSE;
		ptr->hungry = FALSE;
	  }
    }

    else {      /* if predator was not previously chasing animal */

      /* calculate probability of predator spotting the animal.  This will
	  be nil if the animal is in its den */
      prob_spotting = (animal_conspicuousness * 1.0) *
          (M_P1_P - predator_animal_distance) / M_P1_P;
	  if (env_arr[animal_c][animal_r].p_arr[DEN_N] != ((void *) NULL))
		prob_spotting = 0.0;

      if (drand48() < prob_spotting)
        ptr->animal_spotted = TRUE;
	  else
		ptr->animal_spotted = FALSE;
    
      /* have small probability of changing hunger state of the predator */
      if ((ptr->hungry == TRUE) && (drand48() < 0.004)){

        ptr->hungry = FALSE;
	  }
      if ((ptr->hungry == FALSE) && (drand48() < 0.04)) {

        ptr->hungry = TRUE;
	  }

      /* if the predator has spotted the animal and is hungry then make it
	  chase animal */
      if (ptr->animal_spotted && ptr->hungry) {

        ptr->chasing_animal = TRUE;
	 	ptr->time_chasing = 0;
	  } 
    }

    /* if the predator is going to start or continue chasing the animal */
    if (ptr->chasing_animal == TRUE) {

	  moved = TRUE;

	  ptr->time_chasing++;

	  /* decide how many squares the predator_1 can move in this timestep */
	  num_moves = P_1_MOVEMENT();

	  while (num_moves > 0) {

		num_moves--;

		/* get direction of animal from predator (0 = same square) */
		predator_animal_direction = get_direction(c, r, animal_c, animal_r);

		/* if the predator can see the animal at the moment */
		if (ptr->animal_spotted == TRUE) {

          /* keep a record of where the predator thinks the animal is so
          that if it loses sight of it it can head towards that point */
          ptr->prev_animal_direction = predator_animal_direction;
          ptr->prev_animal_distance = (int) predator_animal_distance;

          go_direction(predator_animal_direction, pc, pr);
        }

	    else { 		/* if the predator is chasing the animal but cannot
						perceive it at the current time */

		  go_direction(ptr->prev_animal_direction, pc, pr);

          ptr->prev_animal_distance--;

		  if (ptr->prev_animal_distance <= 0)
			ptr->prev_animal_direction = 0;
		}
      }
    }

    else {      /* predator not about to chase animal */

      /* if this predator_1 is the leader of the pack */
      if (ptr->pack_leader == TRUE) {

        /* have a probability of moving */
        if (drand48() < pack_move_prob) {

          moved = TRUE;

          /* decide which direction to move in */
          if (drand48() < ptr->east_prob)
            c++;
          if (drand48() < ptr->west_prob)
            c--;
          if (drand48() < ptr->north_prob)
            r--;
          if (drand48() < ptr->south_prob)
            r++;

		  /* add in factor which makes predator_1 likely to spend more time
		  around water sources, or close to them, than in the open */
		  if ((min_dist_to_water_source(old_c, old_r) <= 4) &&
			  (drand48() < 0.5))
			head_to_nearest_water_source(old_c, old_r, &c, &r);
        }

        /* change the pack leader's coordinates */
        predator_1_pack[ptr->pack_number].pack_leader_c = c;
        predator_1_pack[ptr->pack_number].pack_leader_r = r;
      }

      else {      /* if this instance not the pack leader */
  
        /* if the pack leader is not still in the environment */
        if (predator_1_pack[ptr->pack_number].pack_leader_in_env == FALSE) {

          /* have a probability of moving */
          if (drand48() < pack_move_prob) {

            moved = TRUE;

            /* decide which direction to move in */
            if (drand48() < ptr->east_prob)
              c++;
            if (drand48() < ptr->west_prob)
              c--;
            if (drand48() < ptr->north_prob)
              r--;
            if (drand48() < ptr->south_prob)
              r++;

			/* add in factor which makes predator_1 likely to spend more
			time around water sources, or close to them, than in the open */
			if ((min_dist_to_water_source(old_c, old_r) <= 4) &&
				(drand48() < 0.5))
			  head_to_nearest_water_source(old_c, old_r, &c, &r);
          }
        }

        else {    /* if the pack leader is still in the environment */
  
          /* have a probability of moving */
          if (drand48() < pack_move_prob) {

            moved = TRUE;

            /* decide which direction to move in */
            if (drand48() < ptr->east_prob)
              c++;
            if (drand48() < ptr->west_prob)
              c--;
            if (drand48() < ptr->north_prob)
              r--;
            if (drand48() < ptr->south_prob)
              r++;

            /* add an attraction towards where the leader of the pack is */
            if ((c < (predator_1_pack[ptr->pack_number].pack_leader_c-1)) &&
                (drand48() < (0.05 * PREDATOR_1_PACK_CLOSENESS)))
              c++;
            else if ((c > (predator_1_pack[ptr->pack_number].pack_leader_c+1))
                     && (drand48() < (0.05 * PREDATOR_1_PACK_CLOSENESS)))
              c--;
            if ((r < (predator_1_pack[ptr->pack_number].pack_leader_r-1)) &&
                (drand48() < (0.05 * PREDATOR_1_PACK_CLOSENESS)))
              r++;
            else if ((r > (predator_1_pack[ptr->pack_number].pack_leader_r+1))
                     && (drand48() < (0.05 * PREDATOR_1_PACK_CLOSENESS)))
              r--;

			/* add in factor which makes predator_1 likely to spend more
			time around water sources, or close to them, than in the open */ 
			if ((min_dist_to_water_source(old_c, old_r) <= 4) &&
				(drand48() < 0.5))
			  head_to_nearest_water_source(old_c, old_r, &c, &r);
          }
        }
      }

	  /* make sure predator does not move more than allowed */
	  if ((c-old_c) > 1)
		c = old_c + 1;
	  else if ((old_c-c) > 1)
		c = old_c - 1;
	  if ((r-old_r) > 1)
		r = old_r + 1;
	  else if ((old_r-r) > 1)
		r = old_r - 1;
    }

    /* movement calculated, now do rest */

    /* if this predator_1 has just moved */
    if (moved == TRUE) {

      /* remove this feature instance from old position in env_array */
      if (env_arr[old_c][old_r].p_arr[nft] == ((void *) ptr)) {
        env_arr[old_c][old_r].p_arr[nft] = (void *) ptr->next_ptr;
        ptr->next_ptr = (PREDATOR_1 *) NULL;
      }

      else {
        ptr1 = (PREDATOR_1 *) env_arr[old_c][old_r].p_arr[nft];
        while (ptr1->next_ptr != ptr)
          ptr1 = ptr1->next_ptr;
        ptr1->next_ptr = ptr->next_ptr;
        ptr->next_ptr = (PREDATOR_1 *) NULL;
      }
/*g*/
/*g*/      /* draw over the position the feature occupied originally */
/*g*/      redraw_square(old_c, old_r);

      /* if the new position is inside the environment then attach it to the
      square, redraw the square and update the coords in the feature list */
      if (square_in_env(c, r)) {

        /* put on beginning of `linked-list' through structures */
        ptr->next_ptr = (PREDATOR_1 *) env_arr[c][r].p_arr[nft];
        env_arr[c][r].p_arr[nft] = (void *) ptr; 
/*g*/  
/*g*/        /* draw the image for the feature in its new position */
/*g*/        add_to_square(nft, c, r);

        /* change the entry in the list to reflect the new position */
        f_list[nft].column[i] = c;
        f_list[nft].row[i] = r;
      }

      else {	/* if the predator_1 has just moved outside the environment,
              then free memory and remove reference from feature list */

        /* remove from pack */
        if (ptr->pack_leader == TRUE) {    /* if this is a pack leader */
 
          predator_1_pack[ptr->pack_number].pack_leader_in_env = FALSE;
          predator_1_pack[ptr->pack_number].num_pack_in_env--;
        }

        else      /* not a pack leader */

          predator_1_pack[ptr->pack_number].num_pack_in_env--;

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

        /* remove this entry from the feature list */
        f_list_remove(nft, i);
      }
    }
  }

  /* if all members of any pack have left the environment, then remove that
  pack structure */
  for (i = 0; i < current_num_predator_1_packs; i++) {

    /* if all pack left env. */
    if (predator_1_pack[i].num_pack_in_env == 0) {

      /* transfer details from last entry in array to current */
      predator_1_pack[i].pack_leader_c =
        predator_1_pack[current_num_predator_1_packs-1].pack_leader_c;
      predator_1_pack[i].pack_leader_r =
        predator_1_pack[current_num_predator_1_packs-1].pack_leader_r;
      predator_1_pack[i].num_pack_in_env =
        predator_1_pack[current_num_predator_1_packs-1].num_pack_in_env;
      predator_1_pack[i].pack_leader_in_env =
        predator_1_pack[current_num_predator_1_packs-1].pack_leader_in_env;

      /* go through all predator_1s, and change pack number if necessary */
      for (j = 0; j < f_list[nft].count; ++j)

        if (((PREDATOR_1 *) f_list[nft].f_ptr[j])->pack_number ==
            (current_num_predator_1_packs-1))

          ((PREDATOR_1 *) f_list[nft].f_ptr[j])->pack_number = i;

      /* reduce counter by 1 */
      current_num_predator_1_packs--;
    }
  }
}


/* function to control movement of predator_2's */
void update_1_predator_2()
{

  int i;
  int old_c, old_r, c, r, *pc, *pr;
  int nft = PREDATOR_2_N;
  PREDATOR_2 *ptr, *ptr1;
  double xdist, ydist;
  double predator_animal_distance;
  double prob_spotting;
  int predator_animal_direction;
  int num_moves;

  /* have a small probability of new predator_2s appearing */
  switch(part_of_day) {
    case(NIGHT) : if (drand48() < PREDATOR_2_NIGHT_APPEARANCE_PROB)
					get_predator_2s(PREDATOR_2_APPEARANCE_NUMBER());
    case(SUNRISE) : if (drand48() < PREDATOR_2_DUSK_APPEARANCE_PROB)
					  get_predator_2s(PREDATOR_2_APPEARANCE_NUMBER());
    case(MORNING) : if (drand48() < PREDATOR_2_DAY_APPEARANCE_PROB)
					  get_predator_2s(PREDATOR_2_APPEARANCE_NUMBER());
    case(MIDDAY) : if (drand48() < PREDATOR_2_DAY_APPEARANCE_PROB)
					 get_predator_2s(PREDATOR_2_APPEARANCE_NUMBER());
	case(AFTERNOON) : if (drand48() < PREDATOR_2_DAY_APPEARANCE_PROB)
					    get_predator_2s(PREDATOR_2_APPEARANCE_NUMBER());
	case(SUNSET) : if (drand48() < PREDATOR_2_DUSK_APPEARANCE_PROB)
					 get_predator_2s(PREDATOR_2_APPEARANCE_NUMBER());
  }

  /* for each predator_2 in the environment */
  for (i = 0; i < f_list[nft].count; ++i) {

    /* get pointer to this predator_2 feature */
    ptr = (PREDATOR_2 *) f_list[nft].f_ptr[i];

	/* get env. coordinates for this instance of the feature type */
    c = f_list[nft].column[i];
    r = f_list[nft].row[i];
    old_c = c;
	old_r = r;
	pc = &c;
	pr = &r;

    /* calculate distance between animal and predator */
    xdist = (double) (animal_c - old_c);
    ydist = (double) (animal_r - old_r);
    predator_animal_distance = sqrt(((xdist * xdist) + (ydist * ydist)));

    /* if the predator was previously chasing the animal */
    if (ptr->chasing_animal == TRUE) {

      /* calculate probability of predator spotting the animal (greater than
      that below since predator knows animal is there).  This will be nil if
	  the animal is in its den */
      prob_spotting = (animal_conspicuousness * 1.5) *
          (M_P2_P - predator_animal_distance) / M_P2_P;
	  if (env_arr[animal_c][animal_r].p_arr[DEN_N] != ((void *) NULL))
		prob_spotting = 0.0;

      if (drand48() < prob_spotting)
        ptr->animal_spotted = TRUE;
	  else
		ptr->animal_spotted = FALSE;

      /* calculate if the predator is going to continue trying to chase the
      animal */
      if (ptr->time_chasing > (ptr->persistence * (0.7+rnd(0.6)))) {
		ptr->chasing_animal = FALSE;
        ptr->hungry = FALSE;
	  }
    }

    else {      /* if predator was not previously chasing animal */

      /* calculate probability of predator spotting the animal.  This will
	  be nil if the animal is in its den */
      prob_spotting = (animal_conspicuousness * 1.0) *
          (M_P2_P - predator_animal_distance) / M_P2_P;
	  if (env_arr[animal_c][animal_r].p_arr[DEN_N] != ((void *) NULL))
		prob_spotting = 0.0;

      if (drand48() < prob_spotting)
        ptr->animal_spotted = TRUE;
	  else
		ptr->animal_spotted = FALSE;
    
      /* have small probability of changing hunger state of the predator */
      if ((ptr->hungry == TRUE) && (drand48() < 0.004)) {

        ptr->hungry = FALSE;
	  }

      if ((ptr->hungry == FALSE) && (drand48() < 0.004)) {

        ptr->hungry = TRUE;
	  }

      /* if the predator has spotted the animal and is hungry then make it
	  chase animal */
      if (ptr->animal_spotted && ptr->hungry) {
        ptr->chasing_animal = TRUE;
		ptr->time_chasing = 0;
	  }
    }

    /* if the predator is going to start or continue chasing the animal */
    if (ptr->chasing_animal == TRUE) {

	  ptr->time_chasing++;

	  /* decide how many squares the predator_1 can move in this timestep */
	  num_moves = P_2_MOVEMENT();

	  while (num_moves > 0) {

		num_moves--;

		/* get direction of animal from predator (0 = same square) */
		predator_animal_direction = get_direction(c, r, animal_c, animal_r);

		/* if the predator can see the animal at the moment */
		if (ptr->animal_spotted == TRUE) {

          /* keep a record of where the predator thinks the animal is so
          that if it loses sight of it it can head towards that point */
          ptr->prev_animal_direction = predator_animal_direction;
          ptr->prev_animal_distance = (int) predator_animal_distance;

          go_direction(predator_animal_direction, pc, pr);
        }

	    else { 		/* if the predator is chasing the animal but cannot
						perceive it at the current time */

		  go_direction(ptr->prev_animal_direction, pc, pr);

          ptr->prev_animal_distance--;

		  if (ptr->prev_animal_distance <= 0)
			ptr->prev_animal_direction = 0;
		}
      }
    }

    else {      /* predator not about to chase animal */

      /* have a probability of predator moving in a semi-random direction */ 
      if (drand48() < PREDATOR_2_MOVE_PROB) {

        /* decide which direction to move in */
        if (drand48() < ptr->east_prob)
          c++;
        if (drand48() < ptr->west_prob)
          c--;
        if (drand48() < ptr->north_prob)
          r--;
        if (drand48() < ptr->south_prob)
          r++;

        /* make sure predator does not move more than allowed */
		if ((c-old_c) > 1)
		  c = old_c + 1;
		else if ((old_c-c) > 1)
		  c = old_c - 1;
		if ((r-old_r) > 1)
		  r = old_r + 1;
		else if ((old_r-r) > 1)
		  r = old_r - 1;
	  }

      else {      /* predator not going to move */

        /* do nothing */
      }
    }

	/* if the predator has just moved */
    if ((c != old_c) || (r != old_r)) {

      /* remove this feature instance from old position in env_array */
      if (env_arr[old_c][old_r].p_arr[nft] == ((void *) ptr)) {
        env_arr[old_c][old_r].p_arr[nft] = (void *) ptr->next_ptr;
        ptr->next_ptr = (PREDATOR_2 *) NULL;
      }
      else {
        ptr1 = (PREDATOR_2 *) env_arr[old_c][old_r].p_arr[nft];
        while (ptr1->next_ptr != ptr) {
          ptr1 = ptr1->next_ptr;
        }
        ptr1->next_ptr = ptr->next_ptr;
        ptr->next_ptr = (PREDATOR_2 *) NULL;
      }
/*g*/
/*g*/      /* draw over the position the feature occupied originally */
/*g*/      redraw_square(old_c, old_r);

      /* if the new position is inside the environment then attach it to the
      square, redraw the square and update the coords in the feature list */
      if (square_in_env(c, r)) {

        /* put on beginning of `linked-list' through structures */
        ptr->next_ptr = (PREDATOR_2 *) env_arr[c][r].p_arr[nft];
        env_arr[c][r].p_arr[nft] = (void *) ptr; 
/*g*/  
/*g*/		/* draw the image for the feature in its new position */
/*g*/        add_to_square(nft, c, r);

        /* change the entry in the list to reflect the new position */
        f_list[nft].column[i] = c;
        f_list[nft].row[i] = r;
      }

      else {	/* if the predator_2 has just moved outside the environment,
                then free memory and remove reference from feature list */ 

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

        /* remove this entry from the feature list */
        f_list_remove(nft, i);
      }
    }
  }
}


/* function to control movement of prey */
void update_1_prey()
{

  int i;
  int old_c, old_r, c, r;
  int nft = PREY_N;
  PREY *ptr, *ptr1;

  /* have a small probability of new prey appearing */
  switch(part_of_day) {
    case(NIGHT) : if (drand48() < PREY_NIGHT_APPEARANCE_PROB)
					get_prey(PREY_APPEARANCE_NUMBER());
    case(SUNRISE) : if (drand48() < PREY_DUSK_APPEARANCE_PROB)
					  get_prey(PREY_APPEARANCE_NUMBER());
    case(MORNING) : if (drand48() < PREY_DAY_APPEARANCE_PROB)
					  get_prey(PREY_APPEARANCE_NUMBER());
    case(MIDDAY) : if (drand48() < PREY_DAY_APPEARANCE_PROB)
					 get_prey(PREY_APPEARANCE_NUMBER());
	case(AFTERNOON) : if (drand48() < PREY_DAY_APPEARANCE_PROB)
					    get_prey(PREY_APPEARANCE_NUMBER());
	case(SUNSET) : if (drand48() < PREY_DUSK_APPEARANCE_PROB)
					 get_prey(PREY_APPEARANCE_NUMBER());
  }

  /* for each prey in the environment */
  for (i = 0; i < f_list[nft].count; ++i) {

    /* have a probability of moving or staying still */
    if (drand48() < PREY_MOVE_PROB) {

      ptr = (PREY *) f_list[nft].f_ptr[i];

      /* get the current position */
      c = f_list[nft].column[i];
      r = f_list[nft].row[i];
	  old_c = c;
	  old_r = r;

      /* remove this feature instance from old position in env_array */
      if (env_arr[c][r].p_arr[nft] == ((void *) ptr)) {
        env_arr[c][r].p_arr[nft] = (void *) ptr->next_ptr;
        ptr->next_ptr = (PREY *) NULL;
      }
      else {
        ptr1 = (PREY *) env_arr[c][r].p_arr[nft];
        while (ptr1->next_ptr != ptr) {
          ptr1 = ptr1->next_ptr;
        }
        ptr1->next_ptr = ptr->next_ptr;
        ptr->next_ptr = (PREY *) NULL;
      }
/*g*/
/*g*/      /* draw over the position the feature occupied originally */
/*g*/      redraw_square(c, r);

      /* decide which direction to move in */
      if (drand48() < ptr->east_prob)
        c++;
      if (drand48() < ptr->west_prob)
        c--;
      if (drand48() < ptr->north_prob)
        r--;
      if (drand48() < ptr->south_prob)
        r++;

	  /* add in factor which makes prey likely to spend more time around
	  water sources, or close to them, than in the open */ 
	  if ((min_dist_to_water_source(old_c, old_r) <= 4) &&
		(drand48() < 0.3))

		head_to_nearest_water_source(old_c, old_r, &c, &r);

	  /* make sure prey does not move more than allowed */
	  if ((c-old_c) > 1)
		c = old_c + 1;
	  else if ((old_c-c) > 1)
		c = old_c - 1;
	  if ((r-old_r) > 1)
		r = old_r + 1;
	  else if ((old_r-r) > 1)
		r = old_r - 1;

      /* if the new position is inside the environment then attach it to the
      square, redraw the square and update the coords in the feature list */
      if (square_in_env(c, r)) {

        /* put on beginning of `linked-list' through structures */
        ptr->next_ptr = (PREY *) env_arr[c][r].p_arr[nft];
        env_arr[c][r].p_arr[nft] = (void *) ptr; 
/*g*/  
/*g*/		/* draw the image for the feature in its new position */
/*g*/        add_to_square(nft, c, r);

        /* change the entry in the list to reflect the new position */
        f_list[nft].column[i] = c;
        f_list[nft].row[i] = r;
      }

      else {	/* if the prey has just moved outside the environment,
                then free memory and remove reference from feature list */

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

        /* remove this entry from the feature list */
        f_list_remove(nft, i);
      }
    }
  }
}


/* function to change the levels of water sources every 10 timesteps */
void update_10_water()
{

  int i, col, row;
  int nft = WATER_N;
  WATER *ptr;
  double previous_value;			/* used to calculate recuperation if cereal
								food just been eaten or dryness has changed */

  /* for each instance of water */
  for (i = 0; i < f_list[nft].count; ++i) {

    /* change the value (ie the amount of water contained) for each water
    source according to the change in environment dryness */
    ptr = (WATER *) f_list[nft].f_ptr[i];

    previous_value = ptr->value;

    /* the amount of water in this source is dependant on the amount of
    rainfall in the recent past, the temperature, and the average size of
    the source */
	ptr->value = get_water_value(ptr->average_size);

    /* if the new calculated value has increased by more than the possible
	regeneration then limit growth to regeneration */
	if ((previous_value+WATER_RECUP_RATE) < ptr->value)
	  ptr->value = previous_value + WATER_RECUP_RATE;
  }
}


/* function to make any changes to cereal food */
void update_day_cereal_food()
{

  int i, col, row;
  int nft = CEREAL_FOOD_N;
  CEREAL_FOOD *ptr;
  double previous_value;			/* used to calculate recuperation if cereal
								food just been eaten or dryness has changed */

  /* for each instance of cereal_food */
  for (i = 0; i < f_list[nft].count; ++i) {

    ptr = (CEREAL_FOOD *) f_list[nft].f_ptr[i];

    previous_value = ptr->value;

    /* change the food value to take into account the new env_dryness
    value */  
    if (env_dryness < OPT_DRYNESS)
      ptr->value = ptr->conditions * env_dryness / ((double)OPT_DRYNESS);
    else
      ptr->value = ptr->conditions * ((1.0/(1.0 - ((double)OPT_DRYNESS)))
        + (env_dryness * (1.0/(((double)OPT_DRYNESS)-1.0))));

    /* if the new calculated value has increased by more than the possible
	regeneration then limit growth to regeneration */
	if ((previous_value+C_F_RECUP_RATE) < ptr->value)
	  ptr->value = previous_value+C_F_RECUP_RATE;
  }
}


/* function to make any changes to fruit food */
void update_day_fruit_food()
{

  int i, col, row;
  int nft = FRUIT_FOOD_N;
  FRUIT_FOOD *ptr;
  double previous_value;			/* used to calculate recuperation if fruit
								food just been eaten */

  /* for each instance of fruit food */
  for (i = 0; i < f_list[nft].count; ++i) {

    /* change the amount of fruit according to state in ripening cycle, etc */
    ptr = (FRUIT_FOOD *) f_list[nft].f_ptr[i];

    previous_value = ptr->value;

    ptr->cycle_state = (ptr->cycle_state+1) % ptr->cycle_length;

	ptr->value = get_fruit_food_value(ptr->cycle_state, ptr->ripe_time,
        ptr->conditions);

    /* if the new calculated value has increased by more than the possible
	regeneration then limit growth to regeneration */
	if ((previous_value+F_F_RECUP_RATE) < ptr->value)
	  ptr->value = previous_value+F_F_RECUP_RATE;
  }
}


/* function to make any changes to water */
void update_day_water()
{

  int i, col, row;
  int nft = WATER_N;
  WATER *ptr;
  double previous_value;			/* used to calculate recuperation if cereal
								food just been eaten or dryness has changed */

  /* for each instance of water */
  for (i = 0; i < f_list[nft].count; ++i) {

    /* change the value (ie the amount of water contained) for each water
    source according to the change in environment dryness */
    ptr = (WATER *) f_list[nft].f_ptr[i];

    previous_value = ptr->value;

    /* the amount of water in this source is dependant on the amount of
    rainfall in the recent past, the temperature, and the average size of
    the source */
	ptr->value = get_water_value(ptr->average_size);

    /* if the new calculated value has increased by more than the possible
	regeneration then limit growth to regeneration */
	if ((previous_value+WATER_RECUP_RATE) < ptr->value)
	  ptr->value = previous_value + WATER_RECUP_RATE;
  }
}


/*g*//* function to redraw all instances of features which might have changed 
/*g*//*colour due to changes in grazing or weather */
/*g*/void update_graded_features()
/*g*/{
/*g*/
/*g*/  int i;
/*g*/  
/*g*/  /* for each instance of cereal_food in the environment (but only once
/*g*//*  every half a day since values won't change that quickly) */
/*g*/  if ((timestep % (DAY_LENGTH/2)) == 0)
/*g*/    for (i = 0; i < f_list[CEREAL_FOOD_N].count; ++i)
/*g*/      redraw_square(f_list[CEREAL_FOOD_N].column[i],
/*g*/      f_list[CEREAL_FOOD_N].row[i]); 
/*g*/    
/*g*/  if ((timestep % 10) == 0)
/*g*/  /* for each instance of fruit food in the environment */
/*g*/  for (i = 0; i < f_list[FRUIT_FOOD_N].count; ++i)
/*g*/    redraw_square(f_list[FRUIT_FOOD_N].column[i], f_list[FRUIT_FOOD_N].row[i]);
/*g*/
/*g*/  if ((timestep % (DAY_LENGTH/2)) == 0)
/*g*/  /* for each instance of water in the environment */
/*g*/  for (i = 0; i < f_list[WATER_N].count; ++i)
/*g*/    redraw_square(f_list[WATER_N].column[i], f_list[WATER_N].row[i]); 
/*g*/}
/*g*/

/* function to calculate an approximate direction from one point (x1, y1) to
another (x2, y2).  The direction is an integer from 0 to 8, with 1 being due
north and so on clockwise around the compass until 8 is north-west (0 is
same square) */
int get_direction(x1, y1, x2, y2)
int x1;
int y1;
int x2;
int y2;
{

  double xdist, ydist, rad_angle, tan_minus_1;

  /* change sign of y_coordinates to compensate for fact that row index
  increases from top to bottom */
  y1 *= -1;
  y2 *= -1;

  xdist = (double) (x2 - x1);
  ydist = (double) (y2 - y1);

  /* return 0 for coincident */
  if ((xdist == 0.0) && (ydist == 0.0))
	return(0);

  /* 1 to 8 for directions */
  else {

	tan_minus_1 = atan2(ydist, xdist);
	while (tan_minus_1 < 0.0)
	  tan_minus_1 += (2.0*PI);

	/* change effect of tan_minus_1 so that it increases in a clockwise
	direction and so that 0.0 corresponds to the direction `north north
	west' instead of `east' (ie. to the right) */
	rad_angle = (2.0*PI-tan_minus_1) + (PI / 2.0) + (PI / 8.0);

	/* get rad_angle back into range 0.0 to 2.0*PI */
	if (rad_angle >= (2.0*PI))
	  rad_angle -= (2.0*PI);

	/* transform from angle in radians to direction from 0 to 7 (0 = north
	then clockwise) */
	return((1 + ((int) (rad_angle * 8.0 / (2.0 * PI)))));
  }
}


/* function to change the third and fourth arguments (which are coordinates)
so that the predator or whatever heads from its current position (first pair
of coordinates) towards the nearest water source */
void head_to_nearest_water_source(c, r, new_c, new_r)
int c;
int r;
int *new_c;
int *new_r;
{

 
  int i;
  int min_dist_sqrd, this_dist_sqrd;
  int nearest_water_c, nearest_water_r;

  /* set to arbitrary high value */
  min_dist_sqrd = 100000;

  /* for each instance of water */
  for (i = 0; i < f_list[WATER_N].count; ++i) {

    /* if distance squared < current minimum distance squared then set
    minimum to that */ 
    this_dist_sqrd =
        (f_list[WATER_N].column[i]-c) * (f_list[WATER_N].column[i]-c)
        + (f_list[WATER_N].row[i]-r) * (f_list[WATER_N].row[i]-r);

    if (this_dist_sqrd < min_dist_sqrd) {

      min_dist_sqrd = this_dist_sqrd;

	  nearest_water_c = f_list[WATER_N].column[i];
	  nearest_water_r = f_list[WATER_N].row[i];
	}
  }

  /* now that have got coordinates of nearest water source, change predator
  or whatever coordinates so that move towards the water source */
  if (nearest_water_c < c)
	*new_c -= 1;
  else if (nearest_water_c > c)
	*new_c += 1;
  if (nearest_water_r < r)
	*new_r -= 1;
  else if (nearest_water_r > r)
	*new_r += 1;
}


/* function which takes an input direction and then changes the coordinates
(whose pointers are given) such that they increase in the direction given */
void go_direction(direction, ptr_to_c, ptr_to_r)
int direction;
int *ptr_to_c;
int *ptr_to_r;
{

  switch(direction) {

    case(1) : *ptr_to_r = (*ptr_to_r) - 1;
              break;
    case(2) : *ptr_to_c = (*ptr_to_c) + 1;
              *ptr_to_r = (*ptr_to_r) - 1;
              break;
    case(3) : *ptr_to_c = (*ptr_to_c) + 1;
              break;
    case(4) : *ptr_to_c = (*ptr_to_c) + 1;
              *ptr_to_r = (*ptr_to_r) + 1;
              break;
    case(5) : *ptr_to_r = (*ptr_to_r) + 1;
              break;
    case(6) : *ptr_to_c = (*ptr_to_c) - 1;
              *ptr_to_r = (*ptr_to_r) + 1;
              break;
    case(7) : *ptr_to_c = (*ptr_to_c) - 1;
              break;
    case(8) : *ptr_to_c = (*ptr_to_c) - 1;
              *ptr_to_r = (*ptr_to_r) - 1;
              break;
	case(0) : break;
  }
}




 
