#include "math.h"
#include "dudes.h"

/************************************/
/* nerph.c - Karl Stiefvater - 1992 */
/************************************/

/************* the type definition block ***************/
int nerph_init();
int nerph_update();
int nerph_create();
void nerph_close();


dude_def nerph_def = {
  "nerph",
  nerph_init,
  nerph_create,
  nerph_update,
  nerph_close,
  20,
  NULL
  };
/************* the type definition block ***************/


typedef struct _nerph_private
{
  float    x,y;
  float    rx,ry;
  int      update;
  int      frame;
  int      cycle;
  dude_def *interest;

} nerph_private;

  
/* tweeks for the nerph personallity */
#define MINUPDATE    4
#define MAXUPDATE    20
#define UPDATECUT    15

#define MINCYCLE     600
#define MAXCYCLE     3000

#define LONELYDIST   20.0
#define LONELYMULT   1.0
#define LONELYPOW    5.0

#define CROWDEDDIST  20.0
#define CROWDEDMULT  -1.0
#define CROWDEDPOW   -3.0

#define INTERDIST    5.0
#define INTERMULT    1.0
#define INTERPOW     1.0


Gob nerph_left_gob[4];
Gob nerph_right_gob[4];

extern dude_def ploing_def,flum_def;
dude_def *(interests[])= {
  &ploing_def,
  &flum_def,
  NULL
  };

#define interest_num sizeof(interests) / sizeof(dude_def *)


int nerph_init()
{
  int loop;
  char filename[1000];
  
  for (loop = 0; loop < 4; loop++)
    {
      sprintf(filename,"%s/nerph%d.left",PIXMAPPATH,loop+1);
      if (load_gob(windowdisplay,window,&nerph_left_gob[loop],filename))
	return -1;
      sprintf(filename,"%s/nerph%d.right",PIXMAPPATH,loop+1);
      if (load_gob(windowdisplay,window,&nerph_right_gob[loop],filename))
	return -1;
    }
  return 0;
}


int nerph_create()
{
  dude *d;
  nerph_private *priv;

  if ((d = alloc_dude(&nerph_def)) == NULL)
    return -1;

  if ( (priv = (nerph_private *)malloc(sizeof (nerph_private))) == NULL)
      return -1;
  
  d->private = (char *)priv;

  priv->x = d->sprite.x = lrand48() % windowwidth;
  priv->y = d->sprite.y = lrand48() % windowheight;
  priv->update = lrand48() % (MAXUPDATE - MINUPDATE) + MINUPDATE;
  priv->cycle  = lrand48() % (MAXCYCLE - MINCYCLE) + MINCYCLE;

  priv->frame = 0;
  priv->rx = priv->ry = 0;

  priv->interest = interests[lrand48() % interest_num];

  d->sprite.gob = &nerph_left_gob[0];

  return 0;
}


int nerph_update(d)
     dude *d;

{
  nerph_private *priv;
  float dx = 0.0, dy = 0.0;
  float dist;        /* the magnitude of how badly we want to move */
  dude  *closest;    /* the closest nerph to me */
  float closest_dist;/* how far away he is */

  /*  The update has two phases: First we determine how badly we want to
      move to a given spot.  Then, we actually update the position based on
      a "I'm a mosy-ing along" algorithm. */

  priv = (nerph_private *)(d->private);

  if ((engine_counter % priv->cycle) == 0)
    priv->interest = interests[lrand48() % interest_num];


  if ( (engine_counter % priv->update) == 0)
    {
      float cycle_factor;


      calc_force_multi(d,&nerph_def,CROWDEDDIST,CROWDEDMULT,CROWDEDPOW,
		       &dx,&dy);

      cycle_factor = (1.0 + 
	sin((double) 2.0 * M_PI * (engine_counter % priv->cycle) 
	    / priv->cycle))/2.0;

      calc_force_closest(d,&ploing_def, INTERDIST, 
			 INTERMULT * cycle_factor,
			 INTERPOW,
			 &dx,&dy); 

      calc_force_closest(d,&nerph_def,LONELYDIST,LONELYMULT,LONELYPOW,
			 &dx,&dy); 

      priv->rx = dx;
      priv->ry = dy;
    }


  /* now we know how badly, we need to decide whether to actually move */

  dx = priv->rx;
  dy = priv->ry;

  dist = sqrt((double) dx*dx + dy*dy);
  
  if ( 
      ((int)dist  >  (engine_counter % priv->update)) &&
      (UPDATECUT > (engine_counter % priv->update)) 
      )
    {
      /* then move! */
      priv-> x += dx / dist;
      priv-> y += dy / dist;

      d->sprite.x = priv->x;
      d->sprite.y = priv->y;

      priv->frame++;

      if (dx < 0.0)
	d->sprite.gob = &nerph_left_gob[priv->frame % 4];
      else
	d->sprite.gob = &nerph_right_gob[priv->frame % 4];
    }
  else
    {
      priv->frame = 0;

      if (dx < 0.0)
	d->sprite.gob = &nerph_left_gob[0];
      else
	d->sprite.gob = &nerph_right_gob[0];
    }

  return 1;
}



void nerph_close()
{
  return;
}


/* XPM */
static char * nerph1_left[] = {
"12 18 3 1",
"       s None c None m None"
".      s Outer c blue4 m black"
"X      s Inner c blue3 m white"
"            ",
"    ....    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"     .X.    ",
"     .X.    ",
"    .XX.    ",
"    .XX.    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"     .X.    ",
"   .XXXX.   ",
"  ........  ",
"            "};
/* XPM */
static char * nerph1_right[] = {
"12 18 3 1",
"       s None c None m None"
".      s Outer c blue4 m black"
"X      s Inner c blue3 m white"
"            ",
"    ....    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"    .X.     ",
"    .X.     ",
"    .XX.    ",
"    .XX.    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"    .X.     ",
"   .XXXX.   ",
"  ........  ",
"            "};
/* XPM */
static char * nerph2_left[] = {
"12 18 3 1",
"       s None c None m None"
".      s Outer c blue4 m black"
"X      s Inner c blue3 m white"
"            ",
"    ....    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"     .X.    ",
"     .X.    ",
"    .XX.    ",
"    .XX.    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"    .XXX.   ",
"  .XXXXXX.. ",
" .........  ",
"            "};
/* XPM */
static char * nerph2_right[] = {
"12 18 3 1",
"       s None c None m None"
".      s Outer c blue4 m black"
"X      s Inner c blue3 m white"
"            ",
"    ....    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"    .X.     ",
"    .X.     ",
"    .XX.    ",
"    .XX.    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"   .XXX.    ",
" ..XXXXXX.  ",
"  ......... ",
"            "};
/* XPM */
static char * nerph3_left[] = {
"12 18 3 1",
"       s None c None m None"
".      s Outer c blue4 m black"
"X      s Inner c blue3 m white"
"            ",
"            ",
"    ....    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"     .X.    ",
"     .X.    ",
"    .XX.    ",
"    .XX.    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"  .XXX.XX.. ",
".XXXX. .X.  ",
" ....  ..   ",
"            "};
/* XPM */
static char * nerph3_right[] = {
"12 18 3 1",
"       s None c None m None"
".      s Outer c blue4 m black"
"X      s Inner c blue3 m white"
"            ",
"            ",
"    ....    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"    .X.     ",
"    .X.     ",
"    .XX.    ",
"    .XX.    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
" ..XX.XXX.  ",
"  .X. .XXXX.",
"   ..  .... ",
"            "};
/* XPM */
static char * nerph4_left[] = {
"12 18 3 1",
"       s None c None m None"
".      s Outer c blue4 m black"
"X      s Inner c blue3 m white"
"            ",
"    ....    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"     .X.    ",
"     .X.    ",
"    .XX.    ",
"    .XX.    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"    .XXX.   ",
"  .XXXXXX.. ",
" .........  ",
"            "};
/* XPM */
static char * nerph4_right[] = {
"12 18 3 1",
"       s None c None m None"
".      s Outer c blue4 m black"
"X      s Inner c blue3 m white"
"            ",
"    ....    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"    .X.     ",
"    .X.     ",
"    .XX.    ",
"    .XX.    ",
"   .XXXX.   ",
"   .XXXX.   ",
"   .XXXX.   ",
"    .XX.    ",
"   .XXX.    ",
" ..XXXXXX.  ",
"  ......... ",
"            "};