/************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefiting. We hope that you share your changes too. What goes * * around, comes around. * *************************************************************************** * ROM 2.4 is copyright 1993-1998 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@hypercube.org) * * Gabrielle Taylor (gtaylor@hypercube.org) * * Brian Moore (zump@rom.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * *************************************************************************** * 1stMUD ROM Derivative (c) 2001-2003 by Ryan Jennings * * http://1stmud.dlmud.com/ <r-jenn@shaw.ca> * ***************************************************************************/ /*************************************************************************** * File: string.c * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * * * * This code was freely distributed with the The Isles 1.1 source code, * * and has been used here for OLC - OLC would not be what it is without * * all the previous coders who released their source code. * * * ***************************************************************************/ #include "merc.h" #include "tables.h" #include "olc.h" PROTOTYPE(const char *string_linedel, (const char *, int)); PROTOTYPE(const char *string_lineadd, (const char *, const char *, int)); PROTOTYPE(const char *numlineas, (const char *)); /***************************************************************************** Name: string_edit Purpose: Clears string and puts player into editing mode. Called by: none ****************************************************************************/ void string_edit(CHAR_DATA * ch, const char **pString) { chprintln(ch, "-========- Entering EDIT Mode -=========-"); chprintlnf(ch, " Type %ch on a new line for help", STR_EDIT_KEY(ch)); chprintlnf(ch, " Terminate with a %cq or @ on a blank line.", STR_EDIT_KEY(ch)); chprintln(ch, "-=======================================-"); if (*pString == NULL) { *pString = str_dup(""); } else { *(char *) *pString = '\0'; } ch->desc->pString = pString; return; } /***************************************************************************** Name: string_append Purpose: Puts player into append mode for given string. Called by: (many)olc_act.c ****************************************************************************/ void string_append(CHAR_DATA * ch, const char **pString) { chprintln(ch, "-=======- Entering APPEND Mode -========-"); chprintlnf(ch, " Type %ch on a new line for help", STR_EDIT_KEY(ch)); chprintlnf(ch, " Terminate with a %cq or @ on a blank line.", STR_EDIT_KEY(ch)); chprintln(ch, "-=======================================-"); if (*pString == NULL) { *pString = str_dup(""); } chprint(ch, numlineas(*pString)); /* numlineas entrega el string con \n\r */ /* if ( *(*pString + strlen( *pString ) - 1) != '\r' ) chprint( "\n\r", ch ); */ ch->desc->pString = pString; return; } /***************************************************************************** Name: string_replace Purpose: Substitutes one string for another. Called by: string_add(string.c) (aedit_builder)olc_act.c. ****************************************************************************/ const char *string_replace(const char *orig, char *old, char *pnew) { char xbuf[MAX_STRING_LENGTH]; int i; xbuf[0] = '\0'; strcpy(xbuf, orig); if (strstr(orig, old) != NULL) { i = strlen(orig) - strlen(strstr(orig, old)); xbuf[i] = '\0'; strcat(xbuf, pnew); strcat(xbuf, &orig[i + strlen(old)]); free_string(orig); } return str_dup(xbuf); } #define PARSE_FORMAT 0 #define PARSE_REPLACE 1 #define PARSE_REPLACE_ALL 2 #define PARSE_HELP 3 #define PARSE_DELETE 4 #define PARSE_INSERT 5 #define PARSE_LIST_NORM 6 #define PARSE_LIST_NUM 7 #define PARSE_EDIT 8 const char *del_last_line(const char *string) { int len; bool found = FALSE; char xbuf[MSL]; xbuf[0] = '\0'; if (IS_NULLSTR(string)) return (str_dup(xbuf)); strcpy(xbuf, string); for (len = strlen(xbuf); len > 0; len--) { if (xbuf[len] == '\r') { if (!found) { if (len > 0) len--; found = TRUE; } else { xbuf[len + 1] = '\0'; free_string(string); return (str_dup(xbuf)); } } } xbuf[0] = '\0'; free_string(string); return (str_dup(xbuf)); } const char *string_replace_all(const char *orig, char *old, char *newstr) { if (!strstr(orig, old) || !str_cmp(old, newstr)) { return orig; } while (strstr(orig, old)) { orig = string_replace(orig, old, newstr); } return orig; } void parse_action(const char **text, int command, const char *string, CHAR_DATA * ch) { char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH]; switch (command) { case PARSE_HELP: chprintln(ch, "-------------------------------------------------------"); chprintlnf(ch, "Edit help (commands on blank line):\n\r" "%ch - get help (this info)\n\r" "%cs - show string so far\n\r" "%cS - show string so far without line numbers\n\r" "%cf - formats text\n\r" "%cc - clear string so far\n\r" "%cd# - delete line number <num>\n\r" "%cd - delete last line\n\r" "%ci# <str> - insert <str> on line <num>\n\r" "%ce# <str> - replace line <num> with <str>\n\r" "%cr 'a' 'b' - replace first occurance of text\n\r" "%cR 'a' 'b' - replace all occurances of text\n\r" " usage: %cr 'pattern' 'replacement'\n\r" "%c| <command> - execute a mud command\n\r" "%cq - end string", STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch)); chprintln(ch, "------------------------------------------------------"); break; case PARSE_FORMAT: *text = format_string(*text); chprintln(ch, "String formatted."); break; case PARSE_EDIT: string = one_argument(string, arg1); if (IS_NULLSTR(arg1)) { chprintln(ch, "You must specify a line number."); return; } *text = string_linedel(*text, atoi(arg1)); *text = string_lineadd(*text, string, atoi(arg1)); chprintln(ch, "Line replaced."); break; case PARSE_DELETE: if (IS_NULLSTR(string)) { *text = del_last_line(*text); chprintln(ch, "Last line deleted."); } else { *text = string_linedel(*text, atoi(string)); chprintlnf(ch, "Line %d deleted.", atoi(string)); } break; case PARSE_REPLACE: string = first_arg(string, arg1, FALSE); string = first_arg(string, arg2, FALSE); if (IS_NULLSTR(arg1)) { chprintlnf(ch, "Usage: %cr 'old string' 'new string'", STR_EDIT_KEY(ch)); return; } *text = string_replace(*text, arg1, arg2); chprintlnf(ch, "'%s' replaced with '%s'.", arg1, arg2); break; case PARSE_REPLACE_ALL: string = first_arg(string, arg1, FALSE); string = first_arg(string, arg2, FALSE); if (IS_NULLSTR(arg1)) { chprintlnf(ch, "Usage: %cR 'old string' 'new string'", STR_EDIT_KEY(ch)); return; } *text = string_replace_all(*text, arg1, arg2); chprintlnf(ch, "All occurances of '%s' replaced with '%s'.", arg1, arg2); break; case PARSE_INSERT: string = first_arg(string, arg1, FALSE); *text = string_lineadd(*text, string, atoi(arg1)); chprintlnf(ch, "Line %d inserted.", atoi(arg1)); break; case PARSE_LIST_NORM: chprintln(ch, "String so far:"); sendpage(ch, *text); break; case PARSE_LIST_NUM: chprintln(ch, "String so far:"); sendpage(ch, numlineas(*text)); break; default: chprintln(ch, "Invalid command."); bug("invalid command passed"); break; } } strshow_t parse_string_command(const char **text, const char *str, CHAR_DATA * ch) { int i = 2, j = 0; char actions[MAX_INPUT_LENGTH]; if ((*str == STR_EDIT_KEY(ch))) { while (str[i] != '\0') { actions[j] = str[i]; i++; j++; } actions[j] = '\0'; *(char *) str = '\0'; switch (str[1]) { case 'q': *(char *) str = '\0'; return STRING_END; case '|': interpret(ch, actions); chprintln(ch, "Command performed."); return STRING_FOUND; case 'c': chprintln(ch, "String cleared."); replace_string(*text, ""); return STRING_FOUND; case 's': parse_action(text, PARSE_LIST_NUM, actions, ch); return STRING_FOUND; case 'S': parse_action(text, PARSE_LIST_NORM, actions, ch); return STRING_FOUND; case 'r': parse_action(text, PARSE_REPLACE, actions, ch); return STRING_FOUND; case 'R': parse_action(text, PARSE_REPLACE_ALL, actions, ch); return STRING_FOUND; case 'f': parse_action(text, PARSE_FORMAT, actions, ch); return STRING_FOUND; case 'd': parse_action(text, PARSE_DELETE, actions, ch); return STRING_FOUND; case 'i': parse_action(text, PARSE_INSERT, actions, ch); return STRING_FOUND; case 'e': parse_action(text, PARSE_EDIT, actions, ch); return STRING_FOUND; case 'h': parse_action(text, PARSE_HELP, actions, ch); return STRING_FOUND; default: chprintln(ch, "Invalid command."); return STRING_FOUND; } } else if (*str == '@') { *(char *) str = '\0'; return STRING_END; } return STRING_NONE; } void string_add(CHAR_DATA * ch, char *argument) { char buf[MSL]; strshow_t action; action = parse_string_command(ch->desc->pString, argument, ch); switch (action) { case STRING_END: if (ch->desc->editor == ED_MPCODE) { MOB_INDEX_DATA *mob; int hash; PROG_LIST *mpl; PROG_CODE *mpc; EDIT_MPCODE(ch, mpc); if (mpc != NULL) for (hash = 0; hash < MAX_KEY_HASH; hash++) for (mob = mob_index_hash[hash]; mob; mob = mob->next) for (mpl = mob->first_mprog; mpl; mpl = mpl->next) if (mpl->vnum == mpc->vnum) { chprintlnf(ch, "Fixing mob %ld.", mob->vnum); replace_string(mpl->code, mpc->code); } } if (ch->desc->editor == ED_OPCODE) /* for the objprogs */ { OBJ_INDEX_DATA *obj; int hash; PROG_LIST *opl; PROG_CODE *opc; EDIT_OPCODE(ch, opc); if (opc != NULL) for (hash = 0; hash < MAX_KEY_HASH; hash++) for (obj = obj_index_hash[hash]; obj; obj = obj->next) for (opl = obj->first_oprog; opl; opl = opl->next) if (opl->vnum == opc->vnum) { chprintlnf(ch, "Fixing object %ld.", obj->vnum); replace_string(opl->code, opc->code); } } if (ch->desc->editor == ED_RPCODE) /* for the roomprogs */ { ROOM_INDEX_DATA *room; int hash; PROG_LIST *rpl; PROG_CODE *rpc; EDIT_RPCODE(ch, rpc); if (rpc != NULL) for (hash = 0; hash < MAX_KEY_HASH; hash++) for (room = room_index_hash[hash]; room; room = room->next) for (rpl = room->first_rprog; rpl; rpl = rpl->next) if (rpl->vnum == rpc->vnum) { chprintlnf(ch, "Fixing room %ld.", room->vnum); replace_string(rpl->code, rpc->code); } } ch->desc->pString = NULL; chprintln(ch, "Done editing."); return; case STRING_FOUND: return; default: case STRING_NONE: strcpy(buf, *ch->desc->pString); /* * Truncate strings to MAX_STRING_LENGTH. * -------------------------------------- */ if (strlen(buf) + strlen(argument) >= ((MSL * 2) - 6)) { chprintln(ch, "String too long, last line skipped."); /* Force character out of editing mode. */ ch->desc->pString = NULL; return; } /* * Ensure no tilde's inside string. * -------------------------------- */ smash_tilde(argument); strcat(buf, argument); strcat(buf, "\n\r"); replace_string(*ch->desc->pString, buf); return; } } /* * Thanks to Kalgen for the new procedure (no more bug!) * Original wordwrap() written by Surreality. */ /***************************************************************************** Name: format_string Purpose: Special string formating and word-wrapping. Called by: string_add(string.c) (many)olc_act.c ****************************************************************************/ const char *format_string(const char *oldstring /*, bool fSpace */ ) { char xbuf[MAX_STRING_LENGTH]; char xbuf2[MAX_STRING_LENGTH]; const char *rdesc; int i = 0; bool cap = TRUE; xbuf[0] = xbuf2[0] = 0; i = 0; for (rdesc = oldstring; *rdesc; rdesc++) { if (*rdesc == '\n') { if (xbuf[i - 1] != ' ') { xbuf[i] = ' '; i++; } } else if (*rdesc == '\r'); else if (*rdesc == ' ') { if (xbuf[i - 1] != ' ') { xbuf[i] = ' '; i++; } } else if (*rdesc == ')') { if (xbuf[i - 1] == ' ' && xbuf[i - 2] == ' ' && (xbuf[i - 3] == '.' || xbuf[i - 3] == '?' || xbuf[i - 3] == '!')) { xbuf[i - 2] = *rdesc; xbuf[i - 1] = ' '; xbuf[i] = ' '; i++; } else { xbuf[i] = *rdesc; i++; } } else if (*rdesc == '.' || *rdesc == '?' || *rdesc == '!') { if (xbuf[i - 1] == ' ' && xbuf[i - 2] == ' ' && (xbuf[i - 3] == '.' || xbuf[i - 3] == '?' || xbuf[i - 3] == '!')) { xbuf[i - 2] = *rdesc; if (*(rdesc + 1) != '\"') { xbuf[i - 1] = ' '; xbuf[i] = ' '; i++; } else { xbuf[i - 1] = '\"'; xbuf[i] = ' '; xbuf[i + 1] = ' '; i += 2; rdesc++; } } else { xbuf[i] = *rdesc; if (*(rdesc + 1) != '\"') { xbuf[i + 1] = ' '; xbuf[i + 2] = ' '; i += 3; } else { xbuf[i + 1] = '\"'; xbuf[i + 2] = ' '; xbuf[i + 3] = ' '; i += 4; rdesc++; } } cap = TRUE; } else { xbuf[i] = *rdesc; if (cap) { cap = FALSE; xbuf[i] = UPPER(xbuf[i]); } i++; } } xbuf[i] = 0; strcpy(xbuf2, xbuf); rdesc = xbuf2; xbuf[0] = 0; for (;;) { for (i = 0; i < 77; i++) { if (!*(rdesc + i)) break; } if (i < 77) { break; } for (i = (xbuf[0] ? 76 : 73); i; i--) { if (*(rdesc + i) == ' ') break; } if (i) { *(char *) (rdesc + i) = 0; strcat(xbuf, rdesc); strcat(xbuf, "\n\r"); rdesc += i + 1; while (*rdesc == ' ') rdesc++; } else { bug("No spaces"); *(char *) (rdesc + 75) = 0; strcat(xbuf, rdesc); strcat(xbuf, "-\n\r"); rdesc += 76; } } while (*(rdesc + i) && (*(rdesc + i) == ' ' || *(rdesc + i) == '\n' || *(rdesc + i) == '\r')) i--; *(char *) (rdesc + i + 1) = 0; strcat(xbuf, rdesc); if (xbuf[strlen(xbuf) - 2] != '\n') strcat(xbuf, "\n\r"); free_string(oldstring); return (str_dup(xbuf)); } /* * Used above in string_add. Because this function does not * modify case if fCase is FALSE and because it understands * parenthesis, it would probably make a nice replacement * for one_argument. */ /***************************************************************************** Name: first_arg Purpose: Pick off one argument from a string and return the rest. Understands quates, parenthesis (barring ) ('s) and percentages. Called by: string_add(string.c) ****************************************************************************/ const char *first_arg(const char *argument, char *arg_first, bool fCase) { char cEnd; if (IS_NULLSTR(argument)) { arg_first[0] = '\0'; return ""; } while (*argument == ' ') argument++; cEnd = ' '; if (*argument == '\'' || *argument == '"' || *argument == '%' || *argument == '(') { if (*argument == '(') { cEnd = ')'; argument++; } else cEnd = *argument++; } while (*argument != '\0') { if (*argument == cEnd) { argument++; break; } if (fCase) *arg_first = LOWER(*argument); else *arg_first = *argument; arg_first++; argument++; } *arg_first = '\0'; while (*argument == ' ') argument++; return argument; } /* * Used in olc_act.c for aedit_builders. */ const char *string_unpad(const char *argument) { char buf[MAX_STRING_LENGTH]; char *s; s = (char *) argument; while (*s == ' ') s++; strcpy(buf, s); s = buf; if (*s != '\0') { while (*s != '\0') s++; s--; while (*s == ' ') s--; s++; *s = '\0'; } free_string(argument); return str_dup(buf); } /* * Same as capitalize but changes the pointer's data. * Used in olc_act.c in aedit_builder. */ const char *string_proper(const char *argument) { char *s; s = (char *) argument; while (*s != '\0') { if (*s != ' ') { *s = UPPER(*s); while (*s != ' ' && *s != '\0') s++; } else { s++; } } return argument; } const char *string_linedel(const char *string, int line) { const char *strtmp = string; char buf[MAX_STRING_LENGTH]; int cnt = 1, tmp = 0; buf[0] = '\0'; for (; *strtmp != '\0'; strtmp++) { if (cnt != line) buf[tmp++] = *strtmp; if (*strtmp == '\n') { if (*(strtmp + 1) == '\r') { if (cnt != line) buf[tmp++] = *(++strtmp); else ++strtmp; } cnt++; } } buf[tmp] = '\0'; free_string(string); return str_dup(buf); } const char *string_lineadd(const char *string, const char *newstr, int line) { const char *strtmp = string; int cnt = 1, tmp = 0; bool done = FALSE; char buf[MAX_STRING_LENGTH]; buf[0] = '\0'; for (; *strtmp != '\0' || (!done && cnt == line); strtmp++) { if (cnt == line && !done) { strcat(buf, newstr); strcat(buf, "\n\r"); tmp += strlen(newstr) + 2; cnt++; done = TRUE; } buf[tmp++] = *strtmp; if (done && *strtmp == '\0') break; if (*strtmp == '\n') { if (*(strtmp + 1) == '\r') buf[tmp++] = *(++strtmp); cnt++; } buf[tmp] = '\0'; } free_string(string); return str_dup(buf); } const char *getline(const char *str, char *buf) { int tmp = 0; bool found = FALSE; while (*str) { if (*str == '\n') { found = TRUE; break; } buf[tmp++] = *(str++); } if (found) { if (*(str + 1) == '\r') str += 2; else str += 1; } /* para que quedemos en el inicio de la prox linea */ buf[tmp] = '\0'; return str; } const char *numlineas(const char *string) { int cnt = 1; static char buf[MAX_STRING_LENGTH * 2]; char buf2[MAX_STRING_LENGTH], tmpb[MAX_STRING_LENGTH]; buf[0] = '\0'; while (*string) { string = getline(string, tmpb); sprintf(buf2, "%2d. %s\n\r", cnt++, tmpb); strcat(buf, buf2); } return buf; } bool is_ansi_printed_char(char c) { switch (c) { case ' ': case '-': case ANSI_KEY: return TRUE; default: return FALSE; } } /* Converts a ~ into a colour code for ~ */ const char *tilde_to_color(const char *str) { int i = 0; char buf[MSL]; static char buf_new[5][MSL]; static int p; char *result = buf_new[p]; // rotate buffers ++p; p %= 5; memset(buf, 0, MSL); if (IS_NULLSTR(str)) return ""; while (*str != '\0') { if (*str == '~') { buf[i] = ANSI_KEY; i++; buf[i] = '-'; i++; str++; } else { buf[i] = *str; i++; str++; } } strcpy(result, buf); return (result); } const char *smash_colour(const char *str) { int i = 0; char buf[MSL]; static char buf_new[5][MSL]; static int p; char *result = buf_new[p]; // rotate buffers ++p; p %= 5; memset(buf, 0, MSL); if (IS_NULLSTR(str)) return ""; while (*str != '\0') { if (*str == ANSI_KEY) { str++; if (*str == '-') { buf[i] = '~'; i++; } str++; } else if (*str == ANSI_CUSTOM) { str++; while (*str != ANSI_END) str++; str++; } else { buf[i] = *str; i++; str++; } } strcpy(result, buf); return (result); } const char *color_to_tilde(const char *str) { int i = 0; char buf[MSL]; static char buf_new[5][MSL]; static int p; char *result = buf_new[p]; // rotate buffers ++p; p %= 5; memset(buf, 0, MSL); if (IS_NULLSTR(str)) return ""; while (*str != '\0') { if (*str == ANSI_KEY) { if (*(str + 1) == '-') { buf[i] = '~'; i++; str++; str++; } else { buf[i] = *str; i++; str++; } } else { buf[i] = *str; i++; str++; } } strcpy(result, buf); return (result); } const char *stringf(CHAR_DATA * ch, int length, int align, const char *fill, const char *string) { const char *count_string; char temp; int count = 0, nCount = 0; int pos = 0; char *result; static char buf_new[5][MSL]; static int i; // rotate buffers ++i; i %= 5; result = buf_new[i]; count_string = string; if (!fill) fill = " "; if (length <= 0) { length = get_scr_cols(ch); } while (*count_string && nCount != length) { temp = *count_string++; if (temp == ANSI_KEY) { temp = *count_string++; if (is_ansi_printed_char(temp)) nCount++; continue; } else if (temp == ANSI_CUSTOM) { temp = *count_string++; while (temp != ANSI_END) temp = *count_string++; continue; } nCount++; } if (align == ALIGN_RIGHT) { count = (length - ++nCount); while (nCount++ <= length) { result[pos++] = *fill; } } if (align == ALIGN_CENTER) { nCount = (length - nCount) / 2; count = nCount; while (nCount-- > 0) { result[pos++] = *fill; } } while (*string && count != length) { temp = *string++; result[pos++] = temp; if (temp == ANSI_KEY) { temp = result[pos] = *string++; if (is_ansi_printed_char(temp)) count++; pos++; continue; } else if (temp == ANSI_CUSTOM) { temp = result[pos++] = *string++; while (temp != ANSI_END) temp = result[pos++] = *string++; continue; } count++; } while (count++ < length) result[pos++] = *fill; result[pos] = '\0'; return (result); } unsigned int strlen_color(const char *string) { unsigned int count = 0; if (IS_NULLSTR(string)) return count; while (*string != '\0') { if (*string != ANSI_KEY && *string != ANSI_CUSTOM) { count++; string++; continue; } else if (*string == ANSI_KEY && is_ansi_printed_char(*(string + 1))) { string++; string++; count++; continue; } else if (*string == ANSI_KEY && *(string + 1) != '\0') { string++; string++; continue; } else if (*string == ANSI_CUSTOM && *(string + 1) != '\0') { string++; while (*string != '\0' && *string != ANSI_END) string++; string++; continue; } else if ((*string == ANSI_KEY || *string == ANSI_CUSTOM) && *(string + 1) == '\0') { break; } else { count++; string++; continue; } } return count; } /* returns TRUE if the last char in a string i a colour code */ bool check_cstring(char *string) { unsigned int i; if (IS_NULLSTR(string)) { return FALSE; } for (i = 0; i < strlen(string); i++) { if (string[i] == '\0') { return FALSE; } else if (string[i] != ANSI_KEY) { continue; } else if (string[i] == ANSI_KEY && string[i + 1] != '\0') { i++; continue; } else if (string[i] == ANSI_KEY && string[i + 1] == '\0') { return TRUE; } else { continue; } } return FALSE; } /* Can use colour coded fills like eg. draw_line("{w-{W+{R*{W+", 0); */ const char *draw_line(CHAR_DATA * ch, char *fill, int len) { static char buf_new[5][MSL]; static int i; int mod; int l; char lbuf[MSL]; int count; unsigned int m; char *result; // rotate buffers ++i; i %= 5; result = buf_new[i]; result[0] = '\0'; if (!fill) fill = "-"; if (len <= 0) { len = get_scr_cols(ch); } mod = len % strlen_color(fill); len /= strlen_color(fill); for (l = 0; l < len; l++) strcat(result, fill); count = 0; lbuf[0] = '\0'; for (m = 0; m < strlen(fill); m++) { if (fill[m] == ANSI_KEY) { lbuf[m] = fill[m]; m++; lbuf[m] = fill[m]; if (is_ansi_printed_char(lbuf[m])) count++; if (count >= mod) break; continue; } else if (fill[m] == ANSI_CUSTOM) { lbuf[m] = fill[m]; m++; while (fill[m] != ANSI_END) { lbuf[m] = fill[m]; m++; } lbuf[m] = fill[m]; m++; continue; } else { lbuf[m] = fill[m]; count++; if (count >= mod) break; } } if (lbuf[m - 1] == ANSI_KEY) { lbuf[m] = 'x'; } else { lbuf[m] = ANSI_KEY; lbuf[++m] = 'x'; } lbuf[++m] = '\0'; strcat(result, lbuf); return result; } CH_CMD(do_strkey) { if (IS_NPC(ch)) return; if (IS_NULLSTR(argument) || strlen(argument) > 1) { chprintln(ch, "Syntax: strkey <key>"); chprintln(ch, "Where <key> can be any 1 letter you want "); chprintln(ch, "to use for string editor commands."); return; } if (!isascii(argument[0]) || argument[0] == ' ' || argument[0] == '\\') { chprintln(ch, "Invalid string editor key."); return; } ch->pcdata->str_ed_key = argument[0]; chprintlnf(ch, "The string editor now uses %c for commands.", STR_EDIT_KEY(ch)); } char *FORMATF(const char *formatbuf, ...) { static int i; static char buf[10][MSL * 3]; va_list args; if (IS_NULLSTR(formatbuf)) return ""; ++i; i %= 10; va_start(args, formatbuf); vsnprintf(buf[i], sizeof(buf[i]), formatbuf, args); va_end(args); return buf[i]; }