/* * MusicMUD - Traverse an exit 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" #include "hooks.h" #include "death.h" #include "privs.h" #include "units.h" #include "levels.h" #include "events.h" #define MODULE "move" static void deathroom(MudObject *who, MudObject *where) { if (!who->get_priv(PFL_IMMORTAL) && !is_mobile(who)) { if (where->get_flag(FL_DEATH)) { do_die(who, privs_of(who)*20, "deathroom"); return; } } } static const char *motion_verb(MudObject *what) { if (what->get_flag(FL_CANTWALK)) return "ride"; if (what->get_flag(FL_MOBILE)) return "gallop"; if (what->get_flag(FL_FLYING)) return "fly"; if (what->get("motionverb")) return what->get("motionverb"); return "ride"; } #define pl(a, b, c) (a->get_flag(FL_PLURAL)?(b):(c)) int do_traverse(MudObject *player, MudObject *ext, const char *mvrb, MudObject *whofollow) { if (whofollow == player) { /* don't follow self. */ return 0; } if (dotrap(E_BEFORETRAVERSE, player, ext)) return 0; /* ::: before_traverse o1== exit; before everything, including door openness checking. return 1 to abort. */ if (!player->get_flag(FL_FLYING)) { if (streq(body(player), "tree")) { player->printf("As a tree, you are firmly rooted to the spot.\n"); return true; } if (streq(body(player), "plant")) { player->printf("You can't locomote.\n"); return true; } } if (player->get_flag(FL_SITTING)) { player->printf("You clamber to your feet.\n"); player->oprintf(cansee, "%#M %[clambers/clamber] to %s feet.\n", player, his_or_her(player)); setpos(player, P_STANDING); } MudObject *old_loc = player->owner; MudObject *door = ext->get_object("door"); if (door && state(door)) { if (door->get_flag(FL_SECRET)) player->printf("You can't go ^d%s^n.\n", ext->get("short")); else { const char *doorwhy = door->get("doorwhy"); if (!doorwhy) doorwhy = pl(door, "aren't open", "isn't open"); if (whofollow) { player->printf("You can't follow %M as %#Y %s.\n", whofollow, door, doorwhy); } else { player->printf("%#Y %s.\n", door, doorwhy); } } return 0; } int climbing = 0; MudObject *dest = ext->get_object("link"); if (!dest) { dest = ext->get_object("climbto"); climbing = 1; } MudObject *m = mount(player); NewWorld others; if (m) { MudObject *o; int i; foreach(old_loc->children, o, i) { if (mount(o)==m && o != player) others.add(o); } } if (!dest) { player->printf("You can't go ^d%s^n.\n", ext->get("short")); log(PFL_SEEINFO, 0, "bug", "%s found a bad exit %s", player->id, ext->id); return 0; } if (player->owner) player->owner->ref(); if (dest) { dest->ref(); if (dest->get_flag(FL_WILDERNESS) && dest->nuke_me) { MudObject *o; int i; foreach(dest->children, o, i) { if (o->get_flag(FL_TRANSIENT)) { o->nuke_me = 0; } } dest->nuke_me = 0; } } if (is_in(dest, player) || dest==player) { player->printf("PARADOX ALERT!.\n"); return 0; } if (mud->get_int("tournament", 0) && player->get("tourn") && dest->get_flag(FL_SHIP)) { player->printf("You may not leave the station when taking part in a tournament.\n"); return 0; } if (mud->get_int("tournament", 0) && player->get("tourn") && dest->get_flag(FL_SANCTUARY)) { player->printf("You may not enter sanctuary areas when taking part in a tournament.\n"); return 0; } if (mud->get_int("tfrom", 0) && player->get("tourn")) { player->printf("Not until the tournament has formally started.\n"); return 0; } if (is_player(player) && player->get_priv(PFL_REMORT) && !can_affect(player, dest->get("zone"))) { if (whofollow) { player->printf("You can't follow %M as you can't go to that zone (%s) without remorting.\n", whofollow, dest->get("zone")); return 0; } player->printf("You can't go to that zone (%s) without remorting.\n", dest->get("zone")); return 0; } if (!old_loc->get_flag(FL_NOGRAVITY)) { long long left = mass_capacity_left_in_grams(player); if (left < 0) { player->printf("You are carrying too much to move.\n"); return 0; } } if (MudObject *y=get_flagged_object(player, FL_TIEDTOROOM)) { if (whofollow) { player->printf("You can't follow %M whilst carrying %Y.\n", whofollow, y); } else { player->printf("You can't move from here whilst carrying %Y.\n", y); } return 0; } if (!player->get_flag(FL_FLYING)) { if (old_loc->get_flag(FL_BROKEN) && player->get("$camefrom") && !streq(player->get("$camefrom"), ext->get("short"))) { player->printf("You cannot go ^d%s^n as the bridge is broken.\n", ext->get("short")); return 0; } // NOLEGS if (!canwalk(player) && dryland(dest)) { if (whofollow) { player->printf("You can't follow %M onto land.\n", whofollow); } else { player->printf("You can't travel on land.\n"); } return 0; } if (dryland(dest)) { if (m && ((m->get_flag(FL_BOAT) && !m->get_flag(FL_LANDVEHICLE)) || (m->get_flag(FL_CANTWALK)))) { if (whofollow) { player->printf("You can't follow %M ashore on %Y.\n", whofollow, m); } else { player->printf("You can't take %Y ashore.\n", m); } return 0; } } // NOGILLS if (inwater(dest)) { if (m && !m->get_flag(FL_BOAT) && !canswim(m)) { if (whofollow) { player->printf("You can't take %Y to sea to follow %M.\n", m, whofollow); } else { player->printf("You can't take %Y to sea.\n", m); } return 0; } if (!canswim(player)) { if (!m) { if (whofollow) { player->printf("You can't follow %M as you can't swim.\n"); } else { player->printf("You can't swim.\n"); } return 0; } } } } if (m) { if (dotrap(E_BEFOREMOVED, player, m, dest)) /* ::: before_moved o1==object carried/mounted, o2==new room; return 1 to abort */ return 0; } { MudObject *o; int i; foreach(player->children, o, i) if (o != m) if (dotrap(E_BEFOREMOVED, player, o, dest)) return 0; } if (m && climbing) { player->printf("You can't climb on %Y.\n", m); return 0; } if (m && !dest->get_flag(FL_OUTDOORS) && m->get_flag(FL_MOBILE)) { if (whofollow) { player->printf("You try to follow %M %s, but %s %[refuses/refuse] to go that way.\n", whofollow, ext->get("short"), he_or_she(m)); } else { player->printf("%#M %[refuses/refuse] to go that way.\n", m); } return 0; } if (m && streq(ext->get("short"), "up") && m->get_flag(FL_BARUP)) { player->printf("You can't go up on %Y!\n", m); return 0; } // RESERVED ROOMS : int min_level = dest->get_int("min_level"); if (privs_of(player) < min_level) { if (ext->get_flag(FL_SECRET)) { player->printf("You can't go ^d%s^n.\n", ext->get("short")); } else { if (whofollow) { player->printf("You can't follow %M that way : %s\n", whofollow, dest->get("min_why")); } else { player->printf("You can't go that way : %s\n", dest->get("min_why")); } } return 0; } if (is_player(player) && dest->get("nogo")) { if (whofollow) { player->printf("You try to follow %M.\n", whofollow); } player->printf("%#s %s.\n", dest->get("nogo"), ext->get("short")); return 0; } // OBJECT NEEDED ROOMS : (wizards ignore) if (!player->get_priv(PFL_GOTO)) { MudObject *needed = dest->get_object("obj_need"); if (needed && needed->owner != player) { if (whofollow) { player->printf("You try to follow %M.\n", whofollow); } player->printf("%#s\n", dest->get("obj_whynot")); return 0; } } // MOBILES WITH "BAR" BEHAVIOR : (wizards ignore) if (!player->get_priv(PFL_NOHASSLE)) if (!trigger_mobiles(player->owner, player, ext)) { return 0; } // ONEPRSON/PRIVATE ROOMS if (!spare_people_capacity(dest)) { if (whofollow) { player->printf("You try to follow %M but don't fit.\n", whofollow); } else { player->printf("That location is full.\n"); } return 0; } // AIRLESS ROOMS if (dest->get_flag(FL_AIRLESS) && !old_loc->get_flag(FL_AIRLESS)) { if (!wf_wears_with_flag(player, FL_SPACESUIT)) { if (whofollow) { player->printf("You can't follow %M into space without wearing a spacesuit.\n", whofollow); } else { player->printf("It's not a good idea to go there without wearing a spacesuit.\n"); } return 0; } } if (dest->get_flag(FL_DEEPSPACE)) { player->printf("You cannot go into deep space.\n"); return 0; } // ROOMS WITH MISSIONS if (!is_mobile(player)) { MudObject *nq = ext->get_object("quest"); if (nq && nq->owner == player) nq = 0; if (!nq) { nq = dest->get_object("quest"); if (nq && nq->owner == player) nq = 0; } if (nq && old_loc->get_object("quest") != nq) { int ok = 0; MudObject *os = old_loc->get_object("ship"); MudObject *ds = dest->get_object("ship"); if (os == dest || ds == old_loc || (os == ds && ds)) { ok = 1; } if (!ok) { if (whofollow) { player->printf("%#M %[has/have] gone into a mission-restricted area which you are not allowed into.\n", whofollow); } else { player->printf("You have no business there.\n"); } } return 0; } } const char *mverb_s = "walks"; const char *mverb_p = "walk"; const char *averb_s = "arrives"; const char *averb_p = "arrive"; string sbuf; if (player->get("motionverb")) { mverb_p = player->get("motionverb"); sbuf = mverb_p; sbuf += "s"; mverb_s = sbuf.c_str(); } if (player->owner->get_flag(FL_NOGRAVITY)) { mverb_s = "goes"; mverb_p = "go"; } if (!player->get_flag(FL_FLYING)) { if (!m) { if (dryland(dest) && player->get_flag(FL_SWIMMING)) { player->set_flag(FL_SWIMMING, 0); player->printf("You get up out of the water.\n"); player->oprintf(cansee, "%#M %[gets/get] up out of the water.\n", player); } if (inwater(dest) && !player->get_flag(FL_SWIMMING) && !player->get_flag(FL_SHIP)) { player->set_flag(FL_SWIMMING, 1); player->printf("You start swimming.\n"); player->oprintf(cansee, "%#M %[starts/start] swimming.\n", player); } } } if (player->get_flag(FL_SHIP)) { if (player->get_flag(FL_LANDVEHICLE)) { mverb_s = "drives"; mverb_p = "drive"; averb_s = "drives in"; averb_p = "drive in"; } else { mverb_s = "sails"; mverb_p = "sail"; averb_s = "sails in"; averb_p = "sail in"; } } else if (player->get_flag(FL_SWIMMING)) { mverb_s = "swims"; mverb_p = "swim"; averb_s = "swims in"; averb_p = "swim in"; } else if (player->get_flag(FL_NOLEGS)) { mverb_s = "slithers"; mverb_p = "slither"; } else if (player->get_flag(FL_FLYING)) { mverb_s = "flies"; mverb_p = "fly"; } string mvs; if (mvrb) { mverb_p = mvrb; mvs = mvrb; mvs += "s"; mverb_s = mvs.c_str(); } if (player->get("_fighting")) { player->printf ("Not while fighting.\n"); return 0; } { MudObject *o; int i; foreach(old_loc->children, o, i) { if (o != player && !o->get_flag(FL_EXIT)) { if (dotrap(E_BEFOREDEPART, player, o, dest)) return 0; /* ::: before_depart o1==every object in from room, o2==destination; before we are about to move. return 1 to abort. */ } } } if (dotrap(E_BEFOREGO, player, player, dest)) return 0; /* ::: before_leave o1== old room, o2== new room; before we are about to move. return 1 to abort. */ if (dotrap(E_BEFORELEAVE, player, old_loc, dest)) return 0; /* ::: before_leave o1== old room, o2== new room; before we are about to move. return 1 to abort. */ if (dotrap(E_BEFOREENTRY, player, dest, old_loc)) return 0; /* ::: before_entry o1== new room, o2== old room; before we are about to move. return 1 to abort. */ player->lprintf(notinroom(dest) && secret(player) && cansee, "%#M %[leaves/leave] %M.\n", player, old_loc); { MudObject *obj; int i; foreach(old_loc->children, obj, i) if (obj != player && visible_to(obj, player) && cansee(obj)) { if (others.get(obj->id)) continue; if (climbing) { obj->printf("%#M %[climbs/climb] %s %M.\n", player, ext->get("dir"), ext); continue; } if (whofollow) { obj->printf("%#M %[follows/follow] %M %s.\n", player, whofollow, ext->get("short")); } else { if (m) { if (others) obj->printf("%#M %s%[s/] %s %P on with %W.\n", player, motion_verb(m), m, ext->get("short"), others); else obj->printf("%#M %s%[s/] %s on %P.\n", player, motion_verb(m), ext->get("short"), m); } else { obj->printf("%#M %s %s.\n", player, player->get_flag(FL_PLURAL)?mverb_p:mverb_s, ext->get("short")); } } } } if (!player->get_flag(FL_SWIMMING) && (is_player(player)||is_mobile(player))) { old_loc->set("$lastperson", player->id); old_loc->set("$lastdir", ext->id); old_loc->set("$lasttime", now); } { MudObject *tr; int i; foreach(&player->tracers, tr, i) { tr->printf("[trace : ^Z%M %[goes/go] %s from %s %s]\n", player, ext->get("short"), player->owner->id, format_roomname(dest, player, "", "", "to", 1).c_str(), dest->id); } } set_owner(player, dest); { MudObject *o; int i; foreach((&others), o, i) set_owner(o, dest); } player->unset("$camefrom"); player->unset("$camefromloc"); { MudObject *o; int i; foreach(old_loc->children, o, i) { rectify_state(o); } } newplace(player, old_loc); string to = format_roomname(dest, player, "^{D\3RName\4", "^}\3/RName\4", "to", IS_COMMANDER(player)); int oddlook = 0; if (climbing) { player->printf("You climb %s %M %s.\n", ext->get("dir"), ext, to); oddlook = 1; } else { if (whofollow) { player->printf("You follow %M %s %s.\n", whofollow, ext->get("short"), to); oddlook = 1; } else { if (m) { player->printf("You %s %s on %Y %s.\n", motion_verb(m), ext->get("short"), m, to); oddlook = 1; if (m->owner == old_loc) { set_owner(m, dest); } } else { player->printf("You %s %s %s.\n", mverb_p, ext->get("short"), to); if (player->get_flag(FL_SHIP)) { shipmsg(player, "%#P %s %s %s.\n", player, pl(player,mverb_p,mverb_s), ext->get("short"), to); } oddlook = 1; } } } { MudObject *o; int i; foreach(&others, o, i) { o->printf("%#M %s%[s/] %P %s with you %s.\n", player, motion_verb(m), m, ext->get("short"), to); } } const char *r = exit_rev(ext->get("short")); int i; MudObject *obj; foreach(dest->children, obj, i) if (obj != player && visible_to(obj, player) && cansee(obj)) { if (others.get(obj->id)) continue; if (!whofollow) { if (climbing) { obj->printf("%#M %[climbs/climb] %s %M to here.\n", player, ext->get("dir"), ext); continue; } if (r) { if (m) { obj->printf("%#M %s%[s/] in from %s on %P.\n", player, motion_verb(m), r, m); } else { obj->printf("%#M %s from %s.\n", player, pl(player, averb_p, averb_s), r); } } else { if (m) { obj->printf("%#M %s%[s/] here on %P.\n", player, motion_verb(m), m); } else { obj->printf("%#M %s.\n", player, pl(player, averb_p, averb_s)); } } } else { if (r) { if (obj == whofollow) { obj->printf("%#M %[follows/follow] you here from %s.\n", player, r); } else { obj->printf("%#M %[follows/follow] %M here from %s.\n", player, whofollow, r); } } else { obj->printf("%#M %s.\n", player, pl(player, averb_p, averb_s)); } } } player->set("$camefrom", other_dir(ext->get("short"))); player->set("$camefromloc", old_loc->id); player->lprintf(notinroom(old_loc) && secret(player) && cansee, "%#M %[enters/enter] %M.\n", player, dest); if (is_player(player) || player->snoopers.getsize()) if (oddlook) { player->interpret("look -"); } else { player->interpret("look"); } { MudObject *o; int i; foreach (&others, o, i) { o->interpret("look -"); } } // TRIGGER DEATHROOMS AND SPECIALS deathroom(player, player->owner); { MudObject *o; int i; foreach(&others, o, i) { // TRIGGER DEATHROOMS AND SPECIALS deathroom(o, o->owner); } } dotrap(E_AFTERLEAVE, player, old_loc, dest); /* ::: after_leave o1== old room, o2== new room; just after 'look'. */ dotrap(E_AFTERENTRY, player, dest, old_loc); /* ::: after_entry o1== new room, o2== old room; just after 'look'. */ dotrap(E_AFTERGO, player, player, dest); /* ::: after_go o1== thing moving, o2== new room; just after 'look'. */ if (m) dotrap(E_AFTERMOVED, player, m, dest); /* ::: after_moved o1==object carried/mounted, o2==new room; return 1 to abort */ { MudObject *o; int i; foreach(player->children, o, i) if (o != m) dotrap(E_AFTERMOVED, player, o, dest); } { MudObject *o; int i; foreach(dest->children, o, i) { if (o->get_flag(FL_ENTERFILEPLAN)) { o->set_flag(FL_ENTERFILEPLAN, 0); o->interpret("file_plan"); o->set("!$1", o->id); } if (o != player && !o->get_flag(FL_EXIT)) { dotrap(E_ONARRIVAL, player, o, old_loc); /* ::: arrival o1==everything in destination, o2==old room; just after 'look'. */ if (player->owner != dest) break; } } } NewWorld made; if (player->owner == dest && dest != old_loc) { World<MudObject> fol = player->followers; if (fol.getsize()) { MudObject *d; int i; NewWorld notmade; foreach((&fol), d, i) if (d != player && d->owner == old_loc) { if (!d->get_object("_fighting") && !d->get_flag(FL_SITTING) && !d->get_flag(FL_SLEEPING)) { if (!traverse(d, ext, mvrb, whofollow?whofollow:player)) { notmade.add(*d); } else { made.add(*d); } } } if (notmade.getsize()) { fol.add(*player); foreach((&fol), d, i) if (d->owner == dest && cansee(d)) { d->printf("%#W become separated from the group.\n", ¬made, plural(notmade)?"have":"has"); } } } } if (!whofollow) { if (player->owner == dest) dotrap(E_AFTERPARTYENTRY, player, dest, old_loc); /* ::: after_party_entry o1==new room, o2==old room; after all party has arrived */ if (player->owner == dest) dotrap(E_AFTERPARTYLEAVE, player, old_loc, dest); /* ::: after_party_leave o1==old room, o2==new room; after all party has arrived */ MudObject *o; int i; foreach(dest->children, o, i) if (o != player && !o->get_flag(FL_EXIT) && !made.get(o->id)) { if (player->owner == dest) dotrap(E_ONPARTYARRIVAL, player, o, old_loc); /* ::: party_arrival o1==every object in dest, o2==old room; after all party has arrived */ } } if (player->get_flag(FL_PITIT) && find_pit(player->owner)) { player->interpret("drop all"); } return 1; } #define CLEANUP DO_TRAVERSE = 0; #include "verbmodule.h" void startup() { DO_TRAVERSE = do_traverse; }