/**
* @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;
}
}
}