dw_fluffos_v2/
dw_fluffos_v2/fluffos-2.9-ds2.05/
dw_fluffos_v2/fluffos-2.9-ds2.05/ChangeLog.old/
dw_fluffos_v2/fluffos-2.9-ds2.05/Win32/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/simuls/
dw_fluffos_v2/fluffos-2.9-ds2.05/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/clone/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/command/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/data/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/etc/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/master/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/log/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/compiler/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/efuns/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/operators/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/u/
dw_fluffos_v2/fluffos-2.9-ds2.05/tmp/
dw_fluffos_v2/fluffos-2.9-ds2.05/windows/
dw_fluffos_v2/lib/
dw_fluffos_v2/lib/binaries/cmds/
dw_fluffos_v2/lib/binaries/cmds/creator/
dw_fluffos_v2/lib/binaries/cmds/living/
dw_fluffos_v2/lib/binaries/cmds/player/
dw_fluffos_v2/lib/binaries/d/admin/obj/
dw_fluffos_v2/lib/binaries/d/liaison/
dw_fluffos_v2/lib/binaries/global/virtual/
dw_fluffos_v2/lib/binaries/global/virtual/setup_compiler/
dw_fluffos_v2/lib/binaries/obj/handlers/autodoc/
dw_fluffos_v2/lib/binaries/obj/handlers/terrain_things/
dw_fluffos_v2/lib/binaries/obj/misc/
dw_fluffos_v2/lib/binaries/obj/misc/buckets/
dw_fluffos_v2/lib/binaries/obj/monster/
dw_fluffos_v2/lib/binaries/obj/reactions/
dw_fluffos_v2/lib/binaries/obj/reagents/
dw_fluffos_v2/lib/binaries/secure/cmds/creator/
dw_fluffos_v2/lib/binaries/secure/master/
dw_fluffos_v2/lib/binaries/std/
dw_fluffos_v2/lib/binaries/std/dom/
dw_fluffos_v2/lib/binaries/std/effects/object/
dw_fluffos_v2/lib/binaries/std/guilds/
dw_fluffos_v2/lib/binaries/std/languages/
dw_fluffos_v2/lib/binaries/std/races/
dw_fluffos_v2/lib/binaries/std/room/
dw_fluffos_v2/lib/binaries/std/room/basic/
dw_fluffos_v2/lib/binaries/std/shops/
dw_fluffos_v2/lib/binaries/std/shops/inherit/
dw_fluffos_v2/lib/binaries/www/
dw_fluffos_v2/lib/cmds/guild-race/
dw_fluffos_v2/lib/cmds/guild-race/crafts/
dw_fluffos_v2/lib/cmds/guild-race/other/
dw_fluffos_v2/lib/cmds/playtester/
dw_fluffos_v2/lib/cmds/playtester/senior/
dw_fluffos_v2/lib/d/admin/
dw_fluffos_v2/lib/d/admin/log/
dw_fluffos_v2/lib/d/admin/mapper/31-10-01/mapmaker/event/
dw_fluffos_v2/lib/d/admin/meetings/
dw_fluffos_v2/lib/d/admin/obj/
dw_fluffos_v2/lib/d/admin/room/we_care/
dw_fluffos_v2/lib/d/admin/save/
dw_fluffos_v2/lib/d/dist/
dw_fluffos_v2/lib/d/dist/mtf/
dw_fluffos_v2/lib/d/dist/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/chars/
dw_fluffos_v2/lib/d/dist/pumpkin/desert/
dw_fluffos_v2/lib/d/dist/pumpkin/gumboot/
dw_fluffos_v2/lib/d/dist/pumpkin/hospital/
dw_fluffos_v2/lib/d/dist/pumpkin/inherit/
dw_fluffos_v2/lib/d/dist/pumpkin/map/
dw_fluffos_v2/lib/d/dist/pumpkin/plain/
dw_fluffos_v2/lib/d/dist/pumpkin/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/save/
dw_fluffos_v2/lib/d/dist/pumpkin/squash/
dw_fluffos_v2/lib/d/dist/pumpkin/terrain/
dw_fluffos_v2/lib/d/dist/pumpkin/woods/
dw_fluffos_v2/lib/d/dist/start/
dw_fluffos_v2/lib/d/learning/TinyTown/buildings/
dw_fluffos_v2/lib/d/learning/TinyTown/map/
dw_fluffos_v2/lib/d/learning/TinyTown/roads/
dw_fluffos_v2/lib/d/learning/add_command/
dw_fluffos_v2/lib/d/learning/arms_and_weps/
dw_fluffos_v2/lib/d/learning/chars/
dw_fluffos_v2/lib/d/learning/cutnpaste/
dw_fluffos_v2/lib/d/learning/examples/npcs/
dw_fluffos_v2/lib/d/learning/examples/player_houses/npcs/
dw_fluffos_v2/lib/d/learning/examples/terrain_map/basic/
dw_fluffos_v2/lib/d/learning/functions/
dw_fluffos_v2/lib/d/learning/handlers/
dw_fluffos_v2/lib/d/learning/help_topics/npcs/
dw_fluffos_v2/lib/d/learning/help_topics/objects/
dw_fluffos_v2/lib/d/learning/help_topics/rcs_demo/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/crowd/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/situations/
dw_fluffos_v2/lib/d/learning/items/
dw_fluffos_v2/lib/d/learning/save/
dw_fluffos_v2/lib/d/liaison/
dw_fluffos_v2/lib/d/liaison/NEWBIE/doc/
dw_fluffos_v2/lib/d/liaison/NEWBIE/save/oldlog/
dw_fluffos_v2/lib/db/
dw_fluffos_v2/lib/doc/
dw_fluffos_v2/lib/doc/creator/
dw_fluffos_v2/lib/doc/creator/autodoc/include/reaction/
dw_fluffos_v2/lib/doc/creator/autodoc/include/ritual_system/
dw_fluffos_v2/lib/doc/creator/autodoc/include/talker/
dw_fluffos_v2/lib/doc/creator/autodoc/include/terrain_map/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/baggage/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clock/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clothing/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/cont_save/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/corpse/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/money/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/monster/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/scabbard/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/service_provider/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/state_changer/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/wand/
dw_fluffos_v2/lib/doc/creator/autodoc/std/book_dir/
dw_fluffos_v2/lib/doc/creator/autodoc/std/key/
dw_fluffos_v2/lib/doc/creator/autodoc/std/learning/
dw_fluffos_v2/lib/doc/creator/autodoc/std/map/
dw_fluffos_v2/lib/doc/creator/autodoc/std/race/
dw_fluffos_v2/lib/doc/creator/autodoc/std/weapon_logic/
dw_fluffos_v2/lib/doc/creator/files/
dw_fluffos_v2/lib/doc/creator/policy/
dw_fluffos_v2/lib/doc/creator/room/
dw_fluffos_v2/lib/doc/effects/
dw_fluffos_v2/lib/doc/ideas/
dw_fluffos_v2/lib/doc/known_command/
dw_fluffos_v2/lib/doc/lpc/basic_manual/
dw_fluffos_v2/lib/doc/lpc/intermediate/
dw_fluffos_v2/lib/doc/new/add_command/
dw_fluffos_v2/lib/doc/new/handlers/
dw_fluffos_v2/lib/doc/new/living/
dw_fluffos_v2/lib/doc/new/living/race/
dw_fluffos_v2/lib/doc/new/living/spells/
dw_fluffos_v2/lib/doc/new/player/
dw_fluffos_v2/lib/doc/new/room/guild/
dw_fluffos_v2/lib/doc/new/room/outside/
dw_fluffos_v2/lib/doc/new/room/storeroom/
dw_fluffos_v2/lib/doc/object/
dw_fluffos_v2/lib/doc/playtesters/
dw_fluffos_v2/lib/doc/policy/
dw_fluffos_v2/lib/doc/weapons/
dw_fluffos_v2/lib/global/handlers/
dw_fluffos_v2/lib/global/virtual/setup_compiler/
dw_fluffos_v2/lib/include/
dw_fluffos_v2/lib/include/cmds/
dw_fluffos_v2/lib/include/effects/
dw_fluffos_v2/lib/include/npc/
dw_fluffos_v2/lib/include/shops/
dw_fluffos_v2/lib/net/daemon/chars/
dw_fluffos_v2/lib/net/inherit/
dw_fluffos_v2/lib/net/intermud3/
dw_fluffos_v2/lib/net/intermud3/services/
dw_fluffos_v2/lib/net/obj/
dw_fluffos_v2/lib/net/save/
dw_fluffos_v2/lib/net/smnmp/
dw_fluffos_v2/lib/net/snmp/
dw_fluffos_v2/lib/obj/amulets/
dw_fluffos_v2/lib/obj/b_day/
dw_fluffos_v2/lib/obj/examples/
dw_fluffos_v2/lib/obj/food/alcohol/
dw_fluffos_v2/lib/obj/food/chocolates/
dw_fluffos_v2/lib/obj/food/fruits/
dw_fluffos_v2/lib/obj/food/meat/
dw_fluffos_v2/lib/obj/food/nuts/
dw_fluffos_v2/lib/obj/food/seafood/
dw_fluffos_v2/lib/obj/food/vegetables/
dw_fluffos_v2/lib/obj/fungi/
dw_fluffos_v2/lib/obj/furnitures/artwork/
dw_fluffos_v2/lib/obj/furnitures/bathroom/
dw_fluffos_v2/lib/obj/furnitures/beds/
dw_fluffos_v2/lib/obj/furnitures/cabinets/
dw_fluffos_v2/lib/obj/furnitures/chairs/
dw_fluffos_v2/lib/obj/furnitures/chests/
dw_fluffos_v2/lib/obj/furnitures/clocks/
dw_fluffos_v2/lib/obj/furnitures/crockery/
dw_fluffos_v2/lib/obj/furnitures/cupboards/
dw_fluffos_v2/lib/obj/furnitures/cushions/
dw_fluffos_v2/lib/obj/furnitures/fake_plants/
dw_fluffos_v2/lib/obj/furnitures/lamps/
dw_fluffos_v2/lib/obj/furnitures/mirrors/
dw_fluffos_v2/lib/obj/furnitures/outdoor/
dw_fluffos_v2/lib/obj/furnitures/safes/
dw_fluffos_v2/lib/obj/furnitures/shelves/
dw_fluffos_v2/lib/obj/furnitures/sideboards/
dw_fluffos_v2/lib/obj/furnitures/sofas/
dw_fluffos_v2/lib/obj/furnitures/stoves/
dw_fluffos_v2/lib/obj/furnitures/tables/
dw_fluffos_v2/lib/obj/furnitures/wardrobes/
dw_fluffos_v2/lib/obj/handlers/
dw_fluffos_v2/lib/obj/handlers/autodoc/
dw_fluffos_v2/lib/obj/jewellery/anklets/
dw_fluffos_v2/lib/obj/jewellery/bracelets/
dw_fluffos_v2/lib/obj/jewellery/earrings/
dw_fluffos_v2/lib/obj/jewellery/misc/
dw_fluffos_v2/lib/obj/jewellery/necklaces/
dw_fluffos_v2/lib/obj/jewellery/rings/
dw_fluffos_v2/lib/obj/media/
dw_fluffos_v2/lib/obj/misc/buckets/
dw_fluffos_v2/lib/obj/misc/jars/
dw_fluffos_v2/lib/obj/misc/papers/
dw_fluffos_v2/lib/obj/misc/player_shop/
dw_fluffos_v2/lib/obj/misc/shops/
dw_fluffos_v2/lib/obj/misc/traps/
dw_fluffos_v2/lib/obj/monster/
dw_fluffos_v2/lib/obj/monster/godmother/
dw_fluffos_v2/lib/obj/monster/transport/
dw_fluffos_v2/lib/obj/plants/inherit/
dw_fluffos_v2/lib/obj/potions/
dw_fluffos_v2/lib/open/boards/
dw_fluffos_v2/lib/save/autodoc/
dw_fluffos_v2/lib/save/bank_accounts/
dw_fluffos_v2/lib/save/boards/frog/
dw_fluffos_v2/lib/save/books/bed_catalog/
dw_fluffos_v2/lib/save/creators/
dw_fluffos_v2/lib/save/mail/
dw_fluffos_v2/lib/save/mail/p/
dw_fluffos_v2/lib/save/soul/data/
dw_fluffos_v2/lib/save/tasks/
dw_fluffos_v2/lib/save/vaults/
dw_fluffos_v2/lib/secure/cmds/lord/
dw_fluffos_v2/lib/secure/config/
dw_fluffos_v2/lib/secure/items/
dw_fluffos_v2/lib/secure/player/
dw_fluffos_v2/lib/soul/
dw_fluffos_v2/lib/soul/i/
dw_fluffos_v2/lib/soul/j/
dw_fluffos_v2/lib/soul/k/
dw_fluffos_v2/lib/soul/o/
dw_fluffos_v2/lib/soul/q/
dw_fluffos_v2/lib/soul/to_approve/
dw_fluffos_v2/lib/soul/u/
dw_fluffos_v2/lib/soul/v/
dw_fluffos_v2/lib/soul/wish_list/
dw_fluffos_v2/lib/soul/y/
dw_fluffos_v2/lib/soul/z/
dw_fluffos_v2/lib/std/creator/
dw_fluffos_v2/lib/std/effects/
dw_fluffos_v2/lib/std/effects/attached/
dw_fluffos_v2/lib/std/effects/external/
dw_fluffos_v2/lib/std/effects/fighting/
dw_fluffos_v2/lib/std/effects/other/
dw_fluffos_v2/lib/std/environ/
dw_fluffos_v2/lib/std/guilds/
dw_fluffos_v2/lib/std/hospital/
dw_fluffos_v2/lib/std/house/
dw_fluffos_v2/lib/std/house/onebedhouse/
dw_fluffos_v2/lib/std/house/onebedhut/
dw_fluffos_v2/lib/std/house/tworoomflat/
dw_fluffos_v2/lib/std/languages/
dw_fluffos_v2/lib/std/liquids/
dw_fluffos_v2/lib/std/nationality/
dw_fluffos_v2/lib/std/nationality/accents/
dw_fluffos_v2/lib/std/nationality/accents/national/
dw_fluffos_v2/lib/std/nationality/accents/regional/
dw_fluffos_v2/lib/std/npc/goals/
dw_fluffos_v2/lib/std/npc/goals/basic/
dw_fluffos_v2/lib/std/npc/goals/misc/
dw_fluffos_v2/lib/std/npc/inherit/
dw_fluffos_v2/lib/std/npc/plans/
dw_fluffos_v2/lib/std/npc/plans/basic/
dw_fluffos_v2/lib/std/outsides/
dw_fluffos_v2/lib/std/races/shadows/
dw_fluffos_v2/lib/std/room/basic/topography/
dw_fluffos_v2/lib/std/room/controller/
dw_fluffos_v2/lib/std/room/controller/topography/
dw_fluffos_v2/lib/std/room/furniture/games/
dw_fluffos_v2/lib/std/room/furniture/inherit/
dw_fluffos_v2/lib/std/room/inherit/carriage/
dw_fluffos_v2/lib/std/room/inherit/topography/
dw_fluffos_v2/lib/std/room/punishments/
dw_fluffos_v2/lib/std/room/topography/area/
dw_fluffos_v2/lib/std/room/topography/iroom/
dw_fluffos_v2/lib/std/room/topography/milestone/
dw_fluffos_v2/lib/std/shadows/
dw_fluffos_v2/lib/std/shadows/attached/
dw_fluffos_v2/lib/std/shadows/curses/
dw_fluffos_v2/lib/std/shadows/disease/
dw_fluffos_v2/lib/std/shadows/fighting/
dw_fluffos_v2/lib/std/shadows/room/
dw_fluffos_v2/lib/std/shops/controllers/
dw_fluffos_v2/lib/std/shops/objs/
dw_fluffos_v2/lib/std/shops/player_shop/
dw_fluffos_v2/lib/std/shops/player_shop/office_code/
dw_fluffos_v2/lib/std/socket/
dw_fluffos_v2/lib/www/
dw_fluffos_v2/lib/www/external/autodoc/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/images/
dw_fluffos_v2/lib/www/external/java/telnet/examples/
dw_fluffos_v2/lib/www/external/java/telnet/tools/
dw_fluffos_v2/lib/www/pics/
dw_fluffos_v2/lib/www/secure/creator/
dw_fluffos_v2/lib/www/secure/editors/
dw_fluffos_v2/lib/www/secure/survey_results/
dw_fluffos_v2/win32/
/*  -*- LPC -*-  */
/*
 * $Locker:  $
 * $Id: teach.c,v 1.48 2003/02/25 17:20:10 trilogy Exp $
 */
#include <skills.h>
#include <tune.h>
#include <command.h>
#include <cmds/teach.h>
#include <playtesters.h>
#include <player.h>

inherit "/cmds/base";

//#define DEBUG 1
#define DEBUGGER "ceres"

/** If this is defined it enforces a maximum level to teach others. */
#undef ENFORCE_MAX_TEACH_LEVEL

int command_teach( object *obs, string comm, object teacher );
int spell_teach(object *obs, string spell, object teacher);
int teach_skill(object *obs, string str, object teacher);
int cmd_int(string str, object *obs, object teacher);
int check_ignoring(object ignorer, object ignoree);

int query_auto_teaching(object teacher, object learner) {
   return teacher->query_property(TEACH_COMMAND_AUTO_PROPERTY);
} /* query_auto_teaching() */

int cmd(string str, object *obs, object player) {
  int ret;
  object ob;
  object* ear;

  if (this_player()->query_property(PASSED_OUT_PROP)) {
     add_failed_mess("You cannot teach while passed out.\n");
     return 0;
  }

  if (this_player()->query_fighting()) {
    add_failed_mess("You cannot teach or learn anything while you are "
                    "fighting!\n");
    return 0;
  }

  if (this_player()->check_earmuffs("teach")) {
    add_failed_mess("You have teaching earmuffed.\n");
    return 0;
  }

  if (player) {
    ear = filter(obs, (: userp($1) && !interactive($1) :));
    if (sizeof(ear)) {
      obs -= ear;
      add_failed_mess("$C$$I does not have enough responsiveness to teach "
                      "you.\n", ear);
      if (!obs) {
        return 0;
      }
    }

    ear = filter(obs, (: $1->check_earmuffs("teach") :));
    if (sizeof(ear)) {
      obs -= ear;
      if (sizeof(ear) == 1) {
        add_failed_mess("$I has " + ear[0]->query_possessive() + " earmuffs "
                        "on.\n", ear);
      } else {
        add_failed_mess("$I have their earmuffs on.\n", ear);
      }
      if (!obs) {
        return 0;
      }
    }

    ear = filter(obs, (: check_ignoring($1, this_player()) :));
    if (sizeof(ear)) {
      obs -= ear;
      add_failed_mess("$I is ignoring you, or you are ignoring them.\n",
                      ear);
      if (!obs) {
        return 0;
      }
    }

    ear = filter(obs, (: $1->query_property(PASSED_OUT_PROP) :));
    if (sizeof(ear)) {
      obs -= ear;
      add_failed_mess("$I is passed out and looks rather worse for wear.\n",
                      ear);
      if (!obs) {
        return 0;
      }
    }

    ear = filter(obs, (: $1->query_fighting() :));
    if (sizeof(ear)) {
      obs -= ear;
      add_failed_mess("$I is currently beating stuff up, please wait "
                      "for them to finish.\n", ear);
      if (!obs) {
        return 0;
      }
    }

    obs = filter(obs, (: !$1->query_creator() :) );
    if (!sizeof(obs)) {
      add_failed_mess("None of those people are allowed to teach you.\n");
      return 0;
    }

    obs = filter(obs, (: query_auto_teaching($1, this_player()) :));
    if (!sizeof(obs)) {
      add_failed_mess("None of those people have auto teaching turned "
                      "on.\n");
      return 0;
    }
    obs = filter(obs, (: $1->query_time_left() > 0 :));
    if (!sizeof(obs)) {
      add_failed_mess("All the people you are trying to learn from appear "
                      "to be busy.\n");
      return 0;
    }

    foreach (ob in obs) {
      ret |= cmd_int(str, ({ this_player() }), ob);
    }
    return ret;
  }

  return cmd_int(str, obs, this_player());
} /* cmd() */


int cmd_int(string str, object *obs, object teacher) {
  if (teacher->query_property("dead")) {
    add_failed_mess("You wave your arms around, and your lips move but "
                       "they can't hear what you are saying.\n");
    return 0;
  }
   
  obs = filter(obs,  (: !$1->query_property("dead") :));
  if (!sizeof(obs)) {
    add_failed_mess("You must teach someone, preferably living.\n");
    return 0;
  }

  if (sizeof(obs) > 1) {
    add_failed_mess("You can only teach one person at a time.\n");
    return 0;
  }
  
  if (!command_teach(obs, str, teacher) &&
      !spell_teach(obs, str, teacher) &&
      !teach_skill(obs, str, teacher))
  {
    return 0;
  }

  return 1;
} /* cmd() */


int check_ignoring(object ignorer, object ignoree) {
  return (ignorer->query_property("ignoring") &&
          member_array(ignoree->query_name(),
                       ignorer->query_property("ignoring")) != -1);
} /* check_ignoring() */


int command_teach(object *obs, string comm, object teacher) {
  string cmd_ob;
  object *succ;
  object *no_go;
  object *me_low;
  mixed *him_low;
  object *know_already;
  object *ear_muffed;
  object *ignored;
  object *ignoring;
  object ob;
  string *tmp_stuff;
  int i;
  class command cmd = new(class command, verb : comm);
  mixed tmp;

  if (member_array(comm, teacher->query_known_commands()) == -1 ||
      !CMD_D->HandleStars(cmd))
  {
    if (CMD_D->HandleStars(cmd)) {
      if (teacher == this_player()) {
        add_failed_mess("You do not know the command " + comm + ".\n");
      } else {
        add_failed_mess(teacher->the_short(1) +
                        " does not know the command " + comm + ".\n");
      }
    }
    return 0;
  }
  obs -= ({ teacher });
  if (!sizeof(obs)) {
    add_failed_mess("You cannot teach yourself a command.\n");
    return 0;
  }
  if (teacher->check_earmuffs("teach")) {
    if (teacher == this_player()) {
      add_failed_mess("You have teaching earmuffed.\n");
    } else {
      add_failed_mess(teacher->the_short(1) + " has teaching earmuffed.\n");
    }
    return 0;
  }
  cmd_ob = CMD_D->GetPaths(cmd->verb)[0] + "/" + cmd->verb;
  succ = ({ });
  ear_muffed = ({ });
  know_already = ({ });
  no_go = ({ });
  me_low = ({ });
  him_low = ({ });
  ignored = ({ });
  if (teacher->query_property("ignoring")) {
    ignoring = filter(obs, (: check_ignoring($(teacher), $1) :));
    obs -= ignoring;
  }
  foreach(ob in obs) {
    if (!living(ob)) {
      continue;
    }
    if (teacher == this_player()) {
      tmp = ob;
    } else {
      tmp = "you";
    }
    if (member_array(comm, ob->query_known_commands()) != -1) {
      know_already += ({ tmp });
    } else if (ob->check_earmuffs("teach")) {
      ear_muffed += ({ tmp });
    } else if (check_ignoring(ob, teacher)) {
      ignored += ({ tmp });
    } else {
      switch (cmd_ob->can_teach_command(teacher, ob)) {
        case 1:
          succ += ({ ob });
          break;

        case 0 :
          no_go += ({ tmp });
          break;
        case -1 :
          me_low += ({ tmp });
          break;

        case -2 :
          him_low += ({ tmp });
          break;
      }
    }
  }
  if (!succ || !sizeof(succ)) {
    if (teacher != this_player()) {
      tell_object(teacher, this_player()->the_short() + " tried to "
                  "learn " + comm + " from you automatically, "
                  "but failed.\n");
    }

    if (sizeof(no_go) > 0) {
      add_failed_mess(teacher->the_short() + " cannot teach " + comm +
                      " to $I.\n", no_go);
    }
    if (sizeof(me_low)) {
      if (teacher == this_player()) {
        add_failed_mess(teacher->the_short() +
                        " are too low a level to teach " + comm +
                        " to $I.\n", me_low);
      } else {
        add_failed_mess(teacher->the_short() +
                        " is too low a level to teach " + comm +
                        " to $I.\n", me_low);
      }
    }
    if (sizeof(ear_muffed) > 0) {
      add_failed_mess("$I has teaching events earmuffed, you are unable "
                      "to teach them.\n", ear_muffed);
    }
    if (sizeof(him_low) > 0) {
      add_failed_mess("$I " +
                      ((sizeof(him_low) == 1  &&
                        him_low[0] != this_player()) ? "is" : "are") +
                      " too low a level to learn " + comm + ".\n", him_low);
    }
    if (sizeof(know_already)) {
      add_failed_mess("$I already know" +
                      (sizeof(know_already) > 1  ||
                       teacher != this_player()? "" : "s") +
                      " the command " + comm + ".\n", know_already);
    }
    if (sizeof(ignoring)) {
      if (this_player() == teacher) {
        add_failed_mess("You are ignoring $I.\n", ignoring);
      } else {
        add_failed_mess(teacher->the_short(1) + " is ignoring $I.\n",
                        ignoring);
      }
    }
    if (sizeof(ignored)) {
      add_failed_mess("You are being ignored by $I.\n", ignored);
    }
    return 0;
  }
  write(teacher->the_short() + " offer" +
        (this_player() == teacher ? "" : "s") + " to teach " + comm +
        " to " + query_multiple_short(succ) + ".\n");
  if (teacher == this_player()) {
    if (sizeof(no_go)) {
      write("You cannot teach " + comm + " to " +
            query_multiple_short(no_go, "the", 0, 1 ) + ".\n");
    }
    if (sizeof(ear_muffed) > 0) {
      write(capitalize(query_multiple_short(ear_muffed, "the", 0, 1)) +
            " has teaching events earmuffed, you are unable "
            "to teach them.\n");
    }
    if (sizeof(me_low) > 0) {
      write("You are too low a level to teach " + comm + " to " +
            query_multiple_short(me_low, "the", 0, 1) + ".\n");
    }
    if (sizeof(him_low) > 0) {
      write(capitalize(query_multiple_short(him_low, "the", 0, 1)) +
            ((sizeof(him_low) == 1) ? " is" : " are") +" too low a "
            "level to learn " + comm + ".\n");
    }
  } else {
    tell_object(teacher,
                "You automatically offer to teach " + comm + " to " +
                query_multiple_short(succ) + ".\n");
  }
  say(capitalize((string)teacher->short()) + " teaches something to " +
      query_multiple_short(succ) + ".\n", succ + ({ teacher }));

  for (i = 0; i < sizeof(succ); i++) {
    tell_object(succ[i], capitalize(teacher->the_short()) +
                " offers to teach " +
                query_multiple_short(delete(succ, i, 1) +
                ({ "you" }) ) + " the command \"" + comm + "\".\n"
                "Type \"learn " + comm + " from " +
                teacher->query_name() + "\" to learn the command.\n");
    tmp_stuff = succ[i]->query_respond_command(TEACH_COMMAND_TYPE, teacher);
    if (!tmp_stuff) {
      tmp_stuff = ({ comm });
    } else if (member_array(comm, tmp_stuff) == -1) {
      tmp_stuff += ({ comm });
    }
    succ[i]->add_respond_command(TEACH_COMMAND_TYPE, teacher, tmp_stuff);
  }
  add_succeeded_mess("");
  return 1;
} /* command_teach() */


int spell_teach(object *obs, string spell, object teacher) {
  object *succ, *no_go, *me_low, *him_low, ob;
  object *ignoring;
  object *ignored;
  object *ear_muffed;
  string ret;
  string is_are;
  mapping spells;
  mixed tmp;
   
  spells = teacher->query_spells();
 
  if (!spells[spell]) {
    return 0;
  }

  if (teacher == this_player()) {
    is_are = "are";
  } else {
    is_are = "is";
  }
 
  if (teacher->check_earmuffs("teach")) {
    add_failed_mess("You have teaching earmuffed.\n");
    return 0;
  }
  ear_muffed = succ = no_go = me_low = him_low = ({ });
 
  ignored = ({ });
  if (teacher->query_property("ignoring")) {
    ignoring = filter(obs, (: check_ignoring($(teacher), $1) :));
    obs -= ignoring;
  }
  foreach(ob in obs) {
    if (living(ob)) {
      if (ob->check_earmuffs("teach")) {
        ear_muffed += ({ ob });
        continue;
      } else if (check_ignoring(ob, teacher)) {
        ignored += ({ ob });
      } else {
        if (teacher == this_player()) {
          tmp = ob;
        } else {
          tmp = "you";
        }
        switch (spells[spell][0]->teach(ob, spell)) {
          case 1:
            succ += ({ ob });
            break;

          case 0:
            no_go += ({ ob });
            break;

          case -1:
            me_low += ({ ob });
            break;

          case -2:
            him_low += ({ ob });
            break;
        }
      }
    }
  }
  if (sizeof(succ) == 0) {
    if (teacher != this_player()) {
      tell_object(teacher, this_player()->the_short() + " tried to "
                  "learn " + spell +
                  " from you automatically, but failed.\n");
    }
    ret = "";
    if (sizeof(no_go) > 0) {
      add_failed_mess(teacher->the_short() +
                      " cannot teach " + spell + " to $I.\n", no_go);
    }
    if (sizeof(me_low) > 0) {
      add_failed_mess(teacher->the_short() + 
                      " " + is_are + 
                      " too low a level to teach $I " + spell + ".\n",
                      me_low);
    }
    if (sizeof(him_low) > 0) {
      add_failed_mess("$I " + is_are + " too low a level to learn " +
                       spell + ".\n", him_low);
    }
    if (sizeof(ignoring)) {
       add_failed_mess("You are ignoring $I.\n", ignoring);
    }
    if (sizeof(ignored) > 0) {
       add_failed_mess("You are being ignored by $I.\n", ignored);
    }
    if (sizeof(ignored) > 0) {
       add_failed_mess("$I has teaching earmuffed.\n", ignored);
    }
    return 0;
   }
   if (teacher == this_player()) {
     write(teacher->the_short() +
           " successfuly teach " + query_multiple_short(succ) + " " +
           spell + ".\n");
     if (sizeof(no_go) > 0) {
       write("You cannot teach " + spell + " to " +
             query_multiple_short(no_go, "the", 0, 1) + ".\n");
     }
     if (sizeof(me_low) > 0) {
       write("You are too low a level to teach " +
             query_multiple_short(me_low, "the", 0, 1) + " " + spell +
             ".\n");
     }
     if (sizeof(him_low) > 0) {
       write(capitalize(query_multiple_short(him_low, 0, 1)) +
             (sizeof(him_low) == 1 ? " is " : " are ") +
             "too low a level to learn " + spell + ".\n");
     }
     if (sizeof(ignoring) > 0) {
       add_failed_mess("You are ignoring " +
                       query_multiple_short(ignoring, "the", 0, 1) +
                       ".\n");
     }
     if (sizeof(ignored) > 0) {
       add_failed_mess("You are being ignored by " +
                       query_multiple_short(ignored, "the", 0, 1) + ".\n");
     }
   } else {
     write(teacher->the_short() +
           " successfuly teaches " + query_multiple_short(succ) + " " +
           spell + ".\n");
   }
   return 1;
} /* spell_teach() */
     
#define CANNOT 0
#define TOO_LOW 1
#define ONLY_LEAF 2
#define TOO_HIGH 3
#define CANNOT_TEACH 4

int teach_skill(object *obs, string str, object teacher) {
  int num;
  int lvl;
  int my_lvl;
  int lvl_up;
  int j;
  int cost;
  int total;
  int total2;
  int sk;
  int depth;
  object *ok;
  object *too_little;
  mixed  *too_low;
  object *cannot_teach;
  object *only_leaf;
  object *ignored;
  object *ignoring;
  object *ear_muffed;
  object *too_high;
  object ob;
  string skill;
  string skill_start;
  mixed *bits;
  class teaching_skill frog;
  float k;
  mixed tmp;

  num = 1;
  if (sscanf(str, "%d levels of %s", num, skill) != 2) {
    if (sscanf(str, "%d level of %s", num, skill) != 2) {
      if (sscanf(str, "%d %s", num, skill) != 2) {
        num = 1;
        skill = str;
      }
    }
  }
  if (num < 1) {
    add_failed_mess("You cannot teach a negative or zero number of "
                    "levels.\n");
    return 0;
  }
  if (num > 50) {
    add_failed_mess("You cannot teach more than 50 levels at a time.\n");
    return 0;
  }
  if (teacher->check_earmuffs("teach")) {
    add_failed_mess("You have teaching earmuffed.\n");
    return 0;
  }
  /* Make sure its a valid skill */
  skill_start = skill;
  bits = explode(implode(explode(skill, " "), "."), ".") - ({ "" });
  if (!bits || !(skill = (string)SKILL_OB->query_skill(bits))) {
    if (member_array(skill_start, teacher->query_known_commands()) != -1) {
      return 0;
    }
    add_failed_mess("The skill " + implode(bits, ".") + " is invalid.\n");
    return 0;
  }
  
  bits = explode(skill, ".");
  /*
   * We don't do the teaching here.  Figure out how much xp it will cost
   * to go up the levels, and inform the person we are teaching...
   */
  my_lvl = teacher->query_skill_bonus(skill, 1);
  ear_muffed = ({ });
  too_high = ({ });
  only_leaf = ({ });
  too_low = ({ });
  ok = ({ });
  too_little = ({ });
  cannot_teach = ({ });
  ignored = ({ });
  if (teacher->query_property("ignoring")) {
    ignoring = filter(obs, (: check_ignoring($(teacher), $1) :));
    obs -= ignoring;
  }

  foreach (ob in obs) {
    /*
     * First make sure the skill can be taught.  There are only restrictions
     * (currently) on teaching of languages.  You cannot teach yourself
     * levels in a language.  You have to go and research them.
     */
    if (teacher == this_player()) {
      tmp = ob;
    } else {
      tmp = "you";
    }
    if (!interactive(ob)) {
      cannot_teach += ({ tmp });
      continue;
    }
    if (!SKILL_OB->query_allowed_to_teach(skill)) {
      cannot_teach += ({ tmp });
      continue;
    }
    if (ob->check_earmuffs("teach")) {
      ear_muffed += ({ tmp });
      continue;
    }
    if (check_ignoring(ob, teacher)) {
      ignored += ({ tmp });
      continue;
    }
    if (SKILL_OB->query_only_leaf(skill) &&
        sizeof((mixed *)SKILL_OB->query_immediate_children(skill)))
    {
      only_leaf += ({ tmp });
      continue;
    }
    lvl = (int)ob->query_skill(skill);

    if (ob != teacher) {
      if ((int)ob->calc_bonus(lvl + num, skill, 1) > my_lvl) {
        add_failed_mess(teacher->the_short() +
                        " cannot teach $I, since their bonus is " +
                        (teacher == this_player() ? "higher" : "lower") +
                        " than yours.\n", ({ tmp }));
        continue;
      }
#ifdef ENFORCE_MAX_TEACH_LEVEL
      /*
       * Check to see if your level, or the level being taught too is
       * too high.
       */
      if (lvl + num > SKILL_MAX_TEACH) {
        too_high += ({ tmp });
        continue;
      }
#endif
    }

    if (sizeof(bits) > 1) {
      lvl_up = ob->query_skill(implode(bits[0 .. sizeof(bits) - 2], "."));
    } else {
      lvl_up = lvl;
    }

    depth = SKILL_OB->query_skill_depth(bits);
    if (!SKILL_OB->query_only_leaf(skill) && depth * 5 > lvl_up) {
      too_low += ({ tmp });
      continue;
    }

    total = 0;
    total2 = 0;

    foreach (sk in SKILL_OB->query_all_children(skill)) {
      if (SKILL_OB->query_immediate_children(sk) != ({ })) {
        continue;
      }
      my_lvl = teacher->query_skill_bonus(sk, 1);
      lvl = (int)ob->query_skill(sk);
      cost = DEFAULT_COST;
      cost *= STD_COST / 5;

      if (!my_lvl) {
        my_lvl = 1;
      }

      for (j = 0; j < num; j++) {
        k = 0.5 * (int)ob->calc_bonus(lvl + j, sk, 1 ) / my_lvl + 1.0;
        total2 += 500 + to_int(cost * (lvl+j) * exp((lvl + j) / 500.0) * k);
        if (total > total2) {
          num = j;
          break;
        } else {
          total = total2;
        }
      }

#ifdef DEBUG
      tell_object(find_player(DEBUGGER),
                  sprintf("%s:%s j:%d, lvl: %d, mylvl: %d, newbonus: %d, "
                          "total: %d\n",
                          this_player()->query_name(),
                          ob->query_name(),
                          j, lvl,
                          my_lvl,
                          (int)ob->calc_bonus(lvl + j, sk, 1),
                          lvl,
                          total2));
#endif

      if (!total) {
        total = cost;
      }
    }

    if (total > (int)ob->query_xp()) {
      if (teacher == this_player()) {
        add_failed_mess("It would have cost " + total + " xp to teach " +
                        num + " level" + (num > 1 ? "s" : "") + " of " +
                        skill + " to $I.\n", ({ ob }));
      } else {
        add_failed_mess("It would have cost " + total + " xp to teach " +
                        num + " level" + (num > 1 ? "s" : "") + " of " +
                        skill + " to you from " + teacher->the_short() +
                        ".\n");
      }
      too_little += ({ tmp });
      continue;
    }

    if (ob != teacher) {
      if (teacher == this_player()) {
        tell_object(ob, teacher->the_short() + " offers to teach "
                    "you " + num + " level" + (num > 1 ? "s" : "") +
                    " of " + skill + " for " + total + " xp.\nUse "
                    "\"learn\" to learn the skill.\n");
        write("You offer to teach $M$$the_short:" + file_name(ob) +
              "$$M$ " + num + " level" + (num > 1 ? "s" : "") + " of " +
              skill + " for " + total + " xp.\n");
      } else {
        tell_object(ob, teacher->the_short() + " offers to teach "
                    "you " + num + " level" + (num > 1 ? "s" : "") +
                    " of " + skill + " for "+total+" xp.\nUse \"learn\" "
                    "to learn the skill.\n");
        tell_object(teacher,
                    "You offer to teach $M$$the_short:" + file_name(ob) +
                    "$$M$ " + num + " level" + (num > 1 ? "s" : "") +
                    " of " + skill + " for " + total + " xp.\n");
      }
    } else {
      write("You can teach yourself " + num + " level" +
            (num > 1 ? "s" : "") + " of " + skill + " for " + total +
            " xp.\nUse \"learn\" to learn the skill.\n");
      write("You offer to teach $M$$the_short:" + file_name(ob) +
            "$$M$ " + num + " level" + (num > 1 ? "s" : "") + " of " +
            skill + " for " + total + " xp.\n");
    }
    ok += ({ tmp });
    frog = new(class teaching_skill);
    frog->num = num;
    frog->lvl = ob->query_skill(skill);
    frog->skill = skill;
    frog->xp = total;
    frog->room = environment(this_player());
    ob->add_respond_command(TEACH_SKILL_TYPE, teacher, frog);
  }
  if (sizeof(ok) == 0) {
    if (teacher != this_player()) {
      tell_object(teacher,
                  this_player()->the_short() + " tried to learn " + skill +
                  " from you automatically but failed.\n");
    }

    if (sizeof(only_leaf) > 0) {
      add_failed_mess("You cannot teach the skill " + skill +
                      ", as it is only possible to teach leaf skills in "
                      "this skill tree.\n");
    }

    if (sizeof(ear_muffed) > 0) {
      add_failed_mess("You cannot teach any levels of " + skill +
                      " to $I, they have teaching earmuffed and cannot "
                      "hear you.\n", ear_muffed);
    }

    if (sizeof(cannot_teach) > 0) {
      add_failed_mess("You cannot teach any levels of " + skill +
                      "; you need to look for alternative methods of "
                      "advancement.\n");
    }

    if (sizeof(too_low) > 0) {
      add_failed_mess(query_multiple_short(too_low, "the", 0, 1) +
                      ((sizeof(too_low) > 1    ||
                        too_low[0] == teacher  ||
                        teacher != this_player()) ? " are " : " is ") +
                      "not at a high enough level in the outer skills to "
                      "learn " + num + " levels of " + skill + ".   See "
                      "'help skills' for more details.\n");
    }

    if (sizeof(too_high) > 0) {
      add_failed_mess(query_multiple_short(too_low, "the", 0, 1) +
                      ((sizeof(too_high) > 1     ||
                        teacher != this_player() ||
                        too_low[0] == teacher) ? " are " : " is ") +
                      "too high a level to learn " + num + " levels of " +
                      skill + ", they must be less than " +
                      SKILL_MAX_TEACH + " to learn from someone else.\n");
    }

    if (sizeof(ignoring) > 0) {
      add_failed_mess("You are ignoring $I.\n", ignoring);
    }

    if (sizeof(ignored) > 0) {
      add_failed_mess("You are being ignored by $I.\n", ignored);
    }
  }

  return sizeof(ok);
} /* teach_skill() */

mixed *query_patterns() {
   return ({
      "<string:'skill|n levels of skill|command'> to <indirect:living>",
                   (: cmd($4[0], $1, 0) :),
      "me <string:'skill|n levels of skill|command'> from <indirect:living>",
                   (: cmd($4[0], $1, this_player()) :)});
} /* query_patterns() */