/** * This is an inherit for special attacks made with weapons. * @author Sandoz, June 2003. */ #define P_SKILL "fighting.combat.special.weapon" #define __SPECIAL_ATTACK_DATA_CLASS__ #include <combat.h> #include <tasks.h> #include <weapon.h> private string skill, name, verb; private class message_data messages; private int cost, learn_level; /** @ignore yes */ void create() { TO->setup(); if( base_name(TO) != __FILE__[0..<3] ) { if( !skill ) error("Weapon skill unset.\n"); if( !name ) error("Attack name unset.\n"); if( !cost ) error("Guild point cost unset.\n"); if( !verb ) verb = name; if( !learn_level ) learn_level = 150; if( !classp(messages) ) { messages = new( class message_data ); messages->attacker = "You tighten the grip on $Dposs and "+ verb+" at $I with full force"; messages->defender = "$N tightens the grip on $Dposs and "+ pluralize(verb)+" at you with full force"; messages->others = "$N tightens the grip on $Dposs and "+ pluralize(verb)+" at $I with full force"; } } } /* create() */ /** * This method queries whether a specific player can learn this command. * @param ob the player to test * @return 1 if they could learn it, 0 if not */ int query_learnable_by( object ob ) { return ob->query_skill(MELEE+skill) >= learn_level && ob->query_skill(P_SKILL) >= learn_level; } /* query_learnable_by() */ /** * This method sets the level at which this command can be learnt. * This is the same for special.weapon and the melee skill used. * @param level the level we can learn this command at */ void set_learn_level( int level ) { learn_level = level; } /** * This method returns the melee skill this command is using. * @return the melee skill used by the command */ string query_attack_skill() { return skill; } /** * This method sets the skill for this special attack. * This should be one of either sharp, pierce, blunt or unarmed * @param str the skill to use */ void set_attack_skill( string str ) { skill = str; } /** * This method sets the name for this special attack. * @param str the attack name to use */ void set_attack_name( string str ) { name = str; } /** * This method sets the verb to use for this special attack. * This is used along with "at" in messages, and isn't needed * if the attack name works with "at" by itself. * @param str the attack verb to use */ void set_attack_verb( string str ) { verb = str; } /** * This method sets the messages to display to the attacker, the target * and the room when this attack is executed. * This message should not include a newline or a period. * String expansion will be done to the following: * $Iposs - possessive short of the target * $I - target's short * $Dposs - possessive short of the weapon * $D - weapon's short * $p - possessive of the target * $r - pronoun of the target * $o - objective of the target * $N - attacker's short (only for the messages to the target and room) * @param attacker the message to display to the attacker * @param target the message to display to the target * @param room the message to display to the room */ void set_attack_messages( string attacker, string target, string room ) { messages = new( class message_data ); messages->attacker = attacker; messages->defender = target; messages->others = room; } /* set_attack_messages() */ /** * This method sets the guild point cost of the command. * @param i the guild point cost to set */ void set_attack_cost( int i ) { cost = i; } /** @ignore yes */ class message_data query_messages( object off, object def, object wep ) { class message_data ret; ret = new( class message_data ); ret->attacker = replace( messages->attacker, ({ "$Iposs", def->poss_short(), "$I", def->the_short(), "$Dposs", wep->poss_short(), "$D", wep == off ? "unarmed combat" : wep->the_short(), "$p ", def->HIS+" ", "$r", def->HE, "$o ", def->HIM+" ", }) ); ret->defender = replace( messages->defender, ({ "$N", off->the_short(), "$Iposs", "your", "$I", "you", "$Dposs", wep->poss_short(), "$D", wep == off ? "unarmed combat" : wep->the_short(), "$p ", "your ", "$r", "you", "$o ", "you ", }) ); ret->others = replace( messages->others, ({ "$N", off->the_short(), "$Iposs", def->poss_short(), "$I", def->the_short(), "$Dposs", wep->poss_short(), "$D", wep == off ? "unarmed combat" : wep->the_short(), "$p ", def->HIS+" ", "$r", def->HE, "$o ", def->HIM+" ", }) ); return ret; } /* parse_mess() */ /** @ignore yes */ class special_attack_data do_special( object off, object def, object wep ) { int i; if( ( i = member_array( name, wep->query_attack_names() ) ) != -1 ) { class special_attack_data ret; mixed data; int j; j = i * W_ARRAY_SIZE; data = wep->query_attack_data()[j..j+W_ARRAY_SIZE-1]; if( data[W_SKILL] == skill ) { int perc, bonus, dam; object *obs; obs = filter( off->query_holding() - ({ 0 }), (: $1->query_weapon() :) ); bonus = off->query_skill_bonus(MELEE+skill); perc = COMBAT_H->calc_attack_percentage( off, off->query_weapons(), obs, 0 ) + bonus; // Weapon damage. j = wep->calc_attack( i, perc ); // Attack damage. dam = sqrt( j * bonus ); // Cap it at 3 * weapon damage as well. if( dam > 3 * j ) dam = 3 * j; dam += bonus / 2; ret = new( class special_attack_data ); ret->attacks = ({ dam, skill, data[W_TYPE], name }); ret->messages = query_messages( off, def, wep ); tell_creator("sandoz", "%s %s damage using %s: %i.\n" "Weapon damage: %i, bonus: %i, percentage: %i, " "attitude: %s.", off->poss_short(), name, wep->a_short(), dam, j, bonus, perc, off->query_combat_attitude() ); return ret; } } tell_object( off, "Oh dear, "+wep->poss_short()+" seems to have " "transmuted and cannot be used to "+name+" anymore.\n"); return 0; } /* special_attack() */ /** @ignore yes */ int cmd( object *targets, object *weps ) { int i; object target, wep; if( sizeof(targets) > 1 ) { add_failed_mess("You can only $V one target at a time.\n"); return 0; } if( sizeof(weps) > 1 ) { add_failed_mess("You can only $V with one weapon at a time.\n"); return 0; } target = targets[ 0 ]; if( !TP->is_fighting( target ) ) { add_failed_mess("You are not fighting $I.\n", targets ); return 0; } wep = weps[ 0 ]; if( wep->query_wielded() != TP ) { add_failed_mess("You are not holding $I.\n", weps ); return 0; } if( ( i = member_array( name, wep->query_attack_names() ) ) != -1 ) { int j; mixed data; j = i * W_ARRAY_SIZE; data = wep->query_attack_data()[j..j+W_ARRAY_SIZE-1]; if( data[W_SKILL] == skill ) { object *obs; if( !TASKER->point_tasker( TP, "fighting", cost ) ) { add_failed_mess("You do not have enough energy to $V $I " "with "+wep->the_short()+".\n", targets ); return 0; } obs = filter( TP->query_holding() - ({ 0 }), (: $1->query_weapon() :) ); j = COMBAT_H->calc_attack_percentage( TP, TP->query_weapons(), obs, 1 ); i = wep->calc_attack( i, j ); if( data[W_CHANCE] < 100 ) i += i * ( 100 - data[W_CHANCE] ) / 50; i += wep->query_weight(); event( TP, "inform", sprintf("%s preparation difficulty: %i", name, i ), "debug"); switch( TASKER->perform_task( TP, P_SKILL, i, TM_COMMAND ) ) { case AWARD: tell_object( TP, "%^YELLOW%^"+({ "You feel more confident in your ability to plan special " "attacks", "You discover a new facet to planning special " "attacks", "You feel more adept at planning special " "attacks"})[ random( 3 ) ]+" as you prepare to "+ name+" "+target->the_short()+" with "+wep->poss_short()+ ".\n%^RESET%^"); case SUCCEED: XP_H->handle_xp( TP, cost, 1 ); TP->register_special_attack( target, wep, (: do_special :), 0, TP->query_skill_bonus(P_SKILL) / 25 ); tell_object( TP, "You clear your mind and prepare to "+ name+" "+target->the_short()+" with "+ wep->poss_short()+".\n"); return 1; default: XP_H->handle_xp( TP, cost, 0 ); add_failed_mess("You attempt to clear your mind to "+name+" "+ target->the_short()+" with "+wep->poss_short()+", " "but the weapon feels too unwieldy and you give up.\n"); return 0; } } } add_failed_mess( wep->the_short()+" does not appear to be a suitable " "weapon to $V with.\n", weps ); return 0; } /* cmd() */ /** @ignore yes */ mixed query_patterns() { return ({ "<indirect:living:here'target'> [with] <indirect:object:me'weapon'>", (: cmd( $1[0], $1[1] ) :), }); } /* query_patterns() */ /** @ignore yes */ mixed stats() { return ({ ({"weapon skill", skill }), ({"name", name }), ({"verb", verb }), ({"cost", cost }), ({"learn level", learn_level }), }); } /* stats() */