/**
* 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; }