#include "copyright.h" #include "config.h" #include "db.h" #include "params.h" #include "interface.h" #include "match.h" #include "externs.h" #include "money.h" static char buf[BUFFER_LEN]; void moveto(dbref what, dbref where) { dbref loc, old; if (where == HOME) where = DBFETCH(what)->link; if (parent_loop_check(what, where)) return; if((loc = DBFETCH(what)->location) != NOTHING) { if (Typeof(what) == TYPE_EXIT) { DBSTORE(loc, exits, remove_first(DBFETCH(loc)->exits, what)); } else { DBSTORE(loc, contents, remove_first(DBFETCH(loc)->contents, what)); } } /* now put what in where */ if (where != NOTHING) { if (Typeof(what) == TYPE_EXIT) { PUSH(what, DBFETCH(where)->exits); } else { PUSH(what, DBFETCH(where)->contents); } DBDIRTY(where); #ifdef MUSH if (!Dark(where)) { old = DBFETCH(what)->location; did_it(what, old, "LEAVE", NULL, "OLEAVE", NULL, "ALEAVE", old); if(Typeof(where) != TYPE_ROOM) did_it(what, where, NULL, NULL, "OXENTER", NULL, NULL, old); if(Typeof(old) != TYPE_ROOM) did_it(what, old, NULL, NULL, "OXLEAVE", NULL, NULL, where); did_it(what, where, "ENTER", NULL, "OENTER", NULL, "AENTER", where); /* Not QUITE MUSH compat */ did_it(what, what, "MOVE", NULL, "OMOVE", NULL, "AMOVE", where); } #endif } DBSTORE(what, location, where); } dbref reverse(dbref); void send_contents(dbref loc, dbref dest) { dbref first; dbref rest; first = DBFETCH(loc)->contents; DBSTORE(loc, contents, NOTHING); while(first != NOTHING) { rest = DBFETCH(first)->next; if((Typeof(first) != TYPE_THING) && (Typeof(first) != TYPE_PROGRAM)) moveto(first, loc); else moveto(first, FLAGS(first) & STICKY ? HOME : dest); first = rest; } DBSTORE(loc, contents, reverse(DBFETCH(loc)->contents)); } void maybe_dropto(dbref loc, dbref dropto) { dbref thing; if(loc == dropto) return; /* bizarre special case */ /* check for players */ DOLIST(thing, DBFETCH(loc)->contents) { if(Typeof(thing) == TYPE_PLAYER) return; } /* no players, send everything to the dropto */ send_contents(loc, dropto); } int parent_loop_check(dbref source, dbref dest) { dbref obj; int count = 0; if (dest == NOTHING) return 0; for(obj = dest; (obj != NOTHING) && (obj != source) && (count < 10000); obj = DBFETCH(obj)->location, count++); return (obj != NOTHING); } void enter_room(dbref player, dbref loc, dbref exit1) { dbref old; dbref dropto; /* check for room == HOME */ if(loc == HOME) loc = DBFETCH(player)->link; /* home */ /* get old location */ old = DBFETCH(player)->location; /* check for self-loop */ /* self-loops don't do move or other player notification */ /* but you still get autolook and penny check */ if(loc != old) { if(old != NOTHING) { /* notify others unless DARK */ if((!Dark(old) && !Dark(player) && (Typeof(exit1) != TYPE_EXIT)) || ((Typeof(exit1) == TYPE_EXIT) && !Dark(exit1) && !(GET_OSUCC(exit1)))) { sprintf(buf, "%s has left.", unparse_name(player)); notify_except(player, old, player, buf); } } /* go there */ moveto(player, loc); /* if old location has STICKY dropto, send stuff through it */ if(old != NOTHING && (dropto = DBFETCH(old)->link) != NOTHING && (FLAGS(old) & STICKY)) maybe_dropto(old, dropto); /* tell other folks in new location if not DARK */ if((!Dark(loc) && !Dark(player) && (Typeof(exit1) != TYPE_EXIT)) || ((Typeof(exit1) == TYPE_EXIT) && !Dark(exit1) && !(GET_ODROP(exit1)))) { sprintf(buf, "%s has arrived.", unparse_name(player)); notify_except(player, loc, player, buf); } } /* autolook */ look_room(player, loc); if (o_penny_rate) { /* check for pennies */ if(!controls(player, loc) && DBFETCH(player)->pennies <= MAX_PENNIES && random() % PENNY_RATE == 0) { notify(player, player, tprintf("You found a %s!", S_MONEY)); DBFETCH(player)->pennies++; DBDIRTY(player); } } } void send_home(dbref thing) { switch(Typeof(thing)) { case TYPE_PLAYER: /* send his possessions home first! */ /* that way he sees them when he arrives */ send_contents(thing, HOME); enter_room(thing, DBFETCH(thing)->link, DBFETCH(thing)->location); break; case TYPE_THING: moveto(thing, DBFETCH(thing)->link); break; case TYPE_PROGRAM: moveto(thing, OWNER(thing)); break; } } /* * trigger() * * This procedure triggers a series of actions, or meta-actions * which are contained in the 'dest' field of the exit. * Locks other than the first one are over-ridden. * * `player' is the player who triggered the exit * `exit' is the exit triggered * `pflag' is a flag which indicates whether player and room exits * are to be used (non-zero) or ignored (zero). Note that * player/room destinations triggered via a meta-link are * ignored. * */ void trigger(dbref player, dbref exit1, int pflag) { frame *fr; int i; dbref dest; int sobjact; /* sticky object action flag, sends home source obj */ int succ; sobjact = 0; succ = 0; for (i = 0; i < DBFETCH(exit1)->sp.exit.ndest; i++) { dest = (DBFETCH(exit1)->sp.exit.dest)[i]; if (dest == HOME) dest = DBFETCH(player)->link; if ((FLAGS(dest) & ENTER_OK) || (Typeof(dest) == TYPE_ROOM)) { if (pflag && !parent_loop_check(player, dest)) { if (GET_DROP(exit1)) exec_or_notify(player, exit1, GET_DROP(exit1)); if (GET_ODROP(exit1) && !Dark(player)) { sprintf(buf, "%s %s", unparse_name(player), pronoun_substitute(player, GET_ODROP(exit1))); notify_except(player, dest, player, buf); } enter_room(player, dest, exit1); succ = 1; } } else { switch(Typeof(dest)) { case TYPE_THING: if (Typeof(DBFETCH(exit1)->location) == TYPE_THING) { moveto (dest, DBFETCH(DBFETCH(exit1)->location)->location); if (!(FLAGS(exit1) & STICKY)) sobjact = 1; } else moveto (dest, DBFETCH(exit1)->location); if (GET_SUCC(exit1)) succ = 1; break; case TYPE_EXIT: /* It's a meta-link(tm)! */ trigger(player, (DBFETCH(exit1)->sp.exit.dest)[i], 0); if (GET_SUCC(exit1)) succ = 1; break; case TYPE_PLAYER: if (pflag && DBFETCH(dest)->location != NOTHING) { succ = 1; if (FLAGS(dest) & JUMP_OK) { if (GET_DROP(exit1)) exec_or_notify(player, exit1, GET_DROP(exit1)); if (GET_ODROP(exit1) && !Dark(player)) { sprintf(buf, "%s %s", unparse_name(player), pronoun_substitute(player, GET_ODROP(exit1))); notify_except(player, DBFETCH(dest)->location, player, buf); } enter_room(player, DBFETCH(dest)->location, exit1); } else notify(player, player, "That player does not wish to be disturbed."); } break; case TYPE_PROGRAM: #ifdef MUSH if(mush_interp) /* Don't allow MUSH commands to go INTERACTIVE */ fr = new_frame(player, dest, exit1, DBFETCH(player)->location, 1); else fr = new_frame(player, dest, exit1, DBFETCH(player)->location, 0); #else fr = new_frame(player, dest, exit1, DBFETCH(player)->location, 0); #endif /* MUSH */ add_frame(fr); run_frame(fr, 0); succ = 1; } } } if (sobjact) send_home(DBFETCH(exit1)->location); if (!succ && pflag) notify(player, player, "Done."); } int can_move(dbref player, char *direction) { match_data md; if(!string_compare(direction, "home")) return 1; /* otherwise match on exits */ init_match(player, direction, TYPE_EXIT, &md); match_all_exits(&md); return(last_match_result(&md) != NOTHING); } void do_earthquake(__DO_PROTO) { dbref victim, temp; char buffer[80]; if (!Wizard(player)) { notify_nolisten(player, "Ha! You _wish_ you had that much clout!"); } else { /* Use this in extreme cases of duress. Should sanitize the crap out * of your database. Not responsible for any damage. Read directions * carefully. Do not take internally. In case of eye contact, flush well. * In case of ingestion, induce vomiting and contact a doctor immediately. */ /* nuke the victims contents, exits, and next fields */ /* and sanitize their location, link, and destinations */ /* also do a call to sanitize the locks on the object */ for (victim = (dbref) 0 ; victim < db_top ; victim++) { if ((victim %1000) == 0) { sprintf(buffer, "Sanitizing: %d", victim); notify_nolisten(player, buffer); } DBSTORE(victim, contents, NOTHING); DBSTORE(victim, exits, NOTHING); DBSTORE(victim, next, NOTHING); temp = DBFETCH(victim)->location; if (temp < 0 || temp >= db_top) DBSTORE(victim, location, GLOBAL_ENVIRONMENT); temp = DBFETCH(victim)->link; if (temp < 0 || temp >= db_top || temp == HOME) DBSTORE(victim, link, NOTHING); /* if (Typeof(victim) == TYPE_EXIT && DBFETCH(victim)->sp.exit.ndest != 0) { for (i = 0; i < DBFETCH(victim)->sp.exit.ndest; i++) { temp = DBFETCH(victim)->sp.exit.dest[i]; if (temp < 0 || temp >= db_top) DBSTORE(temp, sp.exit.dest[i], HOME); } } */ sanitize_lock(DBFETCH(victim)->key); } /* now move them all back where they belong. */ /* a little braindamaged, but the global environment shouldn't */ /* be inside itself :) */ DBSTORE(GLOBAL_ENVIRONMENT, location, NOTHING); for (victim = (dbref) 0 ; victim < db_top ; victim++) { if (victim %1000 == 0) { sprintf(buffer, "Sanitizing: %d", victim); notify_nolisten(player, buffer); } if (Typeof(victim) != TYPE_GARBAGE) moveto(victim, DBFETCH(victim)->location); } /* reset all the backlinks and backlocks too... */ reset_lists(); } } void do_move(__DO_PROTO) { dbref exit1; dbref loc; match_data md; if(!string_compare(argall, "home")) { /* send him home */ /* but steal all his possessions */ if((loc = DBFETCH(player)->location) != NOTHING) { /* tell everybody else */ if(!Dark(player)) { sprintf(buf, "%s goes home.", unparse_name(player)); notify_except(player, loc, player, buf); } } /* give the player the messages */ notify(player, player, "You wake up back home, without your possessions."); send_home(player); } else { /* find the exit */ init_match_check_keys(player, argall, TYPE_EXIT, &md); match_all_exits(&md); switch(exit1 = match_result(&md)) { case NOTHING: notify(player, player, "You can't go that way."); break; case AMBIGUOUS: notify(player, player, "I don't know which way you mean!"); break; default: /* we got one */ /* check to see if we got through */ loc = DBFETCH(player)->location; #ifdef TIMESTAMPS DBFETCH(exit1)->time_used = time((long *)NULL); #endif if(can_doit(player, exit1, "You can't go that way.")) trigger(player, exit1, 1); } } } void do_get(__DO_PROTO) { dbref thing; match_data md; init_match_check_keys(player, arg1, TYPE_THING, &md); match_neighbor(&md); if(Wizard(player)) match_absolute(&md); /* the wizard has long fingers */ if((thing = noisy_match_result(&md)) != NOTHING) { #ifdef TIMESTAMPS DBFETCH(thing)->time_used = time((long *)0); #endif if(DBFETCH(thing)->location == player) { notify(player, player, "You already have that!"); return; } switch(Typeof(thing)) { case TYPE_THING: case TYPE_PROGRAM: if(can_doit(player, thing, "You can't pick that up.")) { moveto(thing, player); notify(player, player, "Taken."); } break; default: notify(player, player, "You can't take that!"); break; } } } void do_drop(__DO_PROTO) { dbref loc; dbref thing; char *ptr; match_data md; if((loc = getloc(player)) == NOTHING) return; init_match(player, arg1, NOTYPE, &md); match_possession(&md); if ((thing = noisy_match_result(&md)) == NOTHING || thing == AMBIGUOUS) return; if (!controls(player, DBFETCH(player)->location) && ((Typeof(thing) == TYPE_EXIT) || (Typeof(thing) == TYPE_ROOM))) { notify(player, player, "Permission denied."); return; } #ifdef TIMESTAMPS DBFETCH(thing)->time_used = time(NULL); #endif if(DBFETCH(thing)->location != player) { /* Shouldn't ever happen. */ notify(player, player, "You can't drop that."); } if ((FLAGS(thing) & STICKY) && Typeof(thing) == TYPE_THING) send_home(thing); else { int immediate_dropto; immediate_dropto = (DBFETCH(loc)->link != NOTHING && !(FLAGS(loc) & STICKY)); moveto(thing, immediate_dropto ? DBFETCH(loc)->link : loc); look_room(thing, loc); } if (GET_DROP(thing)) exec_or_notify(player, thing, GET_DROP(thing)); else notify(player, player, "Dropped."); if (GET_DROP(loc)) exec_or_notify(player, loc, GET_DROP(loc)); if (GET_ODROP(thing)) { strcpy(buf, unparse_name(player)); strcat(buf, " "); #ifdef MUSH ptr = exec(player, GET_ODROP(thing), thing, 0); if(ptr) { strcat(buf, ptr); free(ptr); } #else strcat(buf, pronoun_substitute(player, GET_ODROP(thing))); #endif } else { strcpy(buf, unparse_name(player)); strcat(buf, " drops "); strcat(buf, unparse_name(thing)); } notify_except(player, loc, player, buf); if (GET_ODROP(loc)) { strcpy(buf, unparse_name(thing)); strcat(buf, " "); #ifdef MUSH ptr = exec(player, GET_ODROP(loc), thing, 0); if(ptr) { strcat(buf, ptr); free(ptr); } #else strcat(buf, pronoun_substitute(thing, GET_ODROP(loc))); #endif notify_except(player, loc, player, buf); } #ifdef MUSH /* Is this right???????????? */ did_it(player, thing, NULL, NULL, NULL, NULL, "ADROP", NOTHING); did_it(player, loc, NULL, NULL, NULL, NULL, "ADROP", NOTHING); #endif } void recycle_backlocks(dbref d, boolexp *b) { if (b) { switch (b->type) { case BOOLEXP_AND: case BOOLEXP_OR: recycle_backlocks(d, b->sub2); case BOOLEXP_NOT: recycle_backlocks(d, b->sub1); break; case BOOLEXP_CONST: if (b->thing == d) b->thing = NOTHING; } } } void recycle_locks(dbref d, boolexp *b) { if (b) { switch (b->type) { case BOOLEXP_AND: case BOOLEXP_OR: recycle_locks(d, b->sub2); case BOOLEXP_NOT: recycle_locks(d, b->sub1); break; case BOOLEXP_CONST: if (b->thing == NOTHING) return; DBSTORE(b->thing, backlocks, dbreflist_remove(DBFETCH(b->thing)->backlocks, d)); } } } void recycle(dbref player, dbref thing) { dbref first, rest; dbref_list *drl, *drl_temp; int i, j; #ifdef FLUSH_OWNERSHIP /* change ownership on all the stuff */ for (stuff = thing; stuff != NOTHING; stuff = DBFETCH(stuff)->nextowned) { DBSTORE(stuff, owner, OWNER(player)); } for(stuff = OWNER(player); DBFETCH(stuff)->nextowned != NOTHING; stuff = DBFETCH(stuff)->nextowned); DBSTORE(stuff, nextowned, thing); /* link all objects now linked to the thing to the player */ while (DBFETCH(thing)->backlinks && ((Typeof(DBFETCH(thing)->backlinks->object)) == TYPE_THING)) { tmp = DBFETCH(thing)->backlinks; DBSTORE(thing, backlinks, tmp->next); DBSTORE(tmp->object, link, OWNER(player)); DBSTORE(tmp->object, owner, OWNER(player)); add_backlinks(tmp->object); free(tmp); } for (list = DBFETCH(thing)->backlinks; list && list->next; list = list->next) { if (Typeof(list->next->object) == TYPE_THING) { tmp = list->next; list->next = tmp->next; DBSTORE(tmp->object, link, OWNER(player)); add_backlinks(tmp->object); free(tmp); } } /* and now send all objects currently on the thing to their home */ send_contents(thing, HOME); #endif remove_ownerlist(thing); for (drl = DBFETCH(thing)->backlocks; drl; drl = drl->next) recycle_backlocks(thing, DBFETCH(drl->object)->key); recycle_locks(thing, DBFETCH(thing)->key); DBSTORE(thing, backlocks, NULL); for(drl = DBFETCH(thing)->backlinks; drl; drl = drl->next) { rest = drl->object; switch(Typeof(rest)) { case TYPE_ROOM: if (rest != HOME) { DBSTORE(rest, link, NOTHING); } break; case TYPE_EXIT: for (i = j = 0; i < DBFETCH(rest)->sp.exit.ndest; i++) { if((DBFETCH(rest)->sp.exit.dest)[i] != thing) (DBFETCH(rest)->sp.exit.dest)[j++] = (DBFETCH(rest)->sp.exit.dest)[i]; } if(j < DBFETCH(rest)->sp.exit.ndest) { if (!Wizard(player)) DBFETCH(player)->pennies += LINK_COST; DBSTORE(rest, sp.exit.ndest, j); DBDIRTY(player); } break; default: if (rest == HOME) rest = DBFETCH(OWNER(thing))->link; if(DBFETCH(rest)->link == thing) { DBSTORE(rest, link, PLAYER_START); } else { DBSTORE(rest, link, DBFETCH(rest)->link); } add_backlinks(rest); } } remove_backlinks(thing); for(first = DBFETCH(thing)->exits; first != NOTHING; first = rest) { rest = DBFETCH(first)->next; if(DBFETCH(first)->location == NOTHING || DBFETCH(first)->location == thing) recycle(player, first); } for(first = DBFETCH(thing)->contents; first != NOTHING; first = rest) { rest = DBFETCH(first)->next; if(Typeof(first) == TYPE_PLAYER) { notify_except(first, thing, NOTHING, "You feel a wrenching sensation..."); enter_room(first, HOME, DBFETCH(thing)->location); } else moveto(first, HOME); } switch (Typeof(thing)) { case TYPE_ROOM: if (!Wizard(OWNER(thing))) DBFETCH(OWNER(thing))->pennies += ROOM_COST; DBDIRTY(OWNER(thing)); break; case TYPE_THING: if (!Wizard(OWNER(thing))) DBFETCH(OWNER(thing))->pennies += DBFETCH(thing)->pennies; DBDIRTY(OWNER(thing)); break; case TYPE_EXIT: if (!Wizard(OWNER(thing))) DBFETCH(OWNER(thing))->pennies += EXIT_COST; if( ((DBFETCH(thing)->sp.exit.ndest) != 0) && (!Wizard(OWNER(thing))) ) DBFETCH(OWNER(thing))->pennies += LINK_COST; DBDIRTY(OWNER(thing)); break; case TYPE_PROGRAM: sprintf (buf, "Program %s recycled by ", unparse_name(thing)); strcat(buf, unparse_name(player)); strcat(buf, "."); for (drl = DBFETCH(thing)->sp.program.editlocks; drl; drl = drl_temp) { drl_temp = drl->next; if (drl->object != player) notify(drl->object, drl->object, buf); FLAGS(drl->object) &= ~INTERACTIVE; DBSTORE(drl->object, curr_prog, NOTHING); free (drl); } bump_frames(buf, thing, player); sprintf(buf, "muf/%ld.m", thing); unlink(buf); } DBSTORE(thing, owner, NOTHING); moveto(thing, NOTHING); db_free_object(thing); db_clear_object(thing); DBSTORE(thing, name, COMPOST_NAME); #ifndef USE_DBP_STR DBSTORE(thing, desc, COMPOST_DESC); #else add_property(thing, "desc", COMPOST_DESC, PERMS_COREAD | PERMS_COWRITE | PERMS_OTREAD, ACCESS_CO); #endif DBSTORE(thing, key, TRUE_BOOLEXP); FLAGS(thing) = TYPE_GARBAGE; add_compost(thing); DBDIRTY(thing); } void do_recycle(__DO_PROTO) { dbref thing; match_data md; init_match(player, arg1, NOTYPE, &md); match_all_exits(&md); match_neighbor(&md); match_possession(&md); match_here(&md); match_absolute(&md); if((thing = noisy_match_result(&md)) == NOTHING) { notify(player, player, "Recycle what?"); return; } if(Typeof(thing) == TYPE_GARBAGE) { notify(player, player, "Garbage is already recycled."); return; } if(o_wiz_recycle) { if(!controls(player, thing)) { notify(player, player, "Permission denied."); return; } else { if(OWNER(thing) != player) { notify(player, player, "Permission denied."); return; } } } if(Safe(thing)) { notify(player, player, "Object is set SAFE."); return; } switch(Typeof(thing)) { case TYPE_ROOM: if(thing == PLAYER_START || thing == GLOBAL_ENVIRONMENT) { notify(player, player, "This room may not be recycled."); return; } break; case TYPE_PLAYER: notify(player, player, "You can't recycle a player!"); return; } recycle(player, thing); notify (player, player, "Thank you for recycling."); }