#include "musicmud.h" #include "levels.h" #include "msi.h" #include "nations.h" #include "Socket.h" #include "verbs.h" #include "State.h" #include "emsg.h" #include <algorithm> #define MODULE "who" class orderer { public: bool operator()(const Player *a, const Player *b) const { if (level_of(a) > level_of(b)) return 1; if (level_of(a) < level_of(b)) return 0; if (strcmp(a->id, b->id)<0) return 1; return 0; } }; std::vector<Player*> players_on(MudObject *who=0, bool onlyon=true) { std::vector<Player*> l; iforeach(i, *players) { if (who && (who!=i && !visible_to(who, i))) continue; if (!onlyon || i->get_flag(FL_LOGGEDIN)) l.push_back(i); } std::sort(l.begin(), l.end(), orderer()); return l; } static char object_gender(const MudObject *o) { const char *gender = o->get("gender"); if (gender) return toupper(*gender); else return 'N'; } static const char *g_string(char a) { if (a == 'M') return "^O"; if (a == 'F') return "^F"; if (a == 'N') return "N"; if (a == 'P') return "P"; if (a == 'A') return "A"; return "?"; } static std::string getname(const Player *who) { return who->get("name"); } static std::string getlevel(const Player *who) { return ssprintf("%i", level_of(who)); } static std::string getprivs(const Player *who) { return ssprintf("%i", privs_of(who)); } static std::string getmission(const Player *who) { MudObject *m = who->get_object("mission"); if (!m) return "-"; if (m->owner != (MudObject *)who) return "-"; if (m->get_flag(FL_QUEST) && m->get("mname")) return m->get("mname"); if (m->get_flag(FL_MISSION) && m->get_object("instance")) { MudObject *i = m->get_object("instance"); return ssprintf("%s mini", i->get("mname")); } return "-"; } static std::string getinvis(const Player *who) { return ssprintf("%i", invis(who)); } static std::string getnation(const Player *who) { return prettynation(nation(who)); } static std::string getgender(const Player *who) { return g_string(object_gender(who)); } static std::string getrank(const Player *who) { return get_rank(who); } static std::string getlocation(const Player *who) { return get_zoneprop(who->owner, "planet", "Somewhere"); } static std::string getlocid(const Player *who) { return who->owner->id; } static std::string getlocname(const Player *who) { return who->owner->get("name")?:"Unknown"; } time_t idle_time(const Player *who) { return now - who->get_idle(); } static string format_itime(time_t t) { char thing[256]; time_t seconds = t % 60; time_t minutes = t / 60; time_t hours = minutes / 60; minutes = minutes % 60; sprintf(thing, "%03i:%02i:%02i", (int)hours, (int)minutes, (int)seconds); return thing; } static string time_idle(const Player *o) { return format_itime(now - o->get_idle()); } static string get_state(Player *o) { string thing = ""; if (o->get("away")) thing += " ^G[^gAway^G]"; if (linkdead(o)) thing += " ^Y[^gLinkdead^Y]"; if (idle_time(o)>=(60*60)) thing += " ^R[^rIdle^R]"; else if (idle_time(o)>=(60*15)) thing += " ^Y[^yIdle^Y]"; else if (idle_time(o)>=(60*2)) thing += " ^G[^gIdle^G]"; if (o->get_flag(FL_CODING)) thing += " ^C[^BCoding^C]"; if (o->get_int("remort")!=-1) thing += " ^r[^RRemort^r]"; if (o->get_flag(FL_SLEEPING)) thing += " ^W[^mAsleep^W]"; const char *state = o->get_state()->id; if (state) { if (strstr(state, "make")) thing += " ^R[^YBuilding^R]"; if (strstr(state, "mail")) thing += " ^R[^YMailing^R]"; if (strstr(state, "board")) thing += " ^R[^YPosting^R]"; } if (const char *p=o->get("$piggy")) { thing += ssprintf(" ^g[^G%#s^g]", p); } return thing; } static std::string gettitle(const Player *who) { return ssprintf("%s%s", object_title(who), get_state(const_cast<Player*>(who))); } static std::string getidle(const Player *who) { if (who->p) return ssprintf("^m%s^n", time_idle(who).c_str()); else return ssprintf("^y%s^n", time_idle(who).c_str()); } static std::string gethits(const Player *who) { if (who->get_priv(PFL_IMMORTAL)) return "^-^-^-"; else return ssprintf("^r%i^n", strength_of(who)); } static std::string getarmour(const Player *who) { return ssprintf("%3i", parmour(const_cast<Player*>(who)) + player_armour(const_cast<Player*>(who))); } static std::string get6(const Player *who) { if (!who->p) return "-"; return who->p->socket->is6()?"6":"4"; } static std::string getnaws(const Player *who) { if (!who->p) return "-"; const Player *p = who; if (p->p->row && p->p->col) return ssprintf("%ix%i", p->p->row, p->p->col); return "?x?"; } static std::string getmxp(const Player *who) { if (!who->p) return "-"; const Player *p = who; // return p->p->mxp?ssprintf("MXP (%i)"):""; if (p->p->mxp) if (p->p->mxp_version.length()) return ssprintf("MXP : %s", p->p->mxp_version); else return "MXP"; return ""; } static std::string getterm(const Player *who) { if (!who->p) return "-"; string t = who->p->term; if (t.length()) return t; return "-"; } static std::string getmccp(const Player *who) { #ifndef NOCOMPRESS if (!who->p) #endif return "-"; #ifndef NOCOMPRESS const Player *p = who; if (p->p->compress && p->p->uncbytes) { int pcnt = (p->p->combytes * 100) / p->p->uncbytes; return ssprintf("%i: %2i%%", p->p->will_compress==2?"v2":"v1", pcnt); } return ""; #endif } static std::string getstate(const Player *who) { return who->get_state()->id; } struct mypair { string match; string place; }; list<mypair> localities; int loc_loaded = 0; static const char *locality(const Player *who) { if(!who->p) return ""; string hs = who->p->get_hostname(); const char *h = hs.c_str(); if (!loc_loaded) { FILE *f = xopen(VARDATA, "places", "r"); loc_loaded = 1; if (f) { while (1) { string s = getline(f); if (feof(f)) break; if (s.find(' ')==string::npos) continue; mypair a = { s.substr(0, s.find(' ')), s.substr(s.find(' ')+1) }; localities.push_back(a); } xclose(f); } } list<mypair>::iterator i = localities.begin(); while (i != localities.end()) { if (wcmatch(i->match.c_str(), h)) { return i->place.c_str(); } i++; } return ""; } static string hostuser(const Player *p, int ip) { string h; if(p->p) h=ip?p->p->get_ip():p->p->get_hostname(); else h="(linkdead)"; if (!p->get("_username")) { return h; } string out = p->get("_username"); out += "@"; out += h; return out; } static string gethost(const Player *p) { if (!p->p) return "-"; return hostuser(p, 0); } static string getip(const Player *p) { if (!p->p) return "-"; return hostuser(p, 1); } static string getworld(const Player *p) { if (!p->p) return "-"; return locality(p); } static string getfd(const Player *p) { if (!p->p) return "-"; return ssprintf("%i", p->p->socket->getfd()); } static string getstance(const Player *p) { if (MudObject *f=p->get_object("_fighting")) { return ssprintf("%|fighting %P", p, f); } if (MudObject *m=mount(const_cast<Player*>(p))) { return ssprintf("%|%s %P", p, m->get("riding_verb")?:"riding", m); } if (p->get_flag(FL_SLEEPING)) return "sleeping"; if (p->get_flag(FL_SITTING)) return "sitting"; if (p->get_flag(FL_SWIMMING)) return "swimming"; return "standing"; } static string getclothes(const Player *who) { NewWorld cl = clothes(const_cast<Player*>(who)); return ssprintf("%w", cl); } static string getconnected(const Player *who) { return format_itime(now - who->on_since); } static string gettimeon(const Player *p) { long sadness = p->get_int("timeon", 0) + (now - p->time_since); return ssprintf("%3i %02i:%02i:%02i", (sadness / 3600) / 24, (sadness / 3600) % 24, (sadness / 60) % 60, sadness % 60); } static string getaway(const Player *p) { const char *a = p->get("away"); if (a) if (streq(a, ".")) return ssprintf("Away"); else return ssprintf("Away : %s", a); return ""; } struct col { char code; string name; std::string (*fn)(const Player*); PFlag priv; int wid; string post; string pre; bool right; int pad; }; col possibles[] = { { 'n', "Name", getname }, { 'r', "Rank", getrank }, { 'e', "Rank", getlevel, PFL_SEESTATS }, { 'E', "Rank", getprivs, PFL_SEESTATS }, { 'v', "Inv", getinvis, PFL_SEESTATS }, { 'N', "Nation", getnation }, { 't', "Title", gettitle }, { 'l', "Location", getlocation }, { 'L', "Location", getlocid, PFL_SEESTATS }, { 'R', "Location Name", getlocname, PFL_SEESTATS }, { 'i', "Idle Time", getidle }, { 'g', "Sex", getgender }, { 'q', "Mission", getmission, PFL_SEESTATS }, { 'h', "HP", gethits, PFL_SEESTATS }, { 'a', "Arm", getarmour, PFL_SEESTATS }, { '6', "IPv", get6, PFL_SEESTATS }, { 'z', "MCCP", getmccp, PFL_SEESTATS }, { 'X', "MXP", getmxp, PFL_SEESTATS }, { 's', "Stance", getstance, PFL_SEESTATS }, { 'S', "State", getstate, PFL_SEESTATS }, { 'W', "NAWS", getnaws, PFL_SEESTATS }, { 'T', "Terminal", getterm, PFL_SEESTATS }, { 'I', "IP Address", getip, PFL_HOSTS }, { 'H', "Hostname", gethost, PFL_HOSTS }, { 'w', "Locality", getworld, PFL_HOSTS }, { 'f', "FD", getfd, PFL_HOSTS }, { 'c', "Clothes", getclothes, PFL_SEESTATS }, { 'm', "Time On", gettimeon, PFL_SEESTATS }, { 'M', "Connected", getconnected, PFL_SEESTATS }, { 'A', "Away?", getaway, }, { 0 } }; col find_column(char code, MudObject *who) { for (size_t i = 0;possibles[i].code;i++) { if (possibles[i].code==code) { if (possibles[i].priv!=PFL_NONE && !who->get_priv(possibles[i].priv)) throw emsg(ssprintf("You can't see column '%c'.", code)); return possibles[i]; } } throw emsg(ssprintf("Couldn't find a column for '%c'.", code)); } string strrep(int n, string s) { string q; if (n > 1000) n = 1000; if (n < 0) n = 0; while (n--) q += s; return q; } static void multiwho(MudObject *who, const char *name, const char *code) { bool onlyon = true; if (*code=='*') { code++; if (who->get_priv(PFL_HOSTS)) onlyon = false; } std::vector<Player*> p = players_on(who, onlyon); if (p.size()==0) { who->printf("There is noone visible on.\n"); return; } std::vector<col> cols; while (*code) { col c = find_column(*code, who); c.pre = ""; c.post = ""; while (1) { if (code[1]=='-') { c.right = 1; code++; } else if (code[1]=='[' && code[2] && code[3]) { c.pre = ssprintf("^%c[^%c", code[2], code[3]); c.post = ssprintf("^%c]^n", code[2]); code+=3; } else if (code[1]=='{' && code[2]) { c.pre = ssprintf("^%c", code[2]); c.post = "^n"; code+=2; } else if (code[1]=='<') { code+=2; c.name = ""; while (*code && *code!='>') { c.name += *code; code++; } } else break; } cols.push_back(c); code++; } iforeach(i, p) { iforeach(cit, cols) { string s = (cit->fn)(*i); s += cit->post; s += cit->pre; cit->wid >?= colour_strlen(s.c_str(), who); } } iforeach(cit, cols) { int len = colour_strlen(cit->name.c_str(), who); if ((len < cit->wid) && colour_strlen(cit->pre.c_str(), who)) { cit->pad = 1; } cit->wid >?= len; } Header h(who, name); // titles who->printf("^w"); size_t f = 0; iforeach(cit, cols) { if (f) { who->printf(" "); } f++; if (f == cols.size()) { who->printf("%*s%s", cit->pad, "", cit->name); } else { who->printf("%*s%-*s", cit->pad, "", cit->wid-cit->pad, cit->name); } } who->printf("\n"); // the ---+--- line who->printf("^B"); int wid = columns(who)-1; f = 0; iforeach(cit, cols) { if (f) { who->printf("^+"); wid--; } f = 1; int l = cit->wid; if (wid<l) l = wid; who->printf("%s", strrep(l, "^-")); wid -= l; } who->printf("%s^n\n", strrep(wid, "^-")); // bodies iforeach(i, p) { f = 0; iforeach(cit, cols) { if (f) { who->printf(" "); } f++; string txt = (cit->fn)(*i); int colwidth = cit->wid - (colour_strlen(cit->pre.c_str(), who) + colour_strlen(cit->post.c_str(), who)); if (cit->right) { // we have to right align this who->printf("%s%*s%s", cit->pre, colwidth, txt, cit->post); } else { if (f==cols.size() && colour_strlen(cit->post.c_str(), who)==0) { // left align but don't pad, since we are last column and there's no terminator who->printf("%s^Z%s%s", cit->pre, txt, cit->post); } else { // business as normal who->printf("%s%-*s%s", cit->pre, colwidth, txt, cit->post); } } } who->printf("\n"); } } static bool verb_multiwho(MudObject *who, int argc, const char **argv) { if (!argv[1]) { throw emsg("multiwho <code> [title]"); } multiwho(who, argv[2]?:"Multiwho", argv[1]); return true; } static const char *onoff(MudObject *viewer, bool isoff, MudObject *p, PFlag pflag) { if (pflag != PFL_NONE && !viewer->get_priv(pflag)) return ""; if (pflag != PFL_NONE && !p->get_priv(pflag)) return "^L ^-^-^-^-^-^-^- "; if (isoff) return "^R off "; return "^G on "; } static const char *cnoff(const char *what, MudObject *p, PFlag pflag) { if (pflag != PFL_NONE && !p->get_priv(pflag)) return ""; return what; } static bool verb_acommstats(MudObject *o, int argc, const char **argv) { Header h(o, "ACommstats", 1); std::vector<Player*> p = players_on(o); size_t maxnamelen = 0; iforeach(i, p) { Player *obj = *i; maxnamelen >?= colour_strlen(obj->get("name"), o); } o->printf(" %*s %s%s%s%s%s\n", maxnamelen, "", cnoff("aberchat ", o, PFL_ABERCHAT), cnoff(" achat ", o, PFL_ABERCHAT), cnoff(" atell ", o, PFL_ABERCHAT), cnoff(" acode ", o, PFL_CODER), cnoff(" agod ", o, PFL_GOD)); iforeach(i, p) { Player *obj = *i; o->printf(" %-*M %s%s%s%s%s%s^n\n", maxnamelen, obj, obj==o?"&-b":"", onoff(o, obj->get_flag(FL_NOABERCHAT), obj, PFL_ABERCHAT), onoff(o, obj->get_flag(FL_NOACHAT), obj, PFL_ABERCHAT), onoff(o, obj->get_flag(FL_NOATELL), obj, PFL_ABERCHAT), onoff(o, obj->get_flag(FL_NOACODE), obj, PFL_CODER), onoff(o, obj->get_flag(FL_NOAGOD), obj, PFL_GOD) ); } return true; } static bool verb_wwwho(MudObject *o, int argc, const char **argv) { FILE *f = xopen("tmp", "wwwho-tmp2", "w+"); if (!f) return 1; std::vector<Player*> p = players_on(); iforeach(i, p) { Player *obj = *i; if (!invis(obj)) { string title = lose_colour(object_title(obj).c_str()); fprintf(f, "%s;%s;%s\n", get_long_rank(obj), bwname(obj), title.c_str()); } } xclose(f); chmod("tmp/wwwho-tmp2", 0664); rename("tmp/wwwho-tmp2", "tmp/wwwho-tmp"); return true; } #include "verbmodule.h" void startup() { AUTO_VERB(multiwho, 6, 0, PFL_NONE); AUTO_VERB(acommstats, 5, 0, PFL_ABERCHAT); AUTO_VERB(wwwho, 5, 0, PFL_NONE); }