circlemud_squared_0.5.153/cnf/
circlemud_squared_0.5.153/etc/
circlemud_squared_0.5.153/etc/etc/
circlemud_squared_0.5.153/etc/house/
circlemud_squared_0.5.153/etc/misc/
circlemud_squared_0.5.153/etc/plralias/A-E/
circlemud_squared_0.5.153/etc/plralias/F-J/
circlemud_squared_0.5.153/etc/plralias/K-O/
circlemud_squared_0.5.153/etc/plralias/P-T/
circlemud_squared_0.5.153/etc/plralias/U-Z/
circlemud_squared_0.5.153/etc/plralias/ZZZ/
circlemud_squared_0.5.153/etc/plrobjs/
circlemud_squared_0.5.153/etc/plrobjs/A-E/
circlemud_squared_0.5.153/etc/plrobjs/F-J/
circlemud_squared_0.5.153/etc/plrobjs/K-O/
circlemud_squared_0.5.153/etc/plrobjs/P-T/
circlemud_squared_0.5.153/etc/plrobjs/U-Z/
circlemud_squared_0.5.153/etc/plrobjs/ZZZ/
circlemud_squared_0.5.153/etc/text/
circlemud_squared_0.5.153/etc/text/help/
circlemud_squared_0.5.153/src/util/
circlemud_squared_0.5.153/src/util/worldconv/
/**
 * @file act_social.c
 *
 * Functions to handle socials
 *
 * @author Part of CircleMUD
 *
 * @par Copyright:
 *   Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University<br>
 *   CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.
 *
 * @par
 *   All rights reserved.  See license.doc for complete information.
 *
 * @ingroup social
 * @package cs
 * @version 1.0
 */

#define __ACT_SOCIAL_C__

#include "conf.h"
#include "sysdep.h"
#include "structs.h"

#include "utils.h"
#include "comm.h"
#include "command.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"
#include "log.h"

/* local globals */
static int list_top = -1;

/* local functions */
char *fread_action(FILE *fl, int nr);
socialData_t *find_action(const commandData_t *cmd);
void boot_social_messages(void);
void free_social_messages(void);

/**
 * The global social table.
 * @ingroup social
 * @var socialData_t*
 */
socialData_t *soc_mess_list = NULL;

/**
 * @}
 */

/**
 * Find an action in the soc_mess_list[] array
 *
 * This function searches through the soc_mess_list[] array for a specific
 * social number.  Instead of doing a straight linear search it does it by
 * continual bi-section of the array until it finds the desired number.
 *
 * @param cmd Position of the command array for the social being saught.
 * @return Position of the soc_mess_list array for the social being saught.
 */
socialData_t *find_action(const commandData_t *cmd) {
  int bot, top, mid, cmp = 0;

  bot = 0;
  top = list_top;

  if (top < 0)
    return (NULL);

  for (;;) {
    mid = (bot + top) / 2;

    /* Compare the current command name with the specified command. */
    cmp = strcasecmp(soc_mess_list[mid].command, cmd->command);

    if (cmp == 0)
      return &(soc_mess_list[mid]);
    if (bot >= top)
      return (NULL);

    if (cmp > 0)
      top = --mid;
    else
      bot = ++mid;
  }
}

/**
 * *social command
 *
 * This command is called when the user performs a social
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @returns none
 */
ACMD(do_action)
{
  char buf[MAX_INPUT_LENGTH];
  socialData_t *action;
  charData_t *vict;

  if ((action = find_action(cmd)) == NULL) {
    send_to_char(ch, "That action is not supported.\r\n");
    return;
  }
  if (action->char_found && argument)
    one_argument(argument, buf);
  else
    *buf = '\0';

  if (!*buf) {
    send_to_char(ch, "%s\r\n", action->char_no_arg);
    act(action->others_no_arg, action->hide, ch, 0, 0, TO_ROOM);
    return;
  }
  if (!(vict = get_char_vis(ch, buf, NULL, FIND_CHAR_ROOM)))
    send_to_char(ch, "%s\r\n", action->not_found);
  else if (vict == ch) {
    send_to_char(ch, "%s\r\n", action->char_auto);
    act(action->others_auto, action->hide, ch, 0, 0, TO_ROOM);
  } else {
    if (GET_POS(vict) < action->min_victim_position)
      act("$N is not in a proper position for that.", FALSE, ch, 0, vict, TO_CHAR | TO_SLEEP);
    else {
      act(action->char_found, 0, ch, 0, vict, TO_CHAR | TO_SLEEP);
      act(action->others_found, action->hide, ch, 0, vict, TO_NOTVICT);
      act(action->vict_found, action->hide, ch, 0, vict, TO_VICT);
    }
  }
}

/**
 * INSULT command
 *
 * This command is a hard coded social
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @returns none
 */
ACMD(do_insult)
{
  char arg[MAX_INPUT_LENGTH];
  charData_t *victim;

  one_argument(argument, arg);

  if (*arg) {
    if (!(victim = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM)))
      send_to_char(ch, "Can't hear you!\r\n");
    else {
      if (victim != ch) {
	send_to_char(ch, "You insult %s.\r\n", GET_NAME(victim));

	switch (rand_number(0, 2)) {
	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 lose a beauty contest against a troll.",
		  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(ch, "You feel insulted.\r\n");
      }
    }
  } else
    send_to_char(ch, "I'm sure you don't want to insult *everybody*...\r\n");
}

/**
 * Read a line from file
 *
 * This function will read a line and return a copy of it or NULL if it's #
 *
 * @param fl The File handle being read
 * @param nr The social number currently being read
 * @return A copy of the line read or NULL
 */
char *fread_action(FILE *fl, int nr)
{
  char buf[MAX_STRING_LENGTH];

  fgets(buf, MAX_STRING_LENGTH, fl);
  if (feof(fl)) {
    log("SYSERR: fread_action: unexpected EOF near action #%d", nr);
    exit(1);
  }
  if (*buf == '#')
    return (NULL);

  buf[strlen(buf) - 1] = '\0';
  return (strdup(buf));
}

/**
 * Free the soc_mess_list[] array
 *
 * @param none
 * @return none
 */
void free_social_messages(void)
{
  int ac;
  socialData_t *soc;

  for (ac = 0; ac <= list_top; ac++) {
    soc = &soc_mess_list[ac];

    if (soc->char_no_arg)	free(soc->char_no_arg);
    if (soc->others_no_arg)	free(soc->others_no_arg);
    if (soc->char_found)	free(soc->char_found);
    if (soc->others_found)	free(soc->others_found);
    if (soc->vict_found)	free(soc->vict_found);
    if (soc->not_found)		free(soc->not_found);
    if (soc->char_auto)		free(soc->char_auto);
    if (soc->others_auto)	free(soc->others_auto);
  }
  free(soc_mess_list);
}

/**
 * Load the social messages into soc_mess_list[]
 *
 * This function opens the social file and calls fread_action() to populate
 * the soc_mess_list[] array
 * 
 * @param none
 * @return none
 */
void boot_social_messages(void)
{
  FILE *fl;
  int i, hide, min_pos, curr_soc = -1;
  char next_soc[100];
  socialData_t temp;
  const commandData_t *cmd = NULL;

  /* open social file */
  if (!(fl = fopen(SOCMESS_FILE, "r"))) {
    log("SYSERR: can't open socials file '%s': %s", SOCMESS_FILE, strerror(errno));
    exit(1);
  }
  /* count socials & allocate space */
  for (i = 0; *cmd_info[i].command != '\n'; i++)
    if (cmd_info[i].command_pointer == do_action)
      list_top++;

  CREATE(soc_mess_list, socialData_t, list_top + 1);

  /* now read 'em */
  for (;;) {
    fscanf(fl, " %s ", next_soc);
    if (*next_soc == '$')
      break;
    if (fscanf(fl, " %d %d \n", &hide, &min_pos) != 2) {
      log("SYSERR: format error in social file near social '%s'", next_soc);
      exit(1);
    }
    if (++curr_soc > list_top) {
      log("SYSERR: Ran out of slots in social array. (%d > %d)", curr_soc, list_top);
      break;
    }
 
    /* Look up the command corresponding to the social. */
    cmd = find_command(next_soc);

    /* read the stuff */
    soc_mess_list[curr_soc].command = strdup(cmd->command);
    soc_mess_list[curr_soc].hide = hide;
    soc_mess_list[curr_soc].min_victim_position = min_pos;

#ifdef CIRCLE_ACORN
    if (fgetc(fl) != '\n')
      log("SYSERR: Acorn bug workaround failed.");
#endif

    soc_mess_list[curr_soc].char_no_arg = fread_action(fl, curr_soc);
    soc_mess_list[curr_soc].others_no_arg = fread_action(fl, curr_soc);
    soc_mess_list[curr_soc].char_found = fread_action(fl, curr_soc);

    /* if no char_found, the rest is to be ignored */
    if (!soc_mess_list[curr_soc].char_found)
      continue;

    soc_mess_list[curr_soc].others_found = fread_action(fl, curr_soc);
    soc_mess_list[curr_soc].vict_found = fread_action(fl, curr_soc);
    soc_mess_list[curr_soc].not_found = fread_action(fl, curr_soc);
    soc_mess_list[curr_soc].char_auto = fread_action(fl, curr_soc);
    soc_mess_list[curr_soc].others_auto = fread_action(fl, curr_soc);

    /* If social not found, re-use this slot.  'curr_soc' will be reincremented. */
    if (cmd == NULL) {
      log("SYSERR: Unknown social '%s' in social file.", next_soc);
      memset(&soc_mess_list[curr_soc--], 0, sizeof(socialData_t));
      continue;
    }

    /* If the command we found isn't do_action, we didn't count it for the CREATE(). */
    if (cmd->command_pointer != do_action) {
      log("SYSERR: Social '%s' already assigned to a command.", next_soc);
      memset(&soc_mess_list[curr_soc--], 0, sizeof(socialData_t));
    }
  }

  /* close file & set top */
  fclose(fl);
  list_top = curr_soc;

  /* now, sort 'em */
  for (curr_soc = 0; curr_soc < list_top; curr_soc++) {
    min_pos = curr_soc;
    for (i = curr_soc + 1; i <= list_top; i++) {
      if (strcasecmp(soc_mess_list[i].command,
                     soc_mess_list[min_pos].command) < 0) {
	min_pos = i;
      }
    }
    if (curr_soc != min_pos) {
      temp = soc_mess_list[curr_soc];
      soc_mess_list[curr_soc] = soc_mess_list[min_pos];
      soc_mess_list[min_pos] = temp;
    }
  }
}