/* Do not remove the headers from this file! see /USAGE for more info. */

/*
** smartmove.c
**
** A smarter movement system for some objects.  It handles movement from
** room to room.
*/

#include <move.h>
#include <playerflags.h>
#include <hooks.h>
#include <size.h>
#include <classes.h>

inherit CLASS_MOVE;

varargs mixed call_hooks(string, mixed, mixed);
varargs mixed move(mixed dest, string where);
string query_msg(string which);
int test_flag(int which);
void simple_action(string s,array obs... );
varargs string *action(object *who, mixed msg, array obs...);
varargs string compose_message(object forwhom, string msg, object *who, 
  array obs...);
object query_target();

private nomask int move_me_there(class move_data data)
{
    object last_loc = environment();
    object env;
    object d;
    mixed  r;
    mixed txt;
    string m;

    if ( (r = move(data->destination,data->relation)) != MOVE_OK) {
	if(!stringp(r)) {
	    if(r == MOVE_NO_ERROR) 
		return 1;
	    write("You remain where you are.\n");
	    return 0;
	}

	switch(r) {
	case MOVE_NO_DEST:
	    write("Construction blocks your path.\n");
	    return 0;
	case MOVE_NO_ROOM:
	    d = load_object(data->destination);
	    if(d->query_max_capacity()-d->query_capacity()-VERY_LARGE < 0) {
		if(sizeof(filter(all_inventory(d),(:$1->is_living():)))) {
		    write("You might be able to fit if there weren't "
		      "something moving around there already.\n");
		} 
		else {
		    write("You're unable to fit.\n");
		}
	    }
	    else {
		write("You aren't able to fit with the load you're "
		  "carrying.\n");
	    }
	    return 0;
	default:
	    write("You remain where you are.\n");
	    return 0;
	}
    }
    /* Make sure that there is some type of direction for the exit */
    if ( !data->exit_dir ) {
	data->exit_dir= "somewhere";
    }
    /* Also ensure that there is a valid object being moved */
    if ( !data->who ) {
	data->who = this_body();
    }

    env = environment();

    /* Exit Messages */
    txt = data->exit_messages;

    /* If there is no exit message for the exit, use the default for that body.
     * The default message is not one that should be processed any further.*/
    if ( !txt )
	txt = query_msg("leave");

    /* Display the message */
    if(data->source)
	tell_from_inside(last_loc,action(({data->who}),txt,data->source)[1]);
    else
	tell_from_inside(last_loc,action(({data->who}),txt,data->exit_dir)[1]);

    /* Entrance messages */
    txt = data->enter_messages;

    /* If there is no enter message for the exit, use the default for that body.
     * The default message is not one that should be processed any further.*/
    if ( !txt )
	txt = query_msg("enter");

    /* Display the message */
    if(data->through)
	simple_action(txt,data->through);
    else if(data->source)
	simple_action(txt,data->source);
    else
	simple_action(txt);

    return r == MOVE_OK;
}

//:FUNCTION notify_move
//Basically do a this_body()->force_look().
//Seperated out so vehicles could change this
//without having to override the move_to() function.

void notify_move()
{
    this_object()->force_look(0);
}


//:FUNCTION move_to
//Move the object to a new location.  Returns 1 if the move was successful,
//0 otherwise.  The first arg is a filename, the second is the direction
//that caused the movement to that destination.

//:HOOK person_left
//Called when a person successfully leaves a room in a certain direction
//(called by the room).  The return value is ignored.  The person moving
//is given by this_body().  The direction is passed as an argument.

//:HOOK person_arrived
//Called when a person successfully enters a room from a direction.
//The return value is ignored. The person moving is given by this_body(). 
//The direction is passed as an argument.
//varargs int move_to(string dest, mixed dir, mixed exit, mixed enter)
varargs int move_to(class move_data data)
{
  object where = environment();
  if (move_me_there(data))
  {
    where->call_hooks("person_left", HOOK_IGNORE, 0, data->exit_dir);
    environment()->call_hooks("person_arrived", HOOK_IGNORE, 0, data->exit_dir);
    call_hooks("interrupt", HOOK_IGNORE);
  }

  if ( where != environment() )
  {
    this_object()->notify_move();
    return 1;
  }
  return 0;
}
