/* move.c */ #include "copyright.h" #include <stdio.h> #include <ctype.h> #include <string.h> #include "mudconf.h" #include "config.h" #include "db.h" #include "interface.h" #include "match.h" #include "externs.h" /* --------------------------------------------------------------------------- * process_leave_loc: Generate messages and actions resulting from leaving * a place. */ static void process_leave_loc (dbref thing, dbref dest, dbref cause, int canhear, int hush) { dbref loc; int quiet, oattr, aattr; loc = Location(thing); if ((loc == NOTHING) || (loc == dest)) return; if (dest == HOME) dest = Home(thing); /* Run the LEAVE attributes in the current room if we meet any of * following criteria: * - The current room has wizard privs. * - Neither the current room nor the moving object are dark. * - The moving object can hear and does not hav wizard privs. * EXCEPT if we were called with the HUSH_LEAVE key. */ quiet = (!Wizard(loc) && (Dark(thing) || Dark(loc)) && (!canhear || Wizard(thing))) || (hush & HUSH_LEAVE); oattr = quiet ? 0 : A_OLEAVE; aattr = quiet ? 0 : A_ALEAVE; did_it(thing, loc, A_LEAVE, NULL, oattr, NULL, aattr, (char **)NULL, 0); /* Do OXENTER for receiving room */ if ((dest != NOTHING) && !quiet) did_it(thing, dest, 0, NULL, A_OXENTER, NULL, 0, (char **)NULL, 0); /* Display the 'has left' message if we meet any of the following * criteria: * - Neither the current room nor the moving object are dark. * - The object can hear and is not wizard. */ if ((!Dark(thing) && !Dark(loc)) || (canhear && !Wizard(thing))) { notify_except2(loc, thing, thing, cause, tprintf("%s has left.", Name(thing)), 1); } } /* --------------------------------------------------------------------------- * process_enter_loc: Generate messages and actions resulting from entering * a place. */ static void process_enter_loc (dbref thing, dbref src, dbref cause, int canhear, int hush) { dbref loc; int quiet, oattr, aattr; loc = Location(thing); if ((loc == NOTHING) || (loc == src)) return; /* Run the ENTER attributes in the current room if we meet any of * following criteria: * - The current room has wizard privs. * - Neither the current room nor the moving object are dark. * - The moving object can hear and does not hav wizard privs. * EXCEPT if we were called with the HUSH_ENTER key. */ quiet = (!Wizard(loc) && (Dark(thing) || Dark(loc)) && (!canhear || Wizard(thing))) || (hush & HUSH_ENTER); oattr = quiet ? 0 : A_OENTER; aattr = quiet ? 0 : A_AENTER; did_it(thing, loc, A_ENTER, NULL, oattr, NULL, aattr, (char **)NULL, 0); /* Do OXLEAVE for sending room */ if ((src != NOTHING) && !quiet) did_it(thing, src, 0, NULL, A_OXLEAVE, NULL, 0, (char **)NULL, 0); /* Display the 'has arrived' message if we meet all of the following * criteria: * - The moving object can hear. * - The object is not both dark and wizard. */ if (canhear && !(Dark(thing) && Wizard(thing))) { notify_except2(loc, thing, thing, cause, tprintf("%s has arrived.", Name(thing)), 1); } } /* --------------------------------------------------------------------------- * move_object: Physically move an object from one place to another. * Does not generate any messages or actions. */ void move_object (dbref thing, dbref dest) { dbref src; /* Remove from the source location */ src = Location(thing); if (src != NOTHING) s_Contents(src, remove_first(Contents(src), thing)); /* Special check for HOME */ if (dest == HOME) dest = Home(thing); /* Add to destination location */ if (dest != NOTHING) s_Contents(dest, insert_first(Contents(dest), thing)); else s_Next(thing, NOTHING); s_Location(thing, dest); /* Look around and do the penny check */ look_in (thing, dest, 1); if ((Typeof(thing) == TYPE_PLAYER) && (mudconf.payfind > 0) && (Pennies(thing) < mudconf.paylimit) && (!Controls(thing, dest)) && ((random() % mudconf.payfind) == 0)) { giveto(thing, 1); notify(thing, tprintf("You found a %s!", mudconf.one_coin)); } } /* --------------------------------------------------------------------------- * send_dropto, process_sticky_dropto, process_dropped_dropto, * process_sacrifice_dropto: Check for and process droptos. */ /* send_dropto: Send an object through the dropto of a room */ static void send_dropto (dbref thing, dbref player) { if (!(Flags(thing) & STICKY)) move_via_generic(thing, Dropto(Location(thing)), player, 0); else move_via_generic(thing, HOME, player, 0); divest_object(thing); } /* process_sticky_dropto: Call when an object leaves the room to see if * we should empty the room */ static void process_sticky_dropto (dbref loc, dbref player) { dbref dropto, thing, next; /* Do nothing if checking anything but a sticky room */ if (!Good_obj(loc) || !IS(loc, TYPE_ROOM, STICKY)) return; /* Make sure dropto loc is valid */ dropto = Dropto(loc); if ((dropto == NOTHING) || (dropto == loc)) return; /* Make sure no players hanging out */ DOLIST(thing, Contents(loc)) { if (Dropper(thing)) return; } /* Send everything through the dropto */ s_Contents(loc, reverse_list(Contents(loc))); SAFE_DOLIST(thing, next, Contents(loc)) { send_dropto(thing, player); } } /* process_dropped_dropto: Check what to do when someone drops an object. */ static void process_dropped_dropto (dbref thing, dbref player) { dbref loc; /* If STICKY, send home */ if (Flags(thing) & STICKY) { move_via_generic(thing, HOME, player, 0); divest_object(thing); return; } /* Process the dropto if location is a room and is not STICKY */ loc = Location(thing); if ((Typeof(loc) == TYPE_ROOM) && (Dropto(loc) != NOTHING)) if (!(Flags(loc) & STICKY)) send_dropto(thing, player); } static void process_sacrifice_dropto (dbref thing, dbref player) { dbref loc; /* Check for autodestroy on sacrifice */ if (mudconf.sac_dest || IS(thing, TYPE_THING, THING_DEST_OK)) { move_via_generic(thing, NOTHING, player, 0); empty_obj(thing); destroy_obj(NOTHING, thing); return; } /* If STICKY, send home */ if (Flags(thing) & STICKY) { move_via_generic(thing, HOME, player, 0); divest_object(thing); return; } /* Process the dropto on the location. If none (or if the location * is not a room, send the object home */ loc = Location(thing); if (Typeof(loc) != TYPE_ROOM) { move_via_generic(thing, HOME, player, 0); divest_object(thing); } else if (Dropto(loc) != NOTHING) { send_dropto(thing, player); } else { move_via_generic(thing, HOME, player, 0); divest_object(thing); } } /* --------------------------------------------------------------------------- * move_via_generic: Generic move routine, generates standard messages and * actions. */ void move_via_generic (dbref thing, dbref dest, dbref cause, int hush) { dbref src; int canhear; if (dest == HOME) dest = Home(thing); src = Location(thing); canhear = Hearer(thing); process_leave_loc(thing, dest, cause, canhear, hush); move_object(thing, dest); did_it(thing, thing, A_MOVE, NULL, A_OMOVE, NULL, A_AMOVE, (char **)NULL, 0); process_enter_loc(thing, src, cause, canhear, hush); } /* --------------------------------------------------------------------------- * move_via_exit: Exit move routine, generic + exit messages + dropto check. */ void move_via_exit (dbref thing, dbref dest, dbref cause, dbref exit, int hush) { dbref src; int canhear, darkwiz, quiet, oattr, aattr; if (dest == HOME) dest = Home(thing); src = Location(thing); canhear = Hearer(thing); /* Dark wizards don't trigger OSUCC/ASUCC */ darkwiz = (Wizard(thing) && Dark(thing)); quiet = darkwiz || (hush & HUSH_EXIT); oattr = quiet ? 0 : A_OSUCC; aattr = quiet ? 0 : A_ASUCC; did_it(thing, exit, A_SUCC, NULL, oattr, NULL, aattr, (char **)NULL, 0); process_leave_loc(thing, dest, cause, canhear, hush); move_object(thing, dest); /* Dark wizards don't trigger ODROP/ADROP */ oattr = quiet ? 0 : A_ODROP; aattr = quiet ? 0 : A_ADROP; did_it(thing, exit, A_DROP, NULL, oattr, NULL, aattr, (char **)NULL, 0); did_it(thing, thing, A_MOVE, NULL, A_OMOVE, NULL, A_AMOVE, (char **)NULL, 0); process_enter_loc(thing, src, cause, canhear, hush); process_sticky_dropto(src, thing); } /* --------------------------------------------------------------------------- * move_via_teleport: Teleport move routine, generic + teleport messages + * divestiture + dropto check. */ int move_via_teleport (dbref thing, dbref dest, dbref cause, int hush) { dbref src, curr; int canhear, count; src = Location(thing); if ((dest != HOME) && Good_obj(src)) { curr = src; for (count=20; count>0; count--) { if (!could_doit(thing, curr, A_LTELOUT)) { if ((thing == cause) || (cause == NOTHING)) notify(thing, "You can't teleport out!"); else notify(cause, "You can't teleport that out!"); return 0; } if (Typeof(curr) == TYPE_ROOM) break; curr = Location(curr); } } if (dest == HOME) dest = Home(thing); canhear = Hearer(thing); did_it(thing, thing, 0, NULL, A_OXTPORT, NULL, 0, (char **)NULL, 0); process_leave_loc(thing, dest, NOTHING, canhear, hush); move_object(thing, dest); did_it(thing, thing, A_TPORT, NULL, A_OTPORT, NULL, A_ATPORT, (char **)NULL, 0); did_it(thing, thing, A_MOVE, NULL, A_OMOVE, NULL, A_AMOVE, (char **)NULL, 0); process_enter_loc(thing, src, NOTHING, canhear, hush); divest_object(thing); process_sticky_dropto(src, thing); return 1; } /* --------------------------------------------------------------------------- * move_exit: Try to move a player through an exit. */ void move_exit (dbref player, dbref exit, int divest, const char *failmsg, int hush) { dbref loc; int oattr, aattr; loc = Location(exit); if (loc == HOME) loc = Home(player); if (Good_obj(loc) && could_doit(player, exit, A_LOCK)) { switch (Typeof(loc)) { case TYPE_ROOM: move_via_exit(player, loc, NOTHING, exit, hush); if (divest) divest_object(player); break; case TYPE_PLAYER: case TYPE_THING: if (Flags(loc) & GOING) { notify(player, "You can't go that way."); return; } move_via_exit(player, loc, NOTHING, exit, hush); divest_object(player); break; case TYPE_EXIT: notify(player, "You can't go that way."); return; } } else { if ((Wizard(player) && Dark(player)) || (hush & HUSH_EXIT)) { oattr = 0; aattr = 0; } else { oattr = A_OFAIL; aattr = A_AFAIL; } did_it(player, exit, A_FAIL, failmsg, oattr, NULL, aattr, (char **)NULL, 0); } } /* --------------------------------------------------------------------------- * do_move: Move from one place to another via exits or 'home'. */ void do_move(dbref player, dbref cause, int key, char *direction) { dbref exit, loc; int i, quiet; if (!string_compare(direction, "home")) { /* go home w/o stuff */ if ((loc = Location(player)) != NOTHING && !Dark(player) && !Dark(loc)) { /* tell all */ notify_except(loc, player, player, tprintf("%s goes home.", Name(player)), 1); } /* give the player the messages */ for (i=0; i<3; i++) notify(player, "There's no place like home..."); move_via_generic(player, HOME, NOTHING, 0); divest_object(player); process_sticky_dropto(loc, player); return; } /* find the exit */ init_match_check_keys(player, direction, TYPE_EXIT); match_exit(); exit = match_result(); switch (exit) { case NOTHING: /* try to force the object */ notify(player, "You can't go that way."); break; case AMBIGUOUS: notify(player, "I don't know which way you mean!"); break; default: quiet = 0; if ((key & MOVE_QUIET) && Controls(player, exit)) quiet = HUSH_EXIT; move_exit(player, exit, 0, "You can't go that way.", quiet); } } /* --------------------------------------------------------------------------- * do_get: Get an object. */ void do_get(dbref player, dbref cause, int key, char *what) { dbref thing, loc, exitloc; int quiet, oattr, aattr; quiet = 0; loc = Location(player); if (!Good_obj(loc)) return; /* You can only pick up things in rooms and ENTER_OK objects/players */ if ((Typeof(loc) != TYPE_ROOM) && !(Flags(loc) & ENTER_OK) && !controls(player, loc)) { notify(player, "Permission denied."); return; } /* Handle taking things from other people */ thing = is_possess(player, what); if ((thing != NOTHING) && (thing != AMBIGUOUS)) { if ((key & GET_QUIET) && Controls(player, thing)) quiet = 1; if (could_doit(player, thing, A_LOCK) && (Flags(Location(thing)) & ENTER_OK)) { notify(Location(thing), tprintf("%s was taken from you.", Name(thing))); move_via_generic(thing, player, player, 0); notify(thing, "Taken."); oattr = quiet ? 0 : A_OSUCC; aattr = quiet ? 0 : A_ASUCC; did_it(player, thing, A_SUCC, "Taken.", oattr, NULL, aattr, (char **)NULL, 0); } else { oattr = quiet ? 0 : A_OFAIL; aattr = quiet ? 0 : A_AFAIL; did_it(player, thing, A_FAIL, "You can't take that from there.", oattr, NULL, aattr, (char **)NULL, 0); } return; } /* Look for the object */ init_match_check_keys(player, what, TYPE_THING); match_neighbor(); match_exit(); if (Wizard(player)) match_absolute(); /* the wizard has long fingers */ thing = noisy_match_result(); if (thing == NOTHING) return; switch (Typeof(thing)) { case TYPE_PLAYER: case TYPE_THING: /* You can't take what you already have */ if (Location(thing) == player) { notify(player, "You already have that!"); return; } if ((key & GET_QUIET) && Controls(player, thing)) quiet = 1; if (thing == player) { notify(player, "You cannot get yourself!"); } else if (could_doit(player, thing, A_LOCK)) { move_via_generic(thing, player, player, 0); notify(thing, "Taken."); oattr = quiet ? 0 : A_OSUCC; aattr = quiet ? 0 : A_ASUCC; did_it(player, thing, A_SUCC, "Taken.", oattr, NULL, aattr, (char **)NULL, 0); } else { oattr = quiet ? 0 : A_OFAIL; aattr = quiet ? 0 : A_AFAIL; did_it(player, thing, A_FAIL, "You can't pick that up.", oattr, NULL, aattr, (char **)NULL, 0); } break; case TYPE_EXIT: /* You can't take what you already have */ if (Exits(thing) == player) { notify(player, "You already have that!"); return; } /* You must control either the exit or the location */ if (!Controls(player, thing) && !Controls(player, loc)) { notify(player, "Permission denied."); return; } /* Do it */ exitloc = Exits(thing); s_Exits(exitloc, remove_first(Exits(exitloc), thing)); s_Exits(player, insert_first(Exits(player), thing)); s_Exits(thing, player); if (!Quiet(player)) notify(player, "Exit taken."); break; default: notify(player, "You can't take that!"); break; } } /* --------------------------------------------------------------------------- * drop_sacrifice, do_drop: Drop an object. */ static void drop_sacrifice (dbref player, dbref thing) { dbref loc; char *buf; int reward, maxreward; /* Only players may sacrifice things */ if ((Typeof(player) != TYPE_PLAYER) || (Controls(player, thing)) || (Typeof(thing) == TYPE_PLAYER)) return; loc = Location(player); notify(thing, "You have been sacrificed."); notify(player, tprintf("%s is consumed in a burst of flame!", Name(thing))); if (Good_obj(loc)) { buf = alloc_sbuf("drop_sacrifice"); strcpy(buf, Name(player)); notify_except(loc, player, player, tprintf("%s sacrifices %s.", buf, Name(thing)), 1); free_sbuf(buf); } /* Give the player his reward and tell him about it */ reward = Pennies(thing); maxreward = OBJECT_ENDOWMENT(mudconf.createmax); if ((reward < 1) || (Pennies(Owner(player)) > mudconf.paylimit)) reward = 1; else if (reward > maxreward) reward = maxreward; giveto(Owner(player), reward); notify(player, tprintf("You have received %d %s for your sacrifice.", reward, (reward==1) ? mudconf.one_coin : mudconf.many_coins)); } void do_drop(dbref player, dbref cause, int key, char *name) { dbref loc, exitloc, thing; char *buf; int quiet, oattr, aattr; loc = Location(player); if (!Good_obj(loc)) return; init_match(player, name, TYPE_THING); match_possession(); match_carried_exit(); if (Wizard(player)) match_absolute(); /* the wizard has long fingers */ switch (thing = match_result()) { case NOTHING: notify(player, "You don't have that!"); return; case AMBIGUOUS: notify(player, "I don't know which you mean!"); return; } switch (Typeof(thing)) { case TYPE_THING: case TYPE_PLAYER: /* You have to be carrying it */ if (((Location(thing) != player) && !Wizard(player)) || (!could_doit(player, thing, A_LDROP))) { notify(player, "You can't drop that."); return; } /* Move it */ move_via_generic (thing, Location(player), player, 0); notify(thing, "Dropped."); quiet = 0; if ((key & DROP_QUIET) && Controls(player, thing)) quiet = 1; buf = alloc_lbuf("do_drop.did_it"); sprintf(buf, "dropped %s.", Name(thing)); oattr = quiet ? 0 : A_ODROP; aattr = quiet ? 0 : A_ADROP; did_it(player, thing, A_DROP, "Dropped.", oattr, buf, aattr, (char **)NULL, 0); free_lbuf(buf); /* Check for droptos or sacrifice */ if (IS(loc, TYPE_ROOM, ROOM_TEMPLE)) { drop_sacrifice(player, thing); process_sacrifice_dropto(thing, player); } else { process_dropped_dropto(thing, player); } break; case TYPE_EXIT: /* You have to be carrying it */ if ((Exits(thing) != player) && !Wizard(player)) { notify(player, "You can't drop that."); return; } if (!Controls(player, loc)) { notify(player, "Permission denied."); return; } /* Do it */ exitloc = Exits(thing); s_Exits(exitloc, remove_first(Exits(exitloc), thing)); s_Exits(loc, insert_first(Exits(loc), thing)); s_Exits(thing, loc); if (!Quiet(player)) notify(player, "Exit dropped."); break; default: notify(player, "You can't drop that."); } } /* --------------------------------------------------------------------------- * do_enter, do_leave: The enter and leave commands. */ void do_enter_internal (dbref player, dbref thing, int quiet) { dbref loc; int oattr, aattr; if (!(Flags(thing) & ENTER_OK) && !controls(player, thing)) { oattr = quiet ? 0 : A_OEFAIL; aattr = quiet ? 0 : A_AEFAIL; did_it (player, thing, A_EFAIL, "Permission denied.", oattr, NULL, aattr, (char **)NULL, 0); } else if (player == thing) { notify(player, "You can't enter yourself!"); } else if (could_doit(player, thing, A_LENTER)) { loc = Location(player); oattr = quiet ? HUSH_ENTER : 0; move_via_generic(player, thing, NOTHING, oattr); divest_object(player); process_sticky_dropto(loc, player); } else { oattr = quiet ? 0 : A_OEFAIL; aattr = quiet ? 0 : A_AEFAIL; did_it (player, thing, A_EFAIL, "You can't enter that.", oattr, NULL, aattr, (char **)NULL, 0); } } void do_enter(dbref player, dbref cause, int key, char *what) { dbref thing; int quiet; init_match(player, what, TYPE_THING); match_neighbor(); if (Wizard(player)) match_absolute(); /* the wizard has long fingers */ if ((thing = noisy_match_result()) == NOTHING) return; switch (Typeof(thing)) { case TYPE_PLAYER: case TYPE_THING: quiet = 0; if ((key & MOVE_QUIET) && Controls(player, thing)) quiet = 1; do_enter_internal(player, thing, quiet); break; default: notify(player, "Permission denied."); } return; } void do_leave(dbref player, dbref cause, int key) { dbref loc; int quiet, oattr, aattr; loc = Location(player); if (!Good_obj(loc) || (Typeof(loc) == TYPE_ROOM)) { notify(player, "You can't leave."); return; } quiet = 0; if ((key & MOVE_QUIET) && Controls(player, loc)) quiet = HUSH_LEAVE; if (could_doit(player, loc, A_LLEAVE)) { move_via_generic(player, Location(loc), NOTHING, quiet); } else { oattr = quiet ? 0 : A_OLFAIL; aattr = quiet ? 0 : A_ALFAIL; did_it (player, loc, A_LFAIL, "You can't leave.", oattr, NULL, aattr, (char **)NULL, 0); } }