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