skylib_fluffos_v3/
skylib_fluffos_v3/bin/
skylib_fluffos_v3/bin/db/
skylib_fluffos_v3/fluffos-2.9-ds2.04/
skylib_fluffos_v3/fluffos-2.9-ds2.04/ChangeLog.old/
skylib_fluffos_v3/fluffos-2.9-ds2.04/Win32/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/simuls/
skylib_fluffos_v3/fluffos-2.9-ds2.04/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/clone/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/command/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/data/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/etc/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/master/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/log/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/compiler/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/efuns/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/operators/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/u/
skylib_fluffos_v3/fluffos-2.9-ds2.04/tmp/
skylib_fluffos_v3/fluffos-2.9-ds2.04/windows/
skylib_fluffos_v3/mudlib/
skylib_fluffos_v3/mudlib/cmds/
skylib_fluffos_v3/mudlib/cmds/admin/
skylib_fluffos_v3/mudlib/cmds/guild-race/
skylib_fluffos_v3/mudlib/cmds/living/broken/
skylib_fluffos_v3/mudlib/cmds/player/group_cmds/
skylib_fluffos_v3/mudlib/cmds/playtester/
skylib_fluffos_v3/mudlib/d/admin/
skylib_fluffos_v3/mudlib/d/admin/room/
skylib_fluffos_v3/mudlib/d/admin/room/we_care/
skylib_fluffos_v3/mudlib/d/admin/save/
skylib_fluffos_v3/mudlib/d/admin/text/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/buildings/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/map/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/roads/
skylib_fluffos_v3/mudlib/d/learning/chars/
skylib_fluffos_v3/mudlib/d/learning/functions/
skylib_fluffos_v3/mudlib/d/learning/handlers/
skylib_fluffos_v3/mudlib/d/learning/help_topics/
skylib_fluffos_v3/mudlib/d/learning/help_topics/npcs/
skylib_fluffos_v3/mudlib/d/learning/help_topics/objects/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/crowd/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/situations/
skylib_fluffos_v3/mudlib/d/learning/save/
skylib_fluffos_v3/mudlib/d/learning/school/
skylib_fluffos_v3/mudlib/d/learning/school/add_sc/
skylib_fluffos_v3/mudlib/d/learning/school/characters/
skylib_fluffos_v3/mudlib/d/learning/school/general/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/basic_commands/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/edtutor/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_fluffos_v3/mudlib/d/learning/school/items/
skylib_fluffos_v3/mudlib/d/learning/school/npc_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/room_basic/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/situations/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_fluffos_v3/mudlib/d/learning/text/
skylib_fluffos_v3/mudlib/d/liaison/
skylib_fluffos_v3/mudlib/d/mudlib/
skylib_fluffos_v3/mudlib/d/mudlib/changes/
skylib_fluffos_v3/mudlib/d/playtesters/
skylib_fluffos_v3/mudlib/d/playtesters/effects/
skylib_fluffos_v3/mudlib/d/playtesters/handlers/
skylib_fluffos_v3/mudlib/d/playtesters/items/
skylib_fluffos_v3/mudlib/d/sage/
skylib_fluffos_v3/mudlib/doc/
skylib_fluffos_v3/mudlib/doc/creator/
skylib_fluffos_v3/mudlib/doc/driver/
skylib_fluffos_v3/mudlib/doc/driver/efuns/arrays/
skylib_fluffos_v3/mudlib/doc/driver/efuns/buffers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/calls/
skylib_fluffos_v3/mudlib/doc/driver/efuns/compile/
skylib_fluffos_v3/mudlib/doc/driver/efuns/filesystem/
skylib_fluffos_v3/mudlib/doc/driver/efuns/floats/
skylib_fluffos_v3/mudlib/doc/driver/efuns/functions/
skylib_fluffos_v3/mudlib/doc/driver/efuns/general/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mappings/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mixed/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mudlib/
skylib_fluffos_v3/mudlib/doc/driver/efuns/numbers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/parsing/
skylib_fluffos_v3/mudlib/doc/login/
skylib_fluffos_v3/mudlib/doc/lpc/basic_manual/
skylib_fluffos_v3/mudlib/doc/lpc/intermediate/
skylib_fluffos_v3/mudlib/doc/new/add_command/
skylib_fluffos_v3/mudlib/doc/new/events/
skylib_fluffos_v3/mudlib/doc/new/handlers/
skylib_fluffos_v3/mudlib/doc/new/living/race/
skylib_fluffos_v3/mudlib/doc/new/living/spells/
skylib_fluffos_v3/mudlib/doc/new/object/
skylib_fluffos_v3/mudlib/doc/new/player/
skylib_fluffos_v3/mudlib/doc/new/room/guild/
skylib_fluffos_v3/mudlib/doc/new/room/outside/
skylib_fluffos_v3/mudlib/doc/new/room/storeroom/
skylib_fluffos_v3/mudlib/doc/object/
skylib_fluffos_v3/mudlib/doc/playtesters/
skylib_fluffos_v3/mudlib/doc/policy/
skylib_fluffos_v3/mudlib/doc/weapons/
skylib_fluffos_v3/mudlib/global/
skylib_fluffos_v3/mudlib/global/creator/
skylib_fluffos_v3/mudlib/handlers/
skylib_fluffos_v3/mudlib/include/casino/
skylib_fluffos_v3/mudlib/include/cmds/
skylib_fluffos_v3/mudlib/include/effects/
skylib_fluffos_v3/mudlib/include/npc/
skylib_fluffos_v3/mudlib/include/room/
skylib_fluffos_v3/mudlib/include/shops/
skylib_fluffos_v3/mudlib/net/daemon/
skylib_fluffos_v3/mudlib/net/daemon/chars/
skylib_fluffos_v3/mudlib/net/inherit/
skylib_fluffos_v3/mudlib/net/obj/
skylib_fluffos_v3/mudlib/net/obj/BACKUPS/
skylib_fluffos_v3/mudlib/obj/amulets/
skylib_fluffos_v3/mudlib/obj/armours/plate/
skylib_fluffos_v3/mudlib/obj/b_day/
skylib_fluffos_v3/mudlib/obj/clothes/transport/horse/
skylib_fluffos_v3/mudlib/obj/faith/symbols/
skylib_fluffos_v3/mudlib/obj/fungi/
skylib_fluffos_v3/mudlib/obj/gatherables/
skylib_fluffos_v3/mudlib/obj/instruments/
skylib_fluffos_v3/mudlib/obj/media/
skylib_fluffos_v3/mudlib/obj/misc/player_shop/
skylib_fluffos_v3/mudlib/obj/monster/godmother/
skylib_fluffos_v3/mudlib/obj/monster/transport/
skylib_fluffos_v3/mudlib/obj/rings/
skylib_fluffos_v3/mudlib/obj/scabbards/
skylib_fluffos_v3/mudlib/obj/spells/
skylib_fluffos_v3/mudlib/obj/stationery/
skylib_fluffos_v3/mudlib/obj/stationery/envelopes/
skylib_fluffos_v3/mudlib/obj/toys/
skylib_fluffos_v3/mudlib/obj/vessels/
skylib_fluffos_v3/mudlib/obj/weapons/axes/
skylib_fluffos_v3/mudlib/obj/weapons/chains/
skylib_fluffos_v3/mudlib/obj/weapons/maces/BACKUPS/
skylib_fluffos_v3/mudlib/save/autodoc/
skylib_fluffos_v3/mudlib/save/book_handler/
skylib_fluffos_v3/mudlib/save/books/history/calarien/
skylib_fluffos_v3/mudlib/save/mail/
skylib_fluffos_v3/mudlib/save/new_soul/data/
skylib_fluffos_v3/mudlib/save/parcels/
skylib_fluffos_v3/mudlib/save/playerinfo/
skylib_fluffos_v3/mudlib/save/players/d/
skylib_fluffos_v3/mudlib/save/players/s/
skylib_fluffos_v3/mudlib/save/random_names/
skylib_fluffos_v3/mudlib/save/random_names/data/
skylib_fluffos_v3/mudlib/save/terrains/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_desert/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_grassy_field/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_mountain/
skylib_fluffos_v3/mudlib/save/todo_lists/
skylib_fluffos_v3/mudlib/secure/
skylib_fluffos_v3/mudlib/secure/cmds/admin/
skylib_fluffos_v3/mudlib/secure/cmds/lord/
skylib_fluffos_v3/mudlib/secure/config/
skylib_fluffos_v3/mudlib/secure/handlers/autodoc/
skylib_fluffos_v3/mudlib/secure/handlers/intermud/
skylib_fluffos_v3/mudlib/secure/include/global/
skylib_fluffos_v3/mudlib/secure/save/
skylib_fluffos_v3/mudlib/secure/save/handlers/
skylib_fluffos_v3/mudlib/secure/std/
skylib_fluffos_v3/mudlib/secure/std/classes/
skylib_fluffos_v3/mudlib/secure/std/modules/
skylib_fluffos_v3/mudlib/std/creator/
skylib_fluffos_v3/mudlib/std/dom/
skylib_fluffos_v3/mudlib/std/effects/
skylib_fluffos_v3/mudlib/std/effects/external/
skylib_fluffos_v3/mudlib/std/effects/fighting/
skylib_fluffos_v3/mudlib/std/effects/magic/
skylib_fluffos_v3/mudlib/std/effects/magic/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/other/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/priest/
skylib_fluffos_v3/mudlib/std/effects/room/
skylib_fluffos_v3/mudlib/std/environ/
skylib_fluffos_v3/mudlib/std/guilds/
skylib_fluffos_v3/mudlib/std/guilds/old/
skylib_fluffos_v3/mudlib/std/languages/
skylib_fluffos_v3/mudlib/std/liquids/
skylib_fluffos_v3/mudlib/std/npc/
skylib_fluffos_v3/mudlib/std/npc/goals/
skylib_fluffos_v3/mudlib/std/npc/goals/basic/
skylib_fluffos_v3/mudlib/std/npc/goals/misc/
skylib_fluffos_v3/mudlib/std/npc/plans/
skylib_fluffos_v3/mudlib/std/npc/plans/basic/
skylib_fluffos_v3/mudlib/std/npc/types/
skylib_fluffos_v3/mudlib/std/npc/types/helper/
skylib_fluffos_v3/mudlib/std/npcs/
skylib_fluffos_v3/mudlib/std/outsides/
skylib_fluffos_v3/mudlib/std/races/shadows/
skylib_fluffos_v3/mudlib/std/room/basic/BACKUPS/
skylib_fluffos_v3/mudlib/std/room/basic/topography/
skylib_fluffos_v3/mudlib/std/room/controller/
skylib_fluffos_v3/mudlib/std/room/inherit/topography/
skylib_fluffos_v3/mudlib/std/room/topography/area/
skylib_fluffos_v3/mudlib/std/room/topography/iroom/
skylib_fluffos_v3/mudlib/std/room/topography/milestone/
skylib_fluffos_v3/mudlib/std/shadows/curses/
skylib_fluffos_v3/mudlib/std/shadows/disease/
skylib_fluffos_v3/mudlib/std/shadows/fighting/
skylib_fluffos_v3/mudlib/std/shadows/healing/
skylib_fluffos_v3/mudlib/std/shadows/magic/
skylib_fluffos_v3/mudlib/std/shadows/poison/
skylib_fluffos_v3/mudlib/std/shadows/room/
skylib_fluffos_v3/mudlib/std/shops/controllers/
skylib_fluffos_v3/mudlib/std/shops/objs/
skylib_fluffos_v3/mudlib/std/shops/player_shop/
skylib_fluffos_v3/mudlib/std/socket/
skylib_fluffos_v3/mudlib/std/soul/d/
skylib_fluffos_v3/mudlib/std/soul/e/
skylib_fluffos_v3/mudlib/std/soul/i/
skylib_fluffos_v3/mudlib/std/soul/j/
skylib_fluffos_v3/mudlib/std/soul/k/
skylib_fluffos_v3/mudlib/std/soul/l/
skylib_fluffos_v3/mudlib/std/soul/n/
skylib_fluffos_v3/mudlib/std/soul/o/
skylib_fluffos_v3/mudlib/std/soul/q/
skylib_fluffos_v3/mudlib/std/soul/r/
skylib_fluffos_v3/mudlib/std/soul/u/
skylib_fluffos_v3/mudlib/std/soul/v/
skylib_fluffos_v3/mudlib/std/soul/y/
skylib_fluffos_v3/mudlib/std/soul/z/
skylib_fluffos_v3/mudlib/std/stationery/
skylib_fluffos_v3/mudlib/w/
skylib_fluffos_v3/mudlib/w/default/
skylib_fluffos_v3/mudlib/w/default/armour/
skylib_fluffos_v3/mudlib/w/default/clothes/
skylib_fluffos_v3/mudlib/w/default/item/
skylib_fluffos_v3/mudlib/w/default/npc/
skylib_fluffos_v3/mudlib/w/default/room/
skylib_fluffos_v3/mudlib/w/default/weapon/
skylib_fluffos_v3/mudlib/www/
skylib_fluffos_v3/mudlib/www/java/
skylib_fluffos_v3/mudlib/www/secure/
skylib_fluffos_v3/mudlib/www/secure/lpc/advanced/
skylib_fluffos_v3/mudlib/www/secure/lpc/intermediate/
skylib_fluffos_v3/win32/
/**
 * A transport NPC, this will be a horse or a camel or whatever.
 * @author Pinkfish
 * @started Tue Sep 21 18:21:13 PDT 1999
 * @changed Fixed up a bunch of things and changed a fair bit
 * - Sandoz, Feb. 2002.
 */

inherit NPC_OBJ;

#include <move_failures.h>
#include <npc/transport.h>
#include <dirs.h>
#include <room.h>
#include <tasks.h>

/** @ignore yes */
#define DO_RUSTLE

/** @ignore yes */
#define WEAR_CMD "/cmds/living/wea_r"
/** @ignore yes */
#define GLANCE_CMD "/cmds/living/glance"

#define ADD_RIDE_COMMAND(xxx,yyy) { \
    TP->add_command( xxx, TO, "["+query_transport_type()+"] <string'direction'>", \
        (: do_ride( $4[0], yyy, "once") :) ); \
    TP->add_command( xxx, TO, "["+query_transport_type()+"] <string'direction'> "\
        "{once|forever|route|roughly|intersection|roughly-intersection}", \
        (: do_ride( $4[0], yyy, $4[1] ) :) ); \
    }

/** @ignore yes */
#define IS_ALLOWED(xxx) \
    if( !is_allowed_to_use( TP->query_name() ) ) { \
        TP->add_failed_mess( TO, xxx ); \
        return 0; \
    }

/**
 * This is the skill base for all the riding skills.
 */
#define TRANSPORT_SKILL_BASE "general.riding."

/**
 * This is the multiplier for the panicing in battle.
 */
#define TRANSPORT_PANIC_IN_BATTLE_MULTIPLIER 4

/**
 * This is the panicing for when the transport sees a battle
 * multiplier.
 */
#define TRANSPORT_PANIC_NORMAL_MULTIPLIER    1

/**
 * This is the panicing divisor for if the horse is riding past.  The
 * faster the horse rides the less the chance.  So we add the speed onto
 * this.
 */
#define TRANSPORT_PANIC_RIDING_DIVISOR       1

/**
 * This is the maximum length of the name the creature can be given.
 */
#define MAX_NAME_LEN                         16

/**
 * @ignore yes
 * These are the move flags for riding the transport.
 */
#define PATH_FOLLOW                          1
#define STOP_AT_INTERSECTION                 2
#define STOP_AFTER_MOVING_ONCE               4

void set_teathered_to( object ob );
object query_teathered_to();
int do_ride( string direction, int speed, string type );
void setup_movement();
int do_allow( string str );
int do_disallow( string str );
int do_list();
int do_name( string name );
int do_offer( object *food );
int do_dress( object *dress );
int do_teather( object *poles );
object* query_riders();
string query_transport_type();
int query_default_direction_difficulty();
int query_default_mount_difficulty();
int query_default_fight_difficulty();
void panic_horse( int multiplier );
void tell_riders( string str );
void set_transport_name( string name );

private int _cur_speed;
private int _cur_exhaustion;
private int _riding_flags;
private int _transport_id;
private string _owner;
private string _last_location;
private string _transport_name;
private string *_allowed;
private string *_route;
private string _cur_direction;
private string _teathered_to_short;
private nosave object _teathered_to;
private nosave object _in_long;
private nosave object _env_repeater;
private nosave object _me_repeater;
private nosave object *_riding;
private nosave int _transport_speed;
private nosave int _max_speed;
private nosave int _max_exhaustion;
private nosave int _move_id;
private nosave int _default_mount_difficulty;
private nosave int _default_direction_difficulty;
private nosave int _default_fight_difficulty;
private nosave int _panic;
private nosave int _last_move;
private nosave int _last_panic;
private nosave string _transport_type;
private nosave string _inside_long;

void create() {
    _max_speed = RIDE_WALK;
    _cur_speed = RIDE_NOT_MOVING;

    _transport_speed = 4;

    _max_exhaustion = 100;
    _cur_exhaustion = 100;

    _riding = ({ });

    _default_direction_difficulty = 500;
    _default_mount_difficulty = 300;
    _default_fight_difficulty = 50;

    add_property("unique", 1 );
    add_property("no_teleport", 1 );

    ::create();

    add_extra_look(TO);

} /* create() */

/** @ignore yes */
string *query_help_files() {
    string *ret;

    if( pointerp( ret = ::query_help_files() ) )
        return ret + ({"mount"});

    return ({"mount"});

} /* query_help_files() */

/** @ignore yes */
int test_add( object ob, int flag ) { return 1; }

/** @ignore yes */
int test_remove( object ob, int flag, mixed dest ) { return 1; }

/** @ignore yes */
void init() {
    string str;

    ::init();

    str = query_name();

    TP->add_command("name", TO, "<direct:living'"+str+"'> as <string'name'>",
        (: do_name($4[1]) :) );

    TP->add_command("mount", TO, "<direct:living>'"+str+"'");
    TP->add_command("dismount", TO, "["+query_transport_type()+"]");

    TP->add_command("allow", TO,
        "<word'player'> to use <direct:living'"+str+"'>",
        (: do_allow($4[0]) :) );
    TP->add_command("allow", TO, "list <direct:living'"+str+"'>",
        (: do_list() :) );
    TP->add_command("disallow", TO,
        "<word'player'> from using <direct:living'"+str+"'>",
        (: do_disallow($4[0]) :) );

    ADD_RIDE_COMMAND("walk", RIDE_WALK );

    if( _max_speed >= RIDE_TROT )
        ADD_RIDE_COMMAND("trot", RIDE_TROT );

    if( _max_speed >= RIDE_CANTER )
        ADD_RIDE_COMMAND("canter", RIDE_CANTER );

    if( _max_speed >= RIDE_GALLOP )
        ADD_RIDE_COMMAND("gallop", RIDE_GALLOP );

    TP->add_command("stop", TO, str);
    TP->add_command("lead", TO, "<direct:living'"+str+"'>");

    TP->add_command("teather", TO,
        "<direct:living'"+str+"'> to <indirect:object>",
        (: do_teather($1) :) );
    TP->add_command("unteather", TO, "<direct:living'"+str+"'>");
    TP->add_command("untie", TO, "<direct:living'"+str+"'>");

    TP->add_command("dress", TO,
        "<direct:living'"+str+"'> {with|in} <indirect:object'garment'>",
        (: do_dress($1) :) );

    TP->add_command("offer", TO,
        "<indirect:object:me'food'> to <direct:living'"+str+"'>",
        (: do_offer($1) :) );

#ifdef DO_RUSTLE
    if( _owner )
        TP->add_command("rustle", TO, "<direct:living'"+str+"'>");
#endif

} /* init() */

/** @ignore yes */
varargs mixed query_contents( string start, object *things, int ignore_liv ) {
    if( !arrayp( things ) ) {
        things = TO->find_inv_match("", TP ) - ({ TP });
        things = filter_array( things, (: ENV($1) == TO :) );
    }

    if( !sizeof( things ) )
        return "";

    if( _in_long )
        things -= ({ _in_long });

    if( !sizeof(things) )
        return 0;

    return ({ ::query_contents( start, things, ignore_liv ), "Ridden by" });

} /* query_contents() */

/**
 * This method returns the string giving some indication about how tired
 * the horse it.
 * @return the exhaustion string of the horse
 */
string query_exhaustion_string() {
    string start;

    start = CAP( HE );

    switch (_cur_exhaustion * 6 / _max_exhaustion) {
      case 5 :
        return start + " looks wonderfully happy and totally rested.\n";
      case 4 :
        return start + " looks a little tired.\n";
      case 3 :
        return start + " looks quite tired.\n";
      case 2 :
        return start + " looks really tired.\n";
      case 1 :
        return start + " looks exhausted.\n";
      case 0 :
        return start + " is totally exhausted.\n";
    }

} /* query_exhaustion_string() */

/** @ignore yes */
string extra_look() { return query_exhaustion_string(); }

/** @ignore yes */
string long( string fluff, int dark ) {
    string str;

    str = "";

    if( ENV(TP) == TO ) {
        // They are in the horse...
        _in_long = TP;

        if( _inside_long ) {
            str += "You are riding on:\n"+::long( fluff, dark );
        } else {
            str += "You are riding on:\n"+_inside_long+
                   query_exhaustion_string();
        }

        _in_long = 0;

        str += "Around " + the_short() + " is:\n";
        str += ( ENV(TO) ? ENV(TO)->long( fluff, dark ) :
            "%^RED%^Limbo! Wandered into an inherit, did we?%^RESET%^\n");

    } else {
        str += ::long( fluff, dark );
    }

    return str;

} /* long() */

/** @ignore yes */
string pretty_short( object player, int no_riding ) {
    string str;

    if( sizeof( _riding - ({ player }) ) && !no_riding ) {
        str = query_multiple_short( _riding - ({ player }) );
        str = player->convert_message(str);
        if( _transport_name ) {
            return str + " riding " + ::pretty_short();
        } else {
            return str + " riding " + add_a( ::pretty_short() );
        }
    }

    return ::pretty_short();

} /* pretty_short() */

/** @ignore yes */
object query_mirror_room() { return ENV(TO); }

/**
 * This method sets the owner of the transport.  This should be used
 * when the owner is changed.
 * @param owner the new owner of the transport
 */
void set_owner( string owner ) {
    int *ids, i;
    string classif;
    object ob;


    // Remove the effect off the old owner and add it to the new one.
    if( _owner && ( ob = find_player(_owner) ) ) {
        classif = TRANSPORT_OWNER_EFFECT->query_classification();
        ids = ob->effects_matching(classif);

        foreach( i in ids )
            TRANSPORT_OWNER_EFFECT->remove_owner( ob, ob->arg_of( i ), i, TO );
    }

    _owner = owner;

    if( _owner && ( ob = find_player(_owner) ) )
        ob->add_effect( TRANSPORT_OWNER_EFFECT, TO );

} /* set_owner() */

/**
 * This method sets the id of the transpot.
 * @param id the id of the transport
 */
void set_transport_id( int id ) { _transport_id = id; }

/**
 * This method returns the id of the transport.
 * @return the id of the transport
 */
int query_transport_id() { return _transport_id; }

/**
 * This method returns the current owner of the transport.
 * @return the current owner of the transport
 */
string query_owner() { return _owner; }

/**
 * This method returns the current owner of the transport, it is used by the
 * pk checking code to make sure that this horse can be used in exciting
 * pk ways.
 * @return the owner
 */
string query_owner_pk_check() { return query_owner(); }

/**
 * This method sets the inside long of the horse.  This is what people
 * will see when they are inside a horse.
 * @param long the inside of the long of the horse
 */
void set_inside_long( string long ) { _inside_long = long; }

/**
 * This method returns the inside long of the horse.
 * @return the inside long of the horse
 */
string query_inside_long() { return _inside_long; }

/**
 * This method sets the maximum exhaustion points for the transport.
 * @param exhaust the maximum exhaustion points
 */
void set_maximum_exhaustion( int num ) {
    _max_exhaustion = num;
    _cur_exhaustion = num;
} /* set_maximum_exhaustion() */

/**
 * This method returns the maximum exhaustion points for the transport.
 * @return the maximum exhaustion points
 */
int query_maximum_exhaustion() { return _max_exhaustion; }

/**
 * This method returns the current exhaustion points for the transport.
 * @return the current exhaustion points
 */
int query_current_exhaustion() { return _cur_exhaustion; }

/**
 * This method sets the current exhaustion points for the transport.
 * @param points the current exhaustion points
 */
int set_current_exhaustion( int points ) { _cur_exhaustion = points; }

/**
 * This method sets the maximum speed for the transport.
 * @param the maximum speed
 * @return 1 if successful, 0 on invalid speed
 */
int set_maximum_speed( int speed ) {
    if( speed < RIDE_WALK || speed > RIDE_GALLOP )
        return 0;

    _max_speed = speed;

    return 1;

} /* set_maximum_speed() */

/**
 * This method queries the maximum speed for the transport.
 * @return the maximum speed for the transport
 */
int query_maximum_speed() { return _max_speed; }

/**
 * This method returns the string associated with the specified speed.
 * @param speed the speed to check
 * @param panic if the horse is panicing
 * @return the name of the speed
 */
string query_speed_string( int speed, int panic ) {
    if( panic )
        return "flee";

    switch( speed ) {
      case RIDE_WALK :
        return "walk";
      case RIDE_CANTER :
        return "canter";
      case RIDE_GALLOP :
        return "gallop";
      case RIDE_TROT :
        return "trot";
      default :
        return "unknown speed";
    }

} /* query_speed_string() */

/**
 * This method expands the name of the direction.
 * @param dir the direction to expand
 * @return the expanded name
 */
string expand_direction( string dir ) { return LENGTHEN[dir] || dir; }

/**
 * This method checks to see if the specified person is allowed to do
 * things to this transport.
 * @param name the name of the person to check
 * @return 1 if they can do things, 0 if not
 */
int is_allowed_to_use( string name ) {
    if( _owner )
        return name == _owner || ( sizeof(_allowed) &&
               member_array( name, _allowed ) != -1 );

    return 0;

} /* is_allowed_to_use() */

/**
 * Mount the horse!
 * @return 1 on success, 0 on failure
 */
int do_mount() {
    class task_class_result result;
    int ret, difficulty;
    object worn;
    string *str, pre;

    IS_ALLOWED("You are not the owner and are not allowed to use $D.\n");

    if( ENV(TP) == TO ) {
        TP->add_failed_mess( TO, "You are already mounted on $D.\n");
        return 0;
    }

    // Diffulty is the default plus any modifiers for what the horse is
    // wearing (ie: saddle).
    difficulty = query_default_mount_difficulty();

    foreach( worn in query_wearing() )
        if( worn->query_mount_difficulty_adjustment() )
            difficulty -= worn->query_mount_difficulty_adjustment();

    if( difficulty < 1 )
        difficulty = 1;

    // First lets do a skill check.
    result = TASKMASTER_H->perform_task( TP,
             TRANSPORT_SKILL_BASE + query_transport_type(),
             difficulty, TM_FREE, 1 );

    switch( result->result ) {
      case AWARD :
        write("%^YELLOW%^You feel more able to climb onto "+the_short()+
            ".\n%^RESET%^");
      case SUCCEED :
        if( ret = TP->move(TO) ) {
            switch( ret ) {
              case MOVE_TOO_HEAVY :
                TP->add_failed_mess( TO, "You are unable to mount $D because "
                    "you are too heavy for "+HIM+".\n");
              break;
              default :
                TP->add_failed_mess( TO, "You are unable to mount $D for some "
                    "reason ("+ret+").\n");
              break;
            }
            return 0;
        }

        switch( result->degree ) {
          case 0..10 :
            str = ({ "You grab the back of $D and heave yourself onto the "
                     "creature with some difficulty, barely managing to keep "
                     "your balance.\n",
                     "$N grab$s the back of $D and heave$s $oself onto the "
                     "creature in a display of uncertain movements, then "
                     "wobble$s for a moment, but regains $p balance.\n"});
          break;
          case 11..40 :
            str = ({ "You grab the back of $D and heave yourself onto the "
                     "creature.\n",
                     "$N grab$s the back of $D and heave$s $oself onto the "
                     "creature.\n"});
          break;
          case 41..80 :
            str = ({ "You grab the back of $D and effortlessly heave yourself "
                     "onto the creature.\n",
                     "$N grab$s the back of $D and effortlessly heave$s "
                     "$oself onto the creature.\n"});
          break;
          default :
            str = ({ "You grab the back of $D and swing yourself onto the "
                     "creature in a display of skill.\n",
                     "$N grab$s the back of $D and swing$s $oself onto the "
                     "creature in a display of skill.\n"});
        }

        TP->add_effect( TRANSPORT_EFFECT, TO );
        TP->add_succeeded_mess( TO, str );

        return 1;

      case FAIL :
        pre = "You attempt to get onto $D, but ";
        switch( result->degree ) {
          case -1000..-71 :
            str = ({ pre + "fail to figure out how to even begin.\n",
                     "$N stare$s at $D with a stupefied expression.\n"});
          break;
          case -70..-41 :
            str = ({ pre + "your grasp of the back of the creature slips "
                     "before you even start to climb.\n",
                     "$N grasp$s the back of $D as if attempting to mount "+
                     HIM+", but fail$s to get a proper hold.\n"});
          break;
          case -40..-16 :
            str = ({ "You grab the back of $D, but don't quite manage to "
                     "heave yourself onto the creature.\n",
                     "$N grab$s the back of $D, but fail$s to heave $oself "
                     "onto the creature.\n"});
          break;
          default :
            str = ({ "You grab the back of $D and heave yourself onto the "
                     "creature, but just as you are done, you lose your "
                     "balance and slide down the other side.\n",
                     "$N grab$s the back of $D and heave$s $oself onto the "
                     "creature, but slide$s down the other side after a "
                     "moment of wobbling.\n"});
        }

        TP->add_succeeded_mess( TO, str );
        return 1;
    }

} /* do_mount() */

/**
 * This method returns whether or not we are following a path.
 * @return 1 if we are following a path, 0 if not
 */
int query_path_follow() { return _riding_flags & PATH_FOLLOW; }

/**
 * This method returns whether or not we should stop at an intersection.
 * @return 1 if we should stop at an intersection, 0 if not
 */
int query_stop_at_intersection() {
    return _riding_flags & STOP_AT_INTERSECTION;
} /* query_stop_at_intersection() */

/**
 * This method returns whether or not we should stop after moving once.
 * @return 1 if we should stop after moving once, 0 if not
 */
int query_stop_after_moving_once() {
    return _riding_flags & STOP_AFTER_MOVING_ONCE;
} /* query_stop_at_intersection() */

/**
 * Ride the horse off into the sunset.
 * @return 1 on success, 0 on failure
 */
int do_ride( string dir, int speed, string type ) {
    string *route;

    if( ENV(TP) != TO ) {
        TP->add_failed_mess( TO, "You must mount $D before you "
            "can ride anywhere on "+HIM+".\n");
        return 0;
    }

    dir = expand_direction(dir);

    _cur_direction = dir;
    _cur_speed = speed;
    _last_location = 0;
    _riding_flags = 0;
    _route = 0;

    switch( type ) {
      case "intersection" :
      case "once" :
      case "forever" :
        // Check to see if the exit exists in that direction.
        if( ENV(TO)->query_destination(dir) == VOID_ROOM ) {
            TP->add_failed_mess( TO, "There is no exit in the direction '"+
                dir+"'.\n");
            return 0;
        }
      break;
      case "route" :
        route = map( explode( replace_string( dir, " ", ""), ",") - ({ 0 }),
                (: expand_direction($1) :) );

        if( !sizeof(route) ) {
            TP->add_failed_mess( TO, "Who are you kidding?  $C$$D is only "
                "capable of following sensible routes.\n");
            return 0;
        }

        if( ENV(TO)->query_destination(route[0]) == VOID_ROOM ) {
            TP->add_failed_mess( TO, "There is no exit in the direction '"+
                route[0]+"'.\n");
            return 0;
        }

        _route = route;

      break;
      case "roughly" :
      case "roughly-intersection" :
        if( member_array( dir, ({"north", "northeast", "east", "southeast",
            "south", "southwest", "west", "northwest"}) ) == -1 ) {
            TP->add_failed_mess( TO, "You can only $V roughly towards the "
                "north, northeast, east, southeast, south, southwest, west "
                "or northwest.\n");
            return 0;
        }
      break;
      default :
    }

    switch( type ) {
      case "roughly" :
        _riding_flags = PATH_FOLLOW;
      break;
      case "intersection" :
        _riding_flags = STOP_AT_INTERSECTION;
      break;
      case "once" :
        _riding_flags = STOP_AFTER_MOVING_ONCE;
      break;
      case "roughly-intersection" :
        _riding_flags = PATH_FOLLOW | STOP_AT_INTERSECTION;
      break;
      case "route" :
        _cur_direction = 0;
      break;
      case "forever" :
      break;
      default :
        _riding_flags = STOP_AFTER_MOVING_ONCE;
    }

    TP->add_succeeded_mess( TO, ({"You start to "+
        query_speed_string( _cur_speed, _panic )+" $D.\n", ""}) );

    setup_movement();
    return 1;

} /* do_ride() */

/**
 * Stop the transport from running off.
 * @return 1 on success, 0 on failure
 */
int do_stop() {
    if( _cur_speed == RIDE_NOT_MOVING ) {
        TP->add_failed_mess( TO, "$D is not moving.\n");
        return 0;
    }

    // I want a skill check here, perhaps we would succeed in calming
    // down the mount. - Sandoz
    if( _panic ) {
        TP->add_failed_mess( TO, "$D is currently panicing and unable "
            "to be stopped.\n");
        return 0;
    }

    _cur_speed = RIDE_NOT_MOVING;
    remove_call_out(_move_id);

    TP->add_succeeded_mess( TO, "$N $V $D.\n");
    return 1;

} /* do_stop() */

/**
 * This is used to get off the horse the easy way.
 * @return 1 on success, 0 on failure
 */
int do_dismount() {
    int ret;

    if( ENV(TP) != TO ) {
        TP->add_failed_mess( TO, "You need to be mounted on $D to "
            "dismount.\n");
        return 0;
    }

    if( !ENV(TO) ) {
        TP->add_failed_mess( TO, "You cannot dismount $D for "+
            HE+" is in limbo.  Looks like you need professional help.\n");
        return 0;
    }

    if( ret = TP->move( ENV(TO) ) ) {
        TP->add_failed_mess( TO, "You failed to dismount $D for some "
            "reason ("+ret+").\n");
        return 0;
    }

    if( _cur_speed )
        do_stop();

    if( _panic ) {
        tell_object( TP, "You throw yourself from "+the_short()+" who is "
            "still panicing.\n");
        tell_room( ENV(TO), TP->the_short()+" throws "+HIM+"self from "+
            the_short()+" who is panicing.\n", ({ TP }) );
    } else {
        tell_object( TP, "You dismount from "+the_short()+".\n");
        tell_room( ENV(TO), TP->the_short()+" dismounts from "+
            the_short()+".\n", ({ TP }) );
    }

    TP->add_succeeded_mess( TO, "");
    return 1;

} /* do_dismount() */

#ifdef DO_RUSTLE
/**
 * This method will attempt to get the horse rustled by some nasty
 * pk person.
 * @return 1 on success, 0 on failure
 */
int do_rustle() {
    object *bing;

    // We need skill checks here.
    // - Sandoz.
    if( !_owner ) {
        set_owner( TP->query_name() );
        write("You successfuly rustle "+the_short()+".\n");
        do_mount();
        return 1;
    }

    if( _owner == TP->query_name() ) {
        TP->add_failed_mess( TO, "You already own $D.\n");
        return 0;
    }

    if( !pk_check( _owner, TP, 1 ) ) {
        // Ok, so they are pkable...
        if( sizeof(query_riders()) ) {
            bing = query_riders();
            TP->add_failed_mess( TO, "It is rather hard to rustle $D when $I "+
                ( sizeof(bing) > 1 ? "are" : "is")+" sitting on "+HIM+".\n", bing );
            return 0;
        }


        // Do the rustle...
//      event( ENV(TP), "theft", TO, TP, find_player(_owner), ({ TO }) );
        TO->set_owner( TP->query_name() );
        return 1;
    }

    TP->add_failed_mess( TO, "Both you and the owner of $D must be "
        "playerkillers in order to rustle the creature.\n");
    return 0;

} /* do_rustle() */
#endif

/**
 * This method puts stuff on the horse, like saddle bags, saddles and things.
 * @param obs the objects to try and dress the horse in
 */
int do_dress( object* obs ) {
    object *good, *bad, blue, old_env;
    mapping errors;
    string result;

    IS_ALLOWED("You are not the owner and are not allowed to use $D.\n");

    // First check to make sure they are for the right race.
    good = filter( obs, (: $1->query_wearable() &&
           $1->query_worn_by_race() == query_race() :) );

    if( !sizeof(good) ) {
        TP->add_failed_mess( TO, "$I cannot be worn by $D.\n", obs );
        return 0;
    }

    bad = ({ });
    errors = ([ ]);

    foreach( blue in good ) {
        // Make sure they can wear it first.
        if( result = WEAR_CMD->can_wear_or_remove( blue, TO ) ) {
            result = replace_string( result, "you ", HE+" ");
            if( !errors[result] )
                errors[result] = ({ blue });
            else
                errors[result] += ({ blue });
            good -= ({ blue });
        } else {
           old_env = ENV(blue);
           if( !blue->move(TO) ) {
               if( result = wear_armour( blue, 0 ) ) {
                   result = replace_string( result, "you ", HE+" ");
                   if( !errors[result] )
                       errors[result] = ({ blue });
                   else
                       errors[result] += ({ blue });
                   blue->move(old_env);
                   good -= ({ blue });
               }
           } else {
               result = "could not be moved into "+HIS+" inventory";
               if( !errors[result] )
                   errors[result] = ({ blue });
               else
                   errors[result] += ({ blue });
               good -= ({ blue });
           }
        }
    }

    if( !sizeof(good) ) {
        foreach( result, bad in errors )
            TP->add_failed_mess( TO, "You cannot dress $D with $I, because "+
                ( query_group( bad ) ? "they" : "it")+" "+result+".\n", bad );
    } else {
        TP->add_succeeded_mess( TO, "$N $V $D with $I.\n", good );
    }

    return sizeof(good) > 0;

} /* do_dress() */

/**
 * This sets up the horse for being led.  Basically it just makes the
 * horse follow you.
 * @return 1 on success, 0 on failure
 */
int do_lead() {
    IS_ALLOWED("You are not the owner and are not allowed to lead $D.\n");
    return command("follow " + TP->query_name() );
} /* do_lead() */

/**
 * This sets the horses name.
 * @param name the name to set the horse to
 * @return 1 on success, 0 on failure
 */
int do_name( string name ) {
    string str;

    if( query_owner() != TP->query_name() ) {
        TP->add_failed_mess( TO, "Sorry, only the owner can change the name "
            "of $D.\n");
        return 0;
    }

    str = lower_case(name);

    if( sizeof(name) > MAX_NAME_LEN ) {
        TP->add_failed_mess("Sorry, the maximum length of the name you can "
            "give $D is "+query_num(MAX_NAME_LEN)+" characters.\n");
        return 0;
    }

    if( sscanf( str, "%*scyber%*s") == 2 ||
        sscanf( str, "%*spenis%*s") == 2 ||
        sscanf( str, "%*scock%*s") == 2 ||
        sscanf( str, "%*spussy%*s") == 2 ||
        sscanf( str, "%*sfuck%*s") == 2 ||
        sscanf( str, "%*sshit%*s") == 2 ||
        sscanf( str, "%*sdragon%*s") == 2 ||
        sscanf( str, "%*sfish%*s") == 2 ||
        sscanf( str, "%*spimp%*s") == 2 ||
        sscanf( str, "%*skiller%*s") == 2 ||
        sscanf( str, "%*sslayer%*s") == 2 ) {
        TP->add_failed_mess( TO, "Sorry, you cannot name $D as '"+
            name+"'.\n");
        return 0;
    }

    if( PLAYER_H->test_user(str) ) {
        TP->add_failed_mess( TO, "You cannot name $D as '"+name+"', because "
            "it is the name of a player.\n");
        return 0;
    }

    if( PLAYER_H->test_banished(str) ) {
        TP->add_failed_mess( TO, "You cannot name $D as '"+name+"'.\n");
        return 0;
    }

    str = TP->convert_message( the_short() );
    set_transport_name(name);
    TP->add_succeeded_mess( TO, "$N set$s the name of "+str+" to "+
        name+".\n");

    return 1;

} /* do_name() */

/**
 * This sets the horses name.
 * @param name the name to set the horse to
 * @return 1 on success, 0 on failure
 */
int do_offer( object *food ) {
    object *ok, *last, ob;

    IS_ALLOWED("Sorry, only the owner can offer food to $D.\n");

    ok = filter( food, (: $1->query_edible() ||
        ( $1->query_liquid() && $1->query_continuous() ) :) );
    last = ({ });

    foreach( ob in ok ) {
        if( ob->do_eat(1) == 2 ) {
            last += ({ ob });
            ok -= ({ ob });
        }
    }

    if( !sizeof(ok) && !sizeof(last) ) {
        TP->add_failed_mess( TO, "You cannot offer $I to $D, because it is "
            "not food.\n", food );
        return 0;
    }

    if( sizeof(last) )
        TP->add_succeeded_mess( TO, "$N $V $I to $D, who munches happily on "
            "the last of it.\n", last );

    if( sizeof(ok) )
        TP->add_succeeded_mess( TO, "$N $V $I to $D, who munches on it "
            "happily.\n", ok );

    return 1;

} /* do_offer() */

/**
 * This allows someone to use the horse.
 * @param person the person to allow
 * @return 1 if successful, 0 if not
 */
int do_allow( string person ) {
    int i;

    if( TP->query_name() != _owner ) {
        TP->add_failed_mess( TO, "You are not the owner of $D and cannot "
            "change "+HIS+" allow list.\n");
        return 0;
    }

    person = lower_case(person);

    if( person == _owner ) {
        TP->add_failed_mess( TO, "You are the owner of $D and don't need to "
            "be added to "+HIS+" allow list.\n");
        return 0;
    }

    if( sizeof( person ) > 20 || !PLAYER_H->test_user( person ) ) {
        TP->add_failed_mess( TO, "There is no such player - "+
            CAP(person)+".\n");
        return 0;
    }

    if( !i = sizeof( _allowed ) ) {
        _allowed = ({ person });
    } else {
        if( member_array( person, _allowed ) != -1 ) {
            TP->add_failed_mess( TO, CAP(person)+" is already allowed to "
                "ride $D.\n");
            return 0;
        }

        if( i >= 10 ) {
            TP->add_failed_mess( TO, "Sorry, you cannot allow more than ten "
                "people to ride $D.\n");
            return 0;
        }

        _allowed += ({ person });
    }

    TP->add_succeeded_mess( TO, ({"You allow "+CAP(person)+" to ride $D.\n",
        ""}) );
    return 1;

} /* do_allow() */

/**
 * This disallows someone to use the horse.
 * @param person the person to disallow
 * @return 1 if successful, 0 if not
 */
int do_disallow( string person ) {
    if( TP->query_name() != _owner ) {
        TP->add_failed_mess( TO, "You are not the owner of $D and cannot "
            "change "+HIS+" allow list.\n");
        return 0;
    }

    person = lower_case(person);

    if( person == _owner ) {
        TP->add_failed_mess( TO, "You cannot disallow yourself from riding "
            "$D, because you are the owner of the creature.\n");
        return 0;
    }

    if( !sizeof(_allowed) ) {
        TP->add_failed_mess( TO, "No-one but you are allowed to ride $D.\n");
        return 0;
    }

    if( member_array( person, _allowed ) == -1 ) {
        TP->add_failed_mess( TO, CAP(person)+" is already not allowed to "
            "ride $D.\n");
        return 0;
    }

    _allowed -= ({ person });

    TP->add_succeeded_mess( TO, ({"You disallow "+CAP(person)+" from "
        "riding $D.\n", ""}) );

    return 1;

} /* do_disallow() */

/**
 * This method lists the people currently able to use your transports.
 * @return 1 on success, 0 on failure
 */
int do_list() {
    if( TP->query_name() != _owner ) {
        TP->add_failed_mess( TO, "You are not the owner of $D and cannot "
            "view "+HIS+" allow list.\n");
        return 0;
    }

    if( !sizeof(_allowed) )
        TP->add_succeeded_mess( TO, ({"No-one but you are currently allowed "
            "to ride $D.\n", ""}) );
    else
        TP->add_succeeded_mess( TO, ({ query_multiple_short( map(
            asort( _allowed ), (: CAP($1) :) ) )+" "+( sizeof(_allowed) == 1 ?
            "is" : "are")+" currently allowed to ride $D.\n", ""}) );

    return 1;

} /* do_list() */

/**
 * This method is used to teather the mount to something.
 * The horse must be wearing something that responds to the id 'teather'.
 * @param obs the thing to teather us too
 * @return 1 on success, 0 on failure
 */
int do_teather( object *obs ) {
    object *teathers, *to;

    IS_ALLOWED("Sorry, only the owner can teather $D.\n");

    teathers = filter( query_wearing(),
        (: $1->query_property(TRANSPORT_TEATHER_PROP) :) );

    if( !sizeof(teathers) ) {
        TP->add_failed_mess( TO, "$D $V$0=does,do$V$ not have anything for "
            "you to teather "+verbalize("them", HIM )+" with.\n");
        return 0;
    }

    if( sizeof(obs) > 1 ) {
        TP->add_failed_mess( TO, "You cannot teather "+the_short()+" to more "
            "than one thing.\n", obs );
        return 0;
    }

    to = filter( obs, (: !living($1) && ENV($1) == ENV(TO) &&
         ( $1->query_property(TRANSPORT_TEATHER_PROP) ||
           $1->id("pole") ) :) );

    if( !sizeof(to) ) {
        TP->add_failed_mess( TO, "You cannot teather "+the_short()+" to "
            "$I.\n", obs );
        return 0;
    }

    // Set us up to be teathered to something.
    set_teathered_to( to[0] );

    TP->add_succeeded_mess( TO, "$N $V $D to $I.\n", to );
    return 1;

} /* do_teather() */

/**
 * This method unteathers the mount if it is teathered to something.
 * @return 1 on success, 0 on failure
 */
int do_unteather() {
    object teather;

    if( !teather = query_teathered_to() ) {
        TP->add_failed_mess( TO, "You cannot unteather $D because "+
            verbalize("they aren't", HE+" isn't")+" teathered.\n");
        return 0;
    }

    IS_ALLOWED("Sorry, only the owner can unteather $D.\n");

    set_teathered_to(0);

    TP->add_succeeded_mess("$N $V $D from $I.\n", ({ teather }) );
    return 1;

} /* do_unteather() */

/**
 * This method is called when ever someone we are following causes us to
 * move.
 */
int check_doing_follow( object thing, string verb, string special ) {
    int exhaust;

    exhaust = time() - _last_move;
    if( !exhaust ) {
        exhaust = _max_speed;
    } else if( exhaust < _transport_speed ) {
        exhaust = _transport_speed / exhaust;
    } else {
        exhaust = 1;
    }

    // Let the exhaustion go down a lot slower when being led as opposed
    // to ridden.
    exhaust--;

    // Try and figure out how much exhaustion this move should give the
    // horse..
    if( _cur_exhaustion < exhaust * exhaust ) {
        tell_room( TO, the_short()+" looks too tired to move.\n");
        tell_object( thing, the_short()+" is too tired to follow you.\n");
        return 0;
    }

    _cur_exhaustion -= exhaust * exhaust;
    return 1;

} /* check_doing_follow() */

/** @ignore yes */
protected void inform_of_move( string dir ) {
    object ob;
    int dark;

    foreach( ob in query_riders() ) {
        dark = ob->check_dark( ENV(TO)->query_light() );
        tell_object( ob, "You "+query_speed_string( _cur_speed, _panic )+" "+
            dir+" on "+the_short()+".\n");
        if( ob->query_verbose("look") ) {
            tell_object( ob, ENV(TO)->long( 0, dark ) );
        } else {
            tell_object( ob, GLANCE_CMD->room_glance( ob, ENV(TO), dark ) );
        }
    }

} /* inform_of_move() */

/**
 * This returns the list of directions the transport can currently
 * move from this location.  It takes in account things like size and
 * if the exit is obvious or not.
 * @param no_last don't go back where we came from
 */
string *query_allowed_directions( int no_last ) {
    mixed dest_other, data;
    string *ret;
    int i;

    dest_other = ENV(TO)->query_dest_other();
    ret = ({ });

    for( i = sizeof( dest_other ) - 2; i > -1; i -= 2 ) {
        data = dest_other[ i + 1 ];

        if( data[ROOM_OBV] && !data[ROOM_REL] &&
            data[ROOM_SIZE] >= query_height() &&
            !( no_last && data[ROOM_DEST] == _last_location ) )
            ret += ({ dest_other[ i ] });
    }

    return ret;

} /* query_allowed_directions() */

private string do_move_direction( string direction ) {
    int difficulty, result;
    object worn;
    string *allowed, new_direction;

    allowed = query_allowed_directions(1);

    // No such exit at all.
    if( member_array( direction, allowed ) == -1 )
        return 0;

    // They could go in a different direction!
    if( sizeof(allowed) > 1 )
        new_direction = choice( allowed );

    if( new_direction && !_panic ) {
        // Difficulty is the default plus any modifiers for what the horse is
        // wearing (ie: saddle).
        difficulty = query_default_direction_difficulty();

        foreach( worn in query_wearing() ) {
            if( worn->query_direction_difficulty_adjustment() )
                difficulty -= worn->query_mount_difficulty_adjustment();
        }

        if( difficulty < 1 )
            difficulty = 1;

        // First lets do a skill check.
        result = TASKMASTER_H->perform_task( TP,
                 TRANSPORT_SKILL_BASE + query_transport_type(),
                 difficulty, TM_FREE );

        switch( result ) {
          case AWARD :
            tell_object( TP, "%^YELLOW%^You feel more able to direct "+
                the_short()+" than ever before.\n%^RESET%^");
          case SUCCEED :
          break;
          case FAIL :
            if( new_direction == direction ) {
                write("You fail totally in your attempt to direct "+
                    the_short()+" to the "+direction+", but "+
                    HE+" decides to wander there anyway.\n");
            } else {
                write("You attempt to move "+the_short()+" to the "+
                    direction+", but "+HE+" attempts to wander off to the "+
                    new_direction+" instead.\n");
                direction = new_direction;
            }
          break;
        }
    }

   command(direction);
   return direction;

} /* do_move_direction() */

/**
 * This method turns a standard direction into a number.
 * @param direction the direction to turn into a number
 * @return the number associated with the direction
 */
int query_direction_as_number( string direction ) {
    switch( direction ) {
      case "north" :
        return 0;
      case "northeast" :
        return 1;
      case "east" :
        return 2;
      case "southeast" :
        return 3;
      case "south" :
        return 4;
      case "southwest" :
        return 5;
      case "west" :
      return 6;
      case "northwest" :
        return 7;
      default :
        return -1;
   }
} /* query_direction_as_number() */

private int query_direction_weight( string direction ) {
    int weight, direction_num, dest_num, dist;
    mixed stuff;

    stuff = ENV(TO)->query_dest_other(direction);
    weight = stuff[ROOM_SIZE];

    if( stuff[ROOM_DEST] == _last_location )
        weight -= 100;

    direction_num = query_direction_as_number(direction);
    dest_num = query_direction_as_number(_cur_direction);

    if( direction_num != -1 && dest_num != -1 ) {
        if( dest_num > direction_num ) {
            dist = dest_num - direction_num;
            if( dist > 4 )
                dist = direction_num + 8 - dest_num;
        } else {
            dist = direction_num - dest_num;
            if( dist > 4 )
                dist = dest_num + 8 - direction_num;
        }
        weight += ( 4 - dist ) * 75;
    }

    return weight;

} /* query_direction_weight() */

private int do_actual_move() {
    string *exits, highest_exit, str;
    int highest_weight, weight;
    object old;

    old = ENV(TO);

    // A route to follow.
    if( sizeof(_route) && !_cur_direction && !_panic ) {
        str = _route[0];
        _route = _route[1..];

        if( str = do_move_direction(str) ) {
            // Tell all the people here about it.
            _last_location = file_name(old);
            inform_of_move(str);
            if( sizeof(_route) )
                return 1;
        }

        tell_object( TP, the_short()+" finishes following "+
            HIS+" route and stops, waiting for more wild commands.\n");
        return 0;
    }

    // Attempting to sort of follow a path.  Heuristics, don't go back the
    // way we came.  Try and follow the biggest exit.  Choose an exit in
    // roughly the direction we are going.
    if( query_path_follow() || _panic ) {
        exits = query_allowed_directions(0);
        do {
            foreach( str in exits ) {
                weight = query_direction_weight(str);
                if( weight > highest_weight ) {
                    highest_weight = weight;
                    highest_exit = str;
                }
            }

            // If the best exit takes us back where we were...  Stop...
            if( ENV(TO)->query_destination(highest_exit) == _last_location ) {
                if( _panic ) {
                    _panic--;
                    exits -= ({ highest_exit });
                } else {
                    tell_object( TP, the_short()+" could not find anywhere "
                        "else to go and stops, waiting for you to do "
                        "something.\n");
                    return 0;
                }
            } else {
                if( str = do_move_direction(highest_exit) ) {
                    // Tell all the people about it.
                    _last_location = file_name(old);
                    inform_of_move(str);
                    if( _panic ) {
                        if( !--_panic ) {
                            tell_riders( the_short()+" calms down and stops "
                                "panicing.\n");
                            return 0;
                        }
                    }
                    return 1;
                } else {
                    exits -= ({ highest_exit });
                }
            }
        } while( _panic && sizeof(exits) );

        tell_object( TP, the_short()+" could not find anywhere else to go "
            "and stops, waiting for you to do something.\n");
        return 0;
    }

    // A specific direction.
    if( str = do_move_direction(_cur_direction) ) {
        // Tell all the people about it.
        _last_location = file_name(old);
        inform_of_move(str);
        return 1;
    }

    tell_object( TP, the_short()+" stops since there is no "+
        _cur_direction+" exit here, or "+HE+" was unable to go that way.\n");

    return 0;

} /* do_actual_move() */

/**
 * This method moves the horse.
 */
void do_move_transport() {
    int fluff, divide, i, ok;
    string *exits;

    if( _cur_speed == RIDE_NOT_MOVING )
        return;

    // Figure out how many bits to move per section.
    divide = _transport_speed / 2;
    if( divide == 0 )
        divide = 1;

    if( _cur_speed < divide )
        fluff = 1;
    else
        fluff = _cur_speed / divide;

    // They don't stop when they are panicing.
    if( _cur_exhaustion <= _cur_speed * _cur_speed && !_panic ) {
        tell_riders( the_short()+" is too exhausted to move any further.\n");
        return;
    }

    // Decrease the exhaustion first.
    _cur_exhaustion -= _cur_speed * _cur_speed;

    // Add in the call_out first to make it less likely for the horse to get
    // stuck panicing (for instance).
    if( _cur_speed < divide )
        _move_id = call_out( (: do_move_transport :),
                   divide * 2 / _cur_speed );
    else
        _move_id = call_out( (: do_move_transport :), 2 );

    // Do the move, see if it succeeded...
    // See how fast we are supposed to be moving.
    for( i = 0; i < fluff; i++ ) {
        ok = do_actual_move();

        // See if we should stop after moving once.
        if( query_stop_after_moving_once() ) {
            _cur_speed = RIDE_NOT_MOVING;
            remove_call_out(_move_id);
            _move_id = 0;
            return;
        }

        // See if we are at an intersection.
        // If we are, then stop...
        if( query_stop_at_intersection() ) {
            exits = query_allowed_directions(1);
            if( sizeof(exits) > 1 ) {
                // Inform the player and stop.
                tell_riders( the_short()+" stops and waits for your next "
                    "direction as you arrive at an intersection.\n");
                _cur_speed = RIDE_NOT_MOVING;
                remove_call_out(_move_id);
                _move_id = 0;
                return;
            }
        }

        if( !ok ) {
            _cur_speed = RIDE_NOT_MOVING;
            remove_call_out(_move_id);
            _move_id = 0;
            return;
        }
    }

} /* do_move_transport() */

/**
 * Sets up the call_out if needed.
 */
void setup_movement() {
    if( _cur_speed == RIDE_NOT_MOVING )
        return;

    if( find_call_out(_move_id) == -1 ) {
        int divide;

        // Figure out how many bits to move per section.
        divide = _transport_speed / 2;
        if( divide == 0 )
            divide = 1;

        if( _cur_speed < divide )
            _move_id = call_out( (: do_move_transport :),
                       divide * 2 / _cur_speed );
        else
            _move_id = call_out( (: do_move_transport :), 2 );
    }

} /* setup_movement() */

/**
 * This sets the speed at which the transport defaults to moving.  This is
 * how long it takes to move one room by default.
 * @param the default number of action points
 */
void set_transport_speed( int num ) { _transport_speed = num; }

/**
 * This method returns the amount of time it takes to move the transport
 * one room.
 * @return the amount of time to move one room
 */
int query_transport_speed() { return _transport_speed; }

/**
 * This method sets the default mount difficulty for the transport.
 * @parm difficulty The default difficulty
 */
void set_default_mount_difficulty( int difficulty ) {
    _default_mount_difficulty = difficulty;
} /* set_default_mount_difficulty() */

/**
 * This method returns the default mount difficulty for the transport.
 * @return the default difficulty
 */
int query_default_mount_difficulty() {
    return _default_mount_difficulty;
} /* query_default_mount_difficulty() */

/**
 * This method determines the default directional control of the transport.
 * (no reins?  Where do you think your going?)
 * @param difficulty the default directional difficulty
 */
void set_default_direction_difficulty( int difficulty ) {
    _default_direction_difficulty = difficulty;
} /* set_default_direction_difficulty() */

/**
 * This method determines the default directional control of the transport.
 * (no reins?  Where do you think your going?)
 * @return the default directional difficulty
 */
int query_default_direction_difficulty() {
    return _default_direction_difficulty;
} /* query_default_direction_difficulty() */

/**
 * This method determines the default difficulty of controlling the
 * transport in combat.
 * @param difficulty the default difficulty of controlling the mount in combat
 */
void set_default_fight_difficulty( int difficulty ) {
    _default_fight_difficulty = difficulty;
} /* set_default_fight_difficulty() */

/**
 * This method returns the default difficulty of controlling the
 * mount in combat.
 * @return the default difficulty of controlling the mount in combat
 */
int query_default_fight_difficulty() {
    return _default_fight_difficulty;
} /* query_default_fight_difficulty() */

/**
 * This method returns the type of transport that this is.
 * @return the type of transport
 */
string query_transport_type() { return _transport_type; }

/**
 * This method returns the type of transport that this is.
 * @param type the type of transport
 */
string set_transport_type( string type ) { _transport_type = type; }

/**
 * This method sets the name of the transport.
 * @param name sets the name of the transport
 */
void set_transport_name( string name ) { _transport_name = name; }

/**
 * This method returns the name of the transport.
 * @return the name of the transport
 */
string query_transport_name() { return _transport_name; }

/** @ignore yes */
string query_quit_handler() { return "/room/transport_start"; }

/**
 * This method returns the current list of people riding the
 * transport.
 * @return the list of people riding the transport
 */
object *query_riders() { return _riding; }

/**
 * This method checks to see if the person specified is actually a
 * rider.
 * @return 1 if they are a rider, 0 if not
 */
int is_rider( object ob ) { return member_array( ob, _riding ) != -1; }

/**
 * This method tells the riders about something.
 * @param str the message to tell the riders
 */
void tell_riders( string str ) {
    object thing;

    foreach( thing in query_riders() )
        tell_object( thing, str );

} /* tell_riders() */

/**
 * Fixes up the current list of people riding the transport.
 */
void fixup_riders() {
    object *old_riders, ob;
    int *ids, fluff;

    old_riders = _riding;
    _riding = filter( INV(TO), (: living($1) &&
        sizeof( $1->effects_matching(
        TRANSPORT_EFFECT->query_classification() ) ) :) );

    old_riders -= _riding + ({ 0 });

    foreach( ob in old_riders ) {
        ids = ob->effects_matching( TRANSPORT_EFFECT->query_classification() );
        foreach( fluff in ids )
            ob->delete_effect(fluff);
    }

} /* fixup_riders() */

/**
 * This method sets the object we are teathered to.
 * @param ob the object we are teathered to, 0 if we are not teathered
 */
void set_teathered_to( object ob ) {
    _teathered_to = ob;
    if( ob ) {
        _teathered_to_short = ob->query_short();
        set_position("teathered");
        set_position_type("to");
        set_position_on(_teathered_to);
    } else {
        _teathered_to_short = 0;
        set_position(0);
        set_position_type(0);
        set_position_on(0);
        // return_to_default_position(0);
    }
} /* set_teathered_to() */

/**
 * This method returns the object we are currently teathetred to.
 * @return the object we are teathered to
 */
object query_teathered_to() { return _teathered_to; }

/**
 * This method is called to make the object slide off.
 * @param ob the object sliding off
 */
void do_slide_off( object thing ) {
    if( ENV(thing) == TO && ( !living(thing) ||
        !sizeof( thing->effects_matching(
        TRANSPORT_EFFECT->query_classification() ) ) ) &&
        thing != _me_repeater && thing != _env_repeater &&
        member_array( thing, query_wearing() ) == -1 ) {
        if( thing->move( ENV(TO) ) ) {
            tell_creator("sandoz", "Failed to move "+
                thing->the_short()+" from "+the_short()+" to "+
                ENV(TO)->the_short()+".\n");
        } else {
            tell_room( TO, thing->the_short()+" slides off "+
                the_short()+".\n");
        }
    } else if( living(thing) ) {
        fixup_riders();
    }

} /* do_slide_off() */

/** @ignore yes */
void repeat_event_person_say( object caller, object ob, string start,
                              string mess, string lang ) {
    object *obs;

    if( ob == TO ) {
        obs = INV(TO) - ({ _me_repeater });
        obs->event_person_say( ob, start, mess, lang );
    } else if( caller == _me_repeater ) {
        // Here, so echo it to the environment.
        obs = INV( ENV(TO) ) - ({ TO, _env_repeater });
        obs->event_person_say( ob, "From the "+pretty_short( TP, 1 )+" "+start,
            mess, lang );
    } else {
        obs = INV(TO) - ({ _me_repeater });
        obs->event_person_say( ob, "From the room "+start, mess, lang );
    }

} /* repeat_event_person_say() */

/** @ignore yes */
void repeat_event_emote( object caller, object ob, string mess ) {
    object *obs;

    if( ob == TO ) {
        obs = INV(TO) - ({ _me_repeater });
        obs->event_emote( ob, mess );
    } else if( caller == _me_repeater ) {
        // Here, so echo it to the environment.
        obs = INV( ENV(TO) ) - ({ TO, _env_repeater });
        obs->event_emote( ob, "From the "+pretty_short( TP, 1 )+" "+mess );
    } else {
        obs = INV(TO) - ({ _me_repeater });
        obs->event_emote( ob, "From the room "+mess );
    }

} /* repeat_event_emote() */

/** @ignore yes */
void repeat_event_say( object caller, object ob, string str,
                       mixed avoid ) {
    object *obs;

    // The environment repeater is actually in us, creates a loop.
    // - Sandoz.
    if( caller == _env_repeater && ENV( _env_repeater ) == TO )
        return;

    if( ob == TO ) {
        obs = INV(TO) - ({ _me_repeater });
        obs->event_say( ob, str, avoid );
    } else if( caller == _me_repeater ) {
        // Here, so echo it to the environment.
        obs = INV( ENV(TO) ) - ({ TO, _env_repeater });
        obs->event_say( ob, str, avoid );
    } else {
        obs = INV(TO) - ({ _me_repeater });
        obs->event_say( ob, str, avoid );
    }

} /* repeat_event_say() */

/** @ignore yes */
void repeat_event_enter( object caller, object thing, string mess,
                         object prev ) {
    object *obs;

    // Things should slide off...
    if( ENV(thing) == TO )
        call_out( (: do_slide_off :), 2, thing );

    if( !stringp(mess) && thing != TO )
        return;

    if( caller == _env_repeater ) {
        // Here, so echo it to the environment.
        obs = INV(TO) - ({ _me_repeater });
        obs->event_enter( thing, mess, prev );
    }

} /* repeat_event_enter() */

/** @ignore yes */
void repeat_event_exit( object caller, object thing, string mess,
                        object dest ) {
    object *obs;

    if( ENV(thing) == TO && living(thing) )
        call_out( (: fixup_riders :), 2 );

    if( !stringp(mess) && thing != TO )
        return;

    if( caller == _env_repeater ) {
        // Here, so echo it to the environment.
        obs = INV(TO) - ({ _me_repeater });
        obs->event_enter( thing, mess, dest );
    }

} /* repeat_event_exit() */

/** @ignore yes */
void repeat_event_soul( object caller, object thing, string mess,
                        object *avoid ) {
    object *obs;

    if( thing == TO ) {
        obs = INV(TO) - ({ _me_repeater });
        obs->event_soul( thing, mess, avoid );
    } else if( caller == _me_repeater ) {
        // Here, so echo it to the environment.
        obs = INV( ENV(TO) ) - ({ TO, _env_repeater });
        obs->event_soul( thing, mess, avoid );
    } else {
        obs = INV(TO) - ({ _me_repeater });
        obs->event_soul( thing, mess, avoid );
    }

} /* repeat_event_soul() */

/**
 * This method creates the repeaters used for delivering the event
 * messages to us.
 */
void create_repeaters() {
    if( !_me_repeater ) {
        _me_repeater = clone_object(TRANSPORT_REPEATER);
        _me_repeater->set_repeater_owner(TO);
        _me_repeater->move(TO);
    }

    if( !_env_repeater ) {
        _env_repeater = clone_object(TRANSPORT_REPEATER);
        _env_repeater->set_repeater_owner(TO);
        _env_repeater->move( ENV(TO) );
    }
} /* create_repeater() */

/** @ignore yes */
private void check_teathered_to() {
    object* obs;

    obs = match_objects_for_existence( _teathered_to_short, ENV(TO) );

    if( sizeof(obs) )
        set_teathered_to( obs[0] );
    else
        set_teathered_to(0);

} /* check_teathered_to() */

/** @ignore yes */
varargs int move( mixed dest, string messin, string messout ) {
    int ret;

    _last_move = time();
    ret = ::move( dest, messin, messout );

    if( ret == MOVE_OK ) {
        if( _env_repeater )
            _env_repeater->move(dest);

        if( !_env_repeater || !_me_repeater )
           call_out( (: create_repeaters :), 2 );
    }

    return ret;

} /* move() */

/**
 * This method is called by the ownership effect when the player logs off.
 */
void retire() {
    // So that we wouldn't dest players and whatnot.
    //  - Sandoz
    if( ENV(TO) ) {
        foreach( object ob in INV(TO) ) {
            if( living(ob) ) {
                tell_object( ob, "You jump off "+the_short()+".\n");
                ob->move_with_look( ENV(TO),
                    "$N jump$s off "+the_short()+".");
            }
        }
    }

    move("/room/rubbish", 0, "$N disappear$s in a puff of fluff.");

} /* retire() */

/** @ignore yes */
void dest_me() {
    if( _env_repeater )
        _env_repeater->dest_me();

    if( _me_repeater )
        _me_repeater->dest_me();

    if( _owner )
        set_owner(0);

    // So that we wouldn't dest players and whatnot.
    //  - Sandoz
    if( ENV(TO) ) {
        string str = PLAYER_OBJ->convert_message( the_short() );

        foreach( object ob in INV(TO) ) {
            if( living(ob) ) {
                tell_object( ob, "You jump off "+str+".\n");
                ob->move_with_look( ENV(TO),
                    "$N jump$s off "+str+".");
            } else {
                ob->move("/room/rubbish");
            }
        }
    } else {
        INV(TO)->move("/room/rubbish");
    }

    ::dest_me();

} /* dest_me() */

/** @ignore yes */
int attack_ob( object ob ) {
    ob->stop_all_fight();
    TO->stop_all_fight();
    return 0;
} /* attack_ob() */

/** @ignore yes */
int second_life() {
    // If we die, move the riders into our environment.
    query_riders()->move( ENV(TO) );
    return 0;
} /* second_life() */

/** @ignore yes */
int query_ok_turn_off_heart_beat() {
    return _cur_exhaustion < _max_exhaustion;
} /* query_ok_turn_off_heart_beat() */

/** @ignore yes */
void heart_beat() {
    if( _cur_exhaustion < _max_exhaustion )
       _cur_exhaustion++;

    ::heart_beat();

} /* heart_beat() */

/**
 * @ignore yes
 * Stuff to mess with light levels...
 */
int query_light() {
    if( PO == ENV(TO) || !ENV(TO) )
        return ::query_light();

    return ENV(TO)->query_light();

} /* query_light() */

/**
 * This method panics the horse when it encounters a fight.
 * @param multiplier make the difficulty harder
 */
void panic_horse( int multiplier ) {
    object main_rider, *riders, rider;
    int result, panic, bonus;

    if( !multiplier )
        multiplier = 1;

    if( sizeof( query_riders() ) ) {
        main_rider = query_riders()[0];

        // First lets do a skill check.
        bonus = _default_fight_difficulty * multiplier;
        if( _cur_speed != RIDE_NOT_MOVING )
            bonus = bonus / ( _cur_speed + TRANSPORT_PANIC_RIDING_DIVISOR );

        result = TASKMASTER_H->perform_task( main_rider,
                 TRANSPORT_SKILL_BASE + query_transport_type(),
                 _default_fight_difficulty * multiplier, TM_FREE );

        switch( result ) {
          case AWARD :
            tell_object( main_rider, "%^YELLOW%^You feel more able to "
                "control "+the_short()+" in combat than you did "
                "before.\n%^RESET%^");
          case SUCCEED :
            tell_object( main_rider, "You manage to keep "+
                the_short()+" calm in the fight going on around you.\n");
            tell_room( ENV(TO), main_rider->the_short()+" manages to keep "+
                the_short()+" calm in the fight going on around you.\n",
                ({ main_rider }) );
            return;
          case FAIL :
            tell_object( main_rider, "Despite your efforts to keep "+
                the_short()+" calm in the fight going on around you, "
                "you lose control over "+HIM+".\n");
            tell_room( ENV(TO), main_rider->the_short()+" loses control "
                "over "+the_short()+" in the fight going on around you.\n",
                ({ main_rider }) );
            // Check and see if they get tossed off...
            result = TASKMASTER_H->perform_task( main_rider,
                     TRANSPORT_SKILL_BASE + query_transport_type(),
                     ( _default_fight_difficulty * multiplier ) / 2, TM_FREE );
            switch( result ) {
              case AWARD :
                tell_object( main_rider, "%^YELLOW%^You feel more able to "
                    "stay on the horse and not be thrown off.\n%^RESET%^");
              case 1 :
                tell_object( main_rider, the_short()+" tries to throw you "
                    "off, but you manage to keep your seating.\n");
                tell_room( ENV(TO), the_short()+" tries to throw "+
                    main_rider->the_short()+" off, but "+
                    main_rider->HE+" manages to keep "+
                    main_rider->HIS+" seating.\n", ({ main_rider }) );
              break;
              case 0 :
                // Throw off all the riders.
                riders = query_riders();

                foreach( rider in riders ) {
                    tell_object( rider, the_short()+" throws you off "+
                        HIS+" back.\n");
                    rider->move( ENV(TO) );
                }

                tell_room( ENV(TO), the_short()+" throws "+
                    query_multiple_short(riders)+" off "+HIS+" back.\n",
                    riders );

              break;
            }
            break;
        }
    }

    // Panic!
    panic = _panic;
    _panic += 4 * multiplier;
    _cur_speed++;

    if( _cur_speed > _max_speed )
        _cur_speed = _max_speed;

    setup_movement();

    if( !panic )
        tell_room( ENV(TO), the_short()+" panics and makes a run for it!\n");

    _last_panic = time();

} /* panic_horse() */

/**
 * If there is a fight nearby the horsey gets a little upset.
 * @ignore yes
 */
void event_fight_in_progress( object attacker, object attackee ) {
    if( time() - _last_panic > 10 ) {
        panic_horse(TRANSPORT_PANIC_NORMAL_MULTIPLIER);
        _last_panic = time();
    }
} /* event_fight_in_progress() */

/**
 * @ignore yes
 * This method allows the container to have stuff inside it checked.
 * @param looker the person doing the checking
 * @return 1 on success, 0 on failur
 */
int can_find_match_reference_inside_object( object thing, object looker ) {
    if( is_rider(thing) )
        return 1;

    if( ::can_find_match_reference_inside_object( thing, looker ) )
        return 1;

    return 0;

} /* can_find_match_recurse_into() */

/**
 * @ignore yes
 * We mess with the followers array so that anything riding the horse that
 * has stuff following it, they follow the horse...
 * @return all the followers
 */
object *query_followers() {
    object *ret, ob;

    // No one can follow us as we zip along.  This should probably check
    // for other horses...
    if( _cur_speed > RIDE_WALK )
        return ({ });

    ret = ::query_followers();
    foreach( ob in query_riders() )
        ret |= ob->query_followers();

    return ret;

} /* query_followers() */

/**
 * This method will tell if the object is a transport or not.
 * @return 1 if it is a transport
 */
int query_transport() { return 1; }

/** @ignore yes */
int adjust_hp( int damage, object attacker, object weapon, string type ) {
    int ret, chance, ac;
    object rider;
    string zone;

    // Do the pk checks and panicing first.
    if( attacker && damage < 0 && _owner && pk_check( attacker, _owner ) )
        return 0;

    if( damage < 0 )
        panic_horse(TRANSPORT_PANIC_IN_BATTLE_MULTIPLIER);

    // Figure out the attack zone...  We will assume that the player
    // is more likely to try and hit the person on the horse.
    if( !sizeof( query_riders() ) || damage >= 0 )
        return ::adjust_hp( damage, attacker );

    // If the type is anything but one of the standard ones, pass on all the
    // damage.
    switch (type) {
      case "blunt" :
      case "sharp" :
      case "pierce" :
        // Figure out armour defenses...
        ret = ::adjust_hp( damage, attacker );
        damage = damage / 2;
        // Do AC stuff and so on.  More likely to hit legs than torso...

        switch( random(40) ) {
          case 0..1:
            zone = "head";
          break;
          case 2:
            zone = "neck";
          break;
          case 3..6:
            zone="chest";
          break;
          case 7..16:
            zone="abdomen";
          break;
          case 17..19:
            zone = "arms";
          break;
          case 20..21:
            zone = "hands";
          break;
          case 22..37:
            zone = "legs";
          break;
          case 38..39:
            zone = "feet";
          break;
        }

        foreach( rider in query_riders() ) {
            ac = rider->query_ac( type, damage, zone );
            if( damage - ac > 0 )
                rider->adjust_hp( damage - ac, attacker );

            // Now check to see if they get tossed off.
            chance = damage - ac * weapon->query_weight();

            switch( TASKMASTER_H->perform_task( TP,
                    TRANSPORT_SKILL_BASE + query_transport_type(), chance,
                    TM_FREE ) ) {
            case 2 :
              tell_object( rider, "%^YELLOW%^You feel more able to stay "
                  "mounted on "+the_short()+" while being hit.\n");
            case 1 :
            break;
            case 0 :
              tell_object( rider, attacker->poss_short()+" blow make you lose "
                  "balance and you fall off "+the_short()+".\n");
              tell_room( ENV(TO), attacker->poss_short()+" blow makes "+
                  rider->the_short()+" lose balance and "+rider->HE+" falls "
                  "off "+the_short()+".\n");
              rider->move( ENV(TO) );
            break;
         }
        }
      break;
    default :
      query_riders()->adjust_hp( damage, attacker );
      ret = ::adjust_hp( damage, attacker );
      break;
    }

    return ret;

} /* adjust_hp() */

/** @ignore yes */
int attack_by( object ob ) {
    object controller;

    if( !_owner )
        return ::attack_by( ob );

    if( ob->query_summoned() && ( controller = ob->query_owner() ) ) {
        if( pk_check( _owner, controller ) ) {
            tell_object( controller, "%^YELLOW%^$C$"+ob->one_short()+" tells "
                "you: I don't want to attack "+the_short()+"%^RESET%^.\n" );
            TO->stop_all_fight();
            ob->stop_fight(TO);
            ob->go_away();
            return 0;
        }
    }

    if( pk_check( _owner, ob ) ) {
        tell_object( ob, "You feel it would be wrong to attack "+
            the_short()+".\n");
        TO->stop_all_fight();
        ob->stop_all_fight();
        return 0;
    }

    panic_horse(TRANSPORT_PANIC_IN_BATTLE_MULTIPLIER);
    query_riders()->attack_by(ob);

    return ::attack_by( ob );

} /* attack_by() */

/**
 * @ignore yes
 * We are still in the same zone as the horse.
 */
string *query_zones() {
    if( ENV(TO) )
        return ENV(TO)->query_zones();
    return ({ });
} /* query_zones() */

/** @ignore yes */
mapping query_dynamic_auto_load() {
    mapping map;

    // Do this so we won't save the repeaters with our inventory.
    // - Sandoz.
    if( _me_repeater )
        _me_repeater->move(VOID_ROOM);
    if( _env_repeater && ENV(_env_repeater) == TO )
        _env_repeater->move(VOID_ROOM);

    map = (["::" : ::query_dynamic_auto_load() ]);

    if( _me_repeater )
        _me_repeater->move(TO);
    if( _env_repeater )
        _env_repeater->move(ENV(TO));

    if( _owner )
        map["owner"] = _owner;
    if( _route )
       map["route"] = _route;
    if( _transport_name )
        map["name"] = _transport_name;
    if( _cur_direction )
        map["cur direction"] = _cur_direction;
    if( _cur_speed )
        map["cur speed"] = _cur_speed;
    if( _last_location )
        map["last location"] = _last_location;
    if( _riding_flags )
        map["riding flags"] = _riding_flags;
    if( _panic )
        map["panic"] = _panic;
    if( _cur_exhaustion )
        map["cur exhaustion"] = _cur_exhaustion;
    if( _transport_id )
        map["transport id"] = _transport_id;
    if( _teathered_to_short )
        map["teathered to"] = _teathered_to_short;
    if( _allowed )
        map["allowed"] = _allowed;

    return map;

} /* query_dynamic_auto_load() */

/** @ignore yes */
void init_dynamic_arg( mapping map ) {
    if( map["::"] )
        ::init_dynamic_arg(map);

    // Do not use set_owner() here, because it will add the owner effect to
    // the player again, and thus breaking their transports array.
    // - Sandoz
    _owner = map["owner"];

    // Set them up to zip off if they were when they exited.
    _cur_direction = map["cur direction"];
    _route = map["route"];
    _transport_name = map["name"];
    _cur_speed = map["cur speed"];
    _last_location = map["last location"];
    _panic = map["panic"];
    _riding_flags = map["riding flags"];
    _cur_exhaustion = map["cur exhaustion"];
    _transport_id = map["transport id"];
    _teathered_to_short = map["teathered to"];
    _allowed = map["allowed"];

    if( _teathered_to_short )
        call_out( (: check_teathered_to :), 2 );

    setup_movement();

} /* init_dynamic_arg() */

/** @ignore yes */
mixed stats() {
    mixed arr;
    int sz, i;

    arr = allocate( sz = sizeof(_riding), (: allocate( 2 ) :) );

    for( ; i < sz; i++ ) {
        arr[i][0] = "rider #"+i;
        arr[i][1] = sprintf("%s (%s)", _riding[i]->query_cap_name(),
                    file_name(_riding[i]) );
    }

    return ::stats() + arr + ({
        ({"owner", _owner }),
        ({"allowed", _allowed }),
        ({"transport name", _transport_name }),
        ({"transport id", _transport_id }),
        ({"transport type", _transport_type }),
        ({"teathered to", _teathered_to }),
        ({"teathered to short", _teathered_to_short }),
        ({"me repeater", _me_repeater }),
        ({"env repeater", _env_repeater }),
        ({"current speed", _cur_speed }),
        ({"current exhaustion", _cur_exhaustion }),
        ({"following path", query_path_follow() }),
        ({"last location", _last_location }),
        ({"route", _route }),
        ({"current direction", _cur_direction }),
        ({"transport speed", _transport_speed }),
        ({"max speed", _max_speed }),
        ({"max exhaustion", _max_exhaustion }),
        ({"last move", _last_move }),
        ({"last panic", _last_panic }),
        });

} /* stats() */