/* * MusicMUD - Rooms module * 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 <ctype.h> #include "events.h" #include "musicmud.h" #include "misc.h" #include "util.h" #include "verbs.h" #include "trap.h" #include "rooms.h" #include "pflags.h" #include "paths.h" #include "shared.h" #include "zoneload.h" #include "move.h" #include "pos.h" #define WIERD get_wierd() #define MODULE "rooms" static bool numeric(const char *what) { while (*what) { if (!isdigit(*what)) return false; what++; } return true; } static bool verb_gotoin(MudObject *player, int argc, const char*argv[]) { if (player->get_flag(FL_SLEEPING)) { player->printf("You toss and turn in your sleep.\n"); player->oprintf(cansee, "%#M tosses and turns in %s sleep.\n", player, his_or_her(player)); return true; } MudObject *dest = 0; MudObject *old = player->owner; if (argc >= 2) { string a1 = argv[1]; dest = find_object(player, a1.c_str()); string name; if (player->owner && (!dest || numeric(a1.c_str()))) { const char *z3 = player->owner->id; if (z3 && strchr(z3, '_')) { z3 = strdup(z3); *strchr(z3, '_')=0; } else { const char *z4 = player->owner->get("zone"); if (!z4) { goto argh; } z3 = strdup(z4); } name = z3; name += "_"; name += a1; dest = planet->get(name.c_str()); strfree(z3); } } else { dest = player->get_object("start"); if (!dest) { MudObject *df = MUD_DEFHOME; if (!df) return true; player->printf ("You appear to have no start property. Setting to %s.\n", df->id); player->set("start", df->id); dest = df; } } argh: MudObject *where = NULL; if (argv[0][2]=='b' && argc >= 2) where = dest ? dest->owner : NULL; else if (argv[0][2]=='t' && argc >= 2) { if (dest) { if (!dest->get_flag(FL_ROOM)) { where = dest->owner; } else where = dest; } } else { where = dest; } if (streq(argv[1],"here") && player->owner && player->owner->owner) { where = player->owner->owner; } if (!where) { player->printf("Can't find '%s'.\n", argv[1]); return true; } if (is_player(player) && dest && !can_affect(player, where->get("zone")) && !player->ilc) { if (where->get("zone")) { player->printf("You can't go to that zone (%s) without remorting.\n", where->get("zone")); } else { player->printf("You can't go to unzoned objects without remorting.\n"); } return true; } if (is_in(where, player)) { player->printf(WIERD); return true; } if (where == player->owner) { player->printf("You are there already!\n"); return true; } if (!spare_people_capacity(where)) { player->printf("That location is full.\n"); return true; } player->oprintf(secret(player) && cansee, "%s\n", build_setin(player, setmout).c_str()); player->lprintf(secret(player) && cansee, "%s\n", build_setin(player, setmout).c_str()); set_owner(player, where); player->printf("You displace yourself %s.\n", format_roomname(where, player, "^{D", "^}", "to", IS_COMMANDER(player)).c_str(), where); player->oprintf(secret(player) && cansee, "%s\n",build_setin(player, setmin).c_str()); player->lprintf(secret(player) && cansee, "%s\n",build_setin(player, setmin).c_str()); rectify_state(player); player->interpret("look -"); newplace(player, old); return true; } static MudObject* random_exit_from(MudObject *where, MudObject *player) { MudObject *o; int i; NewWorld exits; foreach(where->children, o, i) { if (MudObject *l=o->get_object("link")) { if (is_mobile(player) && l->get_flag(FL_NOMOBILES)) continue; exits.add(*o); } } if (exits.getsize()) { return exits.get_nth(random_number(exits.getsize())); } return 0; } static bool verb_go(MudObject *player, int argc, const char*argv[]) { if (player->get_flag(FL_SLEEPING)) { player->printf("You can't sleepwalk.\n"); player->oprintf(cansee, "%#M tosses and turns in %s sleep.\n",player, his_or_her(player)); return true; } if (!player->get_flag(FL_MOBILE) && argc < 2) { player->printf("Go where?\n"); return true; } if (MudObject *vic=player->get_object("_fighting")) { if (vic->owner != player->owner) { player->unset("_fighting"); } else { player->printf("Not whilst fighting.\n"); return true; } } MudObject *what = 0; int pissed = 0; const char *wanted = argv[1]; hmm: if (argc >= 2) { what = find_exit(player->owner, argv[1]); } else { what = random_exit_from(player->owner, player); } if (player->get_flag(FL_SLEEPING)) { player->printf("You can't sleepwalk.\n"); return true; } if (!what || (!what->get_flag(FL_EXIT) && !what->get_flag(FL_PARTEXIT))) { if (player->get_flag(FL_NSEW)) { if (streq(argv[1], "north")|| streq(argv[1], "south")|| streq(argv[1], "east")|| streq(argv[1], "west")) { if (argv[1][0]=='n') argv[1] = "rimwards"; if (argv[1][0]=='s') argv[1] = "hubwards"; if (argv[1][0]=='e') argv[1] = "clockwise"; if (argv[1][0]=='w') argv[1] = "anticlockwise"; goto hmm; } } if (argc>=2) { player->printf("You can't go ^d%s^n.\n", wanted);; } else { player->printf("There is nowhere to go.\n"); } return true; } if ((player->get_int(KEY_PISSED)) && !mount(player)) { pissed = (int)((player->get_int(KEY_PISSED) - now)*(100.0/1200.0)); int r = random_number(100); if (r<pissed) { if (player->get_flag(FL_FLYING)) { player->printf("You flutter around aimlessly.\n"); player->oprintf(secret(player) && cansee, "%#M %[flutters/flutter] around aimlessly.\n", player); } else if (player->get_flag(FL_SWIMMING)) { player->printf("You swim around aimlessly.\n"); player->oprintf(secret(player) && cansee, "%#M %[swims/swim] around aimlessly.\n", player); } else { player->printf("You stagger around aimlessly.\n"); player->oprintf(secret(player) && cansee, "%#M %[staggers/stagger] around aimlessly.\n", player); } what = random_exit_from(player->owner, player); if (!what) return true; } } traverse(player, what); return true; } static const char *expand_dir(const char *arg, MudObject *where) { switch (arg[0]) { case 'n' : case 'N': return "north"; break; case 's' : case 'S': if (where->get_flag(FL_SHIP) || tolower(arg[1])=='t') return "starboard"; else return "south"; break; case 'e' : case 'E': return "east";break; case 'f' : case 'F': return "fore";break; case 'w' : case 'W': return "west";break; case 'u' : case 'U': return "up";break; case 'd' : case 'D': return "down";break; case 'r' : case 'R': return "rimwards"; break; case 'p' : case 'P': return "port"; break; case 'h' : case 'H': return "hubwards";break; case 'a' : case 'A': if (where->get_flag(FL_SHIP) || tolower(arg[1])=='f') return "aft"; else return "anticlockwise"; break; case 'c' : case 'C': return "clockwise";break; case 'o' : case 'O': return "out";break; case 'i' : case 'I': return "in";break; } return "?"; } static bool go_implicit(MudObject *player, int, const char*argv[]) { const char *argv2[] = { "go", NULL, NULL, }; argv2[1] = expand_dir(argv[0], player->owner); return verb_go(player, 2, argv2); } enum qstat_t { Q_UNOWNED, Q_YOURS, Q_OTHERS, }; static qstat_t quarstat(MudObject *where, MudObject *who) { if (where->get("$player")) { const char *own = where->get("$player"); MudObject *hvem = planet->get(own); if (hvem == who) return Q_YOURS; else return Q_OTHERS; } else { return Q_UNOWNED; } } static bool player_exists(const char *name) { if (planet->get(name)) return 1; FILE *f = xopen(DATA_USERS, name, "r"); if (!f) return 0; fclose(f); return 1; } static bool verb_invite(MudObject *who, int argc, const char **argv) { if (!who->owner) return true; if (argc < 2) { who->printf("syntax: invite <who>\n"); return true; } if (!who->owner->get_flag(FL_QUARTERS)) { who->printf("This is not quarters.\n"); return true; } MudObject *q = who->owner; switch (quarstat(who->owner, who)) { case Q_UNOWNED: who->printf("You can't invite someone to unowned quarters.\n"); return true; case Q_OTHERS: who->printf("You can't invite someone to someone else's quarters.\n"); return true; default: if (!player_exists(argv[1])) { who->printf("No such player as ^p%#s^n.\n", argv[1]); return true; } MudObject *hvem = planet->get(argv[1]); if (hvem == who) { who->printf("You can't invite yourself.\n"); return true; } if (q->get("$guestlist")) { if (permitted_access(argv[1], q->get("$guestlist"))) { who->printf("Already invited.\n"); return true; } } if (q->get("$guestlist")) { q->setf("$guestlist", "%s,%s", q->get("$guestlist"), argv[1]); } else { q->set("$guestlist", argv[1]); } who->printf("Guestlist updated.\n"); if (hvem) { hvem->printf("%M %[has/have] added you to %s guest list.\n", who, his_or_her(who)); } // who->printf("Ok. You now own these.\n"); // who->owner->set("$player", who->id); // who->set("quarters", who->owner->id); ; } return true; } static bool verb_uninvite(MudObject *who, int argc, const char **argv) { if (!who->owner) return true; if (argc < 2) { who->printf("syntax: uninvite <who>\n"); return true; } if (!who->owner->get_flag(FL_QUARTERS)) { who->printf("This is not quarters.\n"); return true; } MudObject *q = who->owner; switch (quarstat(who->owner, who)) { case Q_UNOWNED: who->printf("You can't uninvite someone from unowned quarters.\n"); return true; case Q_OTHERS: who->printf("You can't uninvite someone from someone else's quarters.\n"); return true; default: if (!player_exists(argv[1])) { who->printf("No such player as ^p%#s^n.\n", argv[1]); return true; } MudObject *hvem = planet->get(argv[1]); if (hvem == who) { who->printf("You can't uninvite yourself.\n"); return true; } if (q->get("$guestlist")) { if (!permitted_access(argv[1], q->get("$guestlist"))) { who->printf("Not on the guestlist.\n"); return true; } } else who->printf("Not on the guestlist.\n"); q->set("$guestlist", uninvite(argv[1], q->get("$guestlist"))); who->printf("Guestlist updated.\n"); if (hvem) { hvem->printf("%M %[has/have] removed you from %s guest list.\n", who, his_or_her(who)); } // who->printf("Ok. You now own these.\n"); // who->owner->set("$player", who->id); // who->set("quarters", who->owner->id); ; } return true; } static MudObject *load_player(const char *id) { MudObject *p = new MudObject("^thingy"); FILE *f = xopen(DATA_USERS, id, "r"); if (!f) { return 0; } string buf = getline(f); while (buf != "}" && !feof(f)) { buf = getproperty(f); p->load(buf.c_str()); } xclose(f); return p; } static int dispose_contents(MudObject *o2) { if (is_player(o2)) return 0; if (o2->mission) return 0; if (!o2->get_flag(FL_ROOM)) { if (o2->get_object("start")!=o2->owner) vanish(o2); } int cost = o2->get_int("cost", 0); MudObject *o; int i; NewWorld d; foreach(o2->children, o, i) { d.add(*o); } foreach((&d), o, i) { cost += dispose_contents(o); } return cost; } static bool dontbother(MudObject *o2) { if (is_player(o2)) return 1; if (o2->mission) return 1; MudObject *o; int i; foreach(o2->children, o, i) { if (dontbother(o)) return 1; } return 0; } static bool verb_evict(MudObject *who, int argc, const char **argv) { if (!who->owner) return true; MudObject *q = who->owner; if (q->array_size("room")>0 && q->get("qoffice")) { int l = q->array_size("room"); int i=0; for (i=0;i<l;i++) { MudObject *q2 = q->array_get_object("room", i); if (!q2) continue; if (dontbother(q2)) continue; const char *o = q2->get("$player"); if (o) { MudObject *m = planet->get(o); if (!m) { MudObject *p = load_player(o); if (p) { time_t n = p->get_int("lastlogin"); if ((now-n)/(24*60*60)>7) { q2->unset("$player"); int compensate = dispose_contents(q2); char bar[100]; sprintf(bar, "$owe.%s", o); q->set(bar, q->get_int(bar)+(compensate*9)/10); who->printf("%M - %s - %i days, now evicted, %K compensation.\n", q2, p->get("_name")?:p->get("name"), (now-n)/(24*60*60), compensate); log(PFL_SEEINFO, 0, "wiz", "autoevicting %s from %s", p->get("_name"), q2->id); } delete p; } else { log(PFL_SEEINFO, 0, "wiz", "autoevicting %s from %s", q2->get("$player"), q2->id); q2->unset("$player"); q2->unset("$guestlist"); dispose_contents(q2); } } } if (q2->get("$desc") && !q2->get("$player")) { q2->unset("$desc"); } } return true; } return true; } static const char *find_route(MudObject *who, MudObject *src, MudObject *dst) { if (src == dst) return 0; if (dst->l.exit) { find_route(who, src, dst->l.exit->owner); if (dst->l.exit->owner == src) { who->interpretf("go %s", dst->l.exit->get("short")); } } return 0; } static bool verb_route(MudObject *who, int argc, const char **argv) { if (is_player(who) && !who->get_priv(PFL_CODER)) { who->printf("You can't do that.\n"); return true; } if (argc < 2) { who->printf("syntax: route <whereto>\n"); return true; } MudObject *src = who->owner; MudObject *dest = planet->get(argv[1]); if (!dest) { who->printf("Can't find dest.\n"); return true; } MudObject *o; int i; if (who->get_flag(FL_LANDVEHICLE) && who->get_object("$headingfor")==dest) { NewWorld exits; MudObject *cf = who->get_object("$camefromloc"); int cfv = 0; foreach(who->owner->children, o, i) { if (o==who) continue; MudObject *l = o->get_object("link"); if (l==cf) cfv = 1; else if (l) exits.add(o); } if (exits.getsize()==1 && cfv) { who->interpretf("go %s", exits.get(0)->get("short")); if (who->owner != dest) { who->set("!reschedule", 1); } return true; } } foreach(planet, o, i) { o->l.s = 0; o->l.exit = 0; } src->l.s = 1; while (1) { int change = 0; foreach(planet, o, i) if (o->l.s==1) o->l.s = 2; foreach(planet, o, i) { if (o->get_flag(FL_WILDERNESS)) { int ok = 0; if (o->get_int("wild.z", 0)==-2) ok = 1; if (!ok) continue; } if (o->l.s==2) { o->l.s = 3; if (o->get_flag(FL_DEATH)) continue; change = 1; MudObject *p; int j; foreach(o->children, p, j) { MudObject *to = p->get_object("link"); if (to) { if (to->l.s==0) { to->l.s=1; to->l.exit = p; } } } } } if (!change) break; if (dest->l.s) break; } if (dest->l.s) { find_route(who, src, dest); } else { who->printf("Route to %s not found.\n", dest->id); } who->set("$headingfor", dest->id); if (who->owner != dest) { who->set("!reschedule", 1); } return true; } static bool verb_track(MudObject *who, int, const char **) { MudObject *where = who->owner; if (!where) return true; MudObject *last = where->get_object("$lastperson"); MudObject *lastdir = where->get_object("$lastdir"); int when = where->get_int("$lasttime"); const char *whenstr = " very recently"; if (when<(now-60)) whenstr = " recently"; if (when<(now-120)) whenstr = " not long ago"; if (when<(now-300)) whenstr = " at some point"; if (when<(now-600)) whenstr = " a while ago"; if (when<(now-900)) last = NULL; MudObject *fl = floor(where); if (where->get_flag(FL_NOGRAVITY) || !fl) { who->printf("No tracks can be left here.\n"); return true; } if (!last || !lastdir) { who->printf("%#P is undisturbed.\n", fl); return true; } const char *body = last->get("body"); if (!body) body = "human"; who->printf("A %s seems to have gone %s from here%s.\n", body, lastdir->get("short"), whenstr); return true; } static bool verb_links(MudObject *who, int argc, const char **argv) { const char *zone = who->owner?who->owner->get("zone"):0; if (argc > 1) { zone = argv[1]; } if (!zone || !zones->get(zone)) { if (!zone) who->printf("This object has no zone.\n"); else who->printf("No such zone as '%s'.\n", zone); return true; } MudObject *o; int i; who->spec_printf("^W%15s %-15s %s^n\n", "From", "Direction", "To"); bool yes = 0; foreach(planet, o, i) { if (const char *l=o->get("link")) { if (o->owner && o->owner->get_flag(FL_WILDERNESS) && l[0]=='@') continue; MudObject *lo = planet->get(l); if ((l[0]==':'&&streq(o->get("zone"), zone)) || (lo && !streq(lo->get("zone"), o->get("zone")) && (streq(lo->get("zone"), zone) || streq(o->get("zone"), zone)))) { who->printf("%15s %-15s %s\n", o->owner?o->owner->id:"nowhere", o->get("short"), l); yes = 1; } if (streq(o->get("zone"), zone) && !lo) { who->printf("%15s %-15s %s\n", o->owner?o->owner->id:"nowhere", o->get("short"), "-"); yes = 1; } } } if (!yes) { who->cancel_printf(); who->printf("No interzone links involving %s.\n", zone); } return true; } #include "verbmodule.h" void startup() { //AUTO_VERB(quarters, 3, 0, PFL_NONE ); AUTO_VERB(invite, 4, 0, PFL_NONE ); AUTO_VERB(uninvite, 4, 0, PFL_NONE ); AUTO_VERB(evict, 3, 0, PFL_EDITALL, VFL_DENYEXISTS ); AUTO_VERB(route, 3, 0, PFL_NONE ); AUTO_VERB(go, 2, 0, PFL_AWAKE ); ADD_VERB("down", 1, go_implicit, 0, PFL_NONE); ADD_VERB("east", 1, go_implicit, 0, PFL_NONE); ADD_VERB("north", 3, go_implicit, 0, PFL_NONE); ADD_ALIAS(n, 1, north); ADD_VERB("south", 1, go_implicit, 0, PFL_NONE); ADD_VERB("out", 1, go_implicit, 0, PFL_NONE); ADD_VERB("in", 2, go_implicit, 0, PFL_NONE); ADD_VERB("up", 1, go_implicit, 0, PFL_NONE); ADD_VERB("west", 1, go_implicit, 0, PFL_NONE); ADD_VERB("fore", 1, go_implicit, 0, PFL_NONE); ADD_VERB("aft", 2, go_implicit, 0, PFL_NONE); ADD_VERB("port", 1, go_implicit, 0, PFL_NONE); ADD_VERB("starboard", 5, go_implicit, 0, PFL_NONE); ADD_VERB("rimwards", 1, go_implicit, 0, PFL_NONE); ADD_VERB("hubwards", 1, go_implicit, 0, PFL_NONE); ADD_VERB("clockwise", 1, go_implicit, 0, PFL_NONE); ADD_VERB("anticlockwise", 1, go_implicit, 0, PFL_NONE); ADD_VERB("goby", 3, verb_gotoin, 0, PFL_GOTO); ADD_VERB("goto", 3, verb_gotoin, 0, PFL_GOTO); ADD_VERB("goin", 3, verb_gotoin, 0, PFL_GOTO); AUTO_VERB(track, 2, 0, PFL_AWAKE); AUTO_VERB(links, 5, 0, PFL_CODER); }