/* move.c */
#include "copyright.h"
#include <ctype.h>
#include "config.h"
#include "db.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#include "globals.h"
void enter_room();
void moveto(what, where)
dbref what;
dbref where;
{
enter_room(what, where);
}
void moveit(what, where)
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))
void send_contents(loc, dest)
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);
}
void maybe_dropto(loc, 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(player, loc)
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(player, dest)
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(player, direction)
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(player, direction, type)
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(player, what)
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, 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(player, name)
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(player, what)
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(player)
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 (player, direction)
dbref player;
const char *direction;
{
init_match_global(player, direction, TYPE_EXIT);
match_exit();
return (last_match_result() != NOTHING);
}
#endif