/* create.c */ #include "copyright.h" /* Commands that create new objects */ #ifdef WANT_ANSI #ifdef __STDC__ #include <stdlib.h> #include <stddef.h> #endif /* __STDC__ */ #endif /*WANT_ANSI */ #include "mudconf.h" #include "config.h" #include "db.h" #include "interface.h" #include "externs.h" #include "match.h" /* --------------------------------------------------------------------------- * parse_linkable_room: Get a location to link to. */ static dbref parse_linkable_room(dbref player, char *room_name) { dbref room; /* skip leading NUMBER_TOKEN if any */ if (*room_name == NUMBER_TOKEN) room_name++; /* parse room */ if (!string_compare(room_name, "here")) { room = Location(player); } else if (!string_compare(room_name, "home")) { return HOME; /* HOME is always linkable */ } else { room = parse_dbref(room_name); } /* check that we can link there */ if (!Good_obj(room)) { notify(player, "That's not a valid object."); return NOTHING; } else if (!Linkable(player, room)) { notify(player, "You can't link to that."); return NOTHING; } else { return room; } } /* --------------------------------------------------------------------------- * open_exit, do_open: Open a new exit and optionally link it somewhere. */ static void open_exit (dbref player, dbref loc, char *direction, char *linkto) { dbref exit; if (!Good_obj(loc)) return; if (!direction || !*direction) { notify(player, "Open where?"); return; } else if (!controls(player, loc)) { notify(player, "Permission denied."); return; } exit = create_obj(player, TYPE_EXIT, direction, 0); if (exit == NOTHING) return; /* Initialize everything and link it in. */ s_Exits(exit, loc); s_Next(exit, Exits(loc)); s_Exits(loc, exit); /* and we're done */ notify(player, "Opened."); /* See if we should do a link */ if (!linkto || !*linkto) return; loc = parse_linkable_room(player, linkto); if (loc != NOTHING) { /* Make sure the player passes the link lock */ if (!could_doit(player, loc, A_LLINK)) { notify(player, "You can't link to there."); return; } /* Link it if the player can pay for it */ if (!payfor(player, mudconf.linkcost)) { notify(player, tprintf("You don't have enough %s to link.", mudconf.many_coins)); } else { s_Location(exit, loc); notify(player, "Linked."); } } } void do_open(dbref player, dbref cause, int key, char *direction, char *links[], int nlinks) { dbref loc, destnum; char *dest; /* Create the exit and link to the destination, if there is one */ if (nlinks >= 1) dest = links[0]; else dest = NULL; if (key == OPEN_INVENTORY) loc = player; else loc = Location(player); open_exit(player, loc, direction, dest); /* Open the back link if we can */ if (nlinks >= 2) { destnum = parse_linkable_room(player, dest); if (destnum != NOTHING) { open_exit(player, destnum, links[1], tprintf("%d", loc)); } } } /* --------------------------------------------------------------------------- * link_exit, do_link: Set destination(exits), dropto(rooms) or * home(player,thing) */ static void link_exit (dbref player, dbref exit, dbref dest) { int cost; /* Make sure we can link there */ if ((dest != HOME) && ((!controls(player, dest) && !(Flags(dest) & LINK_OK)) || !could_doit(player, dest, A_LLINK))) { notify(player, "Permission denied."); return; } /* Make sure it's not already linked */ if (Location(exit) != NOTHING) { if (controls(player, exit)) { notify(player, "That exit is already linked."); } else { notify(player, "Permission denied."); } return; } /* handle costs */ cost = mudconf.linkcost; if (Owner(exit) != Owner(player)) cost += mudconf.opencost; if (!payfor(player, cost)) { if (cost == 1) { notify(player, tprintf("It costs a %s to link this exit.", mudconf.one_coin)); } else { notify(player, tprintf("It costs %d %s to link this exit.", cost, mudconf.many_coins)); } return; } /* Pay the owner for his loss */ if (Owner(exit) != Owner(player)) { giveto(Owner(exit), mudconf.opencost); s_Owner(exit, Owner(player)); s_Flags(exit, (Flags(exit) & ~(INHERIT|WIZARD)) | HALT); } /* link has been validated and paid for, do it and tell the player */ s_Location(exit, dest); if (!Quiet(player)) notify(player, "Linked."); } void do_link(dbref player, dbref cause, int key, char *what, char *where) { dbref thing, room; char *buff; init_match(player, what, TYPE_EXIT); match_exit(); match_neighbor(); match_possession(); match_me(); match_here(); match_absolute(); match_player(); thing = noisy_match_result(); if (thing == NOTHING) return; switch (Typeof(thing)) { case TYPE_EXIT: /* Set destination */ room = parse_linkable_room(player, where); if (room != NOTHING) link_exit (player, thing, room); break; case TYPE_PLAYER: case TYPE_THING: /* Set home */ if (!Controls(player, thing)) { notify(player, "Permission denied."); break; } init_match(player, where, NOTYPE); match_exit(); match_neighbor(); match_possession(); match_me(); match_here(); match_absolute(); match_player(); room = noisy_match_result(); if (room == NOTHING) break; if (!can_set_home(player, thing, room) || !could_doit(player, room, A_LLINK)) { notify(player, "Permission denied."); } else if (room == HOME) { notify(player, "Can't set home to home."); } else { s_Home(thing, room); if (!Quiet(player)) notify(player, "Home set."); } break; case TYPE_ROOM: /* Set dropto */ if (!Controls(player, thing)) { notify(player, "Permission denied."); break; } room = parse_linkable_room(player, where); if (room == NOTHING) break; if (Typeof(room) != TYPE_ROOM) { notify(player, "That is not a room!"); } else if ((room != HOME) && ((!controls(player, room) && !(Flags(room) & LINK_OK)) || !could_doit(player, room, A_LLINK))) { notify(player, "Permission denied."); } else { s_Dropto(thing, room); if (!Quiet(player)) notify(player, "Dropto set."); } break; default: STARTLOG(LOG_BUGS,"BUG","OTYPE") buff = alloc_mbuf("do_link.LOG.badtype"); sprintf(buff, "Strange object type: object #%d = %d", thing, Typeof(thing)); log_text(buff); free_mbuf(buff); ENDLOG } } /* --------------------------------------------------------------------------- * do_parent: Set an object's parent field. */ void do_parent (dbref player, dbref cause, int key, char *tname, char *pname) { dbref thing, parent, curr; int lev; /* get victim */ init_match(player, tname, NOTYPE); match_neighbor(); match_possession(); match_me(); match_here(); match_absolute(); match_player(); match_exit(); match_carried_exit(); thing = noisy_match_result(); if (thing == NOTHING) return; /* Make sure we can do it */ if (!Controls(player, thing)) { notify(player, "Permission denied."); return; } /* Find out what the new parent is */ if (*pname) { init_match(player, pname, Typeof(thing)); match_neighbor(); match_possession(); match_me(); match_here(); match_absolute(); match_player(); match_exit(); match_carried_exit(); parent = noisy_match_result(); if (parent == NOTHING) return; /* Make sure we have rights to set parent */ if (!Affects(player, parent)) { notify(player, "Permission denied."); return; } /* Verify no recursive reference */ for (lev=0, curr=parent; (Good_obj(curr) && (lev < mudconf.parent_nest_lim)); curr=Parent(curr), lev++) { if (curr==thing) { notify(player, "You can't have yourself as a parent!"); return; } } } else { parent = NOTHING; } s_Parent(thing, parent); if (!Quiet(thing) && !Quiet(player)) { if (parent == NOTHING) notify(player, "Parent cleared."); else notify(player, "Parent set."); } } /* --------------------------------------------------------------------------- * do_dig: Create a new room. */ void do_dig (dbref player, dbref cause, int key, char *name, char *args[], int nargs) { dbref room; char *buff; /* we don't need to know player's location! hooray! */ if (!name || !*name) { notify(player, "Dig what?"); return; } room = create_obj(player, TYPE_ROOM, name, 0); if (room == NOTHING) return; notify(player, tprintf("%s created with room number %d.", name, room)); buff = alloc_sbuf("do_dig"); if ((nargs >= 1) && args[0] && *args[0]) { sprintf(buff, "%d", room); open_exit(player, Location(player), args[0], buff); } if ((nargs >= 2) && args[1] && *args[1]) { sprintf(buff, "%d", Location(player)); open_exit(player, room, args[1], buff); } free_sbuf(buff); if (key == DIG_TELEPORT) (void)move_via_teleport(player, room, cause, 0); } /* --------------------------------------------------------------------------- * do_create: Make a new object. */ void do_create(dbref player, dbref cause, int key, char *name, char *coststr) { dbref thing; int cost; cost = atol(coststr); if (!name || !*name) { notify(player, "Create what?"); return; } else if (cost < 0) { notify(player, "You can't create an object for less than nothing!"); return; } thing = create_obj(player, TYPE_THING, name, cost); if (thing == NOTHING) return; move_via_generic(thing, player, NOTHING, 0); s_Home(thing, new_home(player)); if (!Quiet(player)) { notify(player, tprintf("%s created as object #%d", Name(thing), thing)); } } /* --------------------------------------------------------------------------- * do_clone: Create a copy of an object. */ void do_clone(dbref player, dbref cause, int key, char *name, char *arg2) { dbref clone, thing, new_owner, loc; FLAG rmv_flags; int cost; if (key & CLONE_INVENTORY) loc = player; else loc = Location(player); if (!Good_obj(loc)) return; init_match(player, name, NOTYPE); match_everything(); thing = noisy_match_result(); if ((thing == NOTHING) || (thing == AMBIGUOUS)) return; /* Let players clone things set VISUAL. It's easier than retyping in * all that data */ if (!Examinable(player, thing)) { notify(player, "Permission denied."); return; } if (Typeof(thing) == TYPE_PLAYER) { notify(player, "You cannot clone players!"); return; } new_owner = (key & CLONE_PRESERVE) ? Owner(thing) : Owner(player); if (key & CLONE_SET_COST) { cost = atoi(arg2); arg2 = NULL; } else { cost = 1; switch (Typeof(thing)) { case TYPE_THING: cost = OBJECT_DEPOSIT((mudconf.clone_copy_cost) ? Pennies(thing) : 1); break; case TYPE_ROOM: cost = mudconf.digcost; break; case TYPE_EXIT: if (!Controls(player, loc)) { notify(player, "Permission denied."); return; } cost = mudconf.digcost; break; } } clone = create_obj(new_owner, Typeof(thing), Name(thing), cost); if (clone == NOTHING) return; /* Wipe out any old attributes and copy in the new data */ al_destroy(clone); if (key & CLONE_PARENT) s_Parent(clone, thing); else atr_cpy(clone, thing); if (arg2 && *arg2) s_Name(clone, arg2); else if (key & CLONE_PARENT) s_Name(clone, Name(thing)); /* Clear out problem flags from the original */ rmv_flags = WIZARD; if (!(key & CLONE_INHERIT) || (!Inherits(player))) rmv_flags |= INHERIT; s_Flags(clone, Flags(thing) & ~rmv_flags); /* Tell creator about it */ if (!Quiet(player)) { if (arg2 && *arg2) notify(player, tprintf("%s cloned as %s, new copy is object #%d.", Name(thing), arg2, clone)); else notify(player, tprintf("%s cloned, new copy is object #%d.", Name(thing), clone)); } /* Put the new thing in its new home. Break any dropto or link, then * try to re-establish it. */ switch (Typeof(thing)) { case TYPE_THING: s_Home(clone, clone_home(player, thing)); move_via_generic(clone, loc, player, 0); break; case TYPE_ROOM: s_Dropto(clone, NOTHING); if (Dropto(thing) != NOTHING) link_exit(player, clone, Dropto(thing)); break; case TYPE_EXIT: s_Exits(loc, insert_first(Exits(loc), clone)); s_Exits(clone, loc); s_Location(clone, NOTHING); if (Location(thing) != NOTHING) link_exit(player, clone, Location(thing)); break; } /* If same owner run ACLONE, else halt it. Also copy parent * if we can */ if (new_owner == Owner(thing)) { if (!(key & CLONE_PARENT)) s_Parent(clone, Parent(thing)); did_it(player, clone, 0, NULL, 0, NULL, A_ACLONE, (char **)NULL, 0); } else { if (!(key & CLONE_PARENT) && Affects(player, thing)) s_Parent(clone, Parent(thing)); s_Flags(clone, Flags(clone) | HALT); } } /* --------------------------------------------------------------------------- * do_pcreate: Create new players and robots. */ void do_pcreate(dbref player, dbref cause, int key, char *name, char *pass) { int isrobot; dbref newplayer; char *buff; isrobot = (key == PCRE_ROBOT) ? 1 : 0; newplayer = create_player(name, pass, player, isrobot); if (newplayer == NOTHING) { buff=alloc_lbuf("do_pcreate.failed"); sprintf(buff, "Failure creating '%s'", name); notify(player, buff); free_lbuf(buff); return; } if (isrobot) { move_object(newplayer, Location(player)); buff=alloc_mbuf("do_pcreate.robot"); sprintf(buff, "New robot '%s' created with password '%s'", name, pass); notify(player, buff); notify(player, "Your robot has arrived."); free_mbuf(buff); STARTLOG(LOG_PCREATES,"CRE","ROBOT") log_name(newplayer); log_text((char *)" created by "); log_name(player); ENDLOG } else { move_object(newplayer, mudconf.start_room); buff=alloc_mbuf("do_pcreate.player"); sprintf(buff, "New player '%s' created with password '%s'", name, pass); notify(player, buff); free_mbuf(buff); STARTLOG(LOG_PCREATES|LOG_WIZARD,"WIZ","PCREA") log_name(newplayer); log_text((char *)" created by "); log_name(player); ENDLOG } } /* --------------------------------------------------------------------------- * destroy_exit, destroy_thing, destroy_player, do_destroy: Destroy things. */ static void destroy_exit (dbref player, dbref exit) { dbref loc; loc = Exits(exit); if ((loc != Location(player)) && !Wizard(player)) { notify(player, "You can not destroy exits in another room."); return; } s_Exits(loc, remove_first(Exits(loc), exit)); destroy_obj(player, exit); } static void destroy_thing (dbref player, dbref thing) { move_via_generic(thing, NOTHING, player, 0); empty_obj(thing); destroy_obj(player, thing); } static void destroy_player (dbref player, dbref victim) { dbref aowner; int count, aflags; char *buf; if (!Wizard(player)) { notify(player, "Sorry, no suicide allowed."); return; } if (Wizard(victim)) { notify(player, "Even you can't do that!"); } /* Bye bye... */ boot_off(victim, (char *)"You have been destroyed!"); halt_que(victim, NOTHING); count = chown_all(victim, player); /* Remove the name from the name hash table */ delete_player_name(victim, Name(victim)); buf = atr_pget(victim, A_ALIAS, &aowner, &aflags); delete_player_name(victim, buf); free_lbuf(buf); move_via_generic(victim, NOTHING, player, 0); destroy_obj(player, victim); notify(player, tprintf("(%d objects @chowned to you)", count)); } void do_destroy (dbref player, dbref cause, int key, char *what) { dbref thing; /* if player owns room check for exit */ if (controls(player, Location(player))) { init_match(player, what, TYPE_EXIT); match_exit(); thing = last_match_result(); } else { thing = NOTHING; } if ((thing != NOTHING) && (Typeof(thing) == TYPE_EXIT) && (!Safe(thing, player) || (key & DEST_OVERRIDE))) { destroy_exit(player, thing); return; } /* check for player inventory with destroy_ok bit set */ init_match(player, what, TYPE_THING); match_possession(); thing = last_match_result(); if (thing != NOTHING) { if (controls(player, thing) || IS(thing, TYPE_THING, THING_DEST_OK)) { if (Safe(thing, player) && !(key & DEST_OVERRIDE)) { notify(player, "Sorry, that object is protected. Use @destroy/override to destroy it."); } else { destroy_thing(player, thing); } } else { notify(player, "Permission denied."); } return; } /* Check for things I control */ thing = match_controlled(player, what); if (thing == NOTHING) return; if (Safe(thing, player) && !(key & DEST_OVERRIDE)) { notify(player, "Sorry, that is protected. Use @destroy/override to destroy it."); return; } switch (Typeof(thing)) { case TYPE_EXIT: destroy_exit(player, thing); break; case TYPE_THING: destroy_thing(player, thing); break; case TYPE_PLAYER: destroy_player(player, thing); break; case TYPE_ROOM: if (Flags(thing) & GOING) { notify(player, "No sense beating a dead room."); } else { notify_all(thing, player, "The room shakes and begins to crumble.", 1); if (!Quiet(thing) && !Quiet(Owner(thing))) notify(Owner(thing), tprintf("You will be rewarded shortly for %s(#%d).", Name(thing), thing)); s_Flags(thing, Flags(thing) | GOING); } } }