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