/* This file allows you to output races and classes to your web page.
   I put a significant amount of work into this function, coding and
   debugging for approximately 20 combined hours.  Do not remove the
   copyright statement and link to the Clandestine page included in
   the HTML output. */
/* To implement this code, simply make a call to races_html_update
   somewhere in your code.  You can execute every time by placing it
   in db.c, or you can create a command for it in interp.c and
   execute only when you wish. */
/* The replacement of Clandestine-specific terms is left as an
   exercise for the user.  You will need to change the path to the
   file, modify the raceclass_strip function for the format of your
   help files, and modify the text appropriately for your mud.  In
   addition, the number "5" is used as the max number of skills
   associated with a race.  If you have a different constant in your
   merc.h file you will need to change that portion of the code.
   Clandestine also has 10 affect variables (with 31 affects each)
   built on the same concept as the standard "AFF2" snippet.  If you
   do not have that many, selectively delete or modify the code
   appropriately. */

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <malloc.h>
#include "merc.h"
#include "recycle.h"
#include "tables.h"
 
#if !defined(macintosh)
extern  int     _filbuf         args( (FILE *) );
#endif

/* The under_line() function from webspells.c is needed to create
   valid HTML links. */
void under_line args ((char *under_lined, char *spaced_out ));

/* And a reverse hack of the under_line() function turns a list
   of affects/immunities from "this_affect that_affect the_other_affect"
   to "this affect, that affect, the other affect, " */
void un_under_line(char *spaced_out, char *under_lined )
{
  char * point;
  char * space;

#ifdef DEBUG
        Debug ("un_under_line");
#endif
  spaced_out[0] = '\0';
  space = spaced_out;
  for (point = under_lined; *point; point++)
    {
	/* replace _ with a space */
	if (*point == '_')
	  *space++ = ' ';
	else
	/* and insert a comma where there already is a space */
	if (*point == ' ')
	{
	  *space++ = ',';
	  *space++ = ' ';
	}
	else
	/* otherwise just copy the character */
	{
	  *space++ = *point;
	}
    }
  /* We'll return with a comma at the end so that multiple lists
     can be appended together.  Remove after the last one is appended. */
  *space++ = ',';
  *space++ = ' ';
  *space = '\0';
  return;
} 

/* Clandestine's race and class helps have the description of the
   race or class in between the race/class name and the word VITALS,
   plus the framing characters - | * # and % .  This function strips
   out the description.  Other help files will obviously require
   different treatment. */
void raceclass_help_strip ( char *buffer, char *txt, const char *raceclass_name )
{
    const	char	*point;
    int i;

#ifdef DEBUG
        Debug ("raceclass_help_strip");
#endif
    /* Advance until raceclass_name is recognized */
    for( point = txt ; *point ; point++ )
    {
	if( !str_prefix( raceclass_name, point ))
	{
	  break;
	}
    }	
    /* loop exits with either *point == NULL (not found) or
	 *point at beginning of race string.  Strip out race_string
	 and then return until 'VITALS' */	
    if (*point == '\0')
	{
	  /* String not found, return empty string */
	  *buffer = '\0';
	  return;
	}
    /* String found.  Advance to the end of raceclass_name */
    for ( i = strlen(raceclass_name); i > 0; i-- )
	{
	    point++;
	}		
    /* Now copy characters until "VITALS" is found.  Strip out
       framing characters */
    for( ; *point ; point++ )
    {
	/* Don't copy these characters (copy hyphen if not followed
	   by a space */
	if( (*point == '|') || 
	   ((*point == '-') && (*point+1 == ' ')) ||
	    (*point == '#') || 
	    (*point == '%') || 
	    (*point == '*') )
	{
	    point++;
	    continue;
	}
	/* Don't copy VITALS, and exit loop when it's found */
	if( !str_prefix( "VITALS" , point ))
	{
	  break;
	}
	/* Copy everything else.  Advance buffer */
	*buffer = *point;
	*++buffer = '\0';
    }			
    /* We've either found VITALS or the end of the string.  In either
	 case, terminate the string and return */
    *buffer = '\0';
}

void races_html_update (void)
{

  FILE *fp; 
  int i;
  int j;
  int k;
  int gn;
  int sn;
  HELP_DATA *pHelp;
  BUFFER *output;
  char buf[4*MAX_STRING_LENGTH]; 
  char buf2[MAX_STRING_LENGTH]; 
  char buf3[MAX_STRING_LENGTH]; 
  
#ifdef DEBUG
        Debug ("races_html_update");
#endif

  fclose(fpReserve);
  /* You will have to change this to the absolut path of the
     file you want to use for your race/class page */
  if ( (fp = fopen("/usr/home/redge/public_html/raceclass.html", "w") ) == NULL)
  {
     bug( "raceclass.html: fopen", 0 );
     perror( "raceclass.html" );
  }
  else
  {
  /* Change header information for your MUD here */
  /* Don't forget to add your own fonts, backgrounds, etc. */
  fprintf(fp, "<html>\n");
  fprintf(fp, "<head>\n");
  fprintf(fp, "<title>\n");
  fprintf(fp, "Races and Classes on Clandestine\n");
  fprintf(fp, "</title>\n");
  fprintf(fp, "<CENTER><P><A NAME=\"raceclassmenu\"></A></P></CENTER>\n");
  fprintf(fp, "<BODY TEXT=\"#C0C0C0\" BGCOLOR=\"#000000\" LINK=\"#00FFFF\"\n");
  fprintf(fp, "VLINK=\"#FFFFFF\" ALINK=\"#008080\" BACKGROUND=\"dragbkgd.gif\">\n");
  fprintf(fp, "<h1><center>Races and Classes on Clandestine</center></h1>\n");

  /* Blah blah blah */
  fprintf(fp, "<P>The Realm of Clandestine is host to many unique races and classes\n");
  fprintf(fp, "of characters.  Players who reincarnate have the option of choosing\n");
  fprintf(fp, "from even more powerful races and classes.<BR><BR>\n");
  fprintf(fp, "Each race has certain innate affects, immunities, resistances,\n");
  fprintf(fp, "vulnerabilities, and skills. Beyond this, each class offers a wide\n");
  fprintf(fp, "range of additional spell groups and skills.</P>\n");

  /* Here are the links to the lists of races and classes.  Remove the
     references to reincarnation (remort) if you don't have it.*/
  fprintf(fp, "<CENTER><P><FONT SIZE=+1><A HREF=\"#MortalRaces\">Mortal Races\n");
  fprintf(fp, "</A> - <A HREF=\"#ReincRaces\">Reincarnate Races <BR>\n");
  fprintf(fp, "</A><A HREF=\"#MortalClasses\">Mortal Classes\n");
  fprintf(fp, "</A> - <A HREF=\"#ReincClasses\">Reincarnate Classes </A></FONT><BR>\n");
  fprintf(fp, "</P></CENTER><BR><BR>\n");

/*** DO NOT REMOVE THE FOLLOWING LINK.  INCLUSION OF THIS LINK IS
     REQUIRED FOR YOUR USE OF THIS FUNCTION.  You may change the
     target from "_top" to "_new" if you desire.***/
  fprintf(fp, "<CENTER><P>Automated race/class web update function &copy1998 by Nebseni of \n");
  fprintf(fp, "<A HREF=\"http://clandestine.mudnet.net\" target=\"_top\">\n");
  fprintf(fp, "Clandestine MUD</A></P></CENTER>\n");
/*** DO NOT REMOVE THE PRECEEDING LINK.  INCLUSION OF THIS LINK IS
     REQUIRED FOR YOUR USE OF THIS FUNCTION.  ***/

/* Output a table of races linked to the detailed information to follow.
   If you don't have reincarnates remove that if statement. */
  fprintf(fp, "<A NAME=\"MortalRaces\">\n");
  fprintf(fp, "<hr><h2><center>Mortal Races</center></h2></A>\n");
  fprintf(fp, "<CENTER><TABLE BORDER=0 CELLPADDING=2>\n");
  fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\">\n");
  j = 0;
  for ( i = 1; race_table[i].name != NULL; i++ )
	{
	    if (!race_table[i].pc_race)
		continue;
          if ( !race_table[i].reincarnate_race )
	    {
		under_line(buf3,race_table[i].name);
		sprintf(buf2,"<td><A HREF=\"#%s\">%s</A></td>",
			buf3,
			race_table[i].name);
		fprintf(fp, buf2);
		if (j++ > 3)
		{
		  fprintf(fp, "</tr><tr>\n");
		  j = 0;
		}
	    }
	}
  fprintf(fp, "</tr></TABLE></CENTER>\n");

/* I strongly recommend many internal links within the document for
   easy navigation. */
  fprintf(fp, "<FONT SIZE=0><CENTER><P><A HREF=\"#ReincRaces\">Reincarnate Races\n");
  fprintf(fp, "</A> | <A HREF=\"#MortalClasses\">Mortal Classes\n");
  fprintf(fp, "</A> | <A HREF=\"#ReincClasses\">Reincarnate Classes </A>\n");
  fprintf(fp, "</br>\n");
  fprintf(fp, "<A HREF=\"#raceclassmenu\">\n");
  fprintf(fp, "Races and Classes of Clandestine</A></P></CENTER></FONT>\n");

/* Output a table of races linked to the detailed information to follow.
   If you don't have reincarnates remove this section. */
  fprintf(fp, "<A NAME=\"ReincRaces\">\n");
  fprintf(fp, "<hr><h2><center>Reincarnate Races</center></h2></A>\n");
  fprintf(fp, "<CENTER><TABLE BORDER=0 CELLPADDING=2>\n");
  fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\">\n");
  j = 0;
  for ( i = 1; race_table[i].name != NULL; i++ )
	{
	    if (!race_table[i].pc_race)
		continue;
          if ( race_table[i].reincarnate_race )
	    {
		under_line(buf3,race_table[i].name);
		sprintf(buf2,"<td><A HREF=\"#%s\">%s</A></td>",
			buf3,
			race_table[i].name);
		fprintf(fp, buf2);
		if (j++ > 3)
		{
		  fprintf(fp, "</tr><tr>\n");
		  j = 0;
		}
	    }
	}
  fprintf(fp, "</tr></TABLE></CENTER>\n");  

/* I strongly recommend many internal links within the document for
   easy navigation. */
  fprintf(fp, "<FONT SIZE=0><CENTER><P><A HREF=\"#MortalRaces\">Mortal Races\n");
  fprintf(fp, "</A> | <A HREF=\"#MortalClasses\">Mortal Classes\n");
  fprintf(fp, "</A> | <A HREF=\"#ReincClasses\">Reincarnate Classes </A>\n");
  fprintf(fp, "</br>\n");
  fprintf(fp, "<A HREF=\"#raceclassmenu\">\n");
  fprintf(fp, "Races and Classes of Clandestine</A></P></CENTER></FONT>\n");

  fprintf(fp, "<A NAME=\"MortalClasses\">\n");
  fprintf(fp, "<hr><h2><center>Mortal Classes</center></h2></A>\n");
  fprintf(fp, "<CENTER><TABLE BORDER=0 CELLPADDING=2>\n");
  fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\">\n");
  j = 0;
  for ( i = 0; i < MAX_CLASS; i++ )
	{
        if (!class_table[i].reincarnate_class )
		{	
		under_line(buf3,class_table[i].name);
		sprintf(buf2,"<td><A HREF=\"#%s\">%s</A></td>",
			buf3,
			class_table[i].name);
		fprintf(fp, buf2);
		if (j++ > 3)
		{
		  fprintf(fp, "</tr><tr>\n");
		  j = 0;
		}
		}
	}
  fprintf(fp, "</tr></TABLE></CENTER>\n");

/* I strongly recommend many internal links within the document for
   easy navigation. */
  fprintf(fp, "<FONT SIZE=0><CENTER><P><A HREF=\"#MortalRaces\">Mortal Races\n");
  fprintf(fp, "</A> | <A HREF=\"#ReincRaces\">Reincarnate Races\n");
  fprintf(fp, "</A> | <A HREF=\"#ReincClasses\">Reincarnate Classes </A>\n");
  fprintf(fp, "</br>\n");
  fprintf(fp, "<A HREF=\"#raceclassmenu\">\n");
  fprintf(fp, "Races and Classes of Clandestine</A></P></CENTER></FONT>\n");

  fprintf(fp, "<A NAME=\"ReincClasses\">\n");
  fprintf(fp, "<hr><h2><center>Reincarnate Classes</center></h2></A>\n");
  fprintf(fp, "<CENTER><TABLE BORDER=0 CELLPADDING=2>\n");
  fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\">\n");
  j = 0;
  for ( i = 0; i < MAX_CLASS; i++ )
	{
        if (class_table[i].reincarnate_class )
		{	
		under_line(buf3,class_table[i].name);
		sprintf(buf2,"<td><A HREF=\"#%s\">%s</A></td>",
			buf3,
			class_table[i].name);
		fprintf(fp, buf2);
		if (j++ > 3)
		{
		  fprintf(fp, "</tr><tr>\n");
		  j = 0;
		}
		}
	}
  fprintf(fp, "</tr></TABLE></CENTER>\n");

/* I strongly recommend many internal links within the document for
   easy navigation. */
  fprintf(fp, "<FONT SIZE=0><CENTER><P><A HREF=\"#MortalRaces\">Mortal Races\n");
  fprintf(fp, "</A> | <A HREF=\"#ReincRaces\">Reincarnate Races\n");
  fprintf(fp, "</A> | <A HREF=\"#MortalClasses\">Mortal Classes </A>\n");
  fprintf(fp, "</br>\n");
  fprintf(fp, "<A HREF=\"#raceclassmenu\">\n");
  fprintf(fp, "Races and Classes of Clandestine</A></P></CENTER></FONT>\n");

/* OK the above stuff was easy... the below sections were a total pain
   in the you-know-what.  (Neck of course.)  If you can understand this
   code, you're probably doing better than most people!  The main loops
   in this section are identical to the ones that produced the lists
   earlier on, so if you modified them, you will need to perform 
   similar modifications here. */
/******BEGIN MORTAL RACES SECTION******/
  fprintf(fp, "<hr><h2><center>Mortal Races</center></h2></A><hr>\n");
  for ( i = 1; race_table[i].name != NULL; i++ )
	{
	    if (!race_table[i].pc_race)
		continue;
          if ( !race_table[i].reincarnate_race )
	    {
		/* OK we've decided to create a table for this race.
		   First we do the internal link stuff and set up the
 		   table formatting. */
		under_line(buf3,race_table[i].name);
		sprintf(buf2,"<A NAME=\"%s\"><br></A>",
			buf3);
		fprintf(fp, buf2);
		fprintf(fp, "<CENTER><TABLE BORDER=0 CELLPADDING=2>\n");
		fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\"><td colspan=2>\n");
		sprintf(buf2,"<center><h2>%s</h2></center>",
			race_table[i].name);
		fprintf(fp, buf2);

		/* Now the tricky part.  Let's use a hack of do_help here
		   and grab the information from the help file.  The below
		   loop and associated function took me a full 5 hours to
		   code and debug.  Yeah, I know you coding experts out
		   there could have done it better.  But did you feel as
		   good when you finally got it working?  I think not. 
		   Oh, by the way, those of you who are experts at
		   manipulating strings can probably find some ways to
		   save time here.  I'm no expert, and this works, so
		   to you I say "Thfpbbbbbt!" */
		/* let's store the help info here... */
		output = new_buf();
		/* find the right help item */
		for ( pHelp = help_first; pHelp != NULL; pHelp = pHelp->next )
		{
		 /* we only want the first help keyword to match, otherwise
		    we get Half Dragon when we want Dragon, etc... */
     		 one_argument( pHelp->keyword, buf3 );
		 if ( (buf3[0] != '\0') && !str_cmp( race_table[i].name,
			buf3 ) )
		  {		    
		    /* This is (hopefully) the right help file.  Let's
			 take the help text, pull out what we want, and
			 print it.*/
	 	    add_buf(output,pHelp->text);
		    strcpy(buf, buf_string(output));
		    raceclass_help_strip(buf2, buf, race_table[i].name);	    
		    free_buf(output);
	 	    fprintf(fp, "%s",buf2);
		    break;
		  }
		}
	
		/* OK the hard part's done.  Let's throw in more statistics
		   for this race.  If you don't have the AFF2 code in just
		   delete the aff# statements you don't need. */
		fprintf(fp, "</td></tr><tr><td colspan=2>\n");
		/* Affects */
		fprintf(fp, "Affected by: \n");
		if (	race_table[i].aff || 
			race_table[i].aff2 || 
			race_table[i].aff3 || 
			race_table[i].aff4 || 
			race_table[i].aff5 || 
			race_table[i].aff6 || 
			race_table[i].aff7 || 
			race_table[i].aff8 || 
			race_table[i].aff9 || 
			race_table[i].aff10  )
		  {
		    buf[0] = '\0';
		    /* Each of these, if it returns, will have an extra
			 ", " at the end of it so you can just append them
			 all to each other.  Remove the ", " at the end. */
		    if (race_table[i].aff)
			{
			  un_under_line(buf2,affect_bit_name(race_table[i].aff));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff2)
			{
			  un_under_line(buf2,affect2_bit_name(race_table[i].aff2));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff3)
			{
			  un_under_line(buf2,affect3_bit_name(race_table[i].aff3));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff4)
			{
			  un_under_line(buf2,affect4_bit_name(race_table[i].aff4));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff5)
			{
			  un_under_line(buf2,affect5_bit_name(race_table[i].aff5));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff6)
			{
			  un_under_line(buf2,affect6_bit_name(race_table[i].aff6));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff7)
			{
			  un_under_line(buf2,affect7_bit_name(race_table[i].aff7));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff8)
			{
			  un_under_line(buf2,affect8_bit_name(race_table[i].aff8));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff9)
			{
			  un_under_line(buf2,affect9_bit_name(race_table[i].aff9));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff10)
			{
			  un_under_line(buf2,affect10_bit_name(race_table[i].aff10));
			  strcat(buf, buf2);
			}
		    /* Now kill the ending ", " */
		    if (strlen(buf) > 2)
			buf[strlen(buf)-2] = '\0';
		    fprintf(fp, "%s\n\r", buf);
		  }
		else
		  {
		  fprintf(fp, "no permanent affects.\n\r");
		  }
		fprintf(fp, "</td></tr><tr><td colspan=2>\n");
		/* Skills */
		fprintf(fp, "Skills: \n");
	      buf[0] = '\0';
		/* This is fun.  We have a different table for pc_races and
		   mob/pc combined races.  We need to find the matching one
		   to get the right table.  In case they didn't match because
		   you have a PC race in your normal table that's not in your
		   PC race table your k will point to some other data so
		   always check k before you use it.*/
		for (k = 0; k < MAX_PC_RACE; k++)
		{
		  if (!str_cmp(pc_race_table[k].name,race_table[i].name))
		    break;
		}
		/* Remember to check k here.  And note the 5 in the j
		   loop.  I pulled that out of the merc.h definition
		   for pc_race_type.skills.  Don't know why we don't
		   use a constant there like everywhere else in the code.*/
		if (k < MAX_PC_RACE)
		  for (j = 0; j < 5; j++)
		  {
		    if (pc_race_table[k].skills[j] == NULL)
		 	break;
		    strcat(buf, pc_race_table[k].skills[j]);
		    strcat(buf, ", ");
		  }
		/* Let's get rid of the trailing ", " again */
		if (strlen(buf) > 2)
		  buf[strlen(buf)-2] = '\0';
		else
		  sprintf(buf,"None. ");
		fprintf(fp, "%s\n\r", buf);
		/* I fudged for a while with table widths here.  It appears
		   Netscape makes the columns equal size (50%) regardless
		   of what I put for width here.  Your results may vary. */
		fprintf(fp, "</td></tr><tr><td WIDTH=\"40%%\">\n");
		fprintf(fp, "<TABLE BORDER=0 CELLPADDING=2>\n");
		fprintf(fp, "<tr ALIGN=\"CENTER\"><td VALIGN=\"CENTER\">\n");
		/* Stats header */
		/* If you have other than the 5 standard stats you'll
		   need to change this a bit */
		fprintf(fp, "</td><td>Str</td><td>Int</td><td>Wis</td>");
		fprintf(fp, "<td>Dex</td><td>Con\n");
		fprintf(fp, "</td></tr><tr><td>Base\n");
		/* Stats base */
		if (k < MAX_PC_RACE)
	  	  for (j = 0; j < MAX_STATS; j++)
		    fprintf(fp, "</td><td>%d\n", pc_race_table[k].stats[j] );
		fprintf(fp, "</td></tr><tr><td>Max\n");
		/* Stats max */
		if (k < MAX_PC_RACE)
	  	  for (j = 0; j < MAX_STATS; j++)
		    fprintf(fp, "</td><td>%d\n", pc_race_table[k].max_stats[j] );
		fprintf(fp, "</td></tr></table>\n");
		/* 100% minus 40% is what... */
		fprintf(fp, "</td><td WIDTH=\"60%%\">\n");
		fprintf(fp, "<TABLE BORDER=0 CELLPADDING=2>\n");
		fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\"><td>\n");
		/* This stuff is the same as the affects, only easier */
		/* Immune */
		fprintf(fp, "Immune to: \n");
		if ( race_table[i].imm )
		  {
		    buf[0] = '\0';
		    if (race_table[i].imm)
			{
			  un_under_line(buf2,imm_bit_name(race_table[i].imm));
			  strcat(buf, buf2);
			}
		    if (strlen(buf) > 2)
			buf[strlen(buf)-2] = '\0';
		    fprintf(fp, "%s\n\r", buf);
		  }
		else
		  {
		  fprintf(fp, "no immunities.\n\r");
		  }
		fprintf(fp, "</td></tr><tr><td>\n");
		/* Resistant */
		fprintf(fp, "Resistant to: \n");
		if ( race_table[i].res )
		  {
		    buf[0] = '\0';
		    if (race_table[i].res)
			{
			  un_under_line(buf2,imm_bit_name(race_table[i].res));
			  strcat(buf, buf2);
			}
		    if (strlen(buf) > 2)
			buf[strlen(buf)-2] = '\0';
		    fprintf(fp, "%s\n\r", buf);
		  }
		else
		  {
		  fprintf(fp, "no resistances.\n\r");
		  }
		fprintf(fp, "</td></tr><tr><td>\n");
		/* Vulnerable */
		fprintf(fp, "Vulnerable to: \n");
		if ( race_table[i].vuln )
		  {
		    buf[0] = '\0';
		    if (race_table[i].vuln)
			{
			  un_under_line(buf2,imm_bit_name(race_table[i].vuln));
			  strcat(buf, buf2);
			}
		    if (strlen(buf) > 2)
			buf[strlen(buf)-2] = '\0';
		    fprintf(fp, "%s\n\r", buf);
		  }
		else
		  {
		  fprintf(fp, "no vulnerabilities.\n\r");
		  }
		fprintf(fp, "</td></tr></table>\n");

		/* Hey, that's all I decided to put on my tables.  There
		   is more information available if you want to dig through
		   the type structure and add stuff. */
		fprintf(fp, "</td></tr></TABLE></CENTER>\n");

		/* And of course the links to the various other tables here
		   so your readers don't have to scroll forever. */
		fprintf(fp, "<FONT SIZE=0><CENTER><P><A HREF=\"#MortalRaces\">Mortal Races\n");
		fprintf(fp, "</A> | <A HREF=\"#ReincRaces\">Reincarnate Races\n");
		fprintf(fp, "</A> | <A HREF=\"#MortalClasses\">Mortal Classes\n");
		fprintf(fp, "</A> | <A HREF=\"#ReincClasses\">Reincarnate Classes </A>\n");
		fprintf(fp, "<br><A HREF=\"#raceclassmenu\">\n");
		fprintf(fp, "Races and Classes of Clandestine</A></P></CENTER></FONT><hr>\n");
	    }
	}
/******END MORTAL RACES SECTION******/
/* The Reinc Race section is identical to the Mortal race section
   except for the main loop which has a few boolean variables reversed.
   Sure, I could have probably saved time with some sort of common
   function that both loops could call but it's so much easier to
   just cut and paste the whole thing here.  So take 10 points off
   my grade, I don't care! */
/******BEGIN REINC RACES SECTION******/
  fprintf(fp, "<hr><h2><center>Reincarnate Races</center></h2></A><hr>\n");
  for ( i = 1; race_table[i].name != NULL; i++ )
	{
	    if (!race_table[i].pc_race)
		continue;
	    /* Here's the only change from above.  Delete a "!"! */
          if ( race_table[i].reincarnate_race )
	    {
		/* OK we've decided to create a table for this race.
		   First we do the internal link stuff and set up the
 		   table formatting. */
		under_line(buf3,race_table[i].name);
		sprintf(buf2,"<A NAME=\"%s\"><br></A>",
			buf3);
		fprintf(fp, buf2);
		fprintf(fp, "<CENTER><TABLE BORDER=0 CELLPADDING=2>\n");
		fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\"><td colspan=2>\n");
		sprintf(buf2,"<center><h2>%s</h2></center>",
			race_table[i].name);
		fprintf(fp, buf2);

		/* Now the tricky part.  Let's use a hack of do_help here
		   and grab the information from the help file.  The below
		   loop and associated function took me a full 5 hours to
		   code and debug.  Yeah, I know you coding experts out
		   there could have done it better.  But did you feel as
		   good when you finally got it working?  I think not. 
		   Oh, by the way, those of you who are experts at
		   manipulating strings can probably find some ways to
		   save time here.  I'm no expert, and this works, so
		   to you I say "Thfpbbbbbt!" */
		/* let's store the help info here... */
		output = new_buf();
		/* find the right help item */
		for ( pHelp = help_first; pHelp != NULL; pHelp = pHelp->next )
		{
		 /* we only want the first help keyword to match, otherwise
		    we get Half Dragon when we want Dragon, etc... */
     		 one_argument( pHelp->keyword, buf3 );
		 if ( (buf3[0] != '\0') && !str_cmp( race_table[i].name,
			buf3 ) )
		  {		    
		    /* This is (hopefully) the right help file.  Let's
			 take the help text, pull out what we want, and
			 print it.*/
	 	    add_buf(output,pHelp->text);
		    strcpy(buf, buf_string(output));
		    raceclass_help_strip(buf2, buf, race_table[i].name);	    
		    free_buf(output);
	 	    fprintf(fp, "%s",buf2);
		    break;
		  }
		}
	
		/* OK the hard part's done.  Let's throw in more statistics
		   for this race.  If you don't have the AFF2 code in just
		   delete the aff# statements you don't need. */
		fprintf(fp, "</td></tr><tr><td colspan=2>\n");
		/* Affects */
		fprintf(fp, "Affected by: \n");
		if (	race_table[i].aff || 
			race_table[i].aff2 || 
			race_table[i].aff3 || 
			race_table[i].aff4 || 
			race_table[i].aff5 || 
			race_table[i].aff6 || 
			race_table[i].aff7 || 
			race_table[i].aff8 || 
			race_table[i].aff9 || 
			race_table[i].aff10  )
		  {
		    buf[0] = '\0';
		    /* Each of these, if it returns, will have an extra
			 ", " at the end of it so you can just append them
			 all to each other.  Remove the ", " at the end. */
		    if (race_table[i].aff)
			{
			  un_under_line(buf2,affect_bit_name(race_table[i].aff));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff2)
			{
			  un_under_line(buf2,affect2_bit_name(race_table[i].aff2));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff3)
			{
			  un_under_line(buf2,affect3_bit_name(race_table[i].aff3));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff4)
			{
			  un_under_line(buf2,affect4_bit_name(race_table[i].aff4));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff5)
			{
			  un_under_line(buf2,affect5_bit_name(race_table[i].aff5));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff6)
			{
			  un_under_line(buf2,affect6_bit_name(race_table[i].aff6));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff7)
			{
			  un_under_line(buf2,affect7_bit_name(race_table[i].aff7));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff8)
			{
			  un_under_line(buf2,affect8_bit_name(race_table[i].aff8));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff9)
			{
			  un_under_line(buf2,affect9_bit_name(race_table[i].aff9));
			  strcat(buf, buf2);
			}
		    if (race_table[i].aff10)
			{
			  un_under_line(buf2,affect10_bit_name(race_table[i].aff10));
			  strcat(buf, buf2);
			}
		    /* Now kill the ending ", " */
		    if (strlen(buf) > 2)
			buf[strlen(buf)-2] = '\0';
		    fprintf(fp, "%s\n\r", buf);
		  }
		else
		  {
		  fprintf(fp, "no permanent affects.\n\r");
		  }
		fprintf(fp, "</td></tr><tr><td colspan=2>\n");
		/* Skills */
		fprintf(fp, "Skills: \n");
	      buf[0] = '\0';
		/* This is fun.  We have a different table for pc_races and
		   mob/pc combined races.  We need to find the matching one
		   to get the right table.  In case they didn't match because
		   you have a PC race in your normal table that's not in your
		   PC race table your k will point to some other data so
		   always check k before you use it.*/
		for (k = 0; k < MAX_PC_RACE; k++)
		{
		  if (!str_cmp(pc_race_table[k].name,race_table[i].name))
		    break;
		}
		/* Remember to check k here.  And note the 5 in the j
		   loop.  I pulled that out of the merc.h definition
		   for pc_race_type.skills.  Don't know why we don't
		   use a constant there like everywhere else in the code.*/
		if (k < MAX_PC_RACE)
		  for (j = 0; j < 5; j++)
		  {
		    if (pc_race_table[k].skills[j] == NULL)
		 	break;
		    strcat(buf, pc_race_table[k].skills[j]);
		    strcat(buf, ", ");
		  }
		/* Let's get rid of the trailing ", " again */
		if (strlen(buf) > 2)
		  buf[strlen(buf)-2] = '\0';
		else
		  sprintf(buf,"None. ");
		fprintf(fp, "%s\n\r", buf);
		/* I fudged for a while with table widths here.  It appears
		   Netscape makes the columns equal size (50%) regardless
		   of what I put for width here.  Your results may vary. */
		fprintf(fp, "</td></tr><tr><td WIDTH=\"40%%\">\n");
		fprintf(fp, "<TABLE BORDER=0 CELLPADDING=2>\n");
		fprintf(fp, "<tr ALIGN=\"CENTER\"><td VALIGN=\"CENTER\">\n");
		/* Stats header */
		/* If you have other than the 5 standard stats you'll
		   need to change this a bit */
		fprintf(fp, "</td><td>Str</td><td>Int</td><td>Wis</td>");
		fprintf(fp, "<td>Dex</td><td>Con\n");
		fprintf(fp, "</td></tr><tr><td>Base\n");
		/* Stats base */
		if (k < MAX_PC_RACE)
	  	  for (j = 0; j < MAX_STATS; j++)
		    fprintf(fp, "</td><td>%d\n", pc_race_table[k].stats[j] );
		fprintf(fp, "</td></tr><tr><td>Max\n");
		/* Stats max */
		if (k < MAX_PC_RACE)
	  	  for (j = 0; j < MAX_STATS; j++)
		    fprintf(fp, "</td><td>%d\n", pc_race_table[k].max_stats[j] );
		fprintf(fp, "</td></tr></table>\n");
		/* 100% minus 40% is what... */
		fprintf(fp, "</td><td WIDTH=\"60%%\">\n");
		fprintf(fp, "<TABLE BORDER=0 CELLPADDING=2>\n");
		fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\"><td>\n");
		/* This stuff is the same as the affects, only easier */
		/* Immune */
		fprintf(fp, "Immune to: \n");
		if ( race_table[i].imm )
		  {
		    buf[0] = '\0';
		    if (race_table[i].imm)
			{
			  un_under_line(buf2,imm_bit_name(race_table[i].imm));
			  strcat(buf, buf2);
			}
		    if (strlen(buf) > 2)
			buf[strlen(buf)-2] = '\0';
		    fprintf(fp, "%s\n\r", buf);
		  }
		else
		  {
		  fprintf(fp, "no immunities.\n\r");
		  }
		fprintf(fp, "</td></tr><tr><td>\n");
		/* Resistant */
		fprintf(fp, "Resistant to: \n");
		if ( race_table[i].res )
		  {
		    buf[0] = '\0';
		    if (race_table[i].res)
			{
			  un_under_line(buf2,imm_bit_name(race_table[i].res));
			  strcat(buf, buf2);
			}
		    if (strlen(buf) > 2)
			buf[strlen(buf)-2] = '\0';
		    fprintf(fp, "%s\n\r", buf);
		  }
		else
		  {
		  fprintf(fp, "no resistances.\n\r");
		  }
		fprintf(fp, "</td></tr><tr><td>\n");
		/* Vulnerable */
		fprintf(fp, "Vulnerable to: \n");
		if ( race_table[i].vuln )
		  {
		    buf[0] = '\0';
		    if (race_table[i].vuln)
			{
			  un_under_line(buf2,imm_bit_name(race_table[i].vuln));
			  strcat(buf, buf2);
			}
		    if (strlen(buf) > 2)
			buf[strlen(buf)-2] = '\0';
		    fprintf(fp, "%s\n\r", buf);
		  }
		else
		  {
		  fprintf(fp, "no vulnerabilities.\n\r");
		  }
		fprintf(fp, "</td></tr></table>\n");

		/* Hey, that's all I decided to put on my tables.  There
		   is more information available if you want to dig through
		   the type structure and add stuff. */
		fprintf(fp, "</td></tr></TABLE></CENTER>\n");

		/* And of course the links to the various other tables here
		   so your readers don't have to scroll forever. */
		fprintf(fp, "<FONT SIZE=0><CENTER><P><A HREF=\"#MortalRaces\">Mortal Races\n");
		fprintf(fp, "</A> | <A HREF=\"#ReincRaces\">Reincarnate Races\n");
		fprintf(fp, "</A> | <A HREF=\"#MortalClasses\">Mortal Classes\n");
		fprintf(fp, "</A> | <A HREF=\"#ReincClasses\">Reincarnate Classes </A>\n");
		fprintf(fp, "<br><A HREF=\"#raceclassmenu\">\n");
		fprintf(fp, "Races and Classes of Clandestine</A></P></CENTER></FONT><hr>\n");
	    }
	}
/******END REINC RACES SECTION******/
/* We do a similar thing for classes, except the information in the
   table is different.  The headers and help info is the same. */
/******BEGIN MORTAL CLASS SECTION******/
  fprintf(fp, "<hr><h2><center>Mortal Classes</center></h2></A><hr>\n");
  for ( i = 0; i < MAX_CLASS; i++ )
	{
        if (!class_table[i].reincarnate_class )
	    {
		/* The links and header are pretty much the same as for
		   races, names changed to protect the innocent */
		under_line(buf3,class_table[i].name);
		sprintf(buf2,"<A NAME=\"%s\"><br></A>",
			buf3);
		fprintf(fp, buf2);
		fprintf(fp, "<CENTER><TABLE BORDER=0 CELLPADDING=2>\n");
		fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\"><td>\n");
		sprintf(buf2,"<center><h2>%s</h2></center>",
			class_table[i].name);
		fprintf(fp, buf2);

		output = new_buf();
		for ( pHelp = help_first; pHelp != NULL; pHelp = pHelp->next )
		{

     		one_argument( pHelp->keyword, buf3 );
		if ( (buf3[0] != '\0') && !str_cmp( class_table[i].name,
			buf3 ) )
		  {		    
	 	    add_buf(output,pHelp->text);
		    strcpy(buf, buf_string(output));
		    raceclass_help_strip(buf2, buf, class_table[i].name);	    
		    free_buf(output);
	 	    fprintf(fp, "%s",buf2);
		    break;
		  }
		}

		fprintf(fp, "<ul>\n");
		/* Different info in class table from race table... 
		   this should be self explanatory. */
		/* Primary Statistic */
		fprintf(fp, "<li>Primary Statistic: \n");
		switch ( class_table[i].attr_prime )
		{
		  case STAT_STR: fprintf(fp, "Strength\n\r"); break;
		  case STAT_INT: fprintf(fp, "Intelligence\n\r"); break;
		  case STAT_WIS: fprintf(fp, "Wisdom\n\r"); break;
		  case STAT_DEX: fprintf(fp, "Dexterity\n\r"); break;
		  case STAT_CON: fprintf(fp, "Constitution\n\r"); break;
		}		    
		fprintf(fp, "</li>\n");
		/* Here we could link to the basic/default lists on
		   skills and spells page, but better for user to
		   see the info here.  We'll link for spell groups
		   though.  The loop to create this list, of course,
		   is stolen from webspells.c.  Webspells.c must be
		   in use for these links to work. */
		/* Basic Skills */
		fprintf(fp, "<li>Basic Skills: \n");
		sprintf(buf3,"%s basics",class_table[i].name);
		for (gn = 0; gn < MAX_GROUP; gn++)
		{
	    	  if (group_table[gn].name == NULL)
		    break;
	    	  if (!str_cmp(group_table[gn].name,buf3))
		  {
		    /* Print the skills in the group */	    
		    buf[0] = '\0';  
		    for ( sn = 0; sn < MAX_IN_GROUP; sn++)
		    {
		        if (group_table[gn].spells[sn] == NULL)
		            break;
			  k = skill_lookup(group_table[gn].spells[sn]);
			  if (k != -1) 
			  /* a skill, no link */
			  {
				sprintf(buf2,"%s, ",group_table[gn].spells[sn]);
			  }
			  else
			  /* not a skill, link to spell group */
			  {
				under_line(buf3,group_table[gn].spells[sn]);
				sprintf(buf2,"<A HREF=\"./spells.html#%s\">%s</A>, ",
					buf3,
					group_table[gn].spells[sn]);
			  }
			  strcat(buf, buf2);
		    }
		    if ((buf[0] != '\0') && (strlen(buf) > 2))
			buf[(strlen(buf)-2)] = '\0'; /* remove last ", " */
		    else
			strcpy(buf, "None");
		    break;
		  }
		}
 	      fprintf(fp, "%s",buf);
		fprintf(fp, "</li>\n");

		/* Default Skills */
		fprintf(fp, "<li>Default Skills and Spell Groups: \n");
		sprintf(buf3,"%s default",class_table[i].name);
		for (gn = 0; gn < MAX_GROUP; gn++)
		{
	    	  if (group_table[gn].name == NULL)
		    break;
	    	  if (!str_cmp(group_table[gn].name,buf3))
		  {
		    /* Print the skills in the group */	    
		    buf[0] = '\0';  
		    for ( sn = 0; sn < MAX_IN_GROUP; sn++)
		    {
		        if (group_table[gn].spells[sn] == NULL)
		            break;
			  k = skill_lookup(group_table[gn].spells[sn]);
			  if (k != -1) 
			  /* a skill, no link */
			  {
				sprintf(buf2,"%s, ",group_table[gn].spells[sn]);
			  }
			  else
			  /* not a skill, link to spell group */
			  {
				under_line(buf3,group_table[gn].spells[sn]);
				sprintf(buf2,"<A HREF=\"./spells.html#%s\">%s</A>, ",
					buf3,
					group_table[gn].spells[sn]);
			  }
			  strcat(buf, buf2);
		    }
		    if ((buf[0] != '\0') && (strlen(buf) > 2))
			buf[(strlen(buf)-2)] = '\0'; /* remove last ", " */
		    else
			strcpy(buf, "None");
		    break;
		  }
		}
 	      fprintf(fp, "%s",buf);
		fprintf(fp, "</li></ul>\n");
		fprintf(fp, "</td></tr></TABLE></CENTER>\n");

		/* Don't forget yer links. */
		fprintf(fp, "<FONT SIZE=0><CENTER><P><A HREF=\"#MortalRaces\">Mortal Races\n");
		fprintf(fp, "</A> | <A HREF=\"#ReincRaces\">Reincarnate Races\n");
		fprintf(fp, "</A> | <A HREF=\"#MortalClasses\">Mortal Classes\n");
		fprintf(fp, "</A> | <A HREF=\"#ReincClasses\">Reincarnate Classes </A>\n");
		fprintf(fp, "<br><A HREF=\"#raceclassmenu\">\n");
		fprintf(fp, "Races and Classes of Clandestine</A></P></CENTER></FONT><hr>\n");
	    }
	}
/******END MORTAL CLASS SECTION******/
/* And now the same thing again with one minor change */
/******BEGIN REINC CLASS SECTION******/
  fprintf(fp, "<hr><h2><center>Reincarnate Classes</center></h2></A><hr>\n");
  for ( i = 0; i < MAX_CLASS; i++ )
	{
	  /* The minor change goes right here!*/
        if (class_table[i].reincarnate_class )
	    {
		/* The links and header are pretty much the same as for
		   races, names changed to protect the innocent */
		under_line(buf3,class_table[i].name);
		sprintf(buf2,"<A NAME=\"%s\"><br></A>",
			buf3);
		fprintf(fp, buf2);
		fprintf(fp, "<CENTER><TABLE BORDER=0 CELLPADDING=2>\n");
		fprintf(fp, "<tr ALIGN=\"LEFT\" VALIGN=\"CENTER\"><td>\n");
		sprintf(buf2,"<center><h2>%s</h2></center>",
			class_table[i].name);
		fprintf(fp, buf2);

		output = new_buf();
		for ( pHelp = help_first; pHelp != NULL; pHelp = pHelp->next )
		{

     		one_argument( pHelp->keyword, buf3 );
		if ( (buf3[0] != '\0') && !str_cmp( class_table[i].name,
			buf3 ) )
		  {		    
	 	    add_buf(output,pHelp->text);
		    strcpy(buf, buf_string(output));
		    raceclass_help_strip(buf2, buf, class_table[i].name);	    
		    free_buf(output);
	 	    fprintf(fp, "%s",buf2);
		    break;
		  }
		}
	
		fprintf(fp, "<ul>\n");
		/* Different info in class table from race table... 
		   this should be self explanatory. */
		/* Primary Statistic */
		fprintf(fp, "<li>Primary Statistic: \n");
		switch ( class_table[i].attr_prime )
		{
		  case STAT_STR: fprintf(fp, "Strength\n\r"); break;
		  case STAT_INT: fprintf(fp, "Intelligence\n\r"); break;
		  case STAT_WIS: fprintf(fp, "Wisdom\n\r"); break;
		  case STAT_DEX: fprintf(fp, "Dexterity\n\r"); break;
		  case STAT_CON: fprintf(fp, "Constitution\n\r"); break;
		}		    
		fprintf(fp, "</li>\n");
		/* Here we could link to the basic/default lists on
		   skills and spells page, but better for user to
		   see the info here.  We'll link for spell groups
		   though.  The loop to create this list, of course,
		   is stolen from webspells.c.  Webspells.c must be
		   in use for these links to work. */
		/* Basic Skills */
		fprintf(fp, "<li>Basic Skills: \n");
		sprintf(buf3,"%s basics",class_table[i].name);
		for (gn = 0; gn < MAX_GROUP; gn++)
		{
	    	  if (group_table[gn].name == NULL)
		    break;
	    	  if (!str_cmp(group_table[gn].name,buf3))
		  {
		    /* Print the skills in the group */	    
		    buf[0] = '\0';  
		    for ( sn = 0; sn < MAX_IN_GROUP; sn++)
		    {
		        if (group_table[gn].spells[sn] == NULL)
		            break;
			  k = skill_lookup(group_table[gn].spells[sn]);
			  if (k != -1) 
			  /* a skill, no link */
			  {
				sprintf(buf2,"%s, ",group_table[gn].spells[sn]);
			  }
			  else
			  /* not a skill, link to spell group */
			  {
				under_line(buf3,group_table[gn].spells[sn]);
				sprintf(buf2,"<A HREF=\"./spells.html#%s\">%s</A>, ",
					buf3,
					group_table[gn].spells[sn]);
			  }
			  strcat(buf, buf2);
		    }
		    if ((buf[0] != '\0') && (strlen(buf) > 2))
			buf[(strlen(buf)-2)] = '\0'; /* remove last ", " */
		    else
			strcpy(buf, "None");
		    break;
		  }
		}
 	      fprintf(fp, "%s",buf);
		fprintf(fp, "</li>\n");

		/* Default Skills */
		fprintf(fp, "<li>Default Skills and Spell Groups: \n");
		sprintf(buf3,"%s default",class_table[i].name);
		for (gn = 0; gn < MAX_GROUP; gn++)
		{
	    	  if (group_table[gn].name == NULL)
		    break;
	    	  if (!str_cmp(group_table[gn].name,buf3))
		  {
		    /* Print the skills in the group */	    
		    buf[0] = '\0';  
		    for ( sn = 0; sn < MAX_IN_GROUP; sn++)
		    {
		        if (group_table[gn].spells[sn] == NULL)
		            break;
			  k = skill_lookup(group_table[gn].spells[sn]);
			  if (k != -1) 
			  /* a skill, no link */
			  {
				sprintf(buf2,"%s, ",group_table[gn].spells[sn]);
			  }
			  else
			  /* not a skill, link to spell group */
			  {
				under_line(buf3,group_table[gn].spells[sn]);
				sprintf(buf2,"<A HREF=\"./spells.html#%s\">%s</A>, ",
					buf3,
					group_table[gn].spells[sn]);
			  }
			  strcat(buf, buf2);
		    }
		    if ((buf[0] != '\0') && (strlen(buf) > 2))
			buf[(strlen(buf)-2)] = '\0'; /* remove last ", " */
		    else
			strcpy(buf, "None");
		    break;
		  }
		}
 	      fprintf(fp, "%s",buf);
		fprintf(fp, "</li></ul>\n");
		fprintf(fp, "</td></tr></TABLE></CENTER>\n");

		/* Don't forget yer links. */
		fprintf(fp, "<FONT SIZE=0><CENTER><P><A HREF=\"#MortalRaces\">Mortal Races\n");
		fprintf(fp, "</A> | <A HREF=\"#ReincRaces\">Reincarnate Races\n");
		fprintf(fp, "</A> | <A HREF=\"#MortalClasses\">Mortal Classes\n");
		fprintf(fp, "</A> | <A HREF=\"#ReincClasses\">Reincarnate Classes </A>\n");
		fprintf(fp, "<br><A HREF=\"#raceclassmenu\">\n");
		fprintf(fp, "Races and Classes of Clandestine</A></P></CENTER></FONT><hr>\n");
	    }
	}
/******END REINC CLASS SECTION******/

  fprintf(fp, "<font face=\"Times New Roman\"><center>\n");
  sprintf(buf, "This file last updated at %s Eastern Time.\n", ((char *) ctime( &current_time )));
  fprintf(fp, buf);
  fprintf(fp, "</center></font>\n");

  /* One final link to the top page, change if you want */
  fprintf(fp, "<br><br>\n");
  fprintf(fp, "<CENTER><P><A HREF=\"./\" TARGET=\"_top\"><Font Size=+1>\n");
  fprintf(fp, "The Official Clandestine Homepage</A> </P></CENTER></Font>\n");

  fprintf(fp, "</body>\n");
  fprintf(fp, "</html>\n");
  fclose( fp ); 
  fpReserve = fopen( NULL_FILE, "r" );
  } /*end if */ 
  return;
}/* end function */


