tfe-1.0/area/
tfe-1.0/files/
tfe-1.0/logs/
tfe-1.0/logs/immortal/
tfe-1.0/logs/mob/
tfe-1.0/logs/object/
tfe-1.0/logs/player/
tfe-1.0/logs/room/
tfe-1.0/notes/clans/
tfe-1.0/player/
tfe-1.0/prev/
tfe-1.0/prev/area/
tfe-1.0/prev/player/
tfe-1.0/prev/rooms/
tfe-1.0/rooms/
tfe-1.0/src-gc/
tfe-1.0/src-msvc/
tfe-1.0/src-unix/
tfe-1.0/www/
tfe-1.0/www/html/
#include "ctype.h"
#include "stdio.h"
#include "stdlib.h"
#include "sys/types.h"
#include <syslog.h>
#include "define.h"
#include "struct.h"


#define HELP_IMMORTAL         0
#define HELP_SPELLS           1
#define HELP_FUNCTIONS        2
#define HELP_LOGIN            3


help_data**      help_list;
int               max_help;
bool         help_modified  = TRUE;


void         spell_help      ( char_data*, int );
void         make_w3         ( help_data* help );


/*
 *   HELP_DATA CLASS
 */


class Help_Data
{
 public:
  char*      name;
  char*      text;
  char*  immortal;
  int       level  [ 2 ];
  int    category;

  Help_Data   ( );
  ~Help_Data  ( );

  friend char* name( help_data* help ) {
    return help->name;
    }
};


Help_Data :: Help_Data( )
{
  record_new( sizeof( help_data ), MEM_HELP );

  name      = (char*) empty_string;
  text      = (char*) empty_string;
  immortal  = (char*) empty_string;
  level[0]  = 0;
  level[1]  = 0;
  category  = 0;
}


Help_Data :: ~Help_Data( )
{
  int pos;

  record_delete( sizeof( help_data ), MEM_HELP ); 
  free_string( name, MEM_HELP );
  free_string( text, MEM_HELP );
  free_string( immortal, MEM_HELP );

  for( pos = 0; pos < max_help; pos++ )
    if( help_list[pos] == this ) {
      remove( help_list, max_help, pos );
      break;
      }
}


/*
 *   READ/WRITE ROUTINES
 */


void load_helps( void )
{
  help_data*  help;
  FILE*         fp;
  int          pos;

  echo( "Loading Help ...\n\r" );

  help_list = NULL;
  max_help  = 0;

  fp = open_file( HELP_FILE, "r" );

  if( strcmp( fread_word( fp ), "#HELPS" ) ) 
    panic( "Load_helps: missing header" );

  for( ; ; ) {
    help           = new help_data;
    help->level[0] = fread_number( fp );
    help->level[1] = fread_number( fp );
    help->category = fread_number( fp );
    help->name     = fread_string( fp, MEM_HELP );

    if( *help->name == '$' ) {
      delete help;
      break;
      }

    help->text     = fread_string( fp, MEM_HELP );
    help->immortal = fread_string( fp, MEM_HELP );  

    pos = pntr_search( help_list, max_help, help->name );

    if( pos < 0 )
      pos = -pos-1;

    insert( help_list, max_help, help, pos );
    }

  fclose( fp );
}


bool save_help( char_data* ch )
{
  char         buf  [ TWO_LINES ];
  help_data*  help;
  FILE*         fp;
  int          pos;

  if( !help_modified ) 
    return FALSE;

  if( ( fp = open_file( HELP_FILE, "w" ) ) == NULL )
    return FALSE;

  fprintf( fp, "#HELPS\n" );

  for( pos = 0; pos < max_help; pos++ ) {
    help = help_list[pos];
    fprintf( fp, "%d %d %d %s~\n", help->level[0], help->level[1],
      help->category, help->name );
    fprintf( fp, ".%s~\n\n", help->text );
    fprintf( fp, ".%s~\n\n", help->immortal );
    }
  fprintf( fp, "-1 -1 -1 $~\n" );
  fclose( fp );

  help_modified = FALSE;

  if( ch != NULL ) {
    send( ch, "Help file written.\n\r" );
    sprintf( buf, "Help file written (%s).", ch->real_name() );
    info( "", LEVEL_HELP, buf, IFLAG_WRITES, 1, ch );
    }

  return TRUE;
}


/*
 *   W3 ROUTINES
 */


void smash_color( char* tmp )
{
  int i;
  int j;

  for( i = j = 0; tmp[i] != '\0'; i++ ) {
    if( tmp[i] == '\n' || tmp[i] == '\r' ) 
      continue;
    if( tmp[i] == '@' ) {
      if( tmp[++i] == '\0' )
        break;
      if( tmp[i] != '@' ) 
        continue;
      }
    if( tmp[i] == '<' ) 
      tmp[j++] = '[';
    else if( tmp[i] == '>' ) 
      tmp[j++] = ']';
    else
      tmp[j++] = tmp[i];    
    }

  tmp[j] = '\0';

  return;
}


void w3_help( )
{
  char    tmp  [ FOUR_LINES ];
  int       i;
  int     pos;
  FILE*    fp;

  sprintf( tmp, "%shelp/index.html", W3_DIR );

  if( ( fp = open_file( tmp, "w" ) ) == NULL )
    return;

  fprintf( fp, "<html>\n" );
  fprintf( fp, "<body>\n" );

  for( i = 0; i < MAX_ENTRY_HELP_CAT; i++ ) {
    sprintf( tmp, "./%s/index.html", help_cat_table[i].name );
    smash_spaces( tmp );    
    fprintf( fp, "<p><a href=\"%s\"> %s </a></p>\n",
      tmp, help_cat_table[i].name );
    sprintf( tmp, "mkdir %shelp/%s/", W3_DIR, help_cat_table[i].name );
    smash_spaces( &tmp[6] );    
    system( tmp );
    }

  fprintf( fp, "</html>\n" );
  fprintf( fp, "</body>\n" );
  
  fclose( fp );

  for( i = 0; i < MAX_ENTRY_HELP_CAT; i++ ) {
    sprintf( tmp, "%shelp/%s/index.html", W3_DIR, help_cat_table[i].name );
    smash_spaces( tmp );

    if( ( fp = fopen( tmp, "w" ) ) == NULL ) {
      bug( "W3_Help: Fopen error" );
      return;
      }

    fprintf( fp, "<html>\n" );
    fprintf( fp, "<body>\n" );

    for( pos = 0; pos < max_help; pos++ ) {
      if( help_list[pos]->category == i ) {
        sprintf( tmp, "./%s", help_list[pos]->name );
        smash_spaces( tmp );
        fprintf( fp, "<p><a href=\"%s\"> %s </a></p>\n",
          tmp, help_list[pos]->name );
        }
      }

    fprintf( fp, "</html>\n" );
    fprintf( fp, "</body>\n" );
  
    fclose( fp );
    }

  for( pos = 0; pos < max_help; pos++ ) 
    make_w3( help_list[pos] );
    
  return;
}


void make_w3( help_data* help )
{
  char     tmp  [ FOUR_LINES ];
  char*  input;
  FILE*     fp;

  sprintf( tmp, "%shelp/%s/%s", W3_DIR,
    help_cat_table[ help->category ].name, help->name );
  smash_spaces( tmp );

  if( ( fp = fopen( tmp, "w" ) ) == NULL ) {
    bug( "Make_W3( help ): Fopen error" );
    return;
    }

  fprintf( fp, "<html>\n" );
  fprintf( fp, "<body>\n" );

  for( input = help->text; *input != '\0'; ) {
    input = one_line( input, tmp );
    smash_color( tmp );
    if( !strcasecmp( tmp, "Syntax" ) ) 
      fprintf( fp, "<h1> Syntax </h1>\n" );
    else if( !strcasecmp( tmp, "Description" ) ) 
      fprintf( fp, "<h1> Description </h1>\n" );
    else 
      fprintf( fp, "%s<br>\n", tmp );
    }

  fprintf( fp, "</html>\n" );
  fprintf( fp, "</body>\n" );
  
  fclose( fp );

  return;
}


/*
 *   FIND_HELP ROUTINE
 */


bool can_read( char_data* ch, help_data* help )
{
  return has_permission( ch, help->level );
}



help_data* find_help( char_data* ch, const char* argument )
{
  help_data*        help;
  int              first  = -2;
  int                pos;

  if( number_arg( argument, pos ) ) {
    if( pos < 0 || pos >= max_help ) {
      send( ch, "There is no help file with that index.\n\r" ); 
      return NULL;
      }
    if( !can_read( ch, help_list[pos] ) ) {
      send( ch, "You do not have the required permission.\n\r" );
      return NULL;
      }
    return help_list[pos];
    }

  pos = pntr_search( help_list, max_help, argument );

  if( pos >= 0 ) {
    if( can_read( ch, help_list[pos] ) )
      return help_list[pos];
    pos++;
    }
  else
    pos = -pos-1;

  for( ; pos < max_help; pos++ ) {
    help = help_list[pos];
    if( !fmatches( argument, help->name ) )
      break;
    if( can_read( ch, help ) ) {
      if( first != -2 ) {
        if( first != -1 ) {
          page( ch, "More than one match was found - please be more\
 specific in what topic you\n\rwant help on.\n\r\n\r" );
          page( ch, "  [%3d] %s:%15s%s\n\r", first,
            help_cat_table[help_list[first]->category].name, "",
            help_list[first]->name );
          first = -1;
          }
        page( ch, "  [%3d] %s:%15s%s\n\r", pos,
          help_cat_table[help->category].name, "", help->name );
        }
      else {
        first = pos;
        }
      }
    }

  if( first >= 0 )
    return help_list[first];

  if( first == -2 )
    send( ch, "No matching help file was found - use index to see a list of\
 topics for\n\rwhich help exists.\n\r" );
      
  return NULL;
}


/*
 *   MAIN HELP ROUTINE
 */


void do_help( char_data* ch, char* argument )
{
  char          tmp  [ 3*MAX_STRING_LENGTH ];
  help_data*   help;
  int             i;
  int        length  = strlen( argument );

  if( pet_help( ch ) || ch->link == NULL )
    return;
  
  if( ( help = find_help( ch,
    *argument == '\0' ? "summary" : argument ) ) == NULL ) 
    return;

  if( ch->link->connected != CON_PLAYING ) {
    send( ch, help->text );
    return;
    }

  if( help->category == HELP_SPELLS ) 
    for( i = 0; i < MAX_SPELL; i++ ) 
      if( !strncasecmp( spell_table[i].name, argument, length ) ) {
        spell_help( ch, i );
        return;
        }
 
  page( ch, "Topic: %s\n\r", help->name );

  if( is_builder( ch ) ) {
    strcpy( tmp, "Level: " );
    permission_flags.sprint( &tmp[7], help->level );
    strcat( tmp, "\n\r" );
    page( ch, tmp );
    }

  page( ch, "\n\r" );
  convert_to_ansi( ch, help->text, tmp );
  page( ch, tmp );

  if( help->immortal != empty_string && is_builder( ch ) ) {
    page( ch, "\n\r" );
    convert_to_ansi( ch, help->immortal, tmp );
    page( ch, tmp );
    }

  return;
}


void help_link( link_data* link, const char* argument )
{
  char         tmp  [ 3*MAX_STRING_LENGTH ];
  int          pos;

  pos = pntr_search( help_list, max_help, argument );

  if( pos < 0 ) {
    send( link, "Help subject %s not found.\n\r", argument );
    }
  else if( link->player != NULL && link->player->pcdata != NULL ) {
    convert_to_ansi( link->player, help_list[pos]->text, tmp );
    if( link->connected == CON_PLAYING )
      page( link->player, tmp );
    else
      send( link, tmp );
    }
  else {
    send( link, help_list[pos]->text );
    }

  return;
}


void do_motd( char_data* ch, char* )
{
  do_help( ch, "motd" );
  return;  
}


/*
 *   INDEX COMMAND
 */


void do_index( char_data* ch, char* argument )
{
  char           tmp  [ MAX_STRING_LENGTH ];
  int         length  = strlen( argument ); 
  help_data*    help;
  int           i, j;
  int            pos;
  int          trust  = get_trust( ch );

  if( *argument =='\0' ) {
    page_title( ch, "Help Categories" );
    for( i = j = 0; i < MAX_ENTRY_HELP_CAT; i++ ) 
      if( help_cat_table[i].level <= trust ) {
        sprintf( tmp, "%18s%s", help_cat_table[i].name,
          (j++)%4 != 3 ? "" : "\n\r" );
        page( ch, tmp );
        }
    page( ch, "\n\r%s", j%4 != 0 ? "\n\r" : "" );
    page_centered( ch, "[ Type index <category> to see a list of help\
 files in that category. ]" );
    return;
    }

  for( i = 0; i < MAX_ENTRY_HELP_CAT; i++ ) 
    if( help_cat_table[i].level <= trust
      && !strncasecmp( argument, help_cat_table[i].name, length ) ) 
      break;

  if( i == MAX_ENTRY_HELP_CAT ) {
    send( ch, "Unknown help category.\n\r" );
    return;
    }

  page_title( ch, "Help Files - %s", help_cat_table[i].name );      

  for( j = 0, pos = 0; pos < max_help; pos++ ) {
    help = help_list[pos];
    if( help->category != i || !can_read( ch, help ) )
      continue;
    page( ch, "%18s%s", help->name, ++j%4 ? "" : "\n\r" );
    }
  if( j%4 != 0 )
    page( ch, "\n\r" );
  page( ch, "\n\r" );
  page_centered( ch, "[ Type help <file> to read a help file. ]" );

  return;
}


/*
 *   ONLINE EDITING OF HELP
 */


void do_hedit( char_data *ch, char *argument )
{
  help_data*    help  = ch->pcdata->help_edit;
  wizard_data*   imm;
  int            pos;  

  if( *argument == '\0' ) {
    send( ch, "What help file do you wish to edit?\n\r" );
    return;
    }

  if( !strncasecmp( argument, "delete", 6 ) ) {
    if( help == NULL ) {
      send( ch, "You aren't editing any help file.\n\r" );
      return;
      }
    for( int i = 0; i < player_list; i++ ) {
      if( ( imm = wizard( player_list[i] ) ) != NULL
        && imm->Is_Valid( )
        && imm->pcdata->help_edit == help && imm != ch ) {
        send( ch, "The help file you are editing was just deleted.\n\r" );
        imm->pcdata->help_edit = NULL;
        }
      }
    help_modified         = TRUE;
    ch->pcdata->help_edit = NULL;
    send( ch, "Help file '%s' removed.\n\r", help->name );
    delete help;
    return; 
    }

  if( !strncasecmp( argument, "new ", 4 ) ) {
    argument += 4;
    if( argument[0] == '\0' ) {
      send( "On what subject do you want to create a help?\n\r", ch );
      return;
      }
    help        = new help_data;
    help->name  = alloc_string( argument, MEM_HELP );

    pos = pntr_search( help_list, max_help, "blank" );
    if( pos >= 0 ) 
      help->text = alloc_string( help_list[pos]->text, MEM_HELP );
    else
      help->text = (char*) empty_string;

    pos = pntr_search( help_list, max_help, argument );

    if( pos < 0 )
      pos = -pos-1;

    insert( help_list, max_help, help, pos );
    ch->pcdata->help_edit = help;
    send( "Help subject created.\n\r", ch );
    help_modified = TRUE;
    return;
    }

  if( ( help = find_help( ch, argument ) ) == NULL ) 
    return;

  ch->pcdata->help_edit = help;
  send( ch, "Hdesc and hset now operate on %s.\n\r", help->name );
}  


void do_hdesc( char_data *ch, char *argument ) 
{
  help_data* help = ch->pcdata->help_edit;

  if( help == NULL ) {
    send( ch, "You are not editing any subject.\n\r" );
    return;
    }

  help->text    = edit_string( ch, argument, help->text, MEM_HELP );
  help_modified = TRUE;
}


void do_hbug( char_data* ch, char* argument ) 
{
  help_data* help = ch->pcdata->help_edit;

  if( help == NULL ) {
    send( ch, "You are not editing any subject.\n\r" );
    return;
    }

  help->immortal = edit_string( ch, argument, help->immortal, MEM_HELP );
  help_modified  = TRUE;
}


void do_hset( char_data *ch, char *argument )
{
  help_data*   help  = ch->pcdata->help_edit;

  if( help == NULL ) {
    send( ch, "You are not editing any subject.\n\r" );
    return;
    }

  if( *argument == '\0' ) {
    send( ch, "Syntax: hset <field> <value>\n\r" );
    return;
    }

  help_modified = TRUE;

  if( matches( argument, "level" ) ) {
    permission_flags.set( ch, argument, help->level );
    return;
    }

#define hcn( i )   help_cat_table[i].name

  class type_field type_list[] = {
    { "category",  MAX_ENTRY_HELP_CAT,  &hcn(0),  &hcn(1),  &help->category },
    { "",          0,                   NULL,     NULL,     NULL            }
    };

#undef hcn

  if( process( type_list, ch, help->name, argument ) )
    return;

  if( matches( argument, "name" ) ) {
    if( *argument == '\0' ) {
      send( ch, "What do you want to set the help name to?\n\r" );
      return;
      }
    send( ch, "Help name changed from %s to %s.\n\r",
      help->name, argument );
    free_string( help->name, MEM_HELP );
    help->name = alloc_string( argument, MEM_HELP );
    return;
    }
 
  send( ch, "See help hset.\n\r" );
}


/*
 *  FUNCTION HELP
 */


void do_functions( char_data* ch, char* argument )
{
  char     tmp  [ MAX_STRING_LENGTH ];
  char     buf  [ MAX_STRING_LENGTH ];
  bool   found  = FALSE;
  int   length  = strlen( argument );
  int      pos;

  pos = pntr_search( help_list, max_help, argument );
  
  if( pos >= 0 && help_list[pos]->category == HELP_FUNCTIONS ) {
    convert_to_ansi( ch, help_list[pos]->text, buf );
    page( ch, buf );
    return;
    }

  for( int i = 0; cfunc_list[i].name[0] != '\0'; i++ ) {
    if( strncasecmp( argument, cfunc_list[i].name, length ) )
      continue;
    if( !found ) {
      found = TRUE;
      sprintf( tmp, "%-15s %-45s %s\n\r",
        "Function Name", "Arguments", "Returns" );
      sprintf( tmp+strlen( tmp ), "%-15s %-45s %s\n\r",
        "-------- ----", "---------", "-------" );
      page( ch, tmp );
      }
    sprintf( tmp, "%-15s (", cfunc_list[i].name );
    for( int j = 0; j < 4; j++ )
      if( cfunc_list[i].arg[j] != NONE )
        sprintf( tmp+strlen( tmp ), "%s %s", j == 0 ? "" : ",",
          arg_type_name[ cfunc_list[i].arg[j] ] );
    sprintf( tmp+strlen( tmp ), " )" ); 
    sprintf( buf, "%-61s %s\n\r", tmp,
      arg_type_name[ cfunc_list[i].type ] );
    page( ch, buf );
    }

  if( !found ) 
    send( ch, "No matching function found.\n\r" );
}


/*
 *   SPELL HELP ROUTINE
 */


void do_spells( char_data* ch, char* argument )
{
  int i;

  if( pet_help( ch ) || ch->link == NULL )
    return;

  if( argument[0] == '\0' ) {
    send( "What spell do you want info on?\n\r[To get a list of spells\
 type abil sp <class>.]\n\r", ch );
    return;
    }

  for( i = 0; i < MAX_SPELL; i++ )
    if( !strncasecmp( spell_table[i].name, argument,
      strlen( argument ) ) )
      break;

  if( i == MAX_SPELL ) {
    send( "Unknown Spell.\n\r", ch );
    }
  else {
    spell_help( ch, i );
    }

  return;
}


void spell_help( char_data* ch, int i )
{
  char                tmp  [ 3*MAX_STRING_LENGTH ];
  bool              found  = FALSE;
  obj_clss_data*  reagent;
  int                j, k;
  int                 pos;
  int              length;
  int               level;
  help_data*         help;

  sprintf( tmp,
    "%10sName: %s\n\r   Energy Cost: %s\n\r Turns to Cast: %d\n\r",
    "", spell_table[i].name, spell_table[i].cast_mana,
    spell_table[i].wait );
  page( ch, tmp );

  if( spell_table[i].duration != empty_string )
    page( ch, "      Duration: %s\n\r", spell_table[i].duration );
  if( spell_table[i].damage != empty_string ) 
    page( ch, "        Damage: %s\n\r", spell_table[i].damage );
  if( spell_table[i].leech_mana != empty_string ) 
    page( ch, "  Leech of Max: %s\n\r", spell_table[i].leech_mana );
  if( spell_table[i].regen != empty_string ) 
    page( ch, "   Regen Leech: %s\n\r", spell_table[i].regen );

  if( is_builder( ch ) )
    page( ch, "%10sSlot: %d\n\r", "", i );

  strcpy( tmp, "   Class/Level:" );
  for( j = 0; j < MAX_CLSS; j++ )
    if( ( level = skill_table[SPELL_FIRST+i].level[j] ) > 0
      && clss_table[j].open ) {
      length = strlen( tmp );
      sprintf( tmp+length, "%s %s %d%s",
        found ? "," : "", clss_table[j].name,
        level, number_suffix( level ) );
      length += found+1;
      tmp[length] = toupper( tmp[length] );
      found = TRUE;
      }
  sprintf( tmp+strlen( tmp ), "%s\n\r", found ? "" : " none" ); 
  page( ch, tmp );

  found = FALSE;

  page( ch, "--------------------------------\n\r" );
  page( ch, "Description:\n\r\n\r" );

  pos = pntr_search( help_list, max_help, spell_table[i].name );

  if( pos >= 0 ) {
    help = help_list[pos];
    convert_to_ansi( ch, help->text, tmp );
    page( ch, tmp );

    if( help->immortal != empty_string && is_builder( ch ) ) {
      page( ch, "\n\r" );
      convert_to_ansi( ch, help->immortal, tmp );
      page( ch, tmp );
      }
    }
  else
    page( ch, "none\n\r" );

  page( ch, "\n\rReagents:\n\r" );  
  for( j = 0; j < MAX_SPELL_WAIT; j++ ) {
    for( k = 0; k < j; k++ )
      if( abs( spell_table[i].reagent[j] )
        == abs( spell_table[i].reagent[k] ) )
        break;
    if( k != j )
      continue;
    if( ( reagent = get_obj_index(
      abs( spell_table[i].reagent[j] ) ) )  == NULL )
      continue;
    found = TRUE;
    page( ch, "   %s\n\r", reagent->Name( ) );
    }

  if( !found ) 
    page( ch, "  none\n\r" );

  return;
}