/* move.c */
#include "os.h"
#include "copyright.h"
#include "config.h"
#include "db.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#include "globals.h"
void enter_room ();
void moveto (dbref what, dbref where)
{
enter_room (what, where);
}
void moveit (dbref what, dbref where)
{
dbref loc, old;
/* remove what from old loc */
if ((loc = old = db[what].location) != NOTHING) {
db[loc].contents = remove_first (db[loc].contents, what);
}
/* test for special cases */
switch (where) {
case NOTHING:
db[what].location = NOTHING;
return; /* NOTHING doesn't have contents */
case HOME:
where = db[what].exits; /* home */
safe_tel (what, where);
return;
/*NOTREACHED*/ break;
}
/* now put what in where */
PUSH (what, db[where].contents);
db[what].location = where;
if (Hearer (what) && (where != NOTHING) && !Dark (where) && (old != where)) {
did_it (what, old, "LEAVE", NULL, "OLEAVE", "has left.", "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", "has arrived.", "AENTER",
where);
did_it (what, what, "MOVE", NULL, "OMOVE", NULL, "AMOVE", where);
}
}
#define Dropper(thing) (Hearer(thing) && \
(db[db[thing].owner].flags & PLAYER_CONNECT))
static void send_contents (dbref loc, dbref dest)
{
dbref first;
dbref rest;
first = db[loc].contents;
db[loc].contents = NOTHING;
/* blast locations of everything in list */
DOLIST (rest, first) {
db[rest].location = NOTHING;
}
while (first != NOTHING) {
rest = db[first].next;
if (Dropper (first)) {
db[first].location = loc;
PUSH (first, db[loc].contents);
} else
enter_room (first, (db[first].flags & STICKY) ? HOME : dest);
first = rest;
}
db[loc].contents = reverse (db[loc].contents);
}
static void maybe_dropto (dbref loc, dbref dropto)
{
dbref thing;
if (loc == dropto)
return; /* bizarre special case */
if (Typeof (loc) != TYPE_ROOM)
return;
/* check for players */
DOLIST (thing, db[loc].contents) {
if (Dropper (thing))
return;
}
/* no players, send everything to the dropto */
send_contents (loc, dropto);
}
void enter_room (dbref player, dbref loc)
{
dbref old;
dbref dropto;
static int deep = 0;
if (deep++ > 15) {
deep--;
return;
}
if (player < 0 || player >= db_top) {
deep--;
return;
}
#ifdef notdef
if (loc == NOTHING) { /* death to -1 */
free_object (player);
deep--;
return;
}
#endif
/* check for room == HOME */
if (loc == HOME)
loc = db[player].exits; /* home */
if ((Typeof (player) != TYPE_PLAYER) && (Typeof (player) != TYPE_THING)) {
fprintf (stderr, "ERROR: Non object moved!! %d\n", player);
fflush (stderr);
deep--;
return;
}
if (Typeof (loc) == TYPE_EXIT) {
fprintf (stderr, "ERROR: Attempt to move %d to exit %d\n", player, loc);
deep--;
return;
}
/* get old location */
old = db[player].location;
/* go there */
moveit (player, loc);
/* if old location has STICKY dropto, send stuff through it */
if ((loc != old) && Dropper (player) &&
(old != NOTHING) && (Typeof (old) == TYPE_ROOM) &&
((dropto = db[old].location) != NOTHING) && (db[old].flags & STICKY))
maybe_dropto (old, dropto);
/* autolook */
look_room (player, loc, 0);
deep--;
}
/* teleports player to location while removing items they shouldnt take */
void safe_tel (dbref player, dbref dest)
{
dbref first;
dbref rest;
if (dest == HOME)
dest = db[player].exits;
if (db[db[player].location].owner == db[dest].owner) {
enter_room (player, dest);
return;
}
first = db[player].contents;
db[player].contents = NOTHING;
/* blast locations of everything in list */
DOLIST (rest, first) {
db[rest].location = NOTHING;
}
while (first != NOTHING) {
rest = db[first].next;
/* if thing is ok to take then move to player else send home */
/* thing is not okay to move if it's KEY, or it's STICKY and its */
/* home is not the player */
if (controls (player, first) ||
((Typeof (first) == TYPE_THING && !(db[first].flags & THING_KEY)) &&
(!(db[first].flags & STICKY) || (db[first].exits == player)))) {
PUSH (first, db[player].contents);
db[first].location = player;
} else
enter_room (first, HOME);
first = rest;
}
db[player].contents = reverse (db[player].contents);
enter_room (player, dest);
}
int can_move (dbref player, const char *direction)
{
if (!string_compare (direction, "home"))
return 1;
/* otherwise match on exits */
init_match (player, direction, TYPE_EXIT);
match_exit ();
return (last_match_result () != NOTHING);
}
void do_move (dbref player, const char *direction, int type /* type 0 is normal, type 1 is global */
)
{
dbref exit;
dbref loc;
if (!string_compare (direction, "home")) {
/* send him home */
/* but steal all his possessions */
if ((loc = db[player].location) != NOTHING && !Dark (player) &&
!Dark (loc)) {
/* tell everybody else */
notify_except (db[loc].contents, player,
tprintf ("%s goes home.", db[player].name));
}
/* give the player the messages */
notify (player, "There's no place like home...");
notify (player, "There's no place like home...");
notify (player, "There's no place like home...");
safe_tel (player, HOME);
} else {
/* find the exit */
#ifdef DO_GLOBALS
if (type == 1)
init_match_global_check_keys (player, direction, TYPE_EXIT);
else
#endif
init_match_check_keys (player, direction, TYPE_EXIT);
match_exit ();
switch (exit = match_result ()) {
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:
/* we got one */
/* check to see if we got through */
if (could_doit (player, exit)) {
did_it (player, exit, "SUCCESS", NULL, "OSUCCESS", NULL, "ASUCCESS",
NOTHING);
did_it (player, exit, "DROP", NULL, "ODROP", NULL, "ADROP",
db[exit].location);
switch (Typeof (db[exit].location)) {
case TYPE_ROOM:
enter_room (player, db[exit].location);
break;
case TYPE_PLAYER:
case TYPE_THING:
{
if (db[db[exit].location].flags & GOING) {
notify (player, "You can't go that way.");
return;
}
if (db[db[exit].location].location == NOTHING)
return;
safe_tel (player, db[exit].location);
}
break;
case TYPE_EXIT:
notify (player, "This feature coming soon.");
break;
}
} else
did_it (player, exit, "FAILURE", "You can't go that way.", "OFAILURE",
NULL, "AFAILURE", NOTHING);
break;
}
}
}
void do_get (dbref player, const char *what)
{
dbref loc = db[player].location;
dbref thing;
if ((Typeof (loc) != TYPE_ROOM) && !(db[loc].flags & ENTER_OK) &&
!controls (player, loc)) {
notify (player, "Permission denied.");
return;
}
if (((thing = is_possess (player, (char*)what)) != NOTHING) &&
(thing != AMBIGUOUS)) {
if (could_doit (player, thing) &&
(db[db[thing].location].flags & ENTER_OK)) {
notify (db[thing].location, tprintf ("%s was taken from you.",
db[thing].name));
moveto (thing, player);
notify (thing, "Taken.");
did_it (player, thing, "SUCCESS", "Taken.", "OSUCCESS", NULL,
"ASUCCESS", NOTHING);
} else
did_it (player, thing, "FAILURE", "You can't take that from there.",
"OFAILURE", NULL, "AFAILURE", NOTHING);
} else {
init_match_check_keys (player, what, TYPE_THING);
match_neighbor ();
match_exit ();
if (Wizard (player))
match_absolute (); /* the wizard has long fingers */
if ((thing = noisy_match_result ()) != NOTHING) {
if (db[thing].location == player) {
notify (player, "You already have that!");
return;
}
switch (Typeof (thing)) {
case TYPE_PLAYER:
case TYPE_THING:
if (thing == player) {
notify (player, "You cannot get yourself!");
return;
}
if (could_doit (player, thing)) {
moveto (thing, player);
notify (thing, "Taken.");
did_it (player, thing, "SUCCESS", "Taken.", "OSUCCESS", NULL,
"ASUCCESS", NOTHING);
} else
did_it (player, thing, "FAILURE", "You can't pick that up.",
"OFAILURE", NULL, "AFAILURE", NOTHING);
break;
case TYPE_EXIT:
notify (player, "You can't pick up exits.");
return;
default:
notify (player, "You can't take that!");
break;
}
}
}
}
void do_drop (dbref player, const char *name)
{
dbref loc;
dbref thing;
int reward;
char tbuf1[BUFFER_LEN];
if ((loc = getloc (player)) == NOTHING)
return;
init_match (player, name, TYPE_THING);
match_possession ();
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;
default:
if (db[thing].location != player) {
/* Shouldn't ever happen. */
notify (player, "You can't drop that.");
} else if (Typeof (thing) == TYPE_EXIT) {
notify (player, "Sorry you can't drop exits.");
return;
} else if (db[loc].flags & ROOM_TEMPLE) {
/* sacrifice time */
if (Typeof (thing) == TYPE_PLAYER) {
notify (player, "Hey! No blood sacrifices please!.");
return;
}
if (db[thing].flags & THING_SAFE) {
notify (player,
"That object is marked SAFE and cannot be sacrificed.");
return;
}
notify (thing, "You have been sacrificed.");
moveto (thing, NOTHING);
/* Patched to destroy sacrificed objects */
notify (player, tprintf ("%s is consumed in a burst of flame!",
db[thing].name));
#ifdef FULL_INVIS
if (!Dark (player)) {
notify_except (db[loc].contents, player,
tprintf ("%s sacrifices %s.", db[player].name, db[thing].name));
} else {
notify_except (db[loc].contents, player,
tprintf ("Someone sacrifices %s.", db[thing].name));
}
#else
notify_except (db[loc].contents, player,
tprintf ("%s sacrifices %s.", db[player].name, db[thing].name));
#endif
/* check for reward */
if (!controls (player, thing) || (Typeof (player) != TYPE_PLAYER)) {
reward = Pennies (thing);
if (reward < 1 || (Pennies (db[player].owner) > MAX_PENNIES)) {
reward = 1;
} else if (reward > MAX_OBJECT_ENDOWMENT) {
reward = MAX_OBJECT_ENDOWMENT;
}
giveto (db[player].owner, reward);
notify (player,
tprintf ("You have received %d %s for your sacrifice.", reward,
reward == 1 ? MONEY : MONIES));
db[thing].flags |= THING_DEST_OK;
do_destroy (player, tprintf ("#%d", thing), 1);
}
} else if (db[thing].flags & STICKY) {
notify (thing, "Dropped.");
safe_tel (thing, HOME);
} else if (db[loc].location != NOTHING &&
(Typeof (loc) == TYPE_ROOM) && !(db[loc].flags & STICKY)) {
/* location has immediate dropto */
notify (thing, "Dropped.");
moveto (thing, db[loc].location);
} else {
notify (thing, "Dropped.");
moveto (thing, loc);
}
break;
}
sprintf (tbuf1, "dropped %s.", db[thing].name);
did_it (player, thing, "DROP", "Dropped.", "ODROP", tbuf1, "ADROP",
NOTHING);
}
void do_enter (dbref player, const char *what)
{
dbref thing;
init_match_check_keys (player, what, TYPE_THING);
match_neighbor ();
match_exit ();
match_absolute (); /* necessary for enter aliases to work */
if ((thing = noisy_match_result ()) == NOTHING) {
/* notify(player,"I don't see that here."); */
return;
}
switch (Typeof (thing)) {
case TYPE_ROOM:
case TYPE_EXIT:
notify (player, "Permission denied.");
break;
default:
/* the object must pass the lock. Also, the thing being entered */
/* has to be controlled, or must be enter_ok */
if (!(((db[thing].flags & ENTER_OK) || controls (player, thing)) &&
(eval_boolexp (player, db[thing].enterkey, thing, 0, ENTERLOCK)))) {
did_it (player, thing, "EFAIL", "Permission denied.", "OEFAIL",
NULL, "AEFAIL", NOTHING);
return;
}
if (thing == player) {
notify (player, "Sorry, you must remain beside yourself!");
return;
}
safe_tel (player, thing);
break;
}
}
void do_leave (dbref player)
{
if (Typeof (db[player].location) == TYPE_ROOM) {
notify (player, "You can't leave");
return;
}
enter_room (player, db[db[player].location].location);
}
#ifdef DO_GLOBALS
int global_exit (dbref player, const char *direction)
{
init_match_global (player, direction, TYPE_EXIT);
match_exit ();
return (last_match_result () != NOTHING);
}
#endif