/* 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);
}
}
}