/* * MusicMUD Daemon, version 1.0 * Copyright (C) 1998-2003 Abigail Brady * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include <stdlib.h> #include <stdio.h> #include <time.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #include <ctype.h> #include "Mission.h" #include "musicmud.h" #include "util.h" #include "pflags.h" #include "death.h" #include "misc.h" #include "msi.h" #include "hooks.h" #include "events.h" #include "trap.h" #include "verbs.h" #include "paths.h" #include "units.h" #include "match.h" #include "prep.h" #include "vsprintf.h" #include "paths.h" #include "levels.h" #include "charset.h" #include "emsg.h" #include "actions.h" #include "body.h" #include "musictok.h" bool isvowel(char letter) { if (letter=='a') return 1; if (letter=='e') return 1; if (letter=='i') return 1; if (letter=='o') return 1; if (letter=='u') return 1; return 0; } bool endswith(const string &a, const string &b) { return endswith(a.c_str(), b.c_str()); } void newending(string &s, const char *old, const char *newend) { s = s.substr(0, s.length()-strlen(old)); s += newend; } string plural_word(const char *word) { string w = word; int an = 0; if (w.substr(w.length()-2)=="^n") { w = w.substr(0, w.length()-2); an = 1; } if (endswith(w, "knife")) { newending(w, "fe", "ves"); } else if (endswith(w, "shelf")) { newending(w, "f", "ves"); } else if (endswith(w, "leaf")) { newending(w, "f", "ves"); } else if (endswith(w, "thief")) { newending(w, "f", "ves"); } else if (endswith(w, "potato")) { newending(w, "o", "oes"); } else if (w.substr(w.length()-1)=="s" || w.substr(w.length()-1)=="z" || w.substr(w.length()-1)=="x") { w += "es"; } else if (w.substr(w.length()-2)=="ch" || w.substr(w.length()-2)=="sh") { w += "es"; } else if (w.length()>=2 && w[w.length()-1]=='y' && !isvowel(w[w.length()-2])) { w = w.substr(0, w.length()-1); w += "ies"; } else { w += "s"; } if (an) { w += "^n"; } return w; /* consider having a table of exceptions here knife -> knives leaf -> leaves staff -> staves thief -> thieves wife -> wives foot -> feet goose -> geese louse -> lice mouse -> mice man -> men woman -> women shelf -> shelves potato -> potatoes child -> children */ } string plural_phrase(const char *phrase) { if (const char *br=strstr(phrase, " (")) { string before_p = string(phrase, br-phrase); string after_p = br; return plural_phrase(before_p.c_str())+after_p; } if (const char *of=strstr(phrase, " of ")) { string before = string(phrase, of-phrase); return plural_word(before.c_str()) + of; } return plural_word(phrase); } const char *remove_articles(const char *frase) { if (!strncasecmp(frase, "a ", 2)) return frase+2; if (!strncasecmp(frase, "an ", 3)) return frase+3; if (!strncasecmp(frase, "the ", 4)) return frase+4; if (!strncasecmp(frase, "some ", 5)) return frase+5; return frase; } string remove_articles(const string &s) { return remove_articles(s.c_str()); } const char *numbertostring(int number) { if (number == 0) return "no"; if (number == 1) return "one"; if (number == 2) return "two"; if (number == 3) return "three"; if (number == 4) return "four"; if (number == 5) return "five"; if (number == 6) return "six"; if (number == 7) return "seven"; if (number == 8) return "eight"; if (number == 9) return "nine"; if (number == 10) return "ten"; if (number == 11) return "eleven"; if (number == 12) return "twelve"; if (number == 13) return "thirteen"; if (number == 14) return "fourteen"; if (number == 15) return "fifteen"; return "many"; } const char *numbertostring(int number, MudObject *of) { if (const char *a=of->array_get("num", number)) { return a; } if (number == 0) return "no"; if (number == 1) return "one"; if (number == 2) return "two"; if (number == 3) return "three"; if (number == 4) return "four"; if (number == 5) return "five"; if (number == 6) return "six"; if (number == 7) return "seven"; if (number == 8) return "eight"; if (number == 9) return "nine"; if (number == 10) return "ten"; if (number == 11) return "eleven"; if (number == 12) return "twelve"; if (number == 13) return "thirteen"; if (number == 14) return "fourteen"; if (number == 15) return "fifteen"; return "many"; } string plural_name(MudObject *obj, int islong) { if (const char *p=name(obj, 1, islong)) return p; else { const char *n = name(obj, 0, islong); if (!n) n = name(obj); if (!n) n = "???"; return plural_phrase(remove_articles(n)); } } string give_number(MudObject *obj, int n, const char *adj, int islong, bool dontstate) { if (n == 1) { if (adj) { return ssprintf("%s %s %s", strchr("aeiou", adj[0])?"an":"a", adj, remove_articles(name(obj, 0, islong))); } return name(obj, 0, islong, dontstate)?:""; } if (adj) return ssprintf("%s %s %s", numbertostring(n, obj), adj, plural_name(obj, islong).c_str()); return ssprintf("%s %s", numbertostring(n, obj), plural_name(obj, islong).c_str()); } mudtime_t mudtime(MudObject *location) { int tz = get_zonepropint(location, "timezone", 0); int daylen = get_zonepropint(location, "daylen", -1); if (daylen == 0) { struct tm *t = gmtime(&now); mudtime_t tm; tm.hour = t->tm_hour; tm.min = t->tm_min; return tm; } if (daylen != -1) { mudtime_t tm; tm.hour = ((now/daylen)+tz)%24; tm.min = ((now % daylen)*60)/daylen; return tm; } return (mudtime_t){12, 0}; } struct imperial_weight { int dram; int oz; int lb; int st; int cwt; int ton; imperial_weight(double ounces) { dram = (int)(ounces*16); oz = dram / 16; dram = dram % 16; lb = oz / 16; oz = oz % 16; st = lb / 14; lb = lb % 14; cwt = st / 8; st = st % 8; ton = cwt / 20; cwt = cwt % 20; } }; string format_grams(int m2, MudObject *whofor) { char foo[100]; int m = m2; /* 1KG = 35.274 Ounces */ if (streq(whofor->get("measures"), "imperial")) { double m3 = (m * 35.274)/KILOGRAM; imperial_weight iw(m3); if (iw.ton) sprintf(foo, "^W%i ton %i cwt^n", iw.ton, iw.cwt); else if (iw.cwt) sprintf(foo, "^W%i cwt %i st", iw.cwt, iw.st); else if (iw.st) sprintf(foo, "^W%i st %i lb^n", iw.st, iw.lb); else if (iw.lb) sprintf(foo, "^W%i lb %i oz^n", iw.lb, iw.oz); else if (iw.oz) sprintf(foo, "^W%i oz %i dram^n", iw.oz, iw.dram); else if (iw.dram) sprintf(foo, "^W%i dram^n", iw.dram); else sprintf(foo, "nothing"); return foo; } // m *= HECTOGRAM; if (m > KILOTON) { m /= TON; sprintf(foo, "^W%i.%03i^n kt", m / 1000, m % 1000); } else if (m > TON) { m /= KILOGRAM; sprintf(foo, "^W%i.%03i^n t", m / 1000, m % 1000); } else if (m > KILOGRAM) { sprintf(foo, "^W%i.%03i^n kg", m / KILOGRAM, m % KILOGRAM); } else { sprintf(foo, "^W%i^n g", m); } return foo; } char *pronoun[PRONOUNS][GENDERS] = { /* male female plural neuter androgynous unknown 2nd singular 2nd plural */ {"he", "she", "they", "it", "ey", "[he]", "you", "you" }, {"him", "her", "them", "it", "em", "[him]", "you", "you", }, {"his", "her", "their", "its", "eir", "[his]", "your", "your"}, {"his", "hers", "theirs", "its", "eirs", "[his]", "yours", "yours" }, {"himself", "herself", "themselves", "itself", "emself", "[himself]", "yourself", "yourselves"}, {"man", "woman", "people", "thing", "person", "[man]", "person", "people"}, }; static gender_t char_to_gender (char abbrv) { switch (toupper(abbrv)) { case 'M' : return GENDER_MALE; case 'F' : return GENDER_FEMALE; case 'P' : return GENDER_PLURAL; case 'A' : return GENDER_ANDRO; default: return GENDER_NEUTRAL; } } gender_t get_gender(const MudObject *what) { if (!what) return GENDER_UNKNOWN; if (what->get_flag(FL_PLURAL)) return GENDER_PLURAL; const char *gender = what->get("gender"); if (gender) return char_to_gender(*gender); return GENDER_NEUTRAL; } string printed_name(MudObject *consumer, MudObject *who, int magic) { if (!who) return "[name]"; const char *n = name(who); if (!n) n = who->get("short"); if (!n) n = who->id; if (magic && who==consumer) return "you"; if (!consumer) return n; if (visible_to(consumer, who)) { if (invis(who)) return (string)"^n("+name(who)+"^n)"; else return n; } return "^pSomeone^n"; } string printed_name_aber(MudObject *consumer, MudObject *who) { if (!who) return "[name]"; return name(who); } string sprintf_c(int cap, const char *format, PRINT_ARGS) { string buffer; buffer = formatprint(NULL, format, GET_PARMS()); if (cap) { int idx = 0; if (buffer[0]=='^') idx+=2; buffer[idx] = toupper(buffer[idx]); } return buffer; } static string change_article(MudObject *who, MudObject *what, const char *oname, const char *art) { bool worn = what->get_object(KEY_WORNBY)==who; if (worn && strncmp(oname, "a pair of ", 10)==0) { return ssprintf("%s %s", art, oname+10); } if (strncmp(oname, "a ", 2)==0) { return ssprintf("%s %s", art, oname+2); } if (strncmp(oname, "an ", 2)==0) { return ssprintf("%s %s", art, oname+3); } if (strncmp(oname, "some ", 5)==0) { return ssprintf("%s %s", art, oname+5); } return oname; } string _possess(MudObject *who, const char *str, MudObject *what) { if (!what) return "???"; if (what->owner==who) { return change_article(who, what, str, his_or_her(who)); } else { return change_article(who, what, str, "the"); } } string _mine(MudObject *who, const char *str, MudObject *what) { if (!what) return "???"; if (what->owner==who) { return change_article(who, what, str, "your"); } else { return change_article(who, what, str, "the"); } } static string _mine(MudObject *who, MudObject *what) { return _mine(who, name(what), what); } #define mine(a, b) _mine(a, b).c_str() #define possess(a, b) _mine(a, b).c_str() string sprinta (MudObject *consumer, const char *format, MudObject *sender, MudObject *target, const char *text, int aber, MudObject *prop) { int cap = 0; int always_3rdperson = 0; MudObject *ref=0; set<MudObject *> mentioned; mentioned.insert(sender); string buffer = ""; string restricts = ""; bool likerestrict = 0; while (*format) { int pnoun = -1; int gender = -1; string candidate; if (restricts.length() && *format==')') { restricts = ""; if (likerestrict) break; format++; continue; } if (*format!='%') { candidate = *format; format++; goto docandy; } cap = buffer.length()==0; always_3rdperson = 0; format++; again: switch (*format) { case '#': cap = 1; format++; goto again; case '|': always_3rdperson = 1; format++; goto again; case '*': restricts = ""; format++; while (*format && *format!='(') { restricts += *format; format++; } if (consumer) { likerestrict = 1; const char *restrict = restricts.c_str(); while (*restrict) { if (*restrict=='B' && cansee(consumer)) likerestrict = 0; if (*restrict=='D' && canhear(consumer)) likerestrict = 0; if (*restrict=='M' && consumer->get_flag(FL_DUMB)) likerestrict = 0; if (*restrict=='H' && !wf_wears_with_flag(consumer, FL_HANDSTIED)) likerestrict = 0; restrict++; } } break; case 'w': if (prop && prop->get("short")) candidate = sprintf_c(cap, "^o%s^n", prop->get("short")); else candidate = sprintf_c(cap, "[name]"); break; case 'W': if (prop && is_person(prop->owner) && mentioned.find(prop->owner) == mentioned.end() && prop->owner->owner == consumer->owner && prop->owner != consumer) { candidate = sprintf_c(cap, "%s's %s", name(prop->owner), remove_articles(name(prop))); } else if (prop && name(prop)) if (prop->owner==consumer && aber==2) candidate = sprintf_c(cap, "%s", mine(consumer, prop)); else if (prop->owner==ref) candidate = sprintf_c(cap, "%s", _possess(prop->owner, name(prop), prop).c_str()); else candidate = sprintf_c(cap, "%s", name(prop)); else { candidate = sprintf_c(cap, "the [name]"); } break; case 's': if (text) candidate = sprintf_c(cap, "%s", text); else candidate = sprintf_c (cap, aber==1?printed_name_aber (consumer, sender).c_str(): printed_name (consumer, sender, aber==2).c_str()); candidate += '\2'; break; case '[': { format++; int plur = 0; if (aber==2 && consumer==sender && !always_3rdperson) plur = 1; if (sender && sender->get_flag(FL_PLURAL)) plur = 1; int seens = 0; char *end = strchr(format, ']'); if (!end) { buffer += "^Rmissing ^n]^R!"; return buffer; } while (*format && *format!=']') { if (*format=='/') seens=1; else if (plur == seens) { candidate += *format; } format++; } break; } case '<': { format++; int plur = 0; if (aber==2 && consumer==target && !always_3rdperson) plur = 1; if (target && target->get_flag(FL_PLURAL)) plur = 1; int seens = 0; char *end = strchr(format, '>'); if (!end) { buffer += "^Rmissing ^n>^R!"; return buffer; } while (*format && *format!='>') { if (*format=='/') seens=1; else if (plur == seens) { candidate += *format; } format++; } break; } case '1' : if (!ref) ref = sender; mentioned.insert(sender); if (aber==2 && consumer==sender && format[1]=='\'' && format[2]=='s' && !always_3rdperson) { candidate = cap?"Your":"your"; format+=2; break; } candidate = sprintf_c (cap, aber==1 ?printed_name_aber (consumer, sender).c_str(): printed_name (consumer, sender, always_3rdperson?0:aber==2).c_str()); break; case 'a': if (!ref) ref = sender; mentioned.insert(target); if (aber==2 && consumer==target && format[1]=='\'' && format[2]=='s' && !always_3rdperson) { candidate = cap?"Your":"your"; format+=2; break; } candidate = sprintf_c (cap, aber==1?printed_name_aber (consumer, target).c_str(): printed_name (consumer, target, always_3rdperson?0:aber==2).c_str()); break; case '%': candidate = '%'; break; case '2' : case '3' : case '4' : case '5' : case '6': case '7' : gender = get_gender (sender); pnoun = *format - '2'; if (consumer && sender && !visible_to(consumer, sender)) gender = GENDER_PLURAL; if (aber==2 && sender==consumer && !always_3rdperson) gender = consumer->get_flag(FL_PLURAL)?GENDER_YOU_P:GENDER_YOU_S; /* FALL THROUGH */ case 'b' : case 'c' : case 'd' : case 'e' : case 'f': case 'g': case 'B' : case 'C' : case 'D' : case 'E' : case 'F': case 'G': if (gender == -1) { gender = get_gender (target); if (consumer && target && !visible_to(consumer, target)) gender = GENDER_PLURAL; pnoun = tolower(*format) - 'b'; if (aber==2 && consumer==target && !always_3rdperson) gender = consumer->get_flag(FL_PLURAL)?GENDER_YOU_P:GENDER_YOU_S; } string tmp = pronoun[pnoun][gender]; if (cap) { if (tmp[0]=='[') tmp[1] = toupper(tmp[1]); else tmp[0] = toupper(tmp[0]); } candidate = tmp; } if (*format) format++; docandy: if (!restricts.length() || likerestrict) buffer += candidate; } return buffer; } const char *xname(const char *id) { MudObject *o = planet->get(id); if (!o) return id; return name(o); } string build_setin (MudObject *mynum, const char *q, const char *n, const char *d, const char *v) { if (!n) n = "<name>"; if (!v) v = "<victim>"; if (!d) d = "<dir>"; string p = ""; while (*q) { if (*q != '%') p += *q++; else { switch (*++q) { case 'n': p += n; break; case 'v': p += n; break; case 'd': p += d; break; case 0: --q; break; default: ; } ++q; } } return ssprintf("%#s", p); } static const char *def_setmout = "%n is displaced elsewhere."; static const char *def_setmin = "%n is displaced here."; static const char *def_setvin = "%n suddenly appears!"; static const char *def_setvout = "%n has vanished!"; static const char *def_setqin = "%n enters the game."; static const char *def_setqout = "%n leaves the game."; static const char *def_setsit = "%n, sitting here."; static const char *def_setstand = "%n, standing here."; static const char *def_setsleep = "%n is sleeping here."; static const char *plu_setmout = "%n are displaced elsewhere."; static const char *plu_setmin = "%n are displaced here."; static const char *plu_setvin = "%n suddenly appear!"; static const char *plu_setvout = "%n have vanished!"; static const char *plu_setqin = "%n enter the game."; static const char *plu_setqout = "%n leave the game."; static const char *plu_setsit = "%n, sitting here."; static const char *plu_setstand = "%n, standing here."; static const char *plu_setsleep = "%n are sleeping here."; static const char *def_set[] = { def_setmin, def_setmout, def_setvin, def_setvout, def_setqin, def_setqout, def_setsit, def_setstand, def_setsleep }; static const char *plu_set[] = { plu_setmin, plu_setmout, plu_setvin, plu_setvout, plu_setqin, plu_setqout, plu_setsit, plu_setstand, plu_setsleep }; static const char *prop_name[] = { "setmin", "setmout", "setvin", "setvout", "setqin", "setqout", "setsit", "setstand", "setsum", "setsin", "setsout", "setsleep", }; const char *get_message(MudObject *who, setin_t which) { const char *msg = who->get(prop_name[which]); if (msg && (strstr(msg, "%n") || !is_player(who))) return msg; if (linkdead(who) && which==setqout) return who->get_flag(FL_PLURAL)?"The cardboard cutouts of %n leave the game." :"The cardboard cutout of %n leaves the game."; if (who->get_flag(FL_PLURAL)) return plu_set[which]; else return def_set[which]; } char * howsoon(time_t when, bool secs) { static char boo[256]; char *foo = boo; boo[0] = 0; when -= now; if (when <= 0) return "Now"; if (when > DAY) { int days = when / DAY; foo += sprintf(foo, " %i day", days); if (days > 1) foo += sprintf(foo, "s"); when %= DAY; } if (when > HOUR) { int days = when / HOUR; foo += sprintf(foo, " %i hour", days); if (days > 1) foo += sprintf(foo, "s"); when %= HOUR; } if (when > MINUTE) { int days = when / MINUTE; foo += sprintf(foo, " %i minute", days); if (days > 1) foo += sprintf(foo, "s"); when %= MINUTE; } if (when && secs) { foo += sprintf(foo, " %i second", (int)when); if (when > 1) foo += sprintf(foo, "s"); } return boo+1; } const char *was_or_were(MudObject *of) { if (of->get_flag(FL_PLURAL)) return "were"; return "was"; } string nicetime(int secs) { string s = ""; int hr = (secs / 3600); int mn = (secs / 60) % 60; int sc = (secs % 60); if (hr==1) { s += "1 hour"; } else if (hr) { s += ssprintf("%i hours", hr); } if (mn) { if (hr) s += ", "; if (mn==1) { s += "1 minute"; } else { s += ssprintf("%i minutes", mn); } } if (sc) { if (mn||hr) s += ", "; if (sc==1) { s += "1 second"; } else { s += ssprintf("%i seconds", sc); } } return s; } string possibly_drunkify(MudObject *who, string what2) { { const char *s = what2.c_str(); int upper = 0; int lower = 0; while (*s) { if (isupper(*s)) upper++; if (islower(*s)) lower++; s++; } if (upper>=10 && lower==0) { what2 = make_lower(what2.c_str()); } } if (who->get_int("literate", 1)==0) { what2 = " " + what2 + " "; const char *s = what2.c_str(); string w = ""; int last = 0; while (*s) { static char *literacy_table[] = { " b4", "before", " b", "be", " 4", "for", " 2", "to", " 1", "one", " u", "you", " r", "are", " i", "I", " ill", "I'll", " no", "know", " ive", "I've", " cum", "come", " nos", "knows", " wots", "what's", " wen", "when", " lol", "oh that was so funny", " cant", "can't", " ppl", "people", " tlk", "talk", " tlking", "talking", " dam", "damn", " g2g", "got to go", " txt", "text", " thanx", "thank-you, kind sir", " wot", "what", " ne 1", "anyone", " ne1", "anyone", " every1", "everyone", " sum", "some", " sumtime", "sometime", " y", "why", " yer", "yeah", " ys", "why's", " sum1", "someone", " sum 1", "someone", NULL, }; int lt = 0; while (literacy_table[lt]) { if (!strncmp(s, literacy_table[lt], strlen(literacy_table[lt])) && !isalpha(s[strlen(literacy_table[lt])])) { w += " "; w += literacy_table[lt+1]; s += strlen(literacy_table[lt]); goto blah; } lt+=2; } if (last == *s && (last == '!' || last == '?')) { s++; goto blah; } w += *s; last = *s; s++; blah:; } w = w.substr(1, w.length()-2); what2 = w; } if (is_player(who) && who->get_int("$pigged")>0) { const char *ptype = who->get("$piggy"); for (size_t i=0;animals[i].adj;i++) { if (streq(animals[i].adj, ptype) && animals[i].noise) return animals[i].noise; } } if ((who->get_int(KEY_PISSED))<(now+120)) { return what2; } int needed = who->get_int(KEY_PISSED)-now; needed -= 120; if (needed>1000) needed = 100; else needed /= 10; int booze = who->get_int(KEY_PISSED, now); if (booze - now > 135*12 && randperc() < 10) { who->printf ("You let everyone know what you had for ^Rlunch^n.\n"); who->oprintf(canhear, "%#M ^R%[B U R P S/B U R P]^n loudly^n.\n", who); } const char *what = what2.c_str(); string tmp = ""; while (*what) { if (random_number(100)<=needed) if (*what=='s' && what[1]=='h') tmp += "s"; else if (*what=='s') tmp += "sh"; else if (*what=='c' && what[1]=='e') tmp += "sh"; else if (*what=='c' && what[1]=='i') tmp += "sh"; else if (*what=='r') tmp += "w"; else tmp += *what; else tmp += *what; what++; } return tmp; } string title_for(string a, int width, const colourinfo_t &ci, const char *col, const char *chr) { string f = col; if (!chr) chr = "^="; f += chr; f += chr; f += " ^W" +a + " "; f += col; width -= colour_strlen(a.c_str(), ci); width -= 4; while (width>0) { f+= chr; width--; } f += "^n"; return f; } string title_for(string a, const MudObject *who, const char *col, const char *chr) { return title_for(a, columns(who)-1, colinfo(who), col, chr); } string footer_for(int width, const char *col, const char *chr) { string f = col;; if (!chr) chr = "^="; while (width>0) { f += chr; width--; } f += "^n"; return f; } string footer_for(MudObject *who, const char *fmt, const char *chr) { return footer_for(columns(who)-1, fmt, chr); } int strpos(const char *foo, char a) { char *b = strchr(foo, a); if (!b) return -1; return b-foo; } void mud_fprintf(MudObject *to, FILE *f, const char *fmt, PRINT_PARMS) { string buf = formatprint(NULL, fmt, GET_PARMS()); fprintf(f, "%s", buf.c_str()); return; } string lookup_name(const char *who) { MudObject *wh = planet->get(who); if (wh && (!is_player(wh) || !invis(wh))) { return wh->get("name"); } FILE *f = xopen(VARDATA, "namelist", "r"); if (f) { while (1) { char buffer[1024]; fgets(buffer, sizeof buffer, f); if (feof(f)) break; char *pname = strchr(buffer, ' '); if (!pname) break; *pname = 0; pname++; *strchr(pname, '\n')=0; if (streq(buffer, who)) { xclose(f); return pname; } } xclose(f); } return ssprintf("^p%#s^n", who); } string lookup_name(string who) { return lookup_name(who.c_str()); } const char *room_name(MudObject *where, MudObject *from) { if (from && from->get_flag(FL_OUTDOORS)) { if (const char *outname = where->get("building")) return outname; } const char *room = where->get("room_name"); if (!room) room = name(where); if (!room) room = "???"; return room; } string ssprintf(const char *fmt, PRINT_PARMS) { string foo = formatprint(NULL, fmt, GET_PARMS()); return foo; } string format_roomname(MudObject *room, MudObject *o, const char *ic, const char *oc, const char *notin, int yesid) { string s = format_roomname(room, o, ic, oc, notin); if (yesid) { if (ic && *ic) s += " ^D(^d"; else s += " ("; s += room->id; if (ic && *ic) s += "^D)^n"; else s += ")"; } return s; } string format_roomname(MudObject *room, MudObject *o, const char *ic, const char *oc, const char *notin, const char *myprep) { if (!notin || !*notin) notin = "in"; if (!myprep || !*myprep) myprep = 0; const char *noton = "on", *notat = "at"; if (streq(notin, "to")) noton = "onto"; if (streq(notin, "to")) notat = "to"; string b=""; if (o && room->get_flag(FL_BROKEN) && o->get("$camefrom")) { b = ssprintf("the %s side of ", o->get("$camefrom")); } const char *between=b.c_str(); const char *rn = room_name(room); if (!rn) { return ""; } int raw = 0; if (is_player(room) || is_mobile(room)) { raw = IN; } if (strncasecmp(rn, "a ", 2)==0) raw = IN; if (strncasecmp(rn, "an ", 3)==0) raw = IN; if (strncasecmp(rn, "the ", 4)==0) raw = IN; if (strncasecmp(rn, "at the ", 7)==0) raw = IN; if (strncasecmp(rn, "by ", 3)==0) raw = DIRECT; if (strncasecmp(rn, "at ", 3)==0) raw = DIRECT; if (strncasecmp(rn, "on ", 3)==0) raw = DIRECT; if (strncasecmp(rn, "in ", 3)==0) raw = DIRECT; if (strncasecmp(rn, "inside ", 7)==0) raw = DIRECT; if (strncasecmp(rn, "behind ", 7)==0) raw = DIRECT; if (strncasecmp(rn, "outside ", 8)==0) raw = DIRECT; if (strncasecmp(rn, "under ", 6)==0) raw = DIRECT; string rn2 = rn; if (raw) { rn2[0] = tolower(rn2[0]); rn = rn2.c_str(); } if (strstr(rn, " Street")) raw = IN; if (room->get_int("namestyle")!=-1) { raw = room->get_int("namestyle"); if (streq(myprep, "over")) raw = OVER; } switch (raw) { case DIRECT: return ssprintf("%s%s%s", ic, rn, oc); break; case OVER: return ssprintf("%s %s%s%s", myprep, ic, rn, oc); break; case IN: case 100: return ssprintf("%s %s%s%s%s", notin, between, ic, rn, oc); break; case ON: return ssprintf("%s %s%s%s%s", noton, between, ic, rn, oc); break; case ON_THE: return ssprintf("%s %sthe %s%s%s", noton, between, ic, rn, oc); break; case BY: return ssprintf("by %s%s%s%s", between, ic, rn, oc); break; case BY_THE: return ssprintf("by %sthe %s%s%s", between, ic, rn, oc); break; case AT: return ssprintf("%s %s%s%s%s", notat, between, ic, rn, oc); break; case AT_THE: return ssprintf("%s %sthe %s%s%s", notat, between, ic, rn, oc); break; case ON_BOARD: return ssprintf("on board %s%s%s%s", between, ic, rn, oc); break; case IN_THE: default: return ssprintf("%s %sthe %s%s%s", notin, between, ic, rn, oc); break; case ON_OR_BY: if (o && o->get_flag(FL_SWIMMING)) { return ssprintf("by the %s%s%s", ic, rn, oc); } else { return ssprintf("on the %s%s%s", ic, rn, oc); } break; case ON_OR_IN: if (o && o->get_flag(FL_SWIMMING)) { return ssprintf("%s the %s%s%s", notin, ic, rn, oc); } else { return ssprintf("on the %s%s%s", ic, rn, oc); } } } void rmstuff(World<MudObject> &what, int &items, string &s, const char *itemstr, const char *cat) { NewWorld clothing; NewWorld ctypes; MudObject *o; int i; foreach((&what), o, i) { if (category_match(o, cat)) { clothing.add(*o); MudObject *p = o->get_object("cloneof"); if (!p) p = o; if (!ctypes.get(p->id)) { ctypes.add(*p); } } } if (ctypes.getsize()>2) { foreach((&clothing), o, i) { what.remove(*o); } if (s.length()) { s += ", "; } s += numbertostring(clothing.getsize()); s += itemstr; items++; } } string magiclist(const World<MudObject> &w2, displayname_t r, int further) { MudObject *o; int i; World<MudObject> what = w2; int items = 0; string s = ""; if (further) { rmstuff(what, items, s, " items of clothing", "clothing"); rmstuff(what, items, s, " pieces of jewelry", "jewelry"); rmstuff(what, items, s, " items of food", "food"); rmstuff(what, items, s, " drinks", "drink"); } map<string, int> m; map<string, string> plu; foreach((&what), o, i) { const char *n = 0; string ns; if (r) { ns = r(o); n = ns.c_str(); } else { n = name(o); if (!n) n = o->id; } if (!n) continue; if (m.find(n)!=m.end()) { m[n] = m[n] + 1; } else m[n] = 1; if (name(o, 1) && plu.find(n)==plu.end()) { plu[n] = name(o, 1); } } map<string, int>::iterator it = m.begin(); while (it != m.end()) { string ph = it->first; const char *num = ""; if (it->second != 1) { ph = plural_phrase(remove_articles(ph.c_str())); if (plu.find(it->first)!=plu.end()) { ph = plu.find(it->first)->second; } num = numbertostring(it->second); } if (items == 1) s = " and " + s; else if (items) s = ", " + s; s = ph + s; if (num[0]) { string t = num; t += " "; s = t + s; } it++; items++; } return s; } int unisuits[] = { 0x2660, 0x2665, 0x2663, 0x2666 }; string describe_card(int which, int lon) { if (which<0) return "unknown card"; if (which>=52) return "[]"; int suit = which / 13; int val = which % 13; static const char *suits[] = { "spade", "heart", "club", "diamond" }; const char *cols = "wrwr"; static const char *vals[] = { "ace", "2", "3", "4", "5", "6", "7", "8", "9", "ten", "jack", "queen", "king" }; const char *shortvals = "A23456789TJQK"; if (lon) return ssprintf("the %s of %ss", vals[val], suits[suit]); return ssprintf("^%c^#%i;^n%c", cols[suit], unisuits[suit], shortvals[val]); } string descmob(MudObject *obj, bool col) { if (!is_person(obj)) return ""; string s; const char *b=obj->get("body"); if (!b) b = "human"; s += col?is_player(obj)?"a ^p":"a ^P":"a "; if (streq(b, "human")) { MudObject *wf = wornfrom(obj); int notop = 0, nolegs = 0; if (!worn_on(obj, "body", 0) && (!wf || worn_on(obj, "body", 0))) notop = 1; if (!worn_on(obj, "legs", 0) && (!wf || worn_on(obj, "legs", 0))) nolegs = 1; if (notop && nolegs) s += "naked "; else if (notop) s += "topless "; } if (streq(b, "human")) { gender_t g = get_gender(obj); if (g==GENDER_MALE) s += "male "; if (g==GENDER_FEMALE) s += "female "; } s += b; string r = role(obj); if (r.length()) { s += " "; s += r; } if (col) s += "^n"; return s; } string role(MudObject *who) { if (who->get_flag(FL_POLICE)) { return "constable"; } if (is_player(who)) { string s = get_long_rank(who); for (size_t i=0;i<s.length();i++) { s[i] = tolower(s[i]); } return s; } const char *r = who->get("job"); if (!r) r = who->get("role"); if (!r && who->owner && who->owner->get_object("shopmob")==who) r = "shopkeeper"; return r?r:"serf"; } string owhere(MudObject *who, MudObject *room) { if (!who->owner) return "is nowhere"; if (!room) { room = who->owner; while (room && room->owner && !room->get_flag(FL_ROOM)) room = room->owner; if (!room->get_flag(FL_ROOM)) { room = who->owner; while ((is_mobile(room) || is_player(room)) && room->owner) { room = room->owner; } } } MudObject *owner = who->owner; if (streq(owner->id, "empty")) return "in internal storage"; string rn = format_roomname(room, who, "^{D", "^}"); if (owner == room) { string s = ""; s += rn; s += " ^d("; s += room->id; s += ")^n"; return s; } if (is_mobile(owner) || is_player(owner)) { string s = "carried by "; if (iswornby(who, owner)) { s = "worn by "; } if (owner->get_object(KEY_WIELD)==who) { s = "wielded by "; } s += owner->get("name"); s += " "; s += rn; return s; } if (owner->get_flag(FL_CONTAINER)) { string s = "inside "; s += owner->get("name"); s += " "; s += owhere(owner, room); return s; } return ""; } const char *name(const MudObject *o, int plural, bool islong, bool dontstate) { if (!islong) { if (plural) { if (!dontstate) { if (const char *q=o->get("!name.plural")) return q; string p = ssprintf("name.%i.plural", o->get_int(KEY_STATE, 0)); if (const char *q = o->get(p.c_str())) return q; } if (const char *q=o->get("name.plural")) return q; } else { if (!dontstate) { if (const char *q=o->get("!name")) return q; string p = ssprintf("name.%i", o->get_int(KEY_STATE, 0)); if (const char *q = o->get(p.c_str())) return q; } if (const char *q=o->get("name")) return q; } } else { if (plural) { if (!dontstate) { if (const char *q=o->get("!long.plural")) return q; string p = ssprintf("long.%i.plural", o->get_int(KEY_STATE, 0)); if (const char *q = o->get(p.c_str())) return q; } if (const char *q=o->get("long.plural")) return q; } else { if (!dontstate) { if (const char *q=o->get("!long")) return q; string p = ssprintf("long.%i", o->get_int(KEY_STATE, 0)); if (const char *q = o->get(p.c_str())) return q; } if (const char *q=o->get("long")) return q; } return name(o, plural, 0, dontstate); } return 0; } string mud_sprintf(MudObject *to, const char *fmt, PRINT_PARMS) { return formatprint(to, fmt, GET_PARMS()); } int columns(const MudObject *who) { const Player *p = dynamic_cast<const Player*>(who); if (!p) return 80; int c = p->get_int("columns", 80); if (p->p && p->p->col && !p->get_flag(FL_NONAWS)) c = p->p->col; return c <? 320; } int rows(const MudObject *who) { const Player *p = dynamic_cast<const Player*>(who); if (!p) return 24; int c = p->get_int("rows", 24); if (p->p && p->p->row && !p->get_flag(FL_NONAWS)) c = p->p->row; return c <? 200; }