skylib_mudos_v1/
skylib_mudos_v1/bin/
skylib_mudos_v1/bin/db/
skylib_mudos_v1/mudlib/banish/a/
skylib_mudos_v1/mudlib/banish/b/
skylib_mudos_v1/mudlib/banish/c/
skylib_mudos_v1/mudlib/banish/d/
skylib_mudos_v1/mudlib/banish/e/
skylib_mudos_v1/mudlib/banish/f/
skylib_mudos_v1/mudlib/banish/g/
skylib_mudos_v1/mudlib/banish/h/
skylib_mudos_v1/mudlib/banish/j/
skylib_mudos_v1/mudlib/banish/l/
skylib_mudos_v1/mudlib/banish/m/
skylib_mudos_v1/mudlib/banish/n/
skylib_mudos_v1/mudlib/banish/o/
skylib_mudos_v1/mudlib/banish/p/
skylib_mudos_v1/mudlib/banish/r/
skylib_mudos_v1/mudlib/banish/s/
skylib_mudos_v1/mudlib/banish/t/
skylib_mudos_v1/mudlib/banish/u/
skylib_mudos_v1/mudlib/banish/w/
skylib_mudos_v1/mudlib/cmds/
skylib_mudos_v1/mudlib/cmds/admin/
skylib_mudos_v1/mudlib/cmds/guild-race/
skylib_mudos_v1/mudlib/cmds/guild-race/crafts/
skylib_mudos_v1/mudlib/cmds/guild-race/magic/
skylib_mudos_v1/mudlib/cmds/guild-race/other/
skylib_mudos_v1/mudlib/cmds/living/broken/
skylib_mudos_v1/mudlib/cmds/player/group_cmds/
skylib_mudos_v1/mudlib/d/admin/
skylib_mudos_v1/mudlib/d/admin/room/
skylib_mudos_v1/mudlib/d/admin/room/we_care/
skylib_mudos_v1/mudlib/d/admin/save/
skylib_mudos_v1/mudlib/d/admin/text/
skylib_mudos_v1/mudlib/d/learning/TinyTown/buildings/
skylib_mudos_v1/mudlib/d/learning/TinyTown/map/
skylib_mudos_v1/mudlib/d/learning/TinyTown/roads/
skylib_mudos_v1/mudlib/d/learning/chars/
skylib_mudos_v1/mudlib/d/learning/functions/
skylib_mudos_v1/mudlib/d/learning/handlers/
skylib_mudos_v1/mudlib/d/learning/help_topics/
skylib_mudos_v1/mudlib/d/learning/help_topics/npcs/
skylib_mudos_v1/mudlib/d/learning/help_topics/objects/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/crowd/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/situations/
skylib_mudos_v1/mudlib/d/learning/save/
skylib_mudos_v1/mudlib/d/learning/school/
skylib_mudos_v1/mudlib/d/learning/school/add_sc/
skylib_mudos_v1/mudlib/d/learning/school/characters/
skylib_mudos_v1/mudlib/d/learning/school/general/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/basic_commands/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/edtutor/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_mudos_v1/mudlib/d/learning/school/items/
skylib_mudos_v1/mudlib/d/learning/school/npc_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/room_basic/
skylib_mudos_v1/mudlib/d/learning/school/room_school/situations/
skylib_mudos_v1/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_mudos_v1/mudlib/d/learning/text/
skylib_mudos_v1/mudlib/d/liaison/
skylib_mudos_v1/mudlib/d/mudlib/
skylib_mudos_v1/mudlib/d/mudlib/changes/
skylib_mudos_v1/mudlib/d/playtesters/
skylib_mudos_v1/mudlib/d/playtesters/effects/
skylib_mudos_v1/mudlib/d/playtesters/handlers/
skylib_mudos_v1/mudlib/d/playtesters/items/
skylib_mudos_v1/mudlib/d/sage/
skylib_mudos_v1/mudlib/doc/
skylib_mudos_v1/mudlib/doc/creator/
skylib_mudos_v1/mudlib/doc/driver/
skylib_mudos_v1/mudlib/doc/driver/efuns/arrays/
skylib_mudos_v1/mudlib/doc/driver/efuns/buffers/
skylib_mudos_v1/mudlib/doc/driver/efuns/compile/
skylib_mudos_v1/mudlib/doc/driver/efuns/filesystem/
skylib_mudos_v1/mudlib/doc/driver/efuns/floats/
skylib_mudos_v1/mudlib/doc/driver/efuns/functions/
skylib_mudos_v1/mudlib/doc/driver/efuns/general/
skylib_mudos_v1/mudlib/doc/driver/efuns/mappings/
skylib_mudos_v1/mudlib/doc/driver/efuns/mixed/
skylib_mudos_v1/mudlib/doc/driver/efuns/mudlib/
skylib_mudos_v1/mudlib/doc/driver/efuns/numbers/
skylib_mudos_v1/mudlib/doc/driver/efuns/parsing/
skylib_mudos_v1/mudlib/doc/known_command/
skylib_mudos_v1/mudlib/doc/login/
skylib_mudos_v1/mudlib/doc/lpc/basic_manual/
skylib_mudos_v1/mudlib/doc/lpc/intermediate/
skylib_mudos_v1/mudlib/doc/new/add_command/
skylib_mudos_v1/mudlib/doc/new/events/
skylib_mudos_v1/mudlib/doc/new/handlers/
skylib_mudos_v1/mudlib/doc/new/living/race/
skylib_mudos_v1/mudlib/doc/new/living/spells/
skylib_mudos_v1/mudlib/doc/new/object/
skylib_mudos_v1/mudlib/doc/new/player/
skylib_mudos_v1/mudlib/doc/new/room/guild/
skylib_mudos_v1/mudlib/doc/new/room/outside/
skylib_mudos_v1/mudlib/doc/new/room/storeroom/
skylib_mudos_v1/mudlib/doc/object/
skylib_mudos_v1/mudlib/doc/playtesters/
skylib_mudos_v1/mudlib/doc/policy/
skylib_mudos_v1/mudlib/doc/weapons/
skylib_mudos_v1/mudlib/global/
skylib_mudos_v1/mudlib/global/creator/
skylib_mudos_v1/mudlib/global/handlers/
skylib_mudos_v1/mudlib/global/virtual/setup_compiler/
skylib_mudos_v1/mudlib/include/cmds/
skylib_mudos_v1/mudlib/include/effects/
skylib_mudos_v1/mudlib/include/npc/
skylib_mudos_v1/mudlib/include/room/
skylib_mudos_v1/mudlib/include/shops/
skylib_mudos_v1/mudlib/net/daemon/
skylib_mudos_v1/mudlib/net/daemon/chars/
skylib_mudos_v1/mudlib/net/inherit/
skylib_mudos_v1/mudlib/net/obj/
skylib_mudos_v1/mudlib/obj/amulets/
skylib_mudos_v1/mudlib/obj/b_day/
skylib_mudos_v1/mudlib/obj/clothes/
skylib_mudos_v1/mudlib/obj/dwarmours/plate/
skylib_mudos_v1/mudlib/obj/dwclothes/transport/horse/
skylib_mudos_v1/mudlib/obj/dwscabbards/
skylib_mudos_v1/mudlib/obj/dwweapons/axes/
skylib_mudos_v1/mudlib/obj/dwweapons/chains/
skylib_mudos_v1/mudlib/obj/faith/symbols/
skylib_mudos_v1/mudlib/obj/fungi/
skylib_mudos_v1/mudlib/obj/gatherables/
skylib_mudos_v1/mudlib/obj/instruments/
skylib_mudos_v1/mudlib/obj/magic/
skylib_mudos_v1/mudlib/obj/media/
skylib_mudos_v1/mudlib/obj/misc/player_shop/
skylib_mudos_v1/mudlib/obj/monster/godmother/
skylib_mudos_v1/mudlib/obj/monster/transport/
skylib_mudos_v1/mudlib/obj/rings/
skylib_mudos_v1/mudlib/obj/spells/
skylib_mudos_v1/mudlib/obj/stationery/
skylib_mudos_v1/mudlib/obj/stationery/envelopes/
skylib_mudos_v1/mudlib/obj/stationery/papers/
skylib_mudos_v1/mudlib/obj/toys/
skylib_mudos_v1/mudlib/obj/vessels/
skylib_mudos_v1/mudlib/obj/weapons/swords/
skylib_mudos_v1/mudlib/save/autodoc/
skylib_mudos_v1/mudlib/save/leaflets/
skylib_mudos_v1/mudlib/save/mail/
skylib_mudos_v1/mudlib/save/new_soul/data/
skylib_mudos_v1/mudlib/save/parcels/
skylib_mudos_v1/mudlib/save/playerinfo/
skylib_mudos_v1/mudlib/save/players/d/
skylib_mudos_v1/mudlib/save/random_names/
skylib_mudos_v1/mudlib/save/random_names/data/
skylib_mudos_v1/mudlib/save/terrains/
skylib_mudos_v1/mudlib/save/terrains/tutorial_desert/
skylib_mudos_v1/mudlib/save/terrains/tutorial_grassy_field/
skylib_mudos_v1/mudlib/save/terrains/tutorial_mountain/
skylib_mudos_v1/mudlib/save/todo_lists/
skylib_mudos_v1/mudlib/secure/
skylib_mudos_v1/mudlib/secure/cmds/admin/
skylib_mudos_v1/mudlib/secure/cmds/lord/
skylib_mudos_v1/mudlib/secure/config/
skylib_mudos_v1/mudlib/secure/handlers/autodoc/
skylib_mudos_v1/mudlib/secure/handlers/intermud/
skylib_mudos_v1/mudlib/secure/include/global/
skylib_mudos_v1/mudlib/secure/save/
skylib_mudos_v1/mudlib/secure/save/handlers/
skylib_mudos_v1/mudlib/secure/std/classes/
skylib_mudos_v1/mudlib/secure/std/modules/
skylib_mudos_v1/mudlib/std/commands/
skylib_mudos_v1/mudlib/std/commands/shadows/
skylib_mudos_v1/mudlib/std/creator/
skylib_mudos_v1/mudlib/std/dom/
skylib_mudos_v1/mudlib/std/effects/
skylib_mudos_v1/mudlib/std/effects/external/
skylib_mudos_v1/mudlib/std/effects/fighting/
skylib_mudos_v1/mudlib/std/effects/priest/
skylib_mudos_v1/mudlib/std/effects/room/
skylib_mudos_v1/mudlib/std/environ/
skylib_mudos_v1/mudlib/std/guilds/
skylib_mudos_v1/mudlib/std/guilds/old/
skylib_mudos_v1/mudlib/std/languages/
skylib_mudos_v1/mudlib/std/languages/BACKUPS/
skylib_mudos_v1/mudlib/std/liquids/
skylib_mudos_v1/mudlib/std/npc/
skylib_mudos_v1/mudlib/std/npc/goals/
skylib_mudos_v1/mudlib/std/npc/goals/basic/
skylib_mudos_v1/mudlib/std/npc/goals/misc/
skylib_mudos_v1/mudlib/std/npc/plans/
skylib_mudos_v1/mudlib/std/npc/plans/basic/
skylib_mudos_v1/mudlib/std/npc/types/
skylib_mudos_v1/mudlib/std/npc/types/helper/
skylib_mudos_v1/mudlib/std/npcs/
skylib_mudos_v1/mudlib/std/outsides/
skylib_mudos_v1/mudlib/std/races/shadows/
skylib_mudos_v1/mudlib/std/room/basic/topography/
skylib_mudos_v1/mudlib/std/room/controller/
skylib_mudos_v1/mudlib/std/room/inherit/topography/
skylib_mudos_v1/mudlib/std/room/topography/area/
skylib_mudos_v1/mudlib/std/room/topography/iroom/
skylib_mudos_v1/mudlib/std/room/topography/milestone/
skylib_mudos_v1/mudlib/std/shadows/curses/
skylib_mudos_v1/mudlib/std/shadows/disease/
skylib_mudos_v1/mudlib/std/shadows/fighting/
skylib_mudos_v1/mudlib/std/shadows/healing/
skylib_mudos_v1/mudlib/std/shadows/magic/
skylib_mudos_v1/mudlib/std/shadows/poison/
skylib_mudos_v1/mudlib/std/shadows/rituals/
skylib_mudos_v1/mudlib/std/shadows/room/
skylib_mudos_v1/mudlib/std/shops/controllers/
skylib_mudos_v1/mudlib/std/shops/objs/
skylib_mudos_v1/mudlib/std/shops/player_shop/
skylib_mudos_v1/mudlib/std/socket/
skylib_mudos_v1/mudlib/std/soul/
skylib_mudos_v1/mudlib/std/soul/d/
skylib_mudos_v1/mudlib/std/soul/e/
skylib_mudos_v1/mudlib/std/soul/i/
skylib_mudos_v1/mudlib/std/soul/j/
skylib_mudos_v1/mudlib/std/soul/k/
skylib_mudos_v1/mudlib/std/soul/l/
skylib_mudos_v1/mudlib/std/soul/n/
skylib_mudos_v1/mudlib/std/soul/o/
skylib_mudos_v1/mudlib/std/soul/q/
skylib_mudos_v1/mudlib/std/soul/u/
skylib_mudos_v1/mudlib/std/soul/v/
skylib_mudos_v1/mudlib/std/soul/y/
skylib_mudos_v1/mudlib/std/soul/z/
skylib_mudos_v1/mudlib/std/stationery/
skylib_mudos_v1/mudlib/w/
skylib_mudos_v1/mudlib/w/default/
skylib_mudos_v1/mudlib/w/default/armour/
skylib_mudos_v1/mudlib/w/default/clothes/
skylib_mudos_v1/mudlib/w/default/item/
skylib_mudos_v1/mudlib/w/default/npc/
skylib_mudos_v1/mudlib/w/default/room/
skylib_mudos_v1/mudlib/w/default/weapon/
skylib_mudos_v1/mudlib/www/
skylib_mudos_v1/mudlib/www/download/
skylib_mudos_v1/mudlib/www/java/
skylib_mudos_v1/mudlib/www/secure/
skylib_mudos_v1/mudlib/www/secure/lpc/advanced/
skylib_mudos_v1/mudlib/www/secure/lpc/intermediate/
skylib_mudos_v1/v22.2b14-DSv10/
skylib_mudos_v1/v22.2b14-DSv10/ChangeLog.old/
skylib_mudos_v1/v22.2b14-DSv10/Win32/
skylib_mudos_v1/v22.2b14-DSv10/compat/
skylib_mudos_v1/v22.2b14-DSv10/compat/simuls/
skylib_mudos_v1/v22.2b14-DSv10/include/
skylib_mudos_v1/v22.2b14-DSv10/mudlib/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/clone/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/command/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/data/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/etc/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/include/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/master/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/log/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/compiler/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/efuns/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/operators/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/u/
skylib_mudos_v1/v22.2b14-DSv10/tmp/
skylib_mudos_v1/v22.2b14-DSv10/windows/
/**
 * This is the basic ritual effect, it does all
 * the checks for targets etc. at each ritual stage,
 * and prints the messages.
 * Original by Pinkfish for the wizard's guild.
 * Rewritten by Deutha for the new magic (wizards and witches) skill tree.
 * Rewritten by Olorin for the priests rituals
 * Stats based resistance added by Sandoz
 * Skills based resistance added by Sandoz
 * Alignment bonus added by Sandoz
 */

#include "skillgroups.h"
#include <deity.h>
#include <effect.h>
#include <tasks.h>

#define NUMBER sizeof( ritual[ stage ] ) - 1

int fixed_time,
    learn_lvl,
    gp_cost,
    power_level,
    pk_checked,
    directed,
    silent,       /* not influenced by silence */
    casting_time, /* average time in seconds between each part of the ritual */
    *resist;
string name,
       info,
       ritual_type,
       skill_used,
       resistance_skill,
       resistance_stat,
       all_needed,
       *sym_needed,
       *sym_consumed,
       *consumables,
       *needed;
mixed *ritual;

int query_fixed_time() { return fixed_time; }
void set_fixed_time( int number ) { fixed_time = number; }

int query_learn_lvl() { return learn_lvl; }
void set_learn_lvl( int number ) { learn_lvl = number; }

int query_silent() { return silent; }
void set_silent( int number ) { silent = number; }

int query_pk_checked() { return pk_checked; }
void set_pk_checked( int number ) { pk_checked = number; }

int query_gp_cost( object caster, object *targets ) { return gp_cost; }
void set_gp_cost( int number ) { gp_cost = number; }

int query_power_level( object caster, object *targets ) { return power_level; }
void set_power_level( int number ) { power_level = number; }

int query_directed() { return directed; }
void set_directed( int number ) { directed = number; }

int query_no_move() { return ( directed & NO_MOVE ); }

int query_casting_time() { return casting_time; }
void set_casting_time( int number ) { casting_time = number; }

int *query_resist() { return resist; }
void set_resist( int *numbers ) { resist = numbers; }

string query_name() { return name; }
void set_name( string word ) { name = word; }

string query_info() { return info; }
void set_info( string word ) { info = word; }

string query_ritual_type() { return ritual_type; }
void set_ritual_type( string word ) { ritual_type = word; }

string query_skill_used() { return skill_used; }
void set_skill_used( string word ) { skill_used = word; }

string query_resistance_skill() { return resistance_skill; }
void set_resistance_skill( string word ) { resistance_skill = word; }

string query_resistance_stat() { return resistance_stat; }
void set_resistance_stat( string word ) { resistance_stat = word; }

string *query_consumables() { return consumables; }
void set_consumables( string *words ) { consumables = words; }

string *query_needed() { return needed; }
void set_needed( string *words ) { needed = words; }

string query_all_needed() { return all_needed; }
void set_all_needed( string words ) { all_needed = words; }

string *query_symbols() { return sym_needed; }
void set_symbols( string *words ) { sym_needed = words; }

string *query_symbols_consumed() { return sym_consumed; }
void set_symbols_consumed( string *words ) { sym_consumed = words; }

mixed *query_ritual() { return ritual; }
void set_ritual( mixed *args ) { ritual = args; }

/*
 * directed:     +1 for non-living, +2 for living, +4 for self, +8 for multiple
 * casting_time: average time in seconds between stages of casting
 * skill_used:   skill for powering outcome
 * resist:       ({ div, normal, player, agressive })
 */

/* example of ritual array:
 * ({
 *    ({ [first part]
 *       ({ [first possibility]
 *          message to caster when caster is a target,
 *          message to caster when caster is not a target,
 *          message to room excluding all targets and caster,
 *          message to targets excluding caster,
 *       }),
 *       ({ [other possibilities...]
 *          etc.
 *       }),
 *    }),
 *    ({ [other parts]
 *       etc.
 *    })
 * })
 */

/** @ignore yes */
void create() {
    ritual = ({ });
    needed = ({ });
    consumables = ({ });
    sym_needed = ({ });
    sym_consumed = ({ });
    fixed_time = 1;
    seteuid("Ritual");
    TO->setup();
} /* create() */

/** @ignore yes */
int check_components( object caster ) {
    object item;

    foreach( item in consumables )
      if( !present( item, caster ) )
          return 0;

    foreach( item in needed )
      if( !present( item, caster ) )
          return 0;

    return 1;

} /* check_components() */

/** @ignore yes */
int check_symbols( object caster, string *symbols ) {
    object *inv;
    string deity, sym;

    if( sizeof( symbols ) ) {
        deity = (string)caster->query_deity();
        // All the holy stuff the player has.
        inv = filter( INV(caster), (: $1->query_property( $2 ) :), deity );
        if( !sizeof( inv ) )
            return 0;
        foreach( sym in symbols ) {
            if( sym[0] == '#' ) {
                if( !call_other( TO, sym[1..], caster ) )
                    return 0;
                continue;
            }
            if( !sizeof( filter( inv, (: $1->query_property($2) :), sym ) ) )
                return 0;
        }
    }

    return 1;

} /* check_symbols() */

/** @ignore yes */
string get_actual_skill( object caster, object *targets, string base ) {

    if( undefinedp( SKILLGROUP[ base ] ) )
        return ( base );

    if( !sizeof( targets ) )
        return ( base );

    if( sizeof( targets ) > 1 )
        return base + ( member_array( "area", SKILLGROUP[ base ] ) == -1 ?
                        "" : ".area" );

    if( targets[ 0 ] == caster )
        return base + ( member_array( "self", SKILLGROUP[ base ] ) == -1 ?
                        "" : ".self" );

    if( member_array( "target", SKILLGROUP[ base ] ) != -1 )
        return base + ".target";

    return ( base );

} /* get_actual_skill */

/**
 * This method will return a filtered array of valid targets.
 * It will print a message to the caster if a particular
 * target is invalid.
 * @param caster the caster
 * @param targets the targets to test
 * @param words the string arguments passed into the ritual
 * @return the array of valid targets if any, or 0 if there are none
 */
varargs object *check_target( object caster, object *targets, string words ) {
    object *pk_prevented, target;

    targets = filter( targets, (: ENV($1) == ENV($2) ||
                                  ENV($1) == $2 :), caster );

    if( directed ) {
        if( directed & NOTARGET )
            return ({ });

        if( !sizeof( targets ) ) {
            tell_object( caster, ( !words || words == "" ?
                "You can only perform "+name+" at or on something." :
                "There is no "+words+" to perform "+name+" on." )+"\n");
            return 0;
        }

        if( !( directed & MULTIPLE ) && sizeof( targets ) > 1 ) {
            tell_object( caster, "You cannot perform "+name+" on multiple "
                                 "targets.\n");
            return 0;
        }

        if( !( directed & SELF ) ) {
            if( member_array( caster, targets ) != -1 ) {
                tell_object( caster, "You cannot perform "+name+" on "
                    "yourself.\n");
                return 0;
            }
        }

        if( !( directed & LIVING ) ) {
            foreach( target in targets )
              if( living( target ) ) {
                  tell_object( caster, "You cannot perform "+name+" on "
                      "living targets.\n" );
                  return 0;
              }
        }

        if( !( directed & NONLIVING ) )
            foreach( target in targets ) {
              if( !living( target ) ) {
                  tell_object( caster, "You cannot perform "+name+" on "
                      "non-living targets.\n" );
                  return 0;
              }
              if( userp( target ) && !interactive( target ) ) {
                  tell_object( caster, "You cannot perform "+name+" on "
                      "net-dead players.\n" );
                  return 0;
              }
        }

        if( !( directed & GHOST ) ) {
            targets = filter( targets, (: !$1->query_property("dead") :),
                caster );
            if( !sizeof( targets ) ) {
                tell_object( caster, "You cannot perform "+name+" on "
                    "ghosts.\n");
                return 0;
            }
        }

        if( directed & CHECKED ) {
            targets = filter( targets, (: TO->ritual_check_target( $2, $1 ) :),
                              caster );
            if( !sizeof( targets ) )
                return 0;
        }

        if( pk_checked ) {
            pk_prevented = filter( targets, (: pk_check( $1, $2 ) :), caster );
            pk_prevented -= ({ caster });
            targets -= pk_prevented;
            if( sizeof( pk_prevented ) )
                tell_object( caster, "Something prevents you from affecting "+
                    query_multiple_short( pk_prevented ) + ".\n" );
            if( !sizeof( targets ) )
                return 0;
        }
    }

    return targets;

} /* check_target() */

/**
 * This method is called upon by the cast command,
 * and it will initiate the performing of the ritual.
 * @param args the string arguments passed into the ritual
 * @param targets the targets to perform the ritual on
 * @param using the components to use (currently not used)
 */
int cast_spell( string args, object *targets, object *using ) {
    int time;
    object *things, caster;
    string deity;

    caster = TP;
    deity = (string)caster->query_deity();

    if( !deity || deity == "" )
        return notify_fail( "%^RED%^You have no deity!%^RESET%^\n"
                            "Please bugreport where you got this ritual.\n" );

    if( !DEITY_H->query_deity( deity ) )
        return notify_fail( "%^RED%^Your deity is invalid!%^RESET%^\n"
                            "Please contact a creator immediately.\n" );

    if( caster->query_casting_ritual() )
        return notify_fail( "You are already performing a ritual!\n");

    if( caster->query_casting_spell() )
        return notify_fail( "You cannot perform "+name+" while casting a "+
                            "spell!\n");

    if( !silent && caster->query_silenced() )
        return notify_fail( "You cannot perform "+name+" ritual when you "
                            "are silenced!\n");

    if( directed && !( directed & NOTARGET ) ) {
        sscanf( args, "at %s", args );
        sscanf( args, "on %s", args );
        if( !things = check_target( caster, targets, args ) )
            return 1;
        time = 2 * sizeof( things ) - 1;
    } else {
        time = 1;
        things = ({ });
    }

    if( !check_components( caster ) || !check_symbols( caster, sym_needed ) ||
        !check_symbols( caster, sym_consumed ) )
        return notify_fail("You need "+add_a( all_needed ? all_needed :
            query_multiple_short( needed+consumables+sym_needed+sym_consumed ) )+
            " to perform "+name+".\n");

    if( (int)DEITY_H->query_valid_al( deity, (int)caster->query_al() ) == -1 )
        return notify_fail( "It seems you are of too good alignment "
                            "for "+ CAP( deity )+" to perform "+name+".\n");

    if( (int)DEITY_H->query_valid_al( deity, (int)caster->query_al() ) == 1 )
        return notify_fail( "It seems you are of too evil alignment "
                            "for "+ CAP( deity )+" to perform "+name+".\n");

    if( !TASKER->point_tasker( caster, "faith", time * gp_cost ) )
        return notify_fail( "You do not have enough spiritual strength to "
                            "perform "+name+".\n");

    caster->dest_hide_shadow();

    time = casting_time * ( fixed_time ? 1 : time );

    caster->add_effect( file_name(TO), ({ 0, time, things, 0 }) );

    return 1;

} /* cast_spell() */

/** @ignore yes */
int consume_components( object caster ) {
    object *things, thing;

    if( sizeof( consumables ) ) {
        things = ({ });
        foreach( string item in consumables ) {
            if( !thing = present( item, caster ) ) {
                tell_object( caster, "You seem to have misplaced "+item+"!\n");
                return 0;
            }
            things += ({ thing });
        }
    }

    if( sizeof( things ) )
        things->dest_me();

    return 1;

} /* consume_components() */

/** @ignore yes */
int consume_symbols( object caster ) {
    string deity, symbol;
    object *things, *inv, *tmp;

    if( !sizeof( sym_consumed ) )
        return 1;

    deity = (string)caster->query_deity();

    /* all the holy stuff the player has */
    inv = filter( INV(caster), (: $1->query_property($2) :), deity );
    if( !sizeof( inv ) ) {
        tell_object( caster, "You seem to have misplaced some of the "
            "components needed to perform "+name+"!\n");
        return 0;
    }

    things = ({ });

    foreach( symbol in sym_consumed ) {
        if( symbol[0..0] == "#" ) {
            // not desting the special stuff here.
            // will do it from ritual_succeeded instead.
            if( !call_other( TO, symbol[1..99], caster ) ) {
                tell_object( caster, "You seem to have misplaced some of "
                    "the components needed to perform "+name+"!\n");
                return 0;
            }
            continue;
        }

        tmp = filter( inv, (: $1->query_property($2) :), symbol );

        if( !sizeof( tmp ) ) {
            tell_object( caster, "You seem to have misplaced some of the "
                "components needed to perform "+name+"!\n");
            return 0;
        }

        things += ({ tmp[0] });

    }

    if( sizeof( things ) )
        things->dest_me();

    return 1;

} /* consume_symbols() */

string expand_ritual_message( string message, object caster, object *things,
                              int to_whom ) {
    object target;
    mixed stuff;
    string ob_name, ob_poss, ob_pron, ob_obje;
    string part1, verb, part2, deity, deity_poss;

    // to_whom is -2 for caster, -1 for room and 0, 1, ... for targets
    if( member_array( caster, things ) != -1 ) {
        switch( to_whom ) {
          case -2 :
            ob_name = query_multiple_short( things - ({ caster }) +
                  ({ "yourself" }), "the" );
            switch( sizeof( things ) ) {
              case 1 :
                ob_poss = "your";
                ob_pron = "you";
                ob_obje = "yourself";
              break;
              case 2 :
                target = ( things - ({ caster }) )[ 0 ];
                ob_poss = (string)target->HIS+" and your";
                ob_pron = (string)target->HE+" and you";
                ob_obje = (string)target->HIM+" and yourself";
              break;
              default :
                ob_poss = "their and your";
                ob_pron = "they and you";
                ob_obje = "them and yourself";
            }
          break;
          case -1 :
            stuff = ({ (string)caster->HIM+"self" });
            stuff += things - ({ caster });
            ob_name = query_multiple_short( stuff, "one" );
            if( sizeof( things ) > 2 ) {
                ob_poss = "their";
                ob_pron = "they";
                ob_obje = "them";
            } else {
                ob_poss = (string)caster->HIS;
                ob_pron = (string)caster->HE;
                ob_obje = (string)caster->HIM;
            }
          break;
          default :
            stuff = ({ (string)caster->HIM+"self" });
            stuff += delete( things, to_whom, 1 ) - ({ caster });
            stuff += ({ "you" });
            ob_name = query_multiple_short( stuff, "one" );
            switch( sizeof( things ) ) {
              case 1 :
                ob_poss = "your";
                ob_pron = "you";
                ob_obje = "yourself";
              break;
              case 2 :
                ob_poss = (string)caster->HIS+" and your";
                ob_pron = (string)caster->HE+" and you";
                ob_obje = (string)caster->HIM+" and yourself";
              break;
              default :
                ob_poss = "their and your";
                ob_pron = "they and you";
                ob_obje = "them and yourself";
            }
        }
    } else {
        switch( to_whom ) {
          case -2 :
            if( !sizeof( things ) )
                break;
            ob_name = query_multiple_short( things, "the" );
            if( sizeof( things ) > 2 ) {
                ob_poss = "their";
                ob_pron = "they";
                ob_obje = "them";
            } else {
                ob_poss = (string)things[ 0 ]->HIS;
                ob_pron = (string)things[ 0 ]->HE;
                ob_obje = (string)things[ 0 ]->HIM;
            }
          break;
          case -1 :
            if( !sizeof( things ) )
                break;
            ob_name = query_multiple_short( things, "one" );
            if( sizeof( things ) > 2 ) {
                ob_poss = "their";
                ob_pron = "they";
                ob_obje = "them";
            } else {
                ob_poss = (string)things[ 0 ]->HIS;
                ob_pron = (string)things[ 0 ]->HE;
                ob_obje = (string)things[ 0 ]->HIM;
            }
          break;
          default :
            if( !sizeof( things ) )
                break;
            ob_name = query_multiple_short( delete( things, to_whom, 1 ) +
                                            ({ "you" }), "one" );
            switch( sizeof( things ) ) {
              case 1 :
                ob_poss = "your";
                ob_pron = "you";
                ob_obje = "yourself";
              break;
              case 2 :
                target = delete( things, to_whom, 1 )[ 0 ];
                ob_poss = (string)target->HIS+" and your";
                ob_pron = (string)target->HE+" and you";
                ob_obje = (string)target->HIM+" and yourself";
              break;
              default :
                ob_poss = "their and your";
                ob_pron = "they and you";
                ob_obje = "them and yourself";
            }
        }
    }

    if( deity = (string)caster->query_deity() )
        deity_poss = DEITY_H->query_possessive( deity );

    if( caster )
        message = replace( message, ({
          "$tp_name$", (string)caster->one_short(),
          "$tp_poss$", (string)caster->HIS,
          "$tp_pron$", (string)caster->HE,
          "$tp_obje$", (string)caster->HIM,
          }) );

    stuff = "";

    while( sscanf( message, "%s %s$s%s", part1, verb, part2 ) == 3 ) {
        stuff += part1+" $V$0="+pluralize( verb )+","+verb+"$V$";
        message = part2;
    }

    stuff += message;

    return CAP( replace( stuff, ({
           "$ob_name$", ob_name,
           "$ob_poss$", ob_poss,
           "$ob_pron$", ob_pron,
           "$ob_obje$", ob_obje,
           "$god_poss$", deity_poss,
           "$god$", deity,
           "$r_name$", name }) ) );

} /* expand_ritual_message() */

/** @ignore yes */
void beginning( object caster, mixed *args, int id ) {
    caster->submit_ee("ritual_stage", 0, EE_ONCE );
} /* beginning() */

void ritual_stage( object caster, mixed *args, int id ) {
    int i, amount, stage, time;
    string message, *messages;
    object *things;

    stage = args[ 0 ];
    time = args[ 1 ];
    things = args[ 2 ];

    if( caster->query_property( "dead" ) ) {
        caster->submit_ee( 0, time, EE_REMOVE );
        return;
    }

#ifdef DEBUG
    tell_creator("sandoz", "Args[0] (stage) : %O\nArgs[1] (time) : %O\n"
                           "Args[2] (things) : %O\nArgs[3] : %O\n",
                            args[0], args[1], args[2], args[3] );
#endif

    if( !check_components( caster ) || !check_symbols( caster, sym_needed ) ||
        !check_symbols( caster, sym_consumed ) ) {
        tell_object( caster, "You seem to have misplaced some of the things "
            "needed to perform "+name+".  You need "+add_a( all_needed ?
            all_needed : query_multiple_short( needed+consumables+sym_needed+
            sym_consumed ) )+".\n");
        caster->set_arg_of( (int)caster->sid_to_enum( id ),
            ({ -1 - stage, time, ({ }), args[ 3 ] }) );
        caster->submit_ee( 0, 0, EE_REMOVE );
        return;
    }

    if( amount = sizeof( things ) ) {
        things = filter( things, (: $1 && ENV($1) == $2 || ENV($1) == $3 :),
            caster, ENV(caster) );
        if( !sizeof( things ) ) {
            tell_object( caster, "You seem to have lost "+ ( amount > 1 ?
                "all of your targets" : "your target" ) +"!\n");
            caster->set_arg_of( (int)caster->sid_to_enum( id ),
                ({ -1 - stage, time, ({ }), args[ 3 ] }) );
            caster->submit_ee( 0, 0, EE_REMOVE );
            return;
        }
        switch( amount - sizeof( things ) ) {
          case 0 :
          break;
          case 1 :
            tell_object( caster, "You seem to have lost one of your "+
                "targets!\n" );
          break;
          default :
            tell_object( caster, "You seem to have lost some of your "+
                "targets!\n" );
        }
    }

    if( amount = sizeof( things ) ) {
        if( !( directed & GHOST ) ) {
            things = filter( things, (: !$1->query_property("dead") :) );
            if( !sizeof( things ) ) {
                tell_object( caster, ( amount > 1 ? "All of your targets seem" :
                    "Your target seems")+" to have died!\n");
                caster->set_arg_of( (int)caster->sid_to_enum( id ),
                    ({ -1 - stage, time, ({ }), args[ 3 ] }) );
                caster->submit_ee( 0, 0, EE_REMOVE );
                return;
            }
            switch( amount - sizeof( things ) ) {
              case 0 :
              break;
              case 1 :
                tell_object( caster, "One of your targets seems to have "
                    "died!\n");
              break;
              default :
                tell_object( caster, "Some of your targets seem to have "
                    "died!\n");
            }
        } else {
            things = filter( things, (: $1->query_property("dead") :) );
            if( !sizeof( things ) ) {
                tell_object( caster, ( amount > 1 ?
                    "All of your targets seem" : "Your target seems")+" to "
                    "have come to life!\n");
                caster->set_arg_of( (int)caster->sid_to_enum( id ),
                    ({ -1 - stage, time, ({ }), args[ 3 ] }) );
                caster->submit_ee( 0, 0, EE_REMOVE );
                return;
            }
            switch( amount - sizeof( things ) ) {
              case 0 :
              break;
              case 1 :
                tell_object( caster, "One of your targets seems to have "
                    "come to life!\n");
              break;
              default :
                tell_object( caster, "Some of your targets seem to have "
                    "come to life!\n");
            }
        }
    }

    messages = ritual[ stage ][ random( NUMBER ) ];

    tell_object( caster, expand_ritual_message(
        messages[ ( member_array( caster, things ) == -1 ) ],
        caster, things, -2 ) );

    tell_room( ENV( caster ), expand_ritual_message( messages[ 2 ],
        caster, things, -1 ), things + ({ caster }) );

    message = messages[ 3 ];

    for( i = 0; i < sizeof( things ); i++ )
      if( things[ i ] != caster )
          tell_object( things[ i ], expand_ritual_message( message,
                caster, things, i ) );

    stage++;

    caster->set_arg_of( (int)caster->sid_to_enum( id ),
          ({ stage, time, things, amount }) );

    if( stage == sizeof( ritual ) )
        caster->submit_ee( 0, time, EE_REMOVE );
    else
        caster->submit_ee( "ritual_stage",
                ({ time / 2, ( 3 * time ) / 2 }), EE_ONCE );

} /* ritual_stage() */

/** @ignore yes */
void end( object caster, mixed *args, int id ) {
    int bonus, resistance, al_range, al_offset, al_bonus, difficulty, tmp;
    object *things, thing;
    string actual_skill, *skills, deity;

    class task_class_result tasker_result;

    things = args[ 2 ];

    actual_skill = get_actual_skill( caster, things, skill_used );
    bonus = (int)caster->query_skill_bonus( actual_skill );

    if( caster->query_property("dead") ) {
        TO->ritual_aborted( caster, things, bonus, args[0] );
        return;
    }

    deity = (string)caster->query_deity();

    if( tmp = sizeof( things ) ) {
        things = filter( things, (: $1 && ENV($1) == $2 || ENV($1) == $3 :),
            caster, ENV(caster) );
        if( args[0] > -1 ) {
            if( !sizeof( things ) ) {
                tell_object( caster, "You seem to have lost "+( tmp > 1 ?
                    "all of your targets" : "your target")+"!\n");
                args[0] = -1 - args[0];
            } else {
                switch( tmp - sizeof( things ) ) {
                  case 0 :
                  break;
                  case 1 :
                    tell_object( caster, "You seem to have lost one of your "
                        "targets!\n" );
                  break;
                  default :
                    tell_object( caster, "You seem to have lost some of your "
                        "targets!\n" );
                }
            }
        }
    }

    if( tmp = sizeof( things ) ) {
        if( !( directed & GHOST ) ) {
            things = filter( things, (: !$1->query_property("dead") :) );
            if( args[0] > -1 ) {
                if( !sizeof( things ) ) {
                    tell_object( caster, ( tmp > 1 ? "All of your targets seem" :
                        "Your target seems")+" to have died!\n");
                    args[0] = -1 - args[0];
                } else {
                    switch( tmp - sizeof( things ) ) {
                      case 0 :
                      break;
                      case 1 :
                        tell_object( caster, "One of your targets seems to "
                            "have died!\n");
                      break;
                      default :
                        tell_object( caster, "Some of your targets seem to "
                            "have died!\n");
                    }
                }
            }
        } else {
            things = filter( things, (: $1->query_property("dead") :) );
            if( args[0] > -1 ) {
                if( !sizeof( things ) ) {
                    tell_object( caster, ( tmp > 1 ? "All of your targets "
                        "seem" : "Your target seems")+" to have come to "
                        "life!\n");
                    args[0] = -1 - args[0];
                } else {
                    switch( tmp - sizeof( things ) ) {
                      case 0 :
                      break;
                      case 1 :
                        tell_object( caster, "One of your targets seems to "
                            "have come to life!\n");
                      break;
                      default :
                        tell_object( caster, "Some of your targets seem to "
                            "have come to life!\n");
                    }
                }
            }
        }
    }

    // This will handle the stop command.
    if( !args[ 0 ] )
        args[ 0 ] = -1;

    if( args[ 0 ] < 0 ) {
        args[ 0 ] = -1 - args[ 0 ];
        TO->ritual_aborted( caster, things, bonus, args[ 0 ] );
        return;
    }

    if( !check_components( caster ) ) {
        tell_object( caster, "You seem to have misplaced some of the things "
            "needed to perform "+name+".  You need "+add_a( all_needed ?
            all_needed : query_multiple_short( needed+consumables+sym_needed+
            sym_consumed ) )+".\n");
        return;
    }

    // Consume consumables.
    if( !consume_symbols( caster ) || !consume_components( caster ) )
        return;

    /*
     * Here the alignment bonus calculation starts.
     * It checks the preferred alignment and the total
     * alignment range for a particular god.
     */
    /* The range between maximum and minimum alignment of a god. */
    al_range = ABS( ( DEITY_H->query_al_lower( deity ) -
                      DEITY_H->query_al_upper( deity ) ) );
    al_offset = ( (int)caster->query_al() -
                  DEITY_H->query_al_middle( deity ) ) / ( al_range / 120 );

    /* This calculates the bonus (or as it may be, penalty) to add to
     * the difficulty of the ritual.
     * -30 if the caster if out of alignment.
     * +30 if the caster is in the preferred alignment.
     */
    al_bonus = 30 - ABS(al_offset);
    difficulty = power_level - al_bonus;

    if( difficulty < 5 )
        difficulty = 5;

    tasker_result = new(class task_class_result);
    tasker_result = TASKER->perform_task( caster, actual_skill,
                                          difficulty, TM_RITUAL, 1 );

    switch( tasker_result->result ) {
      case AWARD :
        skills = explode( actual_skill, "." );
        tell_object( caster, "%^YELLOW%^"+({
            "You realise something new about "+GRPDESC[skills[2]]+
            ( living( things[0] ) ? TRGTDESC[skills[3]][0] :
            TRGTDESC[skills[3]][1] )+".",
            "You find yourself more capable of "+GRPDESC[skills[2]]+
            ( living( things[0] ) ? TRGTDESC[skills[3]][0] :
            TRGTDESC[skills[3]][1] )+".",
            "You feel stronger in the art of "+GRPDESC[skills[2]]+
            ( living( things[0] ) ? TRGTDESC[skills[3]][0] :
            TRGTDESC[skills[3]][1] )+".",
            })[random(2)]+ "\n%^RESET%^");
      case SUCCEED :
        /* ritual cast successfully, now calculate resistance */
        if( !resist ) {
            XP_H->handle_xp( caster, gp_cost, 1 );
            TO->ritual_succeeded( caster, things, bonus );
        } else {
            foreach( thing in things ) {
              /* stats based resistance */
              if( resistance_stat ) {
                  switch( resistance_stat ) {
                    case "con":
                      resistance += ( 4 + random( 4 ) +
                                    (int)thing->query_con() ) * 4;
                    break;
                    case "str":
                      resistance += ( 4 + random( 4 ) +
                                    (int)thing->query_str() ) * 4;
                    break;
                    case "dex":
                      resistance += ( 4 + random( 4 ) +
                                    (int)thing->query_dex() ) * 4;
                    break;
                    case "int":
                      resistance += ( 4 + random( 4 ) +
                                    (int)thing->query_int() ) * 4;
                    break;
                    case "wis":
                      resistance += ( 4 + random( 4 ) +
                                    (int)thing->query_wis() ) * 4;
                    break;
                    default:
                  }
              }
              /* skill based resistance */
              if( resistance_skill ) {
                  resistance +=
                      (int)thing->query_skill_bonus( resistance_skill ) /
                      resist[ 0 ];
              } else {
                  /* level based resistance */
                  if( userp( thing ) ) {
                      resistance += (int)thing->query_level() *
                          resist[ 2 ] / resist[ 0 ];
                  } else {
                      resistance += (int)thing->query_level() *
                          resist[ 1 + 2 * thing->query_aggressive() ] /
                          resist[ 0 ];
                  }
              }
          }

          resistance -= al_bonus;

          tasker_result = new( class task_class_result );
          tasker_result = TASKER->perform_task( caster, actual_skill,
                                                resistance, TM_RITUAL, 1 );

          switch( tasker_result->result ) {
            case BARF :
            break;
            case AWARD :
              skills = explode( actual_skill, "." );
              tell_object( caster, "%^YELLOW%^"+({
                  "You realise something new about breaking through "+
                  "people's resistance against "+GRPDESC[ skills[ 2 ] ]+
                  "them.",
                  "You find yourself more capable of breaking through "
                  "people's resistance against "+GRPDESC[ skills[ 2 ] ]+
                  "them.",
                  "You feel stronger in the art of breaking through "
                  "people's resistance against "+GRPDESC[ skills[ 2 ] ]+
                  "them."})[random(2)]+"\n%^RESET%^");

            case SUCCEED :
              XP_H->handle_xp( caster, gp_cost, 1 );
              TO->ritual_succeeded( caster, things, bonus );
            break;
            default :
              XP_H->handle_xp( caster, gp_cost, 0 );
              TO->ritual_resisted( caster, things, bonus );
          }
        }
      break;
      default :
        XP_H->handle_xp( caster, gp_cost, 0 );
        TO->ritual_failed( caster, things, bonus );
    }
} /* end() */

void ritual_aborted( object caster, object *targets, int bonus, int stage ) {
    tell_object( caster, (string)caster->query_deity()+" loses "
        "interest in your unfinished ritual.\n" );
} /* ritual_aborted() */

void ritual_failed( object caster, object *targets, int bonus ) {
    tell_object( caster, "You get the impression that "+
        (string)caster->query_deity()+" ignores your feeble attempts.\n" );
} /* ritual_failed() */

void ritual_resisted( object caster, object *targets, int bonus ) {
    /* default resisted ritual message */
    tell_object( caster, "Your target"+( sizeof(targets) > 1 ? "s" : "" )+
        " resisted the ritual.\n");
} /* ritual_resisted() */

string help() {
    return( replace( info, ({ "$name$", query_name() }) ) );
} /* help() */

/** @ignore yes */
string query_classification() { return "faith.ritual."+ritual_type; }

/** @ignore yes */
string query_shadow_ob() { return SHADOWS+"basic_ritual"; }

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

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