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/
/**
 * *sob* This is, to my knowledge, the 4th complete or major re-write
 * of the magic_spell object that I have done. And this time, it's
 * starting with nothing due to formatting this machine. *sigh*
 * This one better damn well work RIGHT.
 * @author Shiannar
 * @revision 10/05/04 Changed the way that consumables work a tad, to
 * get consumables working right. - Shiannar.
 */

#include <magic.h>
#include <tasks.h>
#include <effect.h>
#include <obj_parser.h>

mixed *ritual;
int gp_cost;
int time;
mapping consumed;
mapping required;
string name;
string help;
string spell_type;

/* Function Prototypes */
void real_end_spell(object, mixed *, int, int);
string query_name();
int query_time();

void create() {
  //Not initialising ritual mapping because if this inherit is ever used in
  //a spell that doesn't have a ritual mapping, it doesn't deserve to work.
  consumed = ([ ]);
  required = ([ ]);

  seteuid("Spell");
  TO->setup();
}

/** Sets the ritual array up. The ritual array is the
 * array of steps that a spell will take.
 */
void set_ritual(mixed *_ritual) {
  if(!arrayp(_ritual) || !sizeof(_ritual)) return;
  ritual = _ritual;
} /* set_ritual() */

/**
 * Returns the ritual array.
 * @see set_ritual
 */
mixed *query_ritual() {
  return ritual;
} /* query_ritual() */

/**
 * Checks to see if the spell can be cast, and if so, casts it.
 * Should never be called directly.
 */
int query_cast_spell(object caster, string arg, object *_targets, object *_using) {
  object *targets;
  mixed *args;

  /* Check to see if the caster is already casting a spell. */
  if(caster->query_casting_spell()) {
    tell_object(caster, "You are already casting a spell, you cannot "
                        "cast "+query_name()+".\n");
    return 1;
  }

  /* See if the caster can cast the spell on their chosen targets.
   * By default, spells can't be cast on anything. */
  targets = TO->check_targets(caster, _targets);
  if(!targets) return 0;

  /* Check to see if everything else has been specified right.
     check_args should be overloaded to do things. */
  args = ({ 1, targets, _using, 0, arg });
  if(!args = TO->check_args(caster, args)) {
    return 0;
  }

  /* Is there _anything_ else we should check for? */
  if(!TO->check_else(caster, args)) {
     return 1;
  }

  /* Does the caster have enough guild points? */
  if(!TASKER->point_tasker(caster, "magic",
                to_int(gp_cost * TO->scale_gp_cost(caster, args)))) {
    tell_object(caster, "You cannot summon enough magical energy to "
                        "cast "+query_name()+".\n");
    return 1;
  }

  /* For all intents and purposes, they can now start casting. */
  caster->add_effect(file_name(TO), args);
  return 1;
} /* query_cast_spell() */

/**
 * @ignore yes
 */
void beginning(object caster, mixed *args, int id) {
  mixed *targets;
  targets = args[ARG_TARGETS];
  if(!sizeof(targets)) {
    tell_object(caster, "You prepare to cast "+query_name()+".\n");
  }
  else {
    if(member_array(caster, targets) != -1) {
      targets -= ({ caster });
      targets = targets + ({ "yourself" });
    }
    tell_object(caster, "You prepare to cast "+query_name()+" on "+
      query_multiple_short(args[ARG_TARGETS])+".\n");
  }

  caster->submit_ee("spell_stage",
                    to_int(time * TO->scale_time(caster, args)),
                    EE_ONCE);
} /* beginning() */

/**
 * @ignore yes
 */
void spell_stage(object caster, mixed *args, int id) {
  object *targets;
  int difficulty;
  class task_class_result tasker_result;

  /* Make sure all targets are still agreeable according to the spell */
  targets = TO->check_targets(caster, args[ARG_TARGETS]);
  if(!targets) {
    TO->end_spell(caster, args, END_ABORT, id);
  }
  else if(sizeof(targets) < sizeof(args[ARG_TARGETS])) {
    if(!sizeof(targets)) {
      tell_object(caster, "You have lost all of your targets.\n");
      TO->end_spell(caster, args, END_ABORT, id);
    }
    if(sizeof(args[ARG_TARGETS]) - sizeof(targets) > 1) {
      tell_object(caster, "You have lost some of your targets.\n");
    }
    else {
      tell_object(caster, "You have lost one of your targets.\n");
    }
  }
  args[ARG_TARGETS] = targets;

  /* Caster has all required components? */
  if(!TO->check_components(caster, args[ARG_STAGE], args)) {
    TO->end_spell(caster, args, END_ABORT, id);
    return;
  }

  /* Check to see if the spell has anything else to do before
     attempting this stage. */
  if(function_exists("fail_stage_"+query_num(args[ARG_STAGE]), TO, 1)) {
    if(call_other(TO, "fail_stage_"+query_num(args[ARG_STAGE]), caster,
        args)) {
      TO->end_spell(caster, args, END_FAIL_HANDLED, id);
    }
    else {
//    TO->end_spell(caster, args, END_FAIL, id);
    }
  }

  /* Work out difficulty for the stage, perform stage. */
  difficulty = to_int( RITUAL_DIFF(args[ARG_STAGE]) *
               TO->scale_difficulty(caster, args) );
  tasker_result = TASKER->perform_task(caster,
                                       RITUAL_SKILL(args[ARG_STAGE]),
                                       difficulty,
                                       TM_SPELL, 1);

  switch(tasker_result->result) {
    case AWARD: {
      tell_object(caster, "%^YELLOW%^"+({
        "Your concentrated mind becomes aware of another facet of "+
        RITUAL_TM_SKILL(args[ARG_STAGE]),
        "While contemplating "+RITUAL_TM_SKILL(args[ARG_STAGE])+", you "
        "obtain a deeper understanding",
        "A more practical application of "+RITUAL_TM_SKILL(args[ARG_STAGE])+
        " suddenly becomes apparent",
        "An obscure theory relating to "+RITUAL_TM_SKILL(args[ARG_STAGE])+
        " becomes suddenly clearer"})[random(4)]+"!%^RESET%^\n");
      break;
    }
    case FAIL: {
      MAGIC_H->write_messages(caster, targets,
                              RITUAL_FAIL_MESSAGES(args[ARG_STAGE]));
      if(!function_exists("fail_stage_"+query_num(args[ARG_STAGE]), TO, 1)) {
        TO->end_spell(caster, args, END_FAIL, id);
      }
      else {
        call_other("fail_stage_"+query_num(args[ARG_STAGE]), TO);
      }
      return;
    }
  }
  MAGIC_H->write_messages(caster, targets,
                          RITUAL_MESSAGES(args[ARG_STAGE]));

  /* Update args */
  args[ARG_BONUS] += tasker_result->degree;
  args[ARG_STAGE] += 1;
  caster->set_arg_of(caster->sid_to_enum(id), args);

  if(args[ARG_STAGE] > RITUAL_STAGES) {
    TO->end_spell(caster, args, END_SUCCEED, id);
    return;
  }
  /* Submit effect event for next stage. */
  caster->submit_ee("spell_stage",
                    to_int(time * TO->scale_time(caster, args)),
                    EE_ONCE);
} /* spell_stage() */

/**
 * Checks to see if valid arguments for the spell have
 * been entered. Should be overloaded by inheriting
 * objects to perform proper checking.
 * @arg caster The person casting the spell
 * @arg args Array of arguments for the spell, accessed through the defines in magic.h
 * @return The new array of arguments, or 0 for failure due to incorrect args
 */
mixed *check_args(object caster, mixed *args) {
  return args;
} /* check_args() */

/**
 * Checks to see if the spell should fail due to any other reasons.
 * Suppresses error messages, thus custom ones must be provided
 * by inheriting objects. Should be overloaded if needed.
 * @arg caster The person casting the spell
 * @arg args Array of arguments for the spell, accessed through the defines in magic.h
 * @return 0 to halt the spell, 1 to continue
 */
int check_else(object caster, mixed *args) {
  return 1;
} /* check_else() */

/**
 * Checks to see if all targets are valid. Called once per
 * spell stage, before the spell stage takes place. Should
 * be overloaded for any targeted spells.
 * @arg caster The person casting the spell
 * @arg targets Object array of all current targets
 * @return Object array of all new targets
 */
object *check_targets(object caster, object *targets) {
  if(sizeof(targets)) {
    tell_object(caster, "You cannot cast "+query_name()+" at anything.\n");
    return 0;
  }
  return ({ });
} /* check_targets() */

/**
 * Scaling function. Overload to scale GP cost to cast a spell
 * if so desired.
 * @arg caster The person casting the spell
 * @arg args The args for the spell, see magic.h
 * @return Float percentage of GP cost, default 1.0
 */
float scale_gp_cost(object caster, mixed *args) {
  return 1.0;
} /* scale_gp_cost() */

/**
 * Scaling function. Overload to scale the time it takes to cast
 * a spell if you so desire.
 * @arg caster The person casting the spell
 * @arg args The args for the spell, see magic.h
 * @return Float percentage of normal speed, for default see code.
 */
float scale_time(object caster, mixed *args) {
  int bnus;
  int ntime;
  if(TO->query_spell_type()) {
    bnus += caster->query_skill_bonus(TO->query_spell_type());
  }
  if(bnus < 0) bnus = 0;
  switch(bnus) {
    case 400..599 : {
      ntime = 2;
      break;
    }
    case 300..399 : {
      ntime = 3;
      break;
    }
    case 200..299 : {
      ntime = 4;
      break;
    }
    case 150..199 : {
      ntime = 5;
      break;
    }
    case 100..149 : {
      ntime = 6;
      break;
    }
    case 50..99 : {
      ntime = 7;
      break;
    }
    case 20..49 : {
      ntime = 8;
      break;
    }
    case 0..19 : {
      ntime = 9;
      break;
    }
    default : {
      ntime = 1;
    }
  }
  return 1.0 + random(to_float(ntime)/2);
} /* scale_time() */

/**
 * Scaling function. Overload to scale difficulty of stages according
 * to any factors you may desire. For example, you could make a spell
 * more difficult if there are more targets.
 * @arg caster The person casting the spell
 * @arg args The spell args, see magic.h
 * @return Float percentage of difficulty, default 1.0
 */
float scale_difficulty(object caster, mixed *args) {
  return 1.0;
} /* scale_difficulty() */

/**
 * @ignore yes
 */
void end_spell(object caster, mixed *args, int end_type, int id) {
  args[ARG_STAGE] = end_type;
  caster->set_arg_of(caster->sid_to_enum(id), args);
  caster->submit_ee(0, 1, EE_REMOVE);
} /* end_spell() */

/**
 * @ignore yes
 */
void end(object caster, mixed *args, int id) {
  int bonus;
  bonus = args[ARG_BONUS] / RITUAL_STAGES;
  if(args[ARG_STAGE] == END_ABORT) {  //No, I'm not proud of this hack,
                                      //But it's the prettiest option.
    tell_object(caster, "You hastily release "+query_name()+"!\n");
    TO->spell_aborted(caster, args, bonus);
    return;
  }
  if(args[ARG_STAGE] == END_SUCCEED) {
    XP_H->handle_xp(caster, to_int(gp_cost*TO->scale_gp_cost(caster, args)), 1);
    TO->spell_succeeded(caster, args, bonus);
  }
  if(args[ARG_STAGE] == END_FAIL_HANDLED) {
    XP_H->handle_xp(caster, to_int((gp_cost*TO->scale_gp_cost(caster, args)/2)), 0);
  }
  if(args[ARG_STAGE] == END_FAIL) {
    XP_H->handle_xp(caster, to_int(gp_cost*TO->scale_gp_cost(caster, args)), 0);
    TO->spell_failed(caster, args, bonus);
  }
} /* end() */

/**
 * @return The name of the spell
 */
string query_name() {
  return name;
} /* query_name() */

/**
 * @arg nname The new name of the spell
 */
void set_name(string nname) {
  name = nname;
} /* set_name() */

/**
 * @return The raw time in seconds per spell stage, I think.
 * @see set_time, scale_time
 */
int query_time() {
  return time;
} /* query_time() */

/**
 * @arg ttime The new raw time in seconds per stage.
 * @see query_time, scale_time
 */
void set_time(int ttime) {
  time = ttime;
} /* set_time() */

/**
 * @arg gp The raw gp cost to cast the spell.
 * @see query_gp, scale_gp_cost
 */
void set_gp(int gp) {
  gp_cost = gp;
} /* set_gp() */

/**
 * @return The raw gp cost to cast the spell.
 * @see set_gp, scale_gp_cost
 */
int query_gp() {
  return gp_cost;
} /* query_gp() */

/**
 * @arg n_type String type of spell, eg "magic.spells.misc"
 * @see query_spell_type
 */
void set_spell_type(string n_type) {
  spell_type = n_type;
} /* set_spell_type() */

/**
 * @return String skill used primarily in spell.
 * @see set_spell_type
 */
string query_spell_type() {
  return spell_type;
} /* query_spell_type() */

/**
 * @arg _help The string help for the spell.
 */
void set_help(string _help) {
  help = _help;
} /* set_help() */

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


/**
 * This function sets the items consumed by the spell, and the stages they're consumed in.
 * @param cconsumed the entire mapping of items consumed in the format:
 * ([
 *   (int)stage : ({ (string)id of the first item, (string)id of the second item}),
 * ])
 */
void set_consumed(mapping cconsumed) {
  if(!mappingp(cconsumed)) return;
  consumed = cconsumed;
} /* set_consumed() */

/**
 * This function sets the items required by the spell, and the stages they're required for.
 * NB: Items that are required are not consumed! Use set_consumed for items that will
 * be consumed by the spell.
 * @param rrequired the entire mapping of items required in the format:
 * ([
 *   (int)stage : ({ (string)id of the first item, (string)id of the second item}),
 * ])
 */
void set_required(mapping rrequired) {
  if(!mappingp(rrequired)) return;
  required = rrequired;
} /* set_required() */

/**
 * @ignore yes
 */
int check_components(object caster, int stage, mixed *args) {
  object *dest;
  string *missing;
  string thing;
  class obj_match result;
  dest = ({});
  missing = ({});

  //Handle consumed items.
  if(consumed[stage] && arrayp(consumed[stage])) {
    foreach(thing in consumed[stage]) {
      result = match_objects_in_environments(thing, caster);
      if(result->result != OBJ_PARSER_SUCCESS) {
        missing += ({thing});
      }
      else {
        dest += result->objects;
      }
    }
  }

  dest->move("/room/rubbish");

  //Handle required, non-consumed items.
  if(required[stage] && arrayp(required[stage])) {
    foreach(thing in required[stage]) {
      result = match_objects_in_environments(thing, caster);
      if(result->result != OBJ_PARSER_SUCCESS) {
        missing += ({thing});
      }
    }
  }

  if(sizeof(missing)) {
    tell_object(caster, "To continue casting "+query_name()+" you require "+
      query_multiple_short(map(missing, (:add_a($1):)))+".\n");
    return 0;
  }
  return 1;
} /* check_components() */

/**
 * @ignore yes
 */
int query_is_spell() { return 1; } /* query_is_spell() */

/**
 * @ignore yes
 */
string query_classification() {
  if(!TO->query_spell_type()) {
    return "magic.spell";
  }
  return "magic.spell."+
     explode(TO->query_spell_type(), ".")[sizeof(explode(TO->query_spell_type(), "."))-1];
} /* query_classification() */

/**
 * @ignore yes
 */
string query_shadow_ob() { return "/std/shadows/magic/magic_spell"; } /* query_shadow_ob() */