/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

socials.c			Online Social Creation and usage code

		******** Heavily modified and expanded ********
		******** 100% Completely Original Code ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** Heavily modified and expanded ********
		******** 100% Completely Original Code ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
*************************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "acmd.h"
#include "handler.h"
#include "db.h"
#include "roaolc.h"
#include "global.h"
#include "exshell.h"

/* extern variables */
extern struct roa_social_data roa_socials[];
extern char *position_types[];

/* internal functions */
ROA_MENU(sedit_top_menu);
ROA_MENU(sedit_confirm_quit);
ROA_MENU(sedit_confirm_save);

/* global vars */
int socialcount = 0;

/******************************************************************
  OLSC - Online Social Creation... everything below is related to OLSC
  following code uses the stuff set up by OLSC to do the various
  tasks related to socials created online
  RoA - jtrhone
*******************************************************************/
/* receives a char, social and argument and performs it */
void do_roa_social(chdata *ch, struct roa_social_struct *action, char *comm)
{
   chdata *vict;
   BOOL selfsocial;

   if (action->minlevel > GET_LEVEL(ch))
   {
     send_to_char("Huh?!?\n\r",ch);
     return;
   }

   if (GET_POS(ch) <= POS_SLEEPING)
   {
     send_to_char("You'd have to be awake to do that...\n\r",ch);
     return;
   }

   if (action->char_found)
      half_chop(comm, buf, buf1);
   else
      *buf1 = '\0';

   if (!*buf1) 
   {
      act(action->char_no_arg, FALSE, ch, 0, 0, TO_CHAR);
      act(action->others_no_arg, action->hide, ch, 0, 0, TO_ROOM);
      return;
   }

   /* check to see if they typed 'me' */
   selfsocial = (!str_cmp("me", buf1) || !str_cmp("self", buf1));
   
   if (!(vict = get_char_room_vis(ch, buf1)) && !selfsocial) 
      act(action->not_found, FALSE, ch, 0, 0, TO_CHAR);
   else 
   if (vict == ch || selfsocial) 
   {
      act(action->char_auto, FALSE, ch, 0, 0, TO_CHAR);
      act(action->others_auto, action->hide, ch, 0, 0, TO_ROOM);
   } 
   else 
   {
      if (GET_POS(vict) < action->min_victim_pos) 
	 act("$N is not in a proper position for that.", FALSE, ch, 0, vict, TO_CHAR);
      else 
      {
	 act(action->char_found, 0, ch, 0, vict, TO_CHAR);
	 act(action->others_found, action->hide, ch, 0, vict, TO_NOTVICT);
	 act(action->vict_found, action->hide, ch, 0, vict, TO_VICT);
      }
   }
}

/* updates and sorts the ROA_SOCIAL_INDEX in lib using unix ls */
/* called at bootup and after a social is editted or created */
void read_sort_roa_socials(void)
{
  FILE *fp;
  int i;

  sprintf(buf, "ls socials > ROA_SOCIAL_INDEX");
  roa_system(buf);

  if (!(fp = fopen("ROA_SOCIAL_INDEX", "r")))
  {
    sprintf(buf, "SYSERR: Error opening ROA_SOCIAL_INDEX.");
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return;
  }

  // make sure we stay in range... 3/23/98 -jtrhone
  i = 0;
  while (!feof(fp) && i < MAX_SOCIALS)
  {
    fscanf(fp, "%s\n", buf);
    strcpy(roa_socials[i].social, buf);
    i++;
  }
  fclose(fp);

  /* how many total socials do we have for www and show stats */
  socialcount = i;

  /* blank out remaining socials */
  for ( ; i < MAX_SOCIALS; i++)
    strcpy(roa_socials[i].social, "");

  /* voila, hack way of updating and sorting social list */
}

/* overkill recursive proc for binary searchin -jtrhone */
BOOL bin_search(char *comm, int low, int high)
{
  int mid = (low+high) / 2;
  int cond;

  if (!(cond = str_cmp(roa_socials[mid].social, comm)))
    return TRUE;
  else
  if (low >= high) 
    return FALSE;
  else
  if (cond > 0)  /* search bottom half */
    return bin_search(comm, low, (mid-1));
  else /* search top half */
    return bin_search(comm, (mid+1), high);
}

// if bin_socials == TRUE, use binary search, else use iterative
// and allow abbreviations
BOOL find_roa_social(char *comm)
{
  char buf[MAX_INPUT_LENGTH];
  int top = 0;

  if (strlen(comm) >= MAX_INPUT_LENGTH)
    return FALSE;

  if (!bin_socials)  // dont do bin search
  {
    half_chop(comm, buf, buf2);
    for (top = 0; *roa_socials[top].social; top++)
      if (is_abbrev(buf, roa_socials[top].social))
      {
	strcpy(comm, roa_socials[top].social);
	if (*buf2)
	{
	  strcat(comm, " ");
	  strcat(comm, buf2);
	}
	return TRUE;
      }
    return FALSE;
  }

  while (roa_socials[top].social[0])
    top++;
  one_argument(comm, buf);

  return bin_search(buf, 0, top);
}

/* frees strings pointed to by a social struct -roa */
void free_social(struct roa_social_struct *roa)
{
  FREENULL(roa->name);
  FREENULL(roa->char_no_arg);
  FREENULL(roa->others_no_arg);
  FREENULL(roa->char_found);
  FREENULL(roa->others_found);
  FREENULL(roa->vict_found);
  FREENULL(roa->not_found);
  FREENULL(roa->char_auto);
  FREENULL(roa->others_auto);
}

/*
   only called if comm was in the index, reads in social file,
   sticks info into a social struct, and sends the stuff to do_roa_social
*/
void perform_roa_social(chdata *ch, char *comm)
{
  FILE *fp;
  struct roa_social_struct roa;
  char buf[MAX_STRING_LENGTH];

  /* yank all the arguments off the command */
  one_argument(comm, buf);
  sprintf(buf1, "socials/%s", buf);
  if (!(fp = fopen(buf1, "r")))
  {
    send_to_char("That action is not supported yet.\n\r",ch);
    sprintf(buf, "SYSERR:  Social in index but not found.");
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return;
  }
 
  roa.name = str_dup(buf);

  /* read the command social */
  fscanf(fp, "%d %d %d\n", &roa.minlevel, &roa.hide, &roa.min_victim_pos);
  roa.minlevel = MIN(LEV_AIMP, roa.minlevel);
  roa.char_no_arg =   fread_string(fp, buf);
  roa.others_no_arg = fread_string(fp, buf);
  roa.char_found =    fread_string(fp, buf);
  roa.others_found =  fread_string(fp, buf);
  roa.vict_found =    fread_string(fp, buf);
  roa.not_found =     fread_string(fp, buf);
  roa.char_auto =     fread_string(fp, buf);
  roa.others_auto =   fread_string(fp, buf);
  fclose(fp);
  do_roa_social(ch, &roa, comm);
  free_social(&roa);
}

/* 
   Beginning of OLSC - Online Social Creation only found here on RoA
   author - James Rhone aka jtrhone aka Vall

   The following code is the menuing system that provides builders with
   a way of creating socials online...
*/

BOOL check_roa_social(struct roa_social_struct *roa)
{
  if (!roa->name || !roa->char_no_arg)
    return FALSE;
  else
    return TRUE;
}

BOOL save_roa_social(struct roa_social_struct *roa)
{
  FILE *fp;

  one_argument(roa->name, buf);
  sprintf(buf1, "socials/%s", buf);
  if (!(fp = fopen(buf1, "wt")))
  {
    sprintf(buf, "SYSERR:  Unable to save social.");
    mudlog(buf, BRF, LEV_IMM, FALSE);
    return FALSE;
  }
  fprintf(fp, "%d %d %d\n", roa->minlevel, roa->hide, roa->min_victim_pos);
  fprintf(fp, "%s~\n", (roa->char_no_arg)?   roa->char_no_arg: "");
  fprintf(fp, "%s~\n", (roa->others_no_arg)? roa->others_no_arg:"");
  fprintf(fp, "%s~\n", (roa->char_found)?    roa->char_found:  "");
  fprintf(fp, "%s~\n", (roa->others_found)?  roa->others_found:"");
  fprintf(fp, "%s~\n", (roa->vict_found)?    roa->vict_found:  "");
  fprintf(fp, "%s~\n", (roa->not_found)?     roa->not_found:   "");
  fprintf(fp, "%s~\n", (roa->char_auto)?     roa->char_auto:   "");
  fprintf(fp, "%s~\n", (roa->others_auto)?   roa->others_auto: "");
  fclose(fp);

  read_sort_roa_socials();
  return TRUE;
}

BOOL fill_social_struct(struct roa_social_struct *roa)
{
  FILE *fp;

  one_argument(roa->name, buf);
  sprintf(buf1, "socials/%s", buf);
  if (!(fp = fopen(buf1, "r")))
    return FALSE;
  /* read the command social */
  fscanf(fp, "%d %d %d\n", &roa->minlevel, &roa->hide, &roa->min_victim_pos);
  roa->minlevel = MIN(LEV_AIMP, roa->minlevel);
  roa->char_no_arg =   fread_string(fp, buf);
  roa->others_no_arg = fread_string(fp, buf);
  roa->char_found =    fread_string(fp, buf);
  roa->others_found =  fread_string(fp, buf);
  roa->vict_found =    fread_string(fp, buf);
  roa->not_found =     fread_string(fp, buf);
  roa->char_auto =     fread_string(fp, buf);
  roa->others_auto =   fread_string(fp, buf);
  fclose(fp);
  return TRUE;
}

/* here we go, do_sedit, to get into social editting menu */
ACMD(do_sedit)
{
    char buf[80];
    extern int get_command(char *comm);

    if (IS_NPC(ch))
	return;

    one_argument(argument, buf);

    if (!*buf)
    {
      send_to_char("usage: SOCEDIT <social command>\n\r", ch);
      return;
    }
    
    // updated for new cmd_info layout 4/9/98 -jtrhone
    if (get_command(buf) >=0)
    {
      send_to_char("Unable to create social, command exists.\n\r",ch);
      return;
    }

    CREATE(ch->pc_specials->soc_editted, struct roa_social_struct, 1);
    ch->pc_specials->soc_editted->name = str_dup(buf);

    if (find_roa_social(buf))
      if (!fill_social_struct(ch->pc_specials->soc_editted))
      {
	sprintf(buf, "SYSERR: social exists but could not be loaded into struct.");
	mudlog(buf, BRF, LEV_IMM, FALSE);
	free_social(ch->pc_specials->soc_editted);
	FREENULL(ch->pc_specials->soc_editted);
	ch->pc_specials->soc_editted = NULL;
	return;
      }

    SET_BIT(PLR_FLAGS(ch), PLR_BUILDING);
    MENU_DEPTH(ch) = 0;
    ch->pc_specials->field_changed = FALSE;
    menu_jump(ch, sedit_top_menu);    
}

ROA_MENU(sedit_top_menu)
{
    extern char *delete_doubledollar(char *string);
    char buf[MAX_STRING_LENGTH];
    char buf2[MAX_STRING_LENGTH];
    char *p;
    int field;
    struct roa_social_struct *s = ch->pc_specials->soc_editted;
    
    if (!input_str)
    {
      menu_title_send("SocialEdit Main Menu", ch);
      sprintf(buf, " 1.) %%6Social%%0      : %s\n\r", s->name); S2C();
      sprintf(buf, " 2.) %%6MinLevel%%0    : %d\n\r", s->minlevel); S2C();
      sprinttype(s->min_victim_pos, position_types, buf2);
      sprintf(buf, " 3.) %%6MinPosition%%0 : %s\n\r", buf2); S2C();
      sprintf(buf, " 4.) %%6Hide invis%%0  : %s\n\r", (s->hide)?"Yes":"No");
      S2C();

      s->char_no_arg = delete_doubledollar(s->char_no_arg);
      sprintf(buf, " 5.) %%6To char no arg%%0:\n\r%s\n\r", s->char_no_arg); 
      S2C();

      s->others_no_arg = delete_doubledollar(s->others_no_arg);
      sprintf(buf, " 6.) %%6To others no arg%%0:\n\r%s\n\r", 
		s->others_no_arg); 
      S2C();

      s->char_found = delete_doubledollar(s->char_found);
      sprintf(buf, " 7.) %%6To char, target found%%0:\n\r%s\n\r", 
		s->char_found);
      S2C();

      s->others_found = delete_doubledollar(s->others_found);
      sprintf(buf, " 8.) %%6To others, target found%%0:\n\r%s\n\r", 
		s->others_found);
      S2C();

      s->vict_found = delete_doubledollar(s->vict_found);
      sprintf(buf, " 9.) %%6To target, if found%%0:\n\r%s\n\r", 
		s->vict_found);
      S2C();

      s->not_found = delete_doubledollar(s->not_found);
      sprintf(buf, "10.) %%6To char, target not found%%0:\n\r%s\n\r", 
		s->not_found);
      S2C();

      s->char_auto = delete_doubledollar(s->char_auto);
      sprintf(buf, "11.) %%6To char, auto (?)%%0:\n\r%s\n\r", 
		s->char_auto);
      S2C();

      s->others_auto = delete_doubledollar(s->others_auto);
      sprintf(buf, "12.) %%6To others, auto (?)%%0:\n\r%s\n\r", 
		s->others_auto);
      S2C();

      send_to_char("\n\r", ch);
      MENU_PROMPT(ch) = "Enter field number to change or 0 to end: ";
      return;
    }

    strcpy(buf, input_str);
    p = strtok(buf, " 	\n\r");
    if (p)
	field = atoi(p);
    else
	field = 0;

    switch (field)
    {
      case 0:
        menu_jump(ch, sedit_confirm_quit);
	break;

      case 1:
	do_string_arg(ch, "Enter new social name:\n\r", &s->name, "");	
	break;

      case 2:
	GET_INTEGER_ARG(ch, "Enter social minlevel: ", s->minlevel, 0, 70);
        break;

      case 3:
	get_integer_list(ch, "Enter number of minimum victim position: ",
			 &s->min_victim_pos,
			 sizeof(s->min_victim_pos),
			 position_types);
	break;

      case 4:
	GET_INTEGER_ARG(ch, "Hide social if invis? (1 - Yes, 0 - No): ", 
		s->hide, 0, 1);
        break;

      case 5:
	do_string_arg(ch, "Send this to char if no arg:\n\r", 
		&s->char_no_arg, "");
	break;
      case 6:
	do_string_arg(ch, "Send this to others if no arg:\n\r", 
		&s->others_no_arg, "");	
	break;
      case 7:
	do_string_arg(ch, "Send this to char if target found:\n\r", 
		&s->char_found, "");	
	break;
      case 8:
	do_string_arg(ch, "Send this to others if target found:\n\r", 
		&s->others_found, "");	
	break;
      case 9:
	do_string_arg(ch, "Send this to target if found:\n\r", 
		&s->vict_found, "");	
	break;
      case 10:
	do_string_arg(ch, "Send this to char if target not found:\n\r", 
		&s->not_found, "");	
	break;
      case 11:
	do_string_arg(ch, "Send this to char if self target:\n\r", 
		&s->char_auto, "");
	break;
      case 12:
	do_string_arg(ch, "Send this to others if self target:\n\r", 
		&s->others_auto, "");	
	break;

      default:
	send_to_char("That field cannot be changed.\n\r", ch);
	break;
    }

    ch->pc_specials->field_changed = TRUE;
}

ROA_MENU(sedit_confirm_quit)
{
    char buf[MAX_STRING_LENGTH];
    char *p;
    
    if (!input_str)
    {
	MENU_PROMPT(ch) = "Quit editting social (yes/NO)? ";
	return;
    }
    
    strcpy(buf, input_str);
    p = strtok(buf, " 	\n\r");
    if (p && strncasecmp("yes", p, strlen(p)) == 0)
      menu_jump(ch, sedit_confirm_save);
    else
      menu_jump(ch, sedit_top_menu);
}

ROA_MENU(sedit_confirm_save)
{
    char buf[MAX_STRING_LENGTH];
    char *p;
    struct roa_social_struct *s = ch->pc_specials->soc_editted;
    
    if (!input_str)
    {
	MENU_PROMPT(ch) = "Save editted social (YES/no)? ";
	return;
    }
    
    strcpy(buf, input_str);
    p = strtok(buf, " 	\n\r");
    if (!p || strncasecmp("no", p, strlen(p)) != 0)
    {
	if (!check_roa_social(s))
	  send_to_char("Error in social format, social not saved.\n\r",ch);
	else
	{
	  if (find_roa_social(s->name))
	  {
	      sprintf(buf, "IMMUPD: %s editted social %s", GET_NAME(ch), 
  		      s->name);
	      mudlog(buf, BRF, GET_LEVEL(ch), TRUE);
	      save_roa_social(s);	
	  }
	  else
 	  {
	      sprintf(buf, "IMMUPD: %s created social %s", GET_NAME(ch), 
	  	      s->name);
	      mudlog(buf, BRF, GET_LEVEL(ch), TRUE);
	      save_roa_social(s);		
	  }
	}
    }
 
    free_social(ch->pc_specials->soc_editted);
    FREENULL(ch->pc_specials->soc_editted);
    ch->pc_specials->soc_editted = NULL;
    MENU_PROMPT(ch) = NULL;
    MENU_HANDLER(ch) = NULL;
    MENU_DEPTH(ch) = 0;
    REMOVE_BIT(PLR_FLAGS(ch), PLR_BUILDING);
}

ROA_MENU(socedit_confirm_delete)
{
    char buf[MAX_STRING_LENGTH];
    char *p;
    
    if (!input_str)
    {
	MENU_PROMPT(ch) = "Delete social (YES/no)? ";
	return;
    }
    
    strcpy(buf, input_str);
    p = strtok(buf, " 	\n\r");
    if (PSTR1(ch))  /* name of social file was stored here */
    {
      if (!p || strncasecmp("no", p, strlen(p)) != 0)
      {
	roa_system(PSTR1(ch));
	read_sort_roa_socials();
	send_to_char("Social removed. Index updated.\n\r",ch);
      }
      else
      send_to_char("Social file not deleted.\n\r",ch);
    }
    else
      send_to_char("Social file not deleted, invalid filename.\n\r",ch);

    FREENULL(PSTR1(ch));
    MENU_PROMPT(ch) = NULL;
    MENU_HANDLER(ch) = NULL;
    MENU_DEPTH(ch) = 0;
}

ACMD(do_socdelete)
{
  char *argu = argument;

  if (IS_NPC(ch)) return;

  if (!*argu)
  {
    send_to_char("Usage: socdelete <social>.\n\r",ch);
    return;
  }

  skip_spaces(&argu);
  if (!find_roa_social(argu))
  {
    send_to_char("Social not found.\n\r",ch);
    return;
  }

  sprintf(buf, "rm socials/%s", argu);
  PSTR1(ch) = str_dup(buf);  /* save command to process on character */

  MENU_DEPTH(ch) = 0;    
  menu_jump(ch, socedit_confirm_delete);
}

/* stock 2.2 insult function */
ACMD(do_insult)
{
   chdata *victim;

   one_argument(argument, arg);

   if (*arg) {
      if (!(victim = get_char_room_vis(ch, arg))) {
	 send_to_char("Can't hear you!\n\r", ch);
      } else {
	 if (victim != ch) {
	    sprintf(buf, "You insult %s.\n\r", GET_NAME(victim) );
	    S2C();

	    switch (random() % 3) {
	    case 0 :
	        {
		  if (GET_SEX(ch) == SEX_MALE) {
		     if (GET_SEX(victim) == SEX_MALE)
			act(
			    "$n accuses you of fighting like a woman!", FALSE,
			    ch, 0, victim, TO_VICT);
		     else
			act("$n says that women can't fight.",
			    FALSE, ch, 0, victim, TO_VICT);
		  } else { /* Ch == Woman */
		     if (GET_SEX(victim) == SEX_MALE)
			act("$n accuses you of having the smallest.... (brain?)",
			    FALSE, ch, 0, victim, TO_VICT );
		     else
			act("$n tells you that you'd loose a beautycontest against an ogre.",
			    FALSE, ch, 0, victim, TO_VICT );
		  }
	       }
	       break;
	    case 1 :
	        {
		  act("$n calls your mother a bitch!",
		      FALSE, ch, 0, victim, TO_VICT );
	       }
	       break;
	    default :
	        {
		  act("$n tells you to get lost!", FALSE, ch, 0, victim, TO_VICT);
	       }
	       break;
	    } /* end switch */

	    act("$n insults $N.", TRUE, ch, 0, victim, TO_NOTVICT);
	 } else { /* ch == victim */
	    send_to_char("You feel insulted.\n\r", ch);
	 }
      }
   } else
      send_to_char("I'm sure you don't want to insult *everybody*...\n\r", ch);
}