/* $Header: /belch_a/users/rearl/tinymuck/src/RCS/wiz.c,v 1.16 90/09/28 12:25:37 rearl Exp $ */ /* * $Log: wiz.c,v $ * Revision 1.16 90/09/28 12:25:37 rearl * Fixed missing newline bug in @newpassword logging. * * Revision 1.15 90/09/18 08:02:56 rearl * Fixed @tel for rooms -- a bug in permissions checking. * * Revision 1.14 90/09/16 04:43:20 rearl * Preparation code added for disk-based MUCK. * * Revision 1.13 90/09/15 22:28:34 rearl * Send inventory of the toad home, not the wizard's! * * Revision 1.12 90/09/13 06:30:20 rearl * @toad modified to chown the victim's items to a recipient player. * * Revision 1.11 90/09/10 02:19:06 rearl * Changed NL line termination to CR/LF pairs. * * Revision 1.10 90/09/05 02:32:31 rearl * Added match_here() for room parent setting. * * Revision 1.9 90/09/01 06:00:02 rearl * Fixed code in @teleport. * * Revision 1.8 90/08/27 03:35:41 rearl * Changed teleport checks... * * Revision 1.7 90/08/11 04:12:47 rearl * *** empty log message *** * * Revision 1.6 90/08/06 03:49:14 rearl * Added logging of @force, @boot, and @toad. * * Revision 1.5 90/08/05 03:20:16 rearl * Redid matching routines. * * Revision 1.4 90/08/02 22:07:04 rearl * Changed one call to a log function, that's it. * * Revision 1.3 90/07/29 17:46:28 rearl * Made @stat command a little cleaner, toaded victims are now * toaded first, then all their connections are booted from the game. * * Revision 1.2 90/07/23 14:48:37 casie * *** empty log message *** * * Revision 1.1 90/07/19 23:04:20 casie * Initial revision * * */ #include "copyright.h" #include "config.h" /* Wizard-only commands */ #include "db.h" #include "params.h" #include "interface.h" #include "match.h" #include "externs.h" void do_teleport(dbref player, const char *arg1, const char *arg2) { dbref victim; dbref destination; const char *to; struct match_data md; /* get victim, destination */ if(*arg2 == '\0') { victim = player; to = arg1; } else { init_match(player, arg1, NOTYPE, &md); match_neighbor(&md); match_possession(&md); match_me(&md); match_here(&md); match_absolute(&md); match_player(&md); if((victim = noisy_match_result(&md)) == NOTHING) { return; } to = arg2; } /* get destination */ init_match(player, to, TYPE_PLAYER, &md); match_here(&md); match_home(&md); match_absolute(&md); match_neighbor(&md); match_me(&md); match_player(&md); switch(destination = match_result(&md)) { case NOTHING: notify(player, "Send it where?"); break; case AMBIGUOUS: notify(player, "I don't know which destination you mean!"); break; case HOME: switch (Typeof(victim)) { case TYPE_PLAYER: destination = DBFETCH(victim)->link; break; case TYPE_THING: destination = DBFETCH(victim)->link; break; case TYPE_ROOM: destination = GLOBAL_ENVIRONMENT; break; case TYPE_PROGRAM: destination = OWNER(victim); break; default: destination = PLAYER_START; /* caught in the next switch anyway */ break; } default: switch (Typeof(victim)) { case TYPE_PLAYER: if (!Arch(player) && (victim != player)) { notify(player, "Permission denied."); break; } if (Typeof(destination) != TYPE_ROOM && Typeof(destination) != TYPE_PLAYER && Typeof(destination) != TYPE_THING) { notify(player, "Bad destination."); break; } if(!Arch(player) && !(controls(player,destination)) && !((FLAGS(destination)&JUMP_OK) #ifdef ABODE || (FLAGS(destination)&ABODE) #else || (FLAGS(destination)&LINK_OK) #endif /* ABODE */ )) { notify(player,"Permission denied!"); break; } if(parent_loop_check(victim,destination)) { notify(player,"Error: would create a loop"); break; } enter_room(victim, destination, DBFETCH(victim)->location); notify(player, "Teleported."); break; case TYPE_THING: case TYPE_PROGRAM: if (Typeof(destination) != TYPE_ROOM && Typeof(destination) != TYPE_PLAYER && Typeof(destination) != TYPE_THING) { notify(player, "Bad destination."); break; } if (!Arch(player) && !((controls(player, destination) #ifdef ABODE || (FLAGS(destination)&ABODE) #else || (FLAGS(destination)&LINK_OK) #endif /* ABODE */ || (FLAGS(destination)&JUMP_OK)) && (controls(player, victim) || controls(player, DBFETCH(victim)->location)))) { notify(player, "Permission denied."); break; } /* check for non-sticky dropto */ if (Typeof(destination) == TYPE_ROOM && DBFETCH(destination)->link != NOTHING && !(FLAGS(destination) & STICKY)) destination = DBFETCH(destination)->link; if(parent_loop_check(victim,destination)) { notify(player,"Would create a loop. sorry."); break; } moveto(victim, destination); notify(player, "Teleported."); break; case TYPE_ROOM: if (Typeof(destination) != TYPE_ROOM) { notify(player, "Bad destination."); break; } if (!controls(player, victim) || !can_link_to(player, NOTYPE, destination) || victim == GLOBAL_ENVIRONMENT) { notify(player, "Permission denied."); break; } if (parent_loop_check(victim, destination)) { notify(player, "Parent would create a loop."); break; } moveto(victim, destination); notify(player, "Parent set."); break; #ifdef RECYCLE case TYPE_GARBAGE: notify(player, "That object is in a place where magic cannot reach it."); break; #endif default: notify(player, "You can't teleport that."); break; } break; } return; } void do_force(dbref player, const char *what, char *command) { dbref victim; struct match_data md; init_match(player,what,TYPE_PLAYER,&md); match_neighbor(&md); match_possession(&md); match_me(&md); match_absolute(&md); if(Wizard(player)) match_player(&md); victim=noisy_match_result(&md); if(victim==NOTHING) { return; } if(player != OWNER(victim) && !Wizard(player)) { notify(player,"Permission denied."); return; } #ifdef GOD_PRIV if (God(victim)) { notify(player, "You cannot force god to do anything."); return; } #endif /* GOD_PRIV */ if(Typeof(victim)!=TYPE_PLAYER && Typeof(victim)!=TYPE_THING) { notify(player, "Illegal object type."); return; } if(Typeof(victim)==TYPE_PLAYER) log_status("FORCED: %s(%d) by %s(%d): %s\n", NAME(victim), victim, NAME(player), player, command); /* force victim to do command */ process_command(victim, command, player,0); } void do_stats(dbref player, const char *name) { int breakdown[10]; int total = 0; dbref i; dbref owner = 0; struct match_data md; char buf[BUFFER_LEN]; if(!payfor(player, LOOKUP_COST)) { notify(player,"You don't have enough pennies."); return; } if (name != NULL && *name != '\0') { owner = lookup_player(name); if (owner == NOTHING) { init_match(player, name, NOTYPE, &md); match_me(&md); match_absolute(&md); match_player(&md); if((owner = match_result(&md)) == NOTHING) { notify(player, "I can't find that player."); return; } } if(!controls(player,owner)) { notify(player, "Permission denied."); return; } } for(i = 0; i < 10; i++) breakdown[i] = 0; if(name != NULL || *name != '\0') { for (i = 0; i < db_top; i++) if ((*name == '\0') || (OWNER(i) == owner)) { total++; breakdown[Typeof(i)]++; } } else { for (i = 0; i < db_top; i++) { total++; breakdown[Typeof(i)]++; } } #ifdef RECYCLE sprintf(buf, "%d object%s = %d room%s, %d exit%s, %d thing%s, %d program%s, %d player%s, %d garbage.", total, (total == 1) ? "" : "s", breakdown[TYPE_ROOM], (breakdown[TYPE_ROOM] == 1) ? "" : "s", breakdown[TYPE_EXIT], (breakdown[TYPE_EXIT] == 1) ? "" : "s", breakdown[TYPE_THING], (breakdown[TYPE_THING] == 1) ? "" : "s", breakdown[TYPE_PROGRAM], (breakdown[TYPE_PROGRAM] == 1) ? "" : "s", breakdown[TYPE_PLAYER], (breakdown[TYPE_PLAYER] == 1) ? "" : "s", breakdown[TYPE_GARBAGE]); #else /* RECYCLE */ sprintf(buf, "%d object%s = %d room%s, %d exit%s, %d thing%s, %d program%s, %d player%s.", total, (total == 1) ? "" : "s", breakdown[TYPE_ROOM], (breakdown[TYPE_ROOM] == 1) ? "" : "s", breakdown[TYPE_EXIT], (breakdown[TYPE_EXIT] == 1) ? "" : "s", breakdown[TYPE_THING], (breakdown[TYPE_THING] == 1) ? "" : "s", breakdown[TYPE_PROGRAM], (breakdown[TYPE_PROGRAM] == 1) ? "" : "s", breakdown[TYPE_PLAYER], (breakdown[TYPE_PLAYER] == 1) ? "" : "s") #endif /* RECYCLE */ notify(player, buf); } void do_boot(dbref player, const char *name) { dbref victim; char buf[BUFFER_LEN]; if((victim = lookup_player(name)) == NOTHING) { notify(player, "That player does not exist."); return; } if(Typeof(victim) != TYPE_PLAYER) { notify(player, "You can only boot players!"); } else if (!Wizard(player) && (OWNER(victim) != player)) { notify(player, "Permission denied."); } #ifdef GOD_PRIV else if(God(victim)) { notify(player, "Permission denied."); } #endif /* GOD_PRIV */ else { notify(victim, "You have been booted off the game."); if (boot_off(victim)) { log_status("BOOTED: %s(%d) by %s(%d)\n", NAME(victim), victim, NAME(player), player); sprintf(buf, "You booted %s off!", NAME(victim)); notify(player, buf); } else { sprintf(buf, "%s is not connected.", NAME(victim)); notify(player, buf); } } } void do_toad(dbref player, const char *name, const char *recip) { dbref victim; dbref recipient; dbref stuff; if(Typeof(player) != TYPE_PLAYER) { notify(player, "Permission denied."); return; } if(!Wizard(player)) { notify(player, "Only a wizard can destroy a player."); return; } if((victim = lookup_player(name)) == NOTHING) { notify(player, "That player does not exist."); return; } if (!*recip) { recipient = GOD; } else { if ((recipient = lookup_player(recip)) == NOTHING || recipient == victim) { notify(player, "That recipient does not exist."); return; } } if(Typeof(victim) != TYPE_PLAYER) { notify(player, "You can only destroy the living!"); } else if(Wizard(victim) || FLAGS(victim)&WIZARD) { /* don't toad Quell W */ notify(player, "You can't destroy a wizard."); } else { /* chown things to recipient, checking for a sane home location */ /* for object. XXX -- if HOME/inventory handling changes, */ /* please check this code.*/ for (stuff = 0; stuff < db_top; stuff++) { if ((Typeof(stuff) == TYPE_THING) && (DBFETCH(stuff)->link == victim)) { DBSTORE(stuff, link, PLAYER_START); } if (OWNER(stuff) == victim) { OWNER(stuff) = recipient; DBDIRTY(stuff); } } /* Take them home; things should no longer be homed here, programs */ /* should not be owned by player */ send_contents(victim, HOME); if(DBFETCH(victim)->sp.player.password) { free((void *) DBFETCH(victim)->sp.player.password); DBFETCH(victim)->sp.player.password = NULL; } FLAGS(victim) = TYPE_THING; OWNER(victim) = player; /* you get it */ /* notify people */ notify(victim, "You have been destroyed."); sprintf(buf, "You destroyed %s!", NAME(victim)); notify(player, buf); log_status("DESTROYED: %s(%d) by %s(%d)\n", NAME(victim), victim, NAME(player), player); delete_player(victim); DBDIRTY(victim); while (boot_off(victim)) ; } } void do_newpassword(dbref player, const char *name, const char *password) { dbref victim; char buf[BUFFER_LEN]; if(!Wizard(player)) { notify(player, "Permission denied."); return; } else if((victim = lookup_player(name)) == NOTHING) { notify(player, "No such player."); } else if(*password != '\0' && !ok_password(password)) { /* Wiz can set null passwords, but not bad passwords */ notify(player, "Bad password"); #ifdef GOD_PRIV } else if (God(victim) && !God(player)) { notify(player, "Permission denied."); return; #endif /* GOD_PRIV */ } else { /* it's ok, do it */ if(DBFETCH(victim)->sp.player.password) free((void *) DBFETCH(victim)->sp.player.password); DBSTORE(victim, sp.player.password, alloc_string(password)); sprintf(buf, "%s's password changed to %s.", NAME(victim),password); notify(player, buf); sprintf(buf, "Your password has been changed by %s.", NAME(player)); notify(victim, buf); log_status("NEWPASS'ED: %s(%d) by %s(%d)\n", NAME(victim), (int) victim, NAME(player), (int) player); } } void do_pcreate(dbref player, const char *user, const char *password) { dbref newguy; char buf[BUFSIZ]; if (!Wizard(player)) { notify(player, "Permission denied."); return; } newguy = create_player (user, password); if (newguy == NOTHING) { notify(player, "Create failed."); } else { log_status("PCREATED %s(%d) by %s(%d)\n", NAME(newguy), (int) newguy, NAME(player), (int) player); sprintf(buf, "%s created.", unparse_object(player, newguy)); notify(player,buf); } } void swap(dbref r1,dbref r2) { dbref lo; struct object tmpobj; #define CSWAP(th1) { if((th1) == r1) (th1) = r2; \ else if((th1) == r2) (th1) = r1; } bcopy(DBFETCH(r1), &tmpobj, sizeof(tmpobj)); bcopy(DBFETCH(r2), DBFETCH(r1), sizeof(tmpobj)); bcopy(&tmpobj, DBFETCH(r2), sizeof(tmpobj)); for(lo = 0; lo < db_top; lo++) { if(Typeof(lo) == TYPE_ROOM || Typeof(lo) == TYPE_THING || Typeof(lo) == TYPE_PLAYER) CSWAP(DBFETCH(lo)->exits); if(Typeof(lo) != TYPE_EXIT) CSWAP(DBFETCH(lo)->link); CSWAP(DBFETCH(lo)->location); CSWAP(DBFETCH(lo)->owner); CSWAP(DBFETCH(lo)->contents); CSWAP(DBFETCH(lo)->next); if(Typeof(lo) == TYPE_EXIT && DBFETCH(lo)->sp.exit.ndest) { int i; for(i = 0; i < (DBFETCH(lo)->sp.exit.ndest); i++) { CSWAP(DBFETCH(lo)->sp.exit.dest[i]); } } if(Typeof(lo) == TYPE_PLAYER) { CSWAP(DBFETCH(lo)->curr_prog); } } } void do_swap(dbref player, char *t1, char *t2) { struct match_data md; dbref r1, r2; if(!Wizard(player)) { notify(player, "Permission denied."); return; } init_match(player,t1,TYPE_THING,&md); match_all_exits(&md); match_neighbor(&md); match_possession(&md); match_here(&md); if(Arch(player)) match_absolute(&md); r1 = noisy_match_result(&md); if(r1 == NOTHING) { notify(player,"Bad first argument."); return; } init_match(player, t2, TYPE_THING, &md); match_all_exits(&md); match_neighbor(&md); match_possession(&md); match_here(&md); if(Arch(player)) match_absolute(&md); r2 = noisy_match_result(&md); if(r2 == NOTHING) { notify(player,"Bad second argument."); return; } if(r1 < 0 || r2 < 0 || r1 >= db_top || r2 >= db_top) { notify(player,"Bad arguments."); return; } if(!controls(player, r1) && Typeof(r1) != TYPE_GARBAGE) { notify(player,"Permission denied."); return; } if(!controls(player, r2) && Typeof(r2) != TYPE_GARBAGE) { notify(player,"Permission denied."); return; } #ifdef GOD_PRIV if((Typeof(r1) == TYPE_PROGRAM || Typeof(r2) == TYPE_PROGRAM || Typeof(r1) == TYPE_PLAYER || Typeof(r2) == TYPE_PLAYER) && !God(player)) { /* very destructive for program calls, */ ; /* and players want to keep their numbers */ ; /* and regular wizards can't do this. */ notify(player,"Permission denied."); return; } if((God(r1) || God(r2)) && !God(player)) notify(player, "Permission denied."); #endif /* GOD_PRIV */ notify(r1, "You sense that your identity has changed."); notify(r2, "You sense that your identity has changed."); swap(r1, r2); notify(player,"Swapped..."); }