//You can now throw items at inanimate objects that have the
//targetable property, the bonus for that object is counted
//as the value that this property is set to!
//IE: add_property( "targetable", 300 );
//When a player attempts to throw something, it calls thrown_at( object player,
//int switch ) on the target, with 1 being a hit, and 0 being a miss.
#define CREATOR "Ceres"
#include <player.h>
#include <move_failures.h>
#include <tasks.h>
#define ASKILL "fighting.combat.range.thrown"
#define DSKILL "fighting.combat.dodging.range"
#define PSKILL "fighting.combat.parry.range"
inherit COMMAND_BASE;
/** @ignore yes */
int valid_target( object target, object thrower, object item ) {
mixed owner;
if( target->query_property("dead") ) {
add_failed_mess("What good would throwing $I at a ghost do?\n",
({ item }) );
return 0;
}
if( target->query_auto_loading() ) {
add_failed_mess("Be fair; $I doesn't have all "+
target->HIS+" equipment yet.\n", ({ target }) );
return 0;
}
if( userp( target ) && !interactive( target ) ) {
add_failed_mess("You cannot throw anything at net dead targets.\n");
return 0;
}
if( pk_check( thrower, target ) ) {
add_failed_mess("You decide against throwing $I at "+
target->the_short()+".\n", ({ item }) );
return 0;
}
if( ( owner = target->query_owner() ) && pk_check( thrower, owner ) ) {
add_failed_mess("You decide against throwing $I at "+
target->the_short()+".\n", ({ item }) );
return 0;
}
return 1;
} /* valid_target() */
/** @ignore yes */
int cmd( object *items, object *targets ) {
object target, item;
int dchance, damage;
if( sizeof( items ) > 1 ) {
add_failed_mess("You can only throw one item at a time.\n");
return 0;
}
item = items[ 0 ];
if( sizeof( targets ) > 1 ) {
add_failed_mess( "You can only throw $I at one target at a time.\n",
items );
return 0;
}
target = targets[ 0 ];
if( item->query_wielded() != TP ) {
add_failed_mess("You must be holding $I to throw it.\n", items );
return 0;
}
if( TP == target ) {
add_failed_mess("You cannot throw $I at yourself.\n", items );
return 0;
}
if( !living( target ) && !target->query_property("targetable") ) {
add_failed_mess("Why do you want to throw $I at "+
target->the_short()+"?\n", items );
return 0;
}
if( !valid_target( target, TP, item ) )
return 0;
if ( living( target ) ) {
switch ( (string)target->query_combat_response() ) {
case "dodge" :
dchance = target->query_skill_bonus( DSKILL );
break;
default:
dchance = target->query_skill_bonus( PSKILL );
}
}
else {
dchance = target->query_property( "targetable" );
}
dchance += item->query_weight() / ( this_player()->query_str() / 2 );
if( !this_player()->query_visible( target ) ) {
dchance /= 2;
}
// lets see if they hit or not.
switch( TASKER->perform_task(this_player(), ASKILL, dchance, TM_FREE) ) {
case AWARD:
tell_object(this_player(), "%^YELLOW%^You feel that your "
"skill in throwing weapons has increased.%^RESET%^\n");
case SUCCEED:
tell_object( this_player(), "You throw " + item->the_short() +
" at " + target->the_short() + " and hit!\n" );
tell_room( environment( this_player() ),
this_player()->the_short() + " throws " + item->a_short() +
" at " + target->the_short() + " and hits!\n",
this_player() );
if ( living( target ) ) {
damage = ( item->query_weight() / 4 ) +
( this_player()->query_str() * 2) +
( this_player()->query_skill_bonus( ASKILL ) / 3 );
damage -= target->query_ac( "blunt", damage );
target->attack_by( this_player() );
target->adjust_hp( -damage, this_player() );
this_player()->attack_ob( target );
this_player()->adjust_time_left(-(ROUND_TIME*2));
}
target->thrown_at( this_player(), 1 );
if ( item->move( target ) != MOVE_OK ) {
item->move( environment( target ) );
}
break;
default:
tell_object( this_player(), "You throw " + item->the_short() +
" at " + target->the_short() + " but miss.\n" );
tell_room( environment( this_player() ),
this_player()->the_short() + " throws " + item->a_short() +
" at " + target->the_short() + " but misses.\n", this_player() );
item->move( environment( target ) );
if( !interactive( target ) && living( target ) ) {
this_player()->attack_ob( target );
target->attack_by( this_player() );
}
// They missed, but lets note that anyway.
target->thrown_at( TP, 0 );
break;
}
return 1;
} /* cmd() */
/** @ignore yes */
mixed query_patterns() {
return ({"<indirect:object:me'weapon'> at <indirect:object'target'>",
(: cmd( $1[0], $1[1] ) :) });
} /* query_patterns() */