/************************************************************************ Realms of Aurealis James Rhone aka Vall of RoA utils.c Various functions of a utility nature. ******** Heavily modified and expanded ******** *** BE AWARE OF ALL RIGHTS AND RESERVATIONS *** ******** Heavily modified and expanded ******** 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" // Added 03/16/98 to facilitate tprintf() - callahan #include <stdio.h> #include <stdarg.h> #include <sys/stat.h> #include "structures.h" #include "utils.h" #include "comm.h" #include "screen.h" #include "magic.h" #include "handler.h" #include "db.h" #include "affect.h" #include "lists.h" #include "global.h" #include "darkenelf.h" // given string, return associated class number 7/8/98 -jtrhone int get_class_num(char *name) { int i; for (i = 1; i <= NUM_CLASSES; i++) if (is_abbrev(name, clarray[i].class_name)) return i; return -1; } // generic player data filename getter 6/21/98 -jtrhone int get_pdata_filename(char *orig_name, char *ext, char *filename) { char *ptr, name[30]; if (!*orig_name) return 0; str_cpy(name, orig_name, 30, "get_pdata_filename"); for (ptr = name; *ptr; ptr++) *ptr = tolower(*ptr); switch (tolower(*name)) { case 'a': case 'b': case 'c': case 'd': case 'e': sprintf(filename, "plrobjs/A-E/%s.%s", name, ext); break; case 'f': case 'g': case 'h': case 'i': case 'j': sprintf(filename, "plrobjs/F-J/%s.%s", name, ext); break; case 'k': case 'l': case 'm': case 'n': case 'o': sprintf(filename, "plrobjs/K-O/%s.%s", name, ext); break; case 'p': case 'q': case 'r': case 's': case 't': sprintf(filename, "plrobjs/P-T/%s.%s", name, ext); break; case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': sprintf(filename, "plrobjs/U-Z/%s.%s", name, ext); break; default: sprintf(filename, "plrobjs/ZZZ/%s.%s", name, ext); break; } return 1; } // returns ptr to space filled null terminated str of i length // 5/28/98 -jtrhone char *padding(int i) { static char pad[MAX_STRING_LENGTH]; int cnt; for (cnt = 0; cnt < i; cnt++) pad[cnt] = ' '; pad[cnt] = '\0'; return pad; } // logging free, keep track of ptrs which we free and log function name... // 5/13/98 -jtrhone void free_log(void *ptr, char *txt) { if (!memfp) { memfp = fopen("misc/memlog.txt", "wt"); if (!memfp) { mudlog("SYSERR: Unable to open memlog...", BRF, LEV_IMM, TRUE); free(ptr); return; } } fprintf(memfp, "%p : %s\n", ptr, txt); fflush(memfp); free(ptr); } // front end to all strcpys, takes two normal args plus max len and name of caller // to help facilitate the discovery of memory overwrites... 4/23/98 -jtrhone char *str_cpy(char *dest, char *src, int max, char *fname) { static char buf[MAX_INPUT_LENGTH]; #ifdef DEBUG if (strlen(src)+1 > max) { sprintf(buf, "!SYSWAR!: str_cpy() bound violation in %s.", fname); mudlog(buf, BRF, LEV_IMM, TRUE); // only copy the amount we can... strncpy(dest, src, max-1); dest[max-1] = '\0'; return dest; } #endif return strcpy(dest, src); } // front end to all strcats, takes two normal args plus max len and name of caller // to help facilitate the discovery of memory overwrites... 4/23/98 -jtrhone char *str_cat(char *dest, char *src, int max, char *fname) { static char buf[MAX_INPUT_LENGTH]; #ifdef DEBUG if (strlen(dest) + strlen(src)+1 > max) { sprintf(buf, "!SYSWAR!: str_cat() bound violation in %s.", fname); mudlog(buf, BRF, LEV_IMM, TRUE); // only copy the amount we can... strncat(dest, src, max-1); dest[max-1] = '\0'; return dest; } #endif return strcat(dest, src); } // Check to see if ch has reached limit for summoning. 04/21/98 -callahan BOOL MaxSummons(CharData *ch) { CharData *mob; int levels; for (levels = 0, mob = character_list; mob; mob = mob->next) if (SUMMONER(mob) == GET_IDNUM(ch)) levels += Level(mob); if (levels >= (2 * Level(ch))) { SendChar("You have reached your maximum summoning capacity.\r\n", ch); return TRUE; } return FALSE; } // Checks to see if two chars share a group relationship. 08/11/98 -callahan BOOL InSameGroup(CharData *ch, CharData *sch) { if (!ch || !sch) return FALSE; if (ch == sch) return TRUE; if (!Master(ch) && !Master(sch)) return FALSE; if ((ch == Master(sch)) || (sch == Master(ch))) return TRUE; if (Master(ch) == Master(sch)) return TRUE; return FALSE; } // Checks to see if a number is within a range. - 04/21/98 -callahan int InRange(int value, int low, int high) { if ((value <= high) && (value >= low)) return TRUE; else return FALSE; } // Attempts to match a player's idnum in the given list. 03/16/98 -callahan int IdListMember(IdList * list, long idnum) { IdList *member; for (member = list; member; member = member->next) if (member->idnum == idnum) return 1; return 0; } // next couple deal with groups... 12/17/97 -jtrhone // get a ptr to the groups leader... chdata *group_leader(chdata *ch) { chdata *k; if (!IS_AFFECTED(ch, AFF_GROUP)) return NULL; if (!(k = ch->master)) k = ch; return k; } // return ptr to next in group... NULL if none or done chdata *group_member(chdata *ch, BOOL inroom) { chdata *l; struct follow_type *f; if (!(l = group_leader(ch))) return NULL; // see if the leader has been returned yet // MUST check room on leader too 1/22/98 -jtrhone if (!CHAR_FLAGGED(l, CH_GRP) && (!inroom || SAME_ROOM(ch, l))) { SET_BIT(CHAR_FLAGS(l), CH_GRP); return l; } for (f = l->followers; f; f=f->next) if (!CHAR_FLAGGED(f->follower, CH_GRP)) if (IS_AFFECTED(f->follower, AFF_GROUP) && (!inroom || SAME_ROOM(f->follower, ch)) && f->follower != l) { SET_BIT(CHAR_FLAGS(f->follower), CH_GRP); return f->follower; } // we must have NO followers left OR they all have the CH_GRP flag on em // so.. go thru group and remove the flag then return NULL REMOVE_BIT(CHAR_FLAGS(l), CH_GRP); for (f = l->followers; f; f=f->next) REMOVE_BIT(CHAR_FLAGS(f->follower), CH_GRP); return NULL; } int num_in_group(chdata *ch) { int count = 0; chdata *k; if (!IS_AFFECTED(ch, AFF_GROUP)) return 0; while ((k = group_member(ch, TRUE))) count++; return count; } int MIN(int a, int b) { return a < b ? a : b; } int MAX(int a, int b) { return a > b ? a : b; } /* creates a random number in interval [from;to] */ int number(int from, int to) { int targ; if (from > to) { targ = from; from = to; to = targ; } targ = (to - from + 1); if (!targ) targ = 1; return((random() % targ) + from); } /* simulates dice roll */ int dice(int number, int size) { int r, sum = 0; size = MAX(size, 1); /* no more crasho */ for (r = 1; r <= number; r++) sum += ((random() % size) + 1); return(sum); } void skip_spaces(char **string) { if (!*string || !**string) return; for (; **string && isspace(**string); (*string)++) ; } /* returns: 0 if equal, 1 if arg1 > arg2, -1 if arg1 < arg2 */ /* scan 'till found different or end of both */ int str_cmp(char *arg1, char *arg2) { int chk, i; if (!arg1) return (-1); if (!arg2) return (1); for (i = 0; *(arg1 + i) || *(arg2 + i); i++) if ((chk = LOWER(*(arg1 + i)) - LOWER(*(arg2 + i)))) if (chk < 0) return (-1); else return (1); return(0); } /* returns: 0 if equal, 1 if arg1 > arg2, -1 if arg1 < arg2 */ /* scan 'till found different, end of both, or n reached */ int strn_cmp(char *arg1, char *arg2, int n) { int chk, i; for (i = 0; (*(arg1 + i) || *(arg2 + i)) && (n > 0); i++, n--) if ((chk = LOWER(*(arg1 + i)) - LOWER(*(arg2 + i)))) if (chk < 0) return (-1); else return (1); return(0); } /* stuff a chunk of chars on end of string, allocate, etc */ /* NOTE, caller must FREE what it gets back... */ char *str_add(char *str, char *add) { if (!add || !*add) return str; if (!str || !*str) /* just strdup it */ { return STR_DUP(add); } RECREATE(str, char, strlen(str) + strlen(add) + 1); return str; } /* go one past eol in a string, used in comlist scanning */ /* RoA jtrhone */ char *scan_past_eol(char *p) { // fastforward while not newline while (*p && !ISNEWL(*p)) p++; // now fastforward while newline while (*p && ISNEWL(*p)) p++; return p; } char *scan_past_eol_and_spaces(char *p) { // fastforward while not newline while (*p && !ISNEWL(*p)) p++; // now fastforward while newline while (*p && ISNEWL(*p)) p++; // now fastforward while space skip_spaces(&p); return p; } // given a ptr to a opening bracket '{' count how many chars are INSIDE this // opening and its matching closing bracket int chars_in_block(char *p) { int i = 0, block = 1; if (!p || !*p || *p != '{') { mudlog("SYSERR: chars_in_block p != {", BRF, LEV_IMM, TRUE); return -1; } p++; for (; *p; p++) { switch (*p) { case '{': block++; break; case '}': block--; break; default: break; } if (block) i++; else break; } // block BETTER be 0, or else we errored... if (block) return -1; else return i; } /* skip an entire zone comlist block of reset commands */ /* used if target mob/obj is not loaded for whatever reason */ /* RoA jtrhone */ /* IMPORTANT!!: ASSUME we are pointing at { */ char *skip_block(char *pt) { int depth; pt++; for (depth = 1; depth > 0 && *pt; pt++) { if (*pt == '{') // go into another block depth++; else if (*pt == '}') // exit a block depth--; } pt = scan_past_eol(pt); // fly past all the newlines return pt; } // given a string, TRANSFORM each piece into underline (-=-=-=) // until \n or \r is reached void underline(char *buf) { int i; char *tmp; char rep = '-'; if (!buf || !*buf) return; for (i = 1, tmp = buf; *tmp && *tmp != '\n' && *tmp != '\r'; tmp++) { if ( (i = !i) ) rep = '='; else rep = '-'; *tmp = rep; } } /* log a death trap hit */ void log_death_trap(chdata *ch) { char buf[MAX_STRING_LENGTH]; sprintf(buf, "%s hit death trap #%d (%s)", GET_NAME(ch), world[ch->in_room].number, world[ch->in_room].name); mudlog(buf, BRF, LEV_IMM, TRUE); } /* writes a string to the log */ void log(char *str) { long ct; char *tmstr; ct = time(0); tmstr = asctime(localtime(&ct)); *(tmstr + strlen(tmstr) - 1) = '\0'; fprintf(stderr, "%-19.19s :: %s\n", tmstr, str); } /* New PROC: syslog by Fen Jul 3, 1992 */ void mudlog(char *str, char type, sbyte level, byte file) { dsdata *i; char *tmp; long ct; char tp; char buf[1024]; ct = time(0); tmp = asctime(localtime(&ct)); // don't send color codes to log... 2/12/98 -jtrhone if (file) { strcpy(buf2, str); killp(buf2); fprintf(stderr, "%-19.19s :: %s\n", tmp, buf2); } if (level < 0) return; if (type < BUG) sprintf(buf, "%%2%%B[%%0 %s %%2%%B]%%0\n\r", str ); else sprintf(buf, "%%5%%B[%%0 %s %%5%%B]%%0\n\r", str ); for (i=descriptor_list; i; i = i->next) if (D_CHECK(i) && SEND_OK(i->character)) { tp = ((PRF_FLAGGED(i->character, PRF_LOG1) ? 1 : 0) + (PRF_FLAGGED(i->character, PRF_LOG2) ? 2 : 0)); if ((GET_LEVEL(i->character) >= level) && (tp >= type || PLR_FLAGGED(i->character, PLR_LOGALL))) send_to_char(buf, i->character); } return; } void sprintbit(long vektor, char *names[], char *result) { long nr; *result = '\0'; if (vektor < 0) { strcpy(result, "SPRINTBIT ERROR!"); return; } // Slightly modified for comma-separation. 03/21/98 -callahan for (nr = 0; vektor; vektor >>= 1) { if (IS_SET(1, vektor)) { if (*names[nr] != '\n') { strcat(result, names[nr]); strcat(result, ", "); } else strcat(result, "UNDEFINED "); } if (*names[nr] != '\n') nr++; } if (!*result) strcat(result, "None."); else { result[strlen(result) - 2] = '\0'; strcat(result, "."); // Add a period to the end. -callahan } } void sprinttype(int type, char *names[], char *result) { int nr; for (nr = 0; (*names[nr] != '\n'); nr++) ; if (type < nr) strcpy(result, names[type]); else strcpy(result, "<UNDEF>"); } // Facilitate easily-read time formats. 03/21/98 -callahan // Formats string as: 3d 04:23, or if no days, 04:23 char *time_format_1(time_t dt) { register struct tm *delta; static char buf[64]; if (dt < 0) dt = 0; delta = gmtime(&dt); if (delta->tm_yday > 0) sprintf(buf, "%dd %02d:%02d", delta->tm_yday, delta->tm_hour, delta->tm_min); else sprintf(buf, "%02d:%02d", delta->tm_hour, delta->tm_min); return buf; } // Formats string as: 3d (for days), 4h (for hours), or 23m (for minutes) char *time_format_2(time_t dt) { register struct tm *delta; static char buf[64]; if (dt < 0) dt = 0; delta = gmtime(&dt); if (delta->tm_yday > 0) sprintf(buf, "%dd", delta->tm_yday); else if (delta->tm_hour > 0) sprintf(buf, "%dh", delta->tm_hour); else if (delta->tm_min > 0) sprintf(buf, "%dm", delta->tm_min); else sprintf(buf, "%ds", delta->tm_sec); return buf; } char *time_format_3(time_t dt) { register struct tm *delta; static char buf[64]; if (dt < 0) dt = 0; delta = gmtime(&dt); if (delta->tm_yday > 0) sprintf(buf, "%d day%s", delta->tm_yday, (delta->tm_yday > 1) ? "s" : ""); else if (delta->tm_hour > 0) sprintf(buf, "%d hour%s", delta->tm_hour, (delta->tm_hour > 1) ? "s" : ""); else if (delta->tm_min > 0) sprintf(buf, "%d minute%s", delta->tm_min, (delta->tm_min > 1) ? "s" : ""); else sprintf(buf, "%d second%s", delta->tm_sec, (delta->tm_sec > 1) ? "s" : ""); return buf; } /* Calculate the REAL time passed over the last t2-t1 centuries (secs) */ struct time_info_data real_time_passed(time_t t2, time_t t1) { long secs; struct time_info_data now; secs = (long) (t2 - t1); now.hours = (secs / SECS_PER_REAL_HOUR) % 24; /* 0..23 hours */ secs -= SECS_PER_REAL_HOUR * now.hours; now.day = (secs / SECS_PER_REAL_DAY); /* 0..34 days */ secs -= SECS_PER_REAL_DAY * now.day; now.month = -1; now.year = -1; return now; } /* Calculate the MUD time passed over the last t2-t1 centuries (secs) */ // changed # of months to 16 ( 0 - 15 ) -roa struct time_info_data mud_time_passed(time_t t2, time_t t1) { long secs; struct time_info_data now; secs = (long) (t2 - t1); now.hours = (secs / SECS_PER_MUD_HOUR) % 24; /* 0..23 (24 hours) */ secs -= SECS_PER_MUD_HOUR * now.hours; now.day = (secs / SECS_PER_MUD_DAY) % 35; /* 0..34 (35 days) */ secs -= SECS_PER_MUD_DAY * now.day; now.month = (secs / SECS_PER_MUD_MONTH) % 16; /* 0..15 (16 months) */ secs -= SECS_PER_MUD_MONTH * now.month; now.year = (secs / SECS_PER_MUD_YEAR); /* 0..XX? years */ return now; } struct time_info_data age(chdata *ch) { struct time_info_data player_age; player_age = mud_time_passed(time(0), ch->player.time.birth); player_age.year += 17; /* All players start at 17 */ return player_age; } // follower stuff, formerly from sparse.c -roa /* Check if making CH follow VICTIM will create an illegal */ /* Follow "Loop/circle" */ BOOL circle_follow(chdata *ch, chdata *victim) { chdata *k; for (k = victim; k; k = k->master) if (k == ch) return(TRUE); return(FALSE); } void CharToDust(CharData *ch) { ObjData *dust, *obj, *next_obj, *money, *create_money(int amount); int i; static char buf[MAX_STRING_LENGTH]; void float_sink_object(obdata *obj, int room); CREATE(dust, ObjData, 1); clear_object(dust); dust->touched = TRUE; dust->item_number = NOWHERE; InRoom(dust) = NOWHERE; dust->plr_num = 0; dust->name = str_dup("dust"); sprintf(buf, "A pile of %s's dust is lying here.", Name(ch)); dust->description = str_dup(buf); sprintf(buf, "%s's dust", Name(ch)); dust->shdesc = str_dup(buf); dust->type_flag = ITEM_CONTAINER; OBJ_WEARS(dust) = ITEM_TAKE; OBJ_EXTRAS(dust) = ITEM_NODONATE; dust->value[0] = 0; dust->weight = 1; dust->timer = max_npc_corpse_time + 10; for (obj = ch->carrying; obj; obj = next_obj) { next_obj = obj->next_content; act("$p falls to the floor from $n's crumbling remains.", FALSE, ch, obj, 0, TO_ROOM); obj_from_char(obj); obj_to_room(obj, InRoom(ch)); } for (i = 0; i < MAX_WEAR; i++) if (EQ(ch, i)) { act("$p falls to the floor from $n's crumbling remains.", FALSE, ch, EQ(ch, i), 0, TO_ROOM); obj_to_room(unequip_char(ch, i, TRUE), InRoom(ch)); } if (Gold(ch) > 0) { money = create_money(Gold(ch)); act("Some gold falls to the floor from $n's crumbling remains.", FALSE, ch, 0, 0, TO_ROOM); obj_to_room(money, InRoom(ch)); Gold(ch) = 0; } object_list_new_owner(dust, NULL); float_sink_object(dust, InRoom(ch)); } /* Called when stop following persons, or stopping charm */ /* This will NOT do if a character quits/dies!! */ void stop_follower(chdata *ch) { struct follow_type *j, *k; assert(ch->master); if (IS_AFFECTED(ch, AFF_CHARM)) { act("You realize that $N is a jerk!", FALSE, ch, 0, ch->master, TO_CHAR); act("$n realizes that $N is a jerk!", FALSE, ch, 0, ch->master, TO_NOTVICT); act("$n hates your guts!", FALSE, ch, 0, ch->master, TO_VICT); if (affected_by_spell(ch, SPELL_CHARM_PERSON)) affect_from_char(ch, SPELL_CHARM_PERSON); } else { act("You stop following $N.", FALSE, ch, 0, ch->master, TO_CHAR); act("$n stops following $N.", FALSE, ch, 0, ch->master, TO_NOTVICT); act("$n stops following you.", FALSE, ch, 0, ch->master, TO_VICT); } if (ch->master->followers->follower == ch) { /* Head of follower-list? */ k = ch->master->followers; ch->master->followers = k->next; FREENULL(k); } else { /* locate follower who is not head of list */ for (k = ch->master->followers; k->next->follower != ch; k = k->next) ; j = k->next; k->next = j->next; free(j); j = NULL; } ch->master = NULL; REMOVE_BIT(AFF_FLAGS(ch), AFF_CHARM | AFF_GROUP); } /* Called when a character that follows/is followed dies */ void die_follower(chdata *ch) { struct follow_type *j, *k; if (ch->master) stop_follower(ch); for (k = ch->followers; k; k = j) { j = k->next; stop_follower(k->follower); } } /* Do NOT call this before having checked if a circle of followers */ /* will arise. CH will follow leader */ void add_follower(chdata *ch, chdata *leader) { struct follow_type *k; assert(!ch->master); ch->master = leader; CREATE(k, struct follow_type, 1); k->follower = ch; k->next = leader->followers; leader->followers = k; act("You now follow $N.", FALSE, ch, 0, leader, TO_CHAR); if (can_see(leader, ch)) act("$n starts following you.", TRUE, ch, 0, leader, TO_VICT); act("$n now follows $N.", TRUE, ch, 0, leader, TO_NOTVICT); } // Translates a number to an english word. 03/16/98 callahan const char *num_to_word[401] = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", "twenty-one", "twenty-two", "twenty-three", "twenty-four", "twenty-five", "twenty-six", "twenty-seven", "twenty-eight", "twenty-nine", "thirty", "thirty-one", "thirty-two", "thirty-three", "thirty-four", "thirty-five", "thirty-six", "thirty-seven", "thirty-eight", "thirty-nine", "forty", "forty-one", "forty-two", "forty-three", "forty-four", "forty-five", "forty-six", "forty-seven", "forty-eight", "forty-nine", "fifty", "fifty-one", "fifty-two", "fifty-three", "fifty-four", "fifty-five", "fifty-six", "fifty-seven", "fifty-eight", "fifty-nine", "sixty", "sixty-one", "sixty-two", "sixty-three", "sixty-four", "sixty-five", "sixty-six", "sixty-seven", "sixty-eight", "sixty-nine", "seventy", "seventy-one", "seventy-two", "seventy-three", "seventy-four", "seventy-five", "seventy-six", "seventy-seven", "seventy-eight", "seventy-nine", "eighty", "eighty-one", "eighty-two", "eighty-three", "eighty-four", "eighty-five", "eighty-six", "eighty-seven", "eighty-eight", "eighty-nine", "ninety", "ninety-one", "ninety-two", "ninety-three", "ninety-four", "ninety-five", "ninety-six", "ninety-seven", "ninety-eight", "ninety-nine", "one-hundred", "one-hundred and one", "one-hundred and two", "one-hundred and three", "one-hundred and four", "one-hundred and five", "one-hundred and six", "one-hundred and seven", "one-hundred and eight", "one-hundred and nine", "one-hundred and ten", "one-hundred and eleven", "one-hundred and twelve", "one-hundred and thirteen", "one-hundred and fourteen", "one-hundred and fifteen", "one-hundred and sixteen", "one-hundred and seventeen", "one-hundred and eighteen", "one-hundred and nineteen", "one-hundred and twenty", "one-hundred and twenty-one", "one-hundred and twenty-two", "one-hundred and twenty-three", "one-hundred and twenty-four", "one-hundred and twenty-five", "one-hundred and twenty-six", "one-hundred and twenty-seven", "one-hundred and twenty-eight", "one-hundred and twenty-nine", "one-hundred and thirty", "one-hundred and thirty-one", "one-hundred and thirty-two", "one-hundred and thirty-three", "one-hundred and thirty-four", "one-hundred and thirty-five", "one-hundred and thirty-six", "one-hundred and thirty-seven", "one-hundred and thirty-eight", "one-hundred and thirty-nine", "one-hundred and forty", "one-hundred and forty-one", "one-hundred and forty-two", "one-hundred and forty-three", "one-hundred and forty-four", "one-hundred and forty-five", "one-hundred and forty-six", "one-hundred and forty-seven", "one-hundred and forty-eight", "one-hundred and forty-nine", "one-hundred and fifty", "one-hundred and fifty-one", "one-hundred and fifty-two", "one-hundred and fifty-three", "one-hundred and fifty-four", "one-hundred and fifty-five", "one-hundred and fifty-six", "one-hundred and fifty-seven", "one-hundred and fifty-eight", "one-hundred and fifty-nine", "one-hundred and sixty", "one-hundred and sixty-one", "one-hundred and sixty-two", "one-hundred and sixty-three", "one-hundred and sixty-four", "one-hundred and sixty-five", "one-hundred and sixty-six", "one-hundred and sixty-seven", "one-hundred and sixty-eight", "one-hundred and sixty-nine", "one-hundred and sevenety", "one-hundred and seventy-one", "one-hundred and seventy-two", "one-hundred and seventy-three", "one-hundred and seventy-four", "one-hundred and seventy-five", "one-hundred and seventy-six", "one-hundred and seventy-seven", "one-hundred and seventy-eight", "one-hundred and seventy-nine", "one-hundred and eighty", "one-hundred and eighty-one", "one-hundred and eighty-two", "one-hundred and eighty-three", "one-hundred and eighty-four", "one-hundred and eighty-five", "one-hundred and eighty-six", "one-hundred and eighty-seven", "one-hundred and eighty-eight", "one-hundred and eighty-nine", "one-hundred and ninety", "one-hundred and ninety-one", "one-hundred and ninety-two", "one-hundred and ninety-three", "one-hundred and ninety-four", "one-hundred and ninety-five", "one-hundred and ninety-six", "one-hundred and ninety-seven", "one-hundred and ninety-eight", "one-hundred and ninety-nine", "two-hundred", "two-hundred and one", "two-hundred and two", "two-hundred and three", "two-hundred and four", "two-hundred and five", "two-hundred and six", "two-hundred and seven", "two-hundred and eight", "two-hundred and nine", "two-hundred and ten", "two-hundred and eleven", "two-hundred and twelve", "two-hundred and thirteen", "two-hundred and fourteen", "two-hundred and fifteen", "two-hundred and sixteen", "two-hundred and seventeen", "two-hundred and eighteen", "two-hundred and nineteen", "two-hundred and twenty", "two-hundred and twenty-one", "two-hundred and twenty-two", "two-hundred and twenty-three", "two-hundred and twenty-four", "two-hundred and twenty-five", "two-hundred and twenty-six", "two-hundred and twenty-seven", "two-hundred and twenty-eight", "two-hundred and twenty-nine", "two-hundred and thirty", "two-hundred and thirty-one", "two-hundred and thirty-two", "two-hundred and thirty-three", "two-hundred and thirty-four", "two-hundred and thirty-five", "two-hundred and thirty-six", "two-hundred and thirty-seven", "two-hundred and thirty-eight", "two-hundred and thirty-nine", "two-hundred and forty", "two-hundred and forty-one", "two-hundred and forty-two", "two-hundred and forty-three", "two-hundred and forty-four", "two-hundred and forty-five", "two-hundred and forty-six", "two-hundred and forty-seven", "two-hundred and forty-eight", "two-hundred and forty-nine", "two-hundred and fifty", "two-hundred and fifty-one", "two-hundred and fifty-two", "two-hundred and fifty-three", "two-hundred and fifty-four", "two-hundred and fifty-five", "two-hundred and fifty-six", "two-hundred and fifty-seven", "two-hundred and fifty-eight", "two-hundred and fifty-nine", "two-hundred and sixty", "two-hundred and sixty-one", "two-hundred and sixty-two", "two-hundred and sixty-three", "two-hundred and sixty-four", "two-hundred and sixty-five", "two-hundred and sixty-six", "two-hundred and sixty-seven", "two-hundred and sixty-eight", "two-hundred and sixty-nine", "two-hundred and sevenety", "two-hundred and seventy-one", "two-hundred and seventy-two", "two-hundred and seventy-three", "two-hundred and seventy-four", "two-hundred and seventy-five", "two-hundred and seventy-six", "two-hundred and seventy-seven", "two-hundred and seventy-eight", "two-hundred and seventy-nine", "two-hundred and eighty", "two-hundred and eighty-one", "two-hundred and eighty-two", "two-hundred and eighty-three", "two-hundred and eighty-four", "two-hundred and eighty-five", "two-hundred and eighty-six", "two-hundred and eighty-seven", "two-hundred and eighty-eight", "two-hundred and eighty-nine", "two-hundred and ninety", "two-hundred and ninety-one", "two-hundred and ninety-two", "two-hundred and ninety-three", "two-hundred and ninety-four", "two-hundred and ninety-five", "two-hundred and ninety-six", "two-hundred and ninety-seven", "two-hundred and ninety-eight", "two-hundred and ninety-nine", "three-hundred", "three-hundred and one", "three-hundred and two", "three-hundred and three", "three-hundred and four", "three-hundred and five", "three-hundred and six", "three-hundred and seven", "three-hundred and eight", "three-hundred and nine", "three-hundred and ten", "three-hundred and eleven", "three-hundred and twelve", "three-hundred and thirteen", "three-hundred and fourteen", "three-hundred and fifteen", "three-hundred and sixteen", "three-hundred and seventeen", "three-hundred and eighteen", "three-hundred and nineteen", "three-hundred and twenty", "three-hundred and twenty-one", "three-hundred and twenty-two", "three-hundred and twenty-three", "three-hundred and twenty-four", "three-hundred and twenty-five", "three-hundred and twenty-six", "three-hundred and twenty-seven", "three-hundred and twenty-eight", "three-hundred and twenty-nine", "three-hundred and thirty", "three-hundred and thirty-one", "three-hundred and thirty-two", "three-hundred and thirty-three", "three-hundred and thirty-four", "three-hundred and thirty-five", "three-hundred and thirty-six", "three-hundred and thirty-seven", "three-hundred and thirty-eight", "three-hundred and thirty-nine", "three-hundred and forty", "three-hundred and forty-one", "three-hundred and forty-two", "three-hundred and forty-three", "three-hundred and forty-four", "three-hundred and forty-five", "three-hundred and forty-six", "three-hundred and forty-seven", "three-hundred and forty-eight", "three-hundred and forty-nine", "three-hundred and fifty", "three-hundred and fifty-one", "three-hundred and fifty-two", "three-hundred and fifty-three", "three-hundred and fifty-four", "three-hundred and fifty-five", "three-hundred and fifty-six", "three-hundred and fifty-seven", "three-hundred and fifty-eight", "three-hundred and fifty-nine", "three-hundred and sixty", "three-hundred and sixty-one", "three-hundred and sixty-two", "three-hundred and sixty-three", "three-hundred and sixty-four", "three-hundred and sixty-five", "three-hundred and sixty-six", "three-hundred and sixty-seven", "three-hundred and sixty-eight", "three-hundred and sixty-nine", "three-hundred and sevenety", "three-hundred and seventy-one", "three-hundred and seventy-two", "three-hundred and seventy-three", "three-hundred and seventy-four", "three-hundred and seventy-five", "three-hundred and seventy-six", "three-hundred and seventy-seven", "three-hundred and seventy-eight", "three-hundred and seventy-nine", "three-hundred and eighty", "three-hundred and eighty-one", "three-hundred and eighty-two", "three-hundred and eighty-three", "three-hundred and eighty-four", "three-hundred and eighty-five", "three-hundred and eighty-six", "three-hundred and eighty-seven", "three-hundred and eighty-eight", "three-hundred and eighty-nine", "three-hundred and ninety", "three-hundred and ninety-one", "three-hundred and ninety-two", "three-hundred and ninety-three", "three-hundred and ninety-four", "three-hundred and ninety-five", "three-hundred and ninety-six", "three-hundred and ninety-seven", "three-hundred and ninety-eight", "three-hundred and ninety-nine", "four-hundred" }; // Works like sprintf(), without the need for a buffer. 03/16/98 callahan char *tprintf(char *format,...) { static char buff[MAX_STRING_LENGTH]; va_list ap; va_start(ap, format); vsprintf(buff, format, ap); va_end(ap); buff[MAX_STRING_LENGTH - 1] = '\0'; return buff; }